]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/radio/radio-tea5761.c
i2c: tea5761: New-style i2c driver
[linux-2.6-omap-h63xx.git] / drivers / media / radio / radio-tea5761.c
1 /*
2  * drivers/media/radio/radio-tea5761.c
3  *
4  * Copyright (C) 2005 Nokia Corporation
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  */
20 #include <linux/module.h>
21 #include <linux/version.h>
22 #include <linux/init.h>
23 #include <linux/i2c.h>
24 #include <linux/delay.h>
25 #include <media/v4l2-common.h>
26
27 #define DRIVER_NAME "tea5761"
28
29 #define TEA5761_VERSION         KERNEL_VERSION(0, 0, 1)
30
31 #define TEA5761_I2C_ADDR        0x10
32
33 #define TEA5761_MANID           0x002b
34 #define TEA5761_CHIPID          0x5761
35
36 #define TEA5761_INTREG_BLMSK    0x0001
37 #define TEA5761_INTREG_FRRMSK   0x0002
38 #define TEA5761_INTREG_LEVMSK   0x0008
39 #define TEA5761_INTREG_IFMSK    0x0010
40 #define TEA5761_INTREG_BLMFLAG  0x0100
41 #define TEA5761_INTREG_FRRFLAG  0x0200
42 #define TEA5761_INTREG_LEVFLAG  0x0800
43 #define TEA5761_INTREG_IFFLAG   0x1000
44
45 #define TEA5761_FRQSET_SUD      0x8000
46 #define TEA5761_FRQSET_SM       0x4000
47
48 #define TEA5761_TNCTRL_PUPD0    0x4000
49 #define TEA5761_TNCTRL_BLIM     0x2000
50 #define TEA5761_TNCTRL_SWPM     0x1000
51 #define TEA5761_TNCTRL_IFCTC    0x0800
52 #define TEA5761_TNCTRL_AFM      0x0400
53 #define TEA5761_TNCTRL_SMUTE    0x0200
54 #define TEA5761_TNCTRL_SNC      0x0100
55 #define TEA5761_TNCTRL_MU       0x0080
56 #define TEA5761_TNCTRL_SSL1     0x0040
57 #define TEA5761_TNCTRL_SSL0     0x0020
58 #define TEA5761_TNCTRL_HLSI     0x0010
59 #define TEA5761_TNCTRL_MST      0x0008
60 #define TEA5761_TNCTRL_SWP      0x0004
61 #define TEA5761_TNCTRL_DTC      0x0002
62 #define TEA5761_TNCTRL_AHLSI    0x0001
63
64 #define TEA5761_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
65 #define TEA5761_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
66 #define TEA5761_TUNCHK_TUNTO    0x0100
67 #define TEA5761_TUNCHK_LD       0x0008
68 #define TEA5761_TUNCHK_STEREO   0x0004
69
70 #define TEA5761_TESTREG_TRIGFR  0x0800
71
72 #define TEA5761_FREQ_LOW        87500
73 #define TEA5761_FREQ_HIGH       108000
74
75 struct tea5761_regs {
76         u16 intreg;
77         u16 frqset;
78         u16 tnctrl;
79         u16 frqchk;
80         u16 tunchk;
81         u16 testreg;
82         u16 manid;
83         u16 chipid;
84 } __attribute__ ((packed));
85
86 struct tea5761_write_regs {
87         u8 intreg;
88         u16 frqset;
89         u16 tnctrl;
90         u16 testreg;
91 } __attribute__ ((packed));
92
93 struct tea5761_device {
94         struct video_device     *video_dev;
95         struct i2c_client       *i2c_dev;
96         struct tea5761_regs     regs;
97         struct mutex            mutex;
98         int                     users;
99 };
100
101 static struct tea5761_device tea5761;
102
103 static struct i2c_driver        tea5761_driver;
104 static int radio_nr = -1;
105
106 static int tea5761_read_regs(struct tea5761_device *tea)
107 {
108         int rc, i;
109         u16 *p = (u16 *) &tea->regs;
110         struct i2c_client *client = tea->i2c_dev;
111
112         rc = i2c_master_recv(client, (void*) &tea->regs, sizeof(tea->regs));
113         for (i = 0; i < 8; i++) {
114                 p[i] = __be16_to_cpu(p[i]);
115         }
116
117         dev_dbg(&client->dev,
118                 "chip state: %04x %04x %04x %04x %04x %04x %04x %04x\n",
119                 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
120
121         if (rc < 0)
122                 dev_err(&client->dev, "read\n");
123
124         return rc;
125 }
126
127 static void tea5761_write_regs(struct tea5761_device *tea)
128 {
129         struct tea5761_write_regs wr;
130         struct tea5761_regs *r = &tea->regs;
131         struct i2c_client *client = tea->i2c_dev;
132         u8 *p = (u8 *) r;
133
134         wr.intreg = r->intreg & 0xff;
135         wr.frqset = __cpu_to_be16(r->frqset);
136         wr.tnctrl = __cpu_to_be16(r->tnctrl);
137         wr.testreg = __cpu_to_be16(r->testreg);
138
139         dev_dbg(&client->dev,
140                 "writing state: %02x %02x %02x %02x %02x %02x %02x\n",
141                 p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
142         if (i2c_master_send(client, (void *) &wr, sizeof(wr)) < 0)
143                 dev_err(&client->dev, "write\n");
144 }
145
146 static void tea5761_power_up(struct tea5761_device *tea)
147 {
148         struct tea5761_regs *r = &tea->regs;
149
150         if (!(r->tnctrl & TEA5761_TNCTRL_PUPD0)) {
151                 r->tnctrl &= ~(TEA5761_TNCTRL_AFM | TEA5761_TNCTRL_MU |
152                                TEA5761_TNCTRL_HLSI);
153                 r->testreg |= TEA5761_TESTREG_TRIGFR;
154                 r->tnctrl |= TEA5761_TNCTRL_PUPD0;
155                 return tea5761_write_regs(tea);
156         }
157 }
158
159 static void tea5761_power_down(struct tea5761_device *tea)
160 {
161         struct tea5761_regs *r = &tea->regs;
162
163         if (r->tnctrl & TEA5761_TNCTRL_PUPD0) {
164                 r->tnctrl &= ~TEA5761_TNCTRL_PUPD0;
165                 return tea5761_write_regs(tea);
166         }
167 }
168
169 static void tea5761_set_freq(struct tea5761_device *tea, int freq)
170 {
171         struct tea5761_regs *r = &tea->regs;
172
173         if (r->tnctrl & TEA5761_TNCTRL_HLSI)
174                 r->frqset = (freq + 225000) / 8192;
175         else
176                 r->frqset = (freq - 225000) / 8192;
177 }
178
179 static int tea5761_get_freq(struct tea5761_device *tea)
180 {
181         struct tea5761_regs *r = &tea->regs;
182
183         if (r->tnctrl & TEA5761_TNCTRL_HLSI)
184                 return (r->frqchk * 8192) - 225000;
185         else
186                 return (r->frqchk * 8192) + 225000;
187 }
188
189 static void tea5761_tune(struct tea5761_device *tea, int freq)
190 {
191         tea5761_set_freq(tea, freq);
192         tea5761_write_regs(tea);
193 }
194
195 static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode)
196 {
197         struct tea5761_regs *r = &tea->regs;
198         int tnctrl = r->tnctrl;
199
200         if (audmode == V4L2_TUNER_MODE_MONO)
201                 r->tnctrl |= TEA5761_TNCTRL_MST;
202         else
203                 r->tnctrl &= ~TEA5761_TNCTRL_MST;
204         if (tnctrl != r->tnctrl)
205                 tea5761_write_regs(tea);
206 }
207
208 static int tea5761_get_audout_mode(struct tea5761_device *tea)
209 {
210         struct tea5761_regs *r = &tea->regs;
211
212         if (r->tnctrl & TEA5761_TNCTRL_MST)
213                 return V4L2_TUNER_MODE_MONO;
214         else
215                 return V4L2_TUNER_MODE_STEREO;
216 }
217
218 static void tea5761_mute(struct tea5761_device *tea, int on)
219 {
220         struct tea5761_regs *r = &tea->regs;
221         int tnctrl = r->tnctrl;
222
223         if (on)
224                 r->tnctrl |= TEA5761_TNCTRL_MU;
225         else
226                 r->tnctrl &= ~TEA5761_TNCTRL_MU;
227         if (tnctrl != r->tnctrl)
228                 tea5761_write_regs(tea);
229 }
230
231 static int tea5761_is_muted(struct tea5761_device *tea)
232 {
233         return tea->regs.tnctrl & TEA5761_TNCTRL_MU;
234 }
235
236 static int tea5761_do_ioctl(struct inode *inode, struct file *file,
237                             unsigned int cmd, void *arg)
238 {
239         struct tea5761_device *tea = file->private_data;
240         struct video_device *dev = tea->video_dev;
241         struct i2c_client *client = tea->i2c_dev;
242         struct tea5761_regs *r = &tea->regs;
243
244         union {
245                 struct v4l2_capability c;
246                 struct v4l2_tuner t;
247                 struct v4l2_frequency f;
248                 struct v4l2_queryctrl qc;
249                 struct v4l2_control ct;
250         } *u = arg;
251
252         tea5761_read_regs(tea);
253
254         switch (cmd) {
255         case VIDIOC_QUERYCAP:
256                 dev_dbg(&client->dev, "VIDIOC_QUERYCAP\n");
257                 memset(&u->c, 0, sizeof(u->c));
258                 strlcpy(u->c.driver, dev->dev->driver->name,
259                         sizeof(u->c.driver));
260                 strlcpy(u->c.card, dev->name, sizeof(u->c.card));
261                 snprintf(u->c.bus_info, sizeof(u->c.bus_info), "I2C:%s",
262                          dev->dev->bus_id);
263                 u->c.version = TEA5761_VERSION;
264                 u->c.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
265                 break;
266
267         case VIDIOC_G_TUNER:
268                 /* Only one tuner chip */
269                 dev_dbg(&client->dev, "VIDIOC_G_TUNER\n");
270                 if (u->t.index != 0)
271                         return -EINVAL;
272
273                 memset(&u->t, 0, sizeof(u->t));
274                 u->t.type = V4L2_TUNER_RADIO;
275                 strlcpy(u->t.name, "FM", sizeof(u->t.name));
276                 /* Freq in 62.5Hz units */
277                 u->t.rangelow = TEA5761_FREQ_LOW * 16;
278                 u->t.rangehigh = TEA5761_FREQ_HIGH * 16;
279                 u->t.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
280                 if (r->tunchk & TEA5761_TUNCHK_STEREO)
281                         u->t.rxsubchans = V4L2_TUNER_SUB_STEREO;
282                 u->t.audmode = tea5761_get_audout_mode(tea);
283                 u->t.signal = TEA5761_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
284                 u->t.afc = TEA5761_TUNCHK_IFCNT(r->tunchk);
285                 break;
286
287         case VIDIOC_S_TUNER:
288                 /* Only tuner nro 0 can be selected. */
289                 dev_dbg(&client->dev, "VIDIOC_S_TUNER\n");
290                 if (u->t.index != 0)
291                         return -EINVAL;
292                 tea5761_set_audout_mode(tea, u->t.audmode);
293                 break;
294
295         case VIDIOC_G_FREQUENCY:
296                 dev_dbg(&client->dev, "VIDIOC_G_FREQUENCY\n");
297                 memset(&u->f, 0, sizeof(u->f));
298                 u->f.type = V4L2_TUNER_RADIO;
299                 if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
300                         u->f.frequency = (tea5761_get_freq(tea) * 2) / 125;
301                 else
302                         u->f.frequency = 0;
303                 break;
304
305         case VIDIOC_S_FREQUENCY:
306                 dev_dbg(&client->dev, "VIDIOC_S_FREQUENCY %u\n",
307                         u->f.frequency);
308                 if (u->f.tuner != 0)
309                         return -EINVAL;
310                 if (u->f.frequency == 0) {
311                         /* We special case this as a power down
312                          * control. */
313                         tea5761_power_down(tea);
314                         break;
315                 }
316                 if (u->f.frequency < 16 * TEA5761_FREQ_LOW)
317                         return -EINVAL;
318                 if (u->f.frequency > 16 * TEA5761_FREQ_HIGH)
319                         return -EINVAL;
320
321                 tea5761_power_up(tea);
322                 tea5761_tune(tea, (u->f.frequency * 125) / 2);
323                 break;
324
325         case VIDIOC_QUERYCTRL:
326                 dev_dbg(&client->dev, "VIDIOC_QUERYCTRL %d\n", u->qc.id);
327                 if (u->qc.id != V4L2_CID_AUDIO_MUTE)
328                         return -EINVAL;
329                 strlcpy(u->qc.name, "Mute", sizeof(u->qc.name));
330                 u->qc.minimum = 0;
331                 u->qc.maximum = 1;
332                 u->qc.step = 1;
333                 u->qc.default_value = 0;
334                 u->qc.type = V4L2_CTRL_TYPE_BOOLEAN;
335                 break;
336
337         case VIDIOC_G_CTRL:
338                 dev_dbg(&client->dev, "VIDIOC_G_CTRL %d\n", u->ct.id);
339                 if (u->ct.id != V4L2_CID_AUDIO_MUTE)
340                         return -EINVAL;
341                 if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
342                         u->ct.value = tea5761_is_muted(tea) ? 1 : 0;
343                 else
344                         u->ct.value = 0;
345                 break;
346
347         case VIDIOC_S_CTRL:
348                 dev_dbg(&client->dev, "VIDIOC_S_CTRL %d\n", u->ct.id);
349                 if (u->ct.id != V4L2_CID_AUDIO_MUTE)
350                         return -EINVAL;
351                 tea5761_mute(tea, u->ct.value);
352                 break;
353
354         default:
355                 return -ENOIOCTLCMD;
356         }
357
358         return 0;
359 }
360
361 static int tea5761_ioctl(struct inode *inode, struct file *file,
362                          unsigned int cmd, unsigned long arg)
363 {
364         return video_usercopy(inode, file, cmd, arg, tea5761_do_ioctl);
365 }
366
367 static int tea5761_open(struct inode *inode, struct file *file)
368 {
369         int minor = iminor(file->f_dentry->d_inode);
370         /* Currently we support only one device */
371         struct tea5761_device *tea = &tea5761;
372
373         if (tea->video_dev->minor != minor)
374                 return -ENODEV;
375
376         mutex_lock(&tea->mutex);
377         /* Only exclusive access */
378         if (tea->users) {
379                 mutex_unlock(&tea->mutex);
380                 return -EBUSY;
381         }
382         tea->users++;
383         mutex_unlock(&tea->mutex);
384
385         file->private_data = tea;
386         return 0;
387 }
388
389 static int tea5761_release(struct inode *inode, struct file *file)
390 {
391         struct tea5761_device *tea = file->private_data;
392
393         mutex_lock(&tea->mutex);
394         tea->users--;
395         mutex_unlock(&tea->mutex);
396
397         return 0;
398 }
399
400 static struct file_operations tea5761_fops = {
401         .owner          = THIS_MODULE,
402         .open           = tea5761_open,
403         .release        = tea5761_release,
404         .ioctl          = tea5761_ioctl,
405         .llseek         = no_llseek,
406 };
407
408 static struct video_device tea5761_video_device = {
409         .owner         = THIS_MODULE,
410         .name          = "TEA5761 FM-Radio",
411         .type          = VID_TYPE_TUNER,
412         .fops          = &tea5761_fops,
413         .release       = video_device_release
414 };
415
416 static int tea5761_i2c_driver_probe(struct i2c_client *client)
417 {
418         struct video_device *video_dev;
419         int err = 0;
420         struct tea5761_device *tea = &tea5761;
421
422         mutex_init(&tea->mutex);
423
424         tea->i2c_dev = client;
425
426         /* V4L initialization */
427         video_dev = video_device_alloc();
428         if (video_dev == NULL) {
429                 dev_err(&client->dev, "couldn't allocate memory\n");
430                 err = -ENOMEM;
431                 goto exit;
432         }
433         tea->video_dev = video_dev;
434
435         *video_dev = tea5761_video_device;
436         video_dev->dev = &client->dev;
437         i2c_set_clientdata(client, video_dev);
438
439         /* initialize and power off the chip */
440         tea5761_read_regs(tea);
441         tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
442         tea5761_mute(tea, 0);
443         tea5761_power_down(tea);
444
445         tea5761.video_dev = video_dev;
446         tea5761.i2c_dev = client;
447
448         err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr);
449         if (err) {
450                 dev_err(&client->dev, "couldn't register video device\n");
451                 goto err_video_alloc;
452         }
453
454         dev_info(&client->dev, "tea5761 (version %d) detected\n",
455                 (tea->regs.manid >> 12) & 0xf);
456
457         return 0;
458
459 err_video_alloc:
460         video_device_release(video_dev);
461 exit:
462         kfree(client);
463         return err;
464 }
465
466 static int tea5761_i2c_driver_remove(struct i2c_client *client)
467 {
468         struct video_device *vd = i2c_get_clientdata(client);
469
470         video_unregister_device(vd);
471
472         return 0;
473 }
474
475 static struct i2c_driver tea5761_driver = {
476         .driver = {
477                 .name   = DRIVER_NAME,
478         },
479         .probe  = tea5761_i2c_driver_probe,
480         .remove = tea5761_i2c_driver_remove,
481 };
482
483 static int __init tea5761_init(void)
484 {
485         int res;
486
487         if ((res = i2c_add_driver(&tea5761_driver))) {
488                 printk(KERN_ERR DRIVER_NAME ": driver registration failed\n");
489                 return res;
490         }
491
492         return 0;
493 }
494
495 static void __exit tea5761_exit(void)
496 {
497         i2c_del_driver(&tea5761_driver);
498 }
499
500 MODULE_AUTHOR("Timo Teräs");
501 MODULE_DESCRIPTION("I2C interface for TEA5761.");
502 MODULE_LICENSE("GPL");
503
504 module_param(radio_nr, int, 0);
505 MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
506
507 module_init(tea5761_init)
508 module_exit(tea5761_exit)