Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / 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
34 MODULE_DESCRIPTION("wm8739 driver");
35 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
36 MODULE_LICENSE("GPL");
37
38 static int debug = 0;
39 static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
40
41 module_param(debug, int, 0644);
42
43 MODULE_PARM_DESC(debug, "Debug level (0-1)");
44
45
46 I2C_CLIENT_INSMOD;
47
48 /* ------------------------------------------------------------------------ */
49
50 enum {
51         R0 = 0, R1,
52         R5 = 5, R6, R7, R8, R9, R15 = 15,
53         TOT_REGS
54 };
55
56 struct wm8739_state {
57         u32 clock_freq;
58         u8 muted;
59         u16 volume;
60         u16 balance;
61         u8 vol_l;               /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
62         u8 vol_r;               /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
63 };
64
65 /* ------------------------------------------------------------------------ */
66
67 static int wm8739_write(struct i2c_client *client, int reg, u16 val)
68 {
69         int i;
70
71         if (reg < 0 || reg >= TOT_REGS) {
72                 v4l_err(client, "Invalid register R%d\n", reg);
73                 return -1;
74         }
75
76         v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
77
78         for (i = 0; i < 3; i++) {
79                 if (i2c_smbus_write_byte_data(client, (reg << 1) |
80                                         (val >> 8), val & 0xff) == 0) {
81                         return 0;
82                 }
83         }
84         v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
85         return -1;
86 }
87
88 /* write regs to set audio volume etc */
89 static void wm8739_set_audio(struct i2c_client *client)
90 {
91         struct wm8739_state *state = i2c_get_clientdata(client);
92         u16 mute = state->muted ? 0x80 : 0;
93
94         /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
95          * Default setting: 0x17 = 0 dB
96          */
97         wm8739_write(client, R0, (state->vol_l & 0x1f) | mute);
98         wm8739_write(client, R1, (state->vol_r & 0x1f) | mute);
99 }
100
101 static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
102 {
103         struct wm8739_state *state = i2c_get_clientdata(client);
104
105         switch (ctrl->id) {
106         case V4L2_CID_AUDIO_MUTE:
107                 ctrl->value = state->muted;
108                 break;
109
110         case V4L2_CID_AUDIO_VOLUME:
111                 ctrl->value = state->volume;
112                 break;
113
114         case V4L2_CID_AUDIO_BALANCE:
115                 ctrl->value = state->balance;
116                 break;
117
118         default:
119                 return -EINVAL;
120         }
121         return 0;
122 }
123
124 static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
125 {
126         struct wm8739_state *state = i2c_get_clientdata(client);
127         unsigned int work_l, work_r;
128
129         switch (ctrl->id) {
130         case V4L2_CID_AUDIO_MUTE:
131                 state->muted = ctrl->value;
132                 break;
133
134         case V4L2_CID_AUDIO_VOLUME:
135                 state->volume = ctrl->value;
136                 break;
137
138         case V4L2_CID_AUDIO_BALANCE:
139                 state->balance = ctrl->value;
140                 break;
141
142         default:
143                 return -EINVAL;
144         }
145
146         /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
147         work_l = (min(65536 - state->balance, 32768) * state->volume) / 32768;
148         work_r = (min(state->balance, (u16)32768) * state->volume) / 32768;
149
150         state->vol_l = (long)work_l * 31 / 65535;
151         state->vol_r = (long)work_r * 31 / 65535;
152
153         /* set audio volume etc. */
154         wm8739_set_audio(client);
155         return 0;
156 }
157
158 /* ------------------------------------------------------------------------ */
159
160 static struct v4l2_queryctrl wm8739_qctrl[] = {
161         {
162                 .id            = V4L2_CID_AUDIO_VOLUME,
163                 .name          = "Volume",
164                 .minimum       = 0,
165                 .maximum       = 65535,
166                 .step          = 65535/100,
167                 .default_value = 58880,
168                 .flags         = 0,
169                 .type          = V4L2_CTRL_TYPE_INTEGER,
170         },{
171                 .id            = V4L2_CID_AUDIO_MUTE,
172                 .name          = "Mute",
173                 .minimum       = 0,
174                 .maximum       = 1,
175                 .step          = 1,
176                 .default_value = 1,
177                 .flags         = 0,
178                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
179         },{
180                 .id            = V4L2_CID_AUDIO_BALANCE,
181                 .name          = "Balance",
182                 .minimum       = 0,
183                 .maximum       = 65535,
184                 .step          = 65535/100,
185                 .default_value = 32768,
186                 .flags         = 0,
187                 .type          = V4L2_CTRL_TYPE_INTEGER,
188         }
189 };
190
191 /* ------------------------------------------------------------------------ */
192
193 static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg)
194 {
195         struct wm8739_state *state = i2c_get_clientdata(client);
196
197         switch (cmd) {
198         case VIDIOC_INT_AUDIO_CLOCK_FREQ:
199         {
200                 u32 audiofreq = *(u32 *)arg;
201
202                 state->clock_freq = audiofreq;
203                 wm8739_write(client, R9, 0x000);        /* de-activate */
204                 switch (audiofreq) {
205                 case 44100:
206                         wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k     */
207                         break;
208                 case 48000:
209                         wm8739_write(client, R8, 0x000); /* 256fps, fs=48k       */
210                         break;
211                 case 32000:
212                         wm8739_write(client, R8, 0x018); /* 256fps, fs=32k       */
213                         break;
214                 default:
215                         break;
216                 }
217                 wm8739_write(client, R9, 0x001);        /* activate */
218                 break;
219         }
220
221         case VIDIOC_G_CTRL:
222                 return wm8739_get_ctrl(client, arg);
223
224         case VIDIOC_S_CTRL:
225                 return wm8739_set_ctrl(client, arg);
226
227         case VIDIOC_QUERYCTRL:
228         {
229                 struct v4l2_queryctrl *qc = arg;
230                 int i;
231
232                 for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
233                         if (qc->id && qc->id == wm8739_qctrl[i].id) {
234                                 memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
235                                 return 0;
236                         }
237                 return -EINVAL;
238         }
239
240         case VIDIOC_G_CHIP_IDENT:
241                 return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
242
243         case VIDIOC_LOG_STATUS:
244                 v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
245                 v4l_info(client, "Volume L:  %02x%s\n", state->vol_l & 0x1f,
246                                 state->muted ? " (muted)" : "");
247                 v4l_info(client, "Volume R:  %02x%s\n", state->vol_r & 0x1f,
248                                 state->muted ? " (muted)" : "");
249                 break;
250
251         default:
252                 return -EINVAL;
253         }
254
255         return 0;
256 }
257
258 /* ------------------------------------------------------------------------ */
259
260 /* i2c implementation */
261
262 static struct i2c_driver i2c_driver;
263
264 static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
265 {
266         struct i2c_client *client;
267         struct wm8739_state *state;
268
269         /* Check if the adapter supports the needed features */
270         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
271                 return 0;
272
273         client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
274         if (client == NULL)
275                 return -ENOMEM;
276
277         client->addr = address;
278         client->adapter = adapter;
279         client->driver = &i2c_driver;
280         snprintf(client->name, sizeof(client->name) - 1, "wm8739");
281
282         v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
283
284         state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
285         if (state == NULL) {
286                 kfree(client);
287                 return -ENOMEM;
288         }
289         state->vol_l = 0x17; /* 0dB */
290         state->vol_r = 0x17; /* 0dB */
291         state->muted = 0;
292         state->balance = 32768;
293         /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */
294         state->volume = ((long)state->vol_l + 1) * 65535 / 31;
295         state->clock_freq = 48000;
296         i2c_set_clientdata(client, state);
297
298         /* initialize wm8739 */
299         wm8739_write(client, R15, 0x00); /* reset */
300         wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */
301         wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */
302         wm8739_write(client, R7, 0x049); /* Digital Audio interface format */
303                                          /* Enable Master mode */
304                                          /* 24 bit, MSB first/left justified */
305         wm8739_write(client, R8, 0x000); /* sampling control */
306                                          /* normal, 256fs, 48KHz sampling rate */
307         wm8739_write(client, R9, 0x001); /* activate */
308         wm8739_set_audio(client);        /* set volume/mute */
309
310         i2c_attach_client(client);
311
312         return 0;
313 }
314
315 static int wm8739_probe(struct i2c_adapter *adapter)
316 {
317         if (adapter->class & I2C_CLASS_TV_ANALOG)
318                 return i2c_probe(adapter, &addr_data, wm8739_attach);
319         return 0;
320 }
321
322 static int wm8739_detach(struct i2c_client *client)
323 {
324         struct wm8739_state *state = i2c_get_clientdata(client);
325         int err;
326
327         err = i2c_detach_client(client);
328         if (err)
329                 return err;
330
331         kfree(state);
332         kfree(client);
333         return 0;
334 }
335
336 /* ----------------------------------------------------------------------- */
337
338 /* i2c implementation */
339 static struct i2c_driver i2c_driver = {
340         .driver = {
341                 .name = "wm8739",
342         },
343         .id = I2C_DRIVERID_WM8739,
344         .attach_adapter = wm8739_probe,
345         .detach_client  = wm8739_detach,
346         .command = wm8739_command,
347 };
348
349
350 static int __init wm8739_init_module(void)
351 {
352         return i2c_add_driver(&i2c_driver);
353 }
354
355 static void __exit wm8739_cleanup_module(void)
356 {
357         i2c_del_driver(&i2c_driver);
358 }
359
360 module_init(wm8739_init_module);
361 module_exit(wm8739_cleanup_module);