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