]> err.no Git - linux-2.6/blob - drivers/media/video/wm8739.c
Merge git://git.infradead.org/battery-2.6
[linux-2.6] / drivers / media / video / wm8739.c
1 /*
2  * wm8739
3  *
4  * Copyright (C) 2005 T. Adachi <tadachi@tadachi-net.com>
5  *
6  * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
7  * - Cleanup
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <linux/module.h>
25 #include <linux/types.h>
26 #include <linux/ioctl.h>
27 #include <asm/uaccess.h>
28 #include <linux/i2c.h>
29 #include <linux/i2c-id.h>
30 #include <linux/videodev.h>
31 #include <media/v4l2-common.h>
32 #include <media/v4l2-chip-ident.h>
33 #include <media/v4l2-i2c-drv.h>
34
35 MODULE_DESCRIPTION("wm8739 driver");
36 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
37 MODULE_LICENSE("GPL");
38
39 static int debug;
40
41 module_param(debug, int, 0644);
42
43 MODULE_PARM_DESC(debug, "Debug level (0-1)");
44
45
46 /* ------------------------------------------------------------------------ */
47
48 enum {
49         R0 = 0, R1,
50         R5 = 5, R6, R7, R8, R9, R15 = 15,
51         TOT_REGS
52 };
53
54 struct wm8739_state {
55         u32 clock_freq;
56         u8 muted;
57         u16 volume;
58         u16 balance;
59         u8 vol_l;               /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
60         u8 vol_r;               /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
61 };
62
63 /* ------------------------------------------------------------------------ */
64
65 static int wm8739_write(struct i2c_client *client, int reg, u16 val)
66 {
67         int i;
68
69         if (reg < 0 || reg >= TOT_REGS) {
70                 v4l_err(client, "Invalid register R%d\n", reg);
71                 return -1;
72         }
73
74         v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
75
76         for (i = 0; i < 3; i++)
77                 if (i2c_smbus_write_byte_data(client,
78                                 (reg << 1) | (val >> 8), val & 0xff) == 0)
79                         return 0;
80         v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
81         return -1;
82 }
83
84 /* write regs to set audio volume etc */
85 static void wm8739_set_audio(struct i2c_client *client)
86 {
87         struct wm8739_state *state = i2c_get_clientdata(client);
88         u16 mute = state->muted ? 0x80 : 0;
89
90         /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
91          * Default setting: 0x17 = 0 dB
92          */
93         wm8739_write(client, R0, (state->vol_l & 0x1f) | mute);
94         wm8739_write(client, R1, (state->vol_r & 0x1f) | mute);
95 }
96
97 static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
98 {
99         struct wm8739_state *state = i2c_get_clientdata(client);
100
101         switch (ctrl->id) {
102         case V4L2_CID_AUDIO_MUTE:
103                 ctrl->value = state->muted;
104                 break;
105
106         case V4L2_CID_AUDIO_VOLUME:
107                 ctrl->value = state->volume;
108                 break;
109
110         case V4L2_CID_AUDIO_BALANCE:
111                 ctrl->value = state->balance;
112                 break;
113
114         default:
115                 return -EINVAL;
116         }
117         return 0;
118 }
119
120 static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
121 {
122         struct wm8739_state *state = i2c_get_clientdata(client);
123         unsigned int work_l, work_r;
124
125         switch (ctrl->id) {
126         case V4L2_CID_AUDIO_MUTE:
127                 state->muted = ctrl->value;
128                 break;
129
130         case V4L2_CID_AUDIO_VOLUME:
131                 state->volume = ctrl->value;
132                 break;
133
134         case V4L2_CID_AUDIO_BALANCE:
135                 state->balance = ctrl->value;
136                 break;
137
138         default:
139                 return -EINVAL;
140         }
141
142         /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
143         work_l = (min(65536 - state->balance, 32768) * state->volume) / 32768;
144         work_r = (min(state->balance, (u16)32768) * state->volume) / 32768;
145
146         state->vol_l = (long)work_l * 31 / 65535;
147         state->vol_r = (long)work_r * 31 / 65535;
148
149         /* set audio volume etc. */
150         wm8739_set_audio(client);
151         return 0;
152 }
153
154 /* ------------------------------------------------------------------------ */
155
156 static struct v4l2_queryctrl wm8739_qctrl[] = {
157         {
158                 .id            = V4L2_CID_AUDIO_VOLUME,
159                 .name          = "Volume",
160                 .minimum       = 0,
161                 .maximum       = 65535,
162                 .step          = 65535/100,
163                 .default_value = 58880,
164                 .flags         = 0,
165                 .type          = V4L2_CTRL_TYPE_INTEGER,
166         }, {
167                 .id            = V4L2_CID_AUDIO_MUTE,
168                 .name          = "Mute",
169                 .minimum       = 0,
170                 .maximum       = 1,
171                 .step          = 1,
172                 .default_value = 1,
173                 .flags         = 0,
174                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
175         }, {
176                 .id            = V4L2_CID_AUDIO_BALANCE,
177                 .name          = "Balance",
178                 .minimum       = 0,
179                 .maximum       = 65535,
180                 .step          = 65535/100,
181                 .default_value = 32768,
182                 .flags         = 0,
183                 .type          = V4L2_CTRL_TYPE_INTEGER,
184         }
185 };
186
187 /* ------------------------------------------------------------------------ */
188
189 static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
190 {
191         struct wm8739_state *state = i2c_get_clientdata(client);
192
193         switch (cmd) {
194         case VIDIOC_INT_AUDIO_CLOCK_FREQ:
195         {
196                 u32 audiofreq = *(u32 *)arg;
197
198                 state->clock_freq = audiofreq;
199                 /* de-activate */
200                 wm8739_write(client, R9, 0x000);
201                 switch (audiofreq) {
202                 case 44100:
203                         /* 256fps, fs=44.1k */
204                         wm8739_write(client, R8, 0x020);
205                         break;
206                 case 48000:
207                         /* 256fps, fs=48k */
208                         wm8739_write(client, R8, 0x000);
209                         break;
210                 case 32000:
211                         /* 256fps, fs=32k */
212                         wm8739_write(client, R8, 0x018);
213                         break;
214                 default:
215                         break;
216                 }
217                 /* activate */
218                 wm8739_write(client, R9, 0x001);
219                 break;
220         }
221
222         case VIDIOC_G_CTRL:
223                 return wm8739_get_ctrl(client, arg);
224
225         case VIDIOC_S_CTRL:
226                 return wm8739_set_ctrl(client, arg);
227
228         case VIDIOC_QUERYCTRL:
229         {
230                 struct v4l2_queryctrl *qc = arg;
231                 int i;
232
233                 for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
234                         if (qc->id && qc->id == wm8739_qctrl[i].id) {
235                                 memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
236                                 return 0;
237                         }
238                 return -EINVAL;
239         }
240
241         case VIDIOC_G_CHIP_IDENT:
242                 return v4l2_chip_ident_i2c_client(client,
243                                 arg, V4L2_IDENT_WM8739, 0);
244
245         case VIDIOC_LOG_STATUS:
246                 v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
247                 v4l_info(client, "Volume L:  %02x%s\n", state->vol_l & 0x1f,
248                                 state->muted ? " (muted)" : "");
249                 v4l_info(client, "Volume R:  %02x%s\n", state->vol_r & 0x1f,
250                                 state->muted ? " (muted)" : "");
251                 break;
252
253         default:
254                 return -EINVAL;
255         }
256
257         return 0;
258 }
259
260 /* ------------------------------------------------------------------------ */
261
262 /* i2c implementation */
263
264 static int wm8739_probe(struct i2c_client *client,
265                         const struct i2c_device_id *id)
266 {
267         struct wm8739_state *state;
268
269         /* Check if the adapter supports the needed features */
270         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
271                 return -EIO;
272
273         v4l_info(client, "chip found @ 0x%x (%s)\n",
274                         client->addr << 1, client->adapter->name);
275
276         state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
277         if (state == NULL) {
278                 kfree(client);
279                 return -ENOMEM;
280         }
281         state->vol_l = 0x17; /* 0dB */
282         state->vol_r = 0x17; /* 0dB */
283         state->muted = 0;
284         state->balance = 32768;
285         /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */
286         state->volume = ((long)state->vol_l + 1) * 65535 / 31;
287         state->clock_freq = 48000;
288         i2c_set_clientdata(client, state);
289
290         /* Initialize wm8739 */
291
292         /* reset */
293         wm8739_write(client, R15, 0x00);
294         /* filter setting, high path, offet clear */
295         wm8739_write(client, R5, 0x000);
296         /* ADC, OSC, Power Off mode Disable */
297         wm8739_write(client, R6, 0x000);
298         /* Digital Audio interface format:
299            Enable Master mode, 24 bit, MSB first/left justified */
300         wm8739_write(client, R7, 0x049);
301         /* sampling control: normal, 256fs, 48KHz sampling rate */
302         wm8739_write(client, R8, 0x000);
303         /* activate */
304         wm8739_write(client, R9, 0x001);
305         /* set volume/mute */
306         wm8739_set_audio(client);
307         return 0;
308 }
309
310 static int wm8739_remove(struct i2c_client *client)
311 {
312         kfree(i2c_get_clientdata(client));
313         return 0;
314 }
315
316 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
317         .name = "wm8739",
318         .driverid = I2C_DRIVERID_WM8739,
319         .command = wm8739_command,
320         .probe = wm8739_probe,
321         .remove = wm8739_remove,
322 };
323