blob: 16939cad987cde2c2bb1d98552f7946bfee3a959 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * i2c tv tuner chip device driver
4 * core core, i.e. kernel interfaces, registering and so on
5 */
6
7#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/string.h>
10#include <linux/timer.h>
11#include <linux/delay.h>
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/poll.h>
15#include <linux/i2c.h>
16#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/init.h>
Hans Verkuil75b4c262009-04-01 03:32:22 -030018#include <linux/videodev2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <media/tuner.h>
Michael Krufky4adad282007-08-27 21:59:08 -030020#include <media/tuner-types.h>
Hans Verkuile8a4a9e2008-11-24 18:21:40 -030021#include <media/v4l2-device.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030022#include <media/v4l2-ioctl.h>
Michael Krufky96c0b7c2007-08-27 21:23:08 -030023#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030024#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030025#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030026#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030027#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030028#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030029#include "tda9887.h"
Steven Toth27c685a2008-01-05 16:50:14 -030030#include "xc5000.h"
Michael Krufky93463892009-09-15 23:04:18 -030031#include "tda18271.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#define UNSET (-1U)
34
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -030035#define PREFIX (t->i2c->driver->driver.name)
Michael Krufky241020d2007-10-30 09:46:10 -030036
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -030037/*
38 * Driver modprobe parameters
39 */
40
41/* insmod options used at init time => read/only */
42static unsigned int addr;
43static unsigned int no_autodetect;
44static unsigned int show_i2c;
45
46module_param(addr, int, 0444);
47module_param(no_autodetect, int, 0444);
48module_param(show_i2c, int, 0444);
49
50/* insmod options used at runtime => read/write */
51static int tuner_debug;
52static unsigned int tv_range[2] = { 44, 958 };
53static unsigned int radio_range[2] = { 65, 108 };
54static char pal[] = "--";
55static char secam[] = "--";
56static char ntsc[] = "-";
57
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -030058module_param_named(debug, tuner_debug, int, 0644);
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -030059module_param_array(tv_range, int, NULL, 0644);
60module_param_array(radio_range, int, NULL, 0644);
61module_param_string(pal, pal, sizeof(pal), 0644);
62module_param_string(secam, secam, sizeof(secam), 0644);
63module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
64
65/*
66 * Static vars
67 */
68
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -030069static LIST_HEAD(tuner_list);
70
71/*
72 * Debug macros
73 */
74
75#define tuner_warn(fmt, arg...) do { \
76 printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
77 i2c_adapter_id(t->i2c->adapter), \
78 t->i2c->addr, ##arg); \
79 } while (0)
80
81#define tuner_info(fmt, arg...) do { \
82 printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
83 i2c_adapter_id(t->i2c->adapter), \
84 t->i2c->addr, ##arg); \
85 } while (0)
86
87#define tuner_err(fmt, arg...) do { \
88 printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
89 i2c_adapter_id(t->i2c->adapter), \
90 t->i2c->addr, ##arg); \
91 } while (0)
92
93#define tuner_dbg(fmt, arg...) do { \
94 if (tuner_debug) \
95 printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
96 i2c_adapter_id(t->i2c->adapter), \
97 t->i2c->addr, ##arg); \
98 } while (0)
99
100/*
101 * Internal struct used inside the driver
102 */
103
104struct tuner {
105 /* device */
106 struct dvb_frontend fe;
107 struct i2c_client *i2c;
108 struct v4l2_subdev sd;
109 struct list_head list;
110
111 /* keep track of the current settings */
112 v4l2_std_id std;
113 unsigned int tv_freq;
114 unsigned int radio_freq;
115 unsigned int audmode;
116
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300117 enum v4l2_tuner_type mode;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300118 unsigned int mode_mask; /* Combination of allowable modes */
119
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300120 bool standby; /* Standby mode */
121
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300122 unsigned int type; /* chip type id */
123 unsigned int config;
124 const char *name;
125};
126
127/*
128 * tuner attach/detach logic
129 */
130
Michael Krufkya07c8772008-04-29 03:54:19 -0300131/** This macro allows us to probe dynamically, avoiding static links */
Mauro Carvalho Chehabff138172008-04-29 23:02:33 -0300132#ifdef CONFIG_MEDIA_ATTACH
Michael Krufkya07c8772008-04-29 03:54:19 -0300133#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
134 int __r = -EINVAL; \
135 typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
136 if (__a) { \
137 __r = (int) __a(ARGS); \
Andrew Mortona1355e52008-04-30 11:40:17 -0300138 symbol_put(FUNCTION); \
Michael Krufkya07c8772008-04-29 03:54:19 -0300139 } else { \
140 printk(KERN_ERR "TUNER: Unable to find " \
141 "symbol "#FUNCTION"()\n"); \
142 } \
Michael Krufkya07c8772008-04-29 03:54:19 -0300143 __r; \
144})
145
146static void tuner_detach(struct dvb_frontend *fe)
147{
148 if (fe->ops.tuner_ops.release) {
149 fe->ops.tuner_ops.release(fe);
150 symbol_put_addr(fe->ops.tuner_ops.release);
151 }
152 if (fe->ops.analog_ops.release) {
153 fe->ops.analog_ops.release(fe);
154 symbol_put_addr(fe->ops.analog_ops.release);
155 }
156}
157#else
158#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
159 FUNCTION(ARGS); \
160})
161
162static void tuner_detach(struct dvb_frontend *fe)
163{
164 if (fe->ops.tuner_ops.release)
165 fe->ops.tuner_ops.release(fe);
166 if (fe->ops.analog_ops.release)
167 fe->ops.analog_ops.release(fe);
168}
169#endif
170
Michael Krufkyf7f427e2007-12-16 22:02:26 -0300171
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300172static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
173{
174 return container_of(sd, struct tuner, sd);
175}
176
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300177/*
178 * struct analog_demod_ops callbacks
179 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Michael Krufkyc7919d52007-12-08 17:06:30 -0300181static void fe_set_params(struct dvb_frontend *fe,
182 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -0300183{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300184 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
185 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -0300186
Michael Krufkye18f9442007-08-21 01:25:48 -0300187 if (NULL == fe_tuner_ops->set_analog_params) {
188 tuner_warn("Tuner frontend module has no way to set freq\n");
189 return;
190 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300191 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300192}
193
Michael Krufky4e9154b2007-10-21 19:39:50 -0300194static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300195{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300196 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300197
198 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300199 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300200}
201
Michael Krufky4e9154b2007-10-21 19:39:50 -0300202static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300203{
Michael Krufky14196832007-10-14 18:11:53 -0300204 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300205
Michael Krufky4e9154b2007-10-21 19:39:50 -0300206 if (fe->ops.tuner_ops.get_rf_strength)
207 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300208
209 return strength;
210}
211
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300212static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
213{
214 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
215 struct tuner *t = fe->analog_demod_priv;
216
217 if (fe_tuner_ops->set_config)
218 return fe_tuner_ops->set_config(fe, priv_cfg);
219
220 tuner_warn("Tuner frontend module has no way to set config\n");
221
222 return 0;
223}
224
Michael Krufky4e9154b2007-10-21 19:39:50 -0300225static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300226
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300227static struct analog_demod_ops tuner_analog_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300228 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300229 .standby = fe_standby,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300230 .has_signal = fe_has_signal,
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300231 .set_config = fe_set_config,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300232 .tuner_status = tuner_status
233};
234
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300235/*
236 * Functions that are common to both TV and radio
237 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300239static void set_tv_freq(struct i2c_client *c, unsigned int freq);
240static void set_radio_freq(struct i2c_client *c, unsigned int freq);
241static const struct v4l2_subdev_ops tuner_ops;
Steven Toth27c685a2008-01-05 16:50:14 -0300242
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700243static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300244 unsigned int new_mode_mask, unsigned int new_config,
Michael Krufkyd7cba042008-09-12 13:31:45 -0300245 int (*tuner_callback) (void *dev, int component, int cmd, int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300247 struct tuner *t = to_tuner(i2c_get_clientdata(c));
Michael Krufkye18f9442007-08-21 01:25:48 -0300248 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300249 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700250 unsigned char buffer[4];
Michael Krufkyd6eef492009-10-24 16:42:16 -0300251 int tune_now = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700253 if (type == UNSET || type == TUNER_ABSENT) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300254 tuner_dbg("tuner 0x%02x: Tuner type absent\n", c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return;
256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 t->type = type;
Michael Krufkye7ddcd92009-03-28 15:35:26 -0300259 /* prevent invalid config values */
Roel Kluinf14a2972009-10-23 07:59:42 -0300260 t->config = new_config < 256 ? new_config : 0;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300261 if (tuner_callback != NULL) {
262 tuner_dbg("defining GPIO callback\n");
Michael Krufkyd7cba042008-09-12 13:31:45 -0300263 t->fe.callback = tuner_callback;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300264 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300265
Michael Krufkyb2083192007-05-29 22:54:06 -0300266 /* discard private data, in case set_type() was previously called */
Michael Krufkya07c8772008-04-29 03:54:19 -0300267 tuner_detach(&t->fe);
268 t->fe.analog_demod_priv = NULL;
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 switch (t->type) {
271 case TUNER_MT2032:
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300272 if (!dvb_attach(microtune_attach,
273 &t->fe, t->i2c->adapter, t->i2c->addr))
274 goto attach_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 break;
276 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300277 {
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300278 struct tda829x_config cfg = {
279 .lna_cfg = t->config,
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300280 };
281 if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
282 t->i2c->addr, &cfg))
283 goto attach_failed;
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300284 break;
285 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700286 case TUNER_TEA5767:
Michael Krufkya07c8772008-04-29 03:54:19 -0300287 if (!dvb_attach(tea5767_attach, &t->fe,
288 t->i2c->adapter, t->i2c->addr))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300289 goto attach_failed;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700290 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700291 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300292 case TUNER_TEA5761:
Michael Krufkya07c8772008-04-29 03:54:19 -0300293 if (!dvb_attach(tea5761_attach, &t->fe,
294 t->i2c->adapter, t->i2c->addr))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300295 goto attach_failed;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300296 t->mode_mask = T_RADIO;
297 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700298 case TUNER_PHILIPS_FMD1216ME_MK3:
299 buffer[0] = 0x0b;
300 buffer[1] = 0xdc;
301 buffer[2] = 0x9c;
302 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700303 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700304 mdelay(1);
305 buffer[2] = 0x86;
306 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700307 i2c_master_send(c, buffer, 4);
Michael Krufkya07c8772008-04-29 03:54:19 -0300308 if (!dvb_attach(simple_tuner_attach, &t->fe,
309 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300310 goto attach_failed;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700311 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800312 case TUNER_PHILIPS_TD1316:
313 buffer[0] = 0x0b;
314 buffer[1] = 0xdc;
315 buffer[2] = 0x86;
316 buffer[3] = 0xa4;
Michael Krufkya07c8772008-04-29 03:54:19 -0300317 i2c_master_send(c, buffer, 4);
318 if (!dvb_attach(simple_tuner_attach, &t->fe,
319 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300320 goto attach_failed;
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200321 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300322 case TUNER_XC2028:
323 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300324 struct xc2028_config cfg = {
325 .i2c_adap = t->i2c->adapter,
326 .i2c_addr = t->i2c->addr,
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300327 };
Michael Krufkya07c8772008-04-29 03:54:19 -0300328 if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300329 goto attach_failed;
Michael Krufkyd6eef492009-10-24 16:42:16 -0300330 tune_now = 0;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300331 break;
332 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300333 case TUNER_TDA9887:
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300334 if (!dvb_attach(tda9887_attach,
335 &t->fe, t->i2c->adapter, t->i2c->addr))
336 goto attach_failed;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300337 break;
Steven Toth27c685a2008-01-05 16:50:14 -0300338 case TUNER_XC5000:
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300339 {
Mauro Carvalho Chehab900f7342011-02-04 12:56:39 -0300340 struct xc5000_config xc5000_cfg = {
341 .i2c_address = t->i2c->addr,
342 /* if_khz will be set at dvb_attach() */
343 .if_khz = 0,
344 };
345
Michael Krufkya07c8772008-04-29 03:54:19 -0300346 if (!dvb_attach(xc5000_attach,
Michael Krufky30650962008-09-06 14:56:58 -0300347 &t->fe, t->i2c->adapter, &xc5000_cfg))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300348 goto attach_failed;
Michael Krufkyd6eef492009-10-24 16:42:16 -0300349 tune_now = 0;
Steven Toth27c685a2008-01-05 16:50:14 -0300350 break;
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300351 }
Michael Krufky93463892009-09-15 23:04:18 -0300352 case TUNER_NXP_TDA18271:
353 {
354 struct tda18271_config cfg = {
355 .config = t->config,
Mauro Carvalho Chehabe350d442010-09-26 22:58:28 -0300356 .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
Michael Krufky93463892009-09-15 23:04:18 -0300357 };
358
359 if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr,
360 t->i2c->adapter, &cfg))
361 goto attach_failed;
Michael Krufkyd6eef492009-10-24 16:42:16 -0300362 tune_now = 0;
Michael Krufky93463892009-09-15 23:04:18 -0300363 break;
364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 default:
Michael Krufkya07c8772008-04-29 03:54:19 -0300366 if (!dvb_attach(simple_tuner_attach, &t->fe,
367 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300368 goto attach_failed;
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 break;
371 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700372
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300373 if ((NULL == analog_ops->set_params) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300374 (fe_tuner_ops->set_analog_params)) {
Michael Krufkya07c8772008-04-29 03:54:19 -0300375
Michael Krufky7271e602008-05-26 16:08:40 +0200376 t->name = fe_tuner_ops->info.name;
Michael Krufkye18f9442007-08-21 01:25:48 -0300377
Michael Krufky4e9154b2007-10-21 19:39:50 -0300378 t->fe.analog_demod_priv = t;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300379 memcpy(analog_ops, &tuner_analog_ops,
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300380 sizeof(struct analog_demod_ops));
Michael Krufkya07c8772008-04-29 03:54:19 -0300381
Michael Krufkya55db8c2007-12-09 13:52:51 -0300382 } else {
Michael Krufky7271e602008-05-26 16:08:40 +0200383 t->name = analog_ops->info.name;
Michael Krufkye18f9442007-08-21 01:25:48 -0300384 }
385
Michael Krufky7271e602008-05-26 16:08:40 +0200386 tuner_dbg("type set to %s\n", t->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300387
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300388 t->mode_mask = new_mode_mask;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700389
Michael Krufkyd6eef492009-10-24 16:42:16 -0300390 /* Some tuners require more initialization setup before use,
391 such as firmware download or device calibration.
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300392 trying to set a frequency here will just fail
393 FIXME: better to move set_freq to the tuner code. This is needed
394 on analog tuners for PLL to properly work
395 */
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300396 if (tune_now) {
397 if (V4L2_TUNER_RADIO == t->mode)
398 set_radio_freq(c, t->radio_freq);
399 else
400 set_tv_freq(c, t->tv_freq);
401 }
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300402
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700403 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100404 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700405 t->mode_mask);
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300406 return;
407
408attach_failed:
409 tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
410 t->type = TUNER_ABSENT;
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300411
412 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700415/*
416 * This function apply tuner config to tuner specified
417 * by tun_setup structure. I addr is unset, then admin status
418 * and tun addr status is more precise then current status,
419 * it's applied. Otherwise status and type are applied only to
420 * tuner with exactly the same addr.
421*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700422
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700423static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700424{
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300425 struct tuner *t = to_tuner(i2c_get_clientdata(c));
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700426
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300427 if ((t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
428 (t->mode_mask & tun_setup->mode_mask))) ||
429 (tun_setup->addr == c->addr)) {
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300430 set_type(c, tun_setup->type, tun_setup->mode_mask,
431 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300432 } else
433 tuner_dbg("set addr discarded for type %i, mask %x. "
434 "Asked to change tuner at addr 0x%02x, with mask %x\n",
435 t->type, t->mode_mask,
436 tun_setup->addr, tun_setup->mode_mask);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700437}
438
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300439static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700440{
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300441 struct tuner *t = to_tuner(sd);
442 struct i2c_client *client = v4l2_get_subdevdata(sd);
443
444 tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
445 type->type,
446 type->addr,
447 type->mode_mask,
448 type->config);
449
450 set_addr(client, type);
451 return 0;
452}
453
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300454static int tuner_s_config(struct v4l2_subdev *sd,
455 const struct v4l2_priv_tun_config *cfg)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300456{
457 struct tuner *t = to_tuner(sd);
458 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
459
460 if (t->type != cfg->tuner)
461 return 0;
462
463 if (analog_ops->set_config) {
464 analog_ops->set_config(&t->fe, cfg->priv);
465 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700466 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700467
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300468 tuner_dbg("Tuner frontend module has no way to set config\n");
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700469 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700470}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700471
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300472/* Search for existing radio and/or TV tuners on the given I2C adapter.
473 Note that when this function is called from tuner_probe you can be
474 certain no other devices will be added/deleted at the same time, I2C
475 core protects against that. */
476static void tuner_lookup(struct i2c_adapter *adap,
477 struct tuner **radio, struct tuner **tv)
478{
479 struct tuner *pos;
480
481 *radio = NULL;
482 *tv = NULL;
483
484 list_for_each_entry(pos, &tuner_list, list) {
485 int mode_mask;
486
487 if (pos->i2c->adapter != adap ||
488 strcmp(pos->i2c->driver->driver.name, "tuner"))
489 continue;
490
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300491 mode_mask = pos->mode_mask;
492 pos->standby = 1;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300493 if (*radio == NULL && mode_mask == T_RADIO)
494 *radio = pos;
495 /* Note: currently TDA9887 is the only demod-only
496 device. If other devices appear then we need to
497 make this test more general. */
498 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
499 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
500 *tv = pos;
501 }
502}
503
504/* During client attach, set_type is called by adapter's attach_inform callback.
505 set_type must then be completed by tuner_probe.
506 */
507static int tuner_probe(struct i2c_client *client,
508 const struct i2c_device_id *id)
509{
510 struct tuner *t;
511 struct tuner *radio;
512 struct tuner *tv;
513
514 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
515 if (NULL == t)
516 return -ENOMEM;
517 v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
518 t->i2c = client;
519 t->name = "(tuner unset)";
520 t->type = UNSET;
521 t->audmode = V4L2_TUNER_MODE_STEREO;
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300522 t->standby = 1;
523 t->radio_freq = 87.5 * 16000; /* Initial freq range */
524 t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300525
526 if (show_i2c) {
527 unsigned char buffer[16];
528 int i, rc;
529
530 memset(buffer, 0, sizeof(buffer));
531 rc = i2c_master_recv(client, buffer, sizeof(buffer));
532 tuner_info("I2C RECV = ");
533 for (i = 0; i < rc; i++)
534 printk(KERN_CONT "%02x ", buffer[i]);
535 printk("\n");
536 }
537
538 /* autodetection code based on the i2c addr */
539 if (!no_autodetect) {
540 switch (client->addr) {
541 case 0x10:
542 if (tuner_symbol_probe(tea5761_autodetection,
543 t->i2c->adapter,
544 t->i2c->addr) >= 0) {
545 t->type = TUNER_TEA5761;
546 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300547 tuner_lookup(t->i2c->adapter, &radio, &tv);
548 if (tv)
549 tv->mode_mask &= ~T_RADIO;
550
551 goto register_client;
552 }
553 kfree(t);
554 return -ENODEV;
555 case 0x42:
556 case 0x43:
557 case 0x4a:
558 case 0x4b:
559 /* If chip is not tda8290, don't register.
560 since it can be tda9887*/
561 if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
562 t->i2c->addr) >= 0) {
563 tuner_dbg("tda829x detected\n");
564 } else {
565 /* Default is being tda9887 */
566 t->type = TUNER_TDA9887;
567 t->mode_mask = T_RADIO | T_ANALOG_TV |
568 T_DIGITAL_TV;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300569 goto register_client;
570 }
571 break;
572 case 0x60:
573 if (tuner_symbol_probe(tea5767_autodetection,
574 t->i2c->adapter, t->i2c->addr)
575 >= 0) {
576 t->type = TUNER_TEA5767;
577 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300578 /* Sets freq to FM range */
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300579 tuner_lookup(t->i2c->adapter, &radio, &tv);
580 if (tv)
581 tv->mode_mask &= ~T_RADIO;
582
583 goto register_client;
584 }
585 break;
586 }
587 }
588
589 /* Initializes only the first TV tuner on this adapter. Why only the
590 first? Because there are some devices (notably the ones with TI
591 tuners) that have more than one i2c address for the *same* device.
592 Experience shows that, except for just one case, the first
593 address is the right one. The exception is a Russian tuner
594 (ACORP_Y878F). So, the desired behavior is just to enable the
595 first found TV tuner. */
596 tuner_lookup(t->i2c->adapter, &radio, &tv);
597 if (tv == NULL) {
598 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
599 if (radio == NULL)
600 t->mode_mask |= T_RADIO;
601 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300602 }
603
604 /* Should be just before return */
605register_client:
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300606 /* Sets a default mode */
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300607 if (t->mode_mask & T_ANALOG_TV)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300608 t->mode = V4L2_TUNER_ANALOG_TV;
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300609 else if (t->mode_mask & T_RADIO)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300610 t->mode = V4L2_TUNER_RADIO;
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300611 else
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300612 t->mode = V4L2_TUNER_DIGITAL_TV;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300613 set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
614 list_add_tail(&t->list, &tuner_list);
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300615
616 tuner_info("Tuner %d found with type(s)%s%s%s.\n",
617 t->type,
618 t->mode_mask & T_RADIO ? " radio" : "",
619 t->mode_mask & T_ANALOG_TV ? " TV" : "",
620 t->mode_mask & T_ANALOG_TV ? " DTV" : "");
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300621 return 0;
622}
623
624static int tuner_remove(struct i2c_client *client)
625{
626 struct tuner *t = to_tuner(i2c_get_clientdata(client));
627
628 v4l2_device_unregister_subdev(&t->sd);
629 tuner_detach(&t->fe);
630 t->fe.analog_demod_priv = NULL;
631
632 list_del(&t->list);
633 kfree(t);
634 return 0;
635}
636
637/*
638 * Functions that are specific for TV mode
639 */
640
641/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
642static void set_tv_freq(struct i2c_client *c, unsigned int freq)
643{
644 struct tuner *t = to_tuner(i2c_get_clientdata(c));
645 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
646
647 struct analog_parameters params = {
648 .mode = t->mode,
649 .audmode = t->audmode,
650 .std = t->std
651 };
652
653 if (t->type == UNSET) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300654 tuner_warn("tuner type not set\n");
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300655 return;
656 }
657 if (NULL == analog_ops->set_params) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300658 tuner_warn("Tuner has no way to set tv freq\n");
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300659 return;
660 }
661 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300662 tuner_dbg("TV freq (%d.%02d) out of range (%d-%d)\n",
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300663 freq / 16, freq % 16 * 100 / 16, tv_range[0],
664 tv_range[1]);
665 /* V4L2 spec: if the freq is not possible then the closest
666 possible value should be selected */
667 if (freq < tv_range[0] * 16)
668 freq = tv_range[0] * 16;
669 else
670 freq = tv_range[1] * 16;
671 }
672 params.frequency = freq;
673 tuner_dbg("tv freq set to %d.%02d\n",
674 freq / 16, freq % 16 * 100 / 16);
675 t->tv_freq = freq;
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300676 t->standby = false;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300677
678 analog_ops->set_params(&t->fe, &params);
679}
680
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700681/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682static int tuner_fixup_std(struct tuner *t)
683{
684 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300686 case '6':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300687 tuner_dbg("insmod fixup: PAL => PAL-60\n");
Hans Verkuile71ced12006-12-11 15:51:43 -0300688 t->std = V4L2_STD_PAL_60;
689 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 case 'b':
691 case 'B':
692 case 'g':
693 case 'G':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300694 tuner_dbg("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 t->std = V4L2_STD_PAL_BG;
696 break;
697 case 'i':
698 case 'I':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300699 tuner_dbg("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 t->std = V4L2_STD_PAL_I;
701 break;
702 case 'd':
703 case 'D':
704 case 'k':
705 case 'K':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300706 tuner_dbg("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 t->std = V4L2_STD_PAL_DK;
708 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700709 case 'M':
710 case 'm':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300711 tuner_dbg("insmod fixup: PAL => PAL-M\n");
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700712 t->std = V4L2_STD_PAL_M;
713 break;
714 case 'N':
715 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200716 if (pal[1] == 'c' || pal[1] == 'C') {
717 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
718 t->std = V4L2_STD_PAL_Nc;
719 } else {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300720 tuner_dbg("insmod fixup: PAL => PAL-N\n");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200721 t->std = V4L2_STD_PAL_N;
722 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700723 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700724 case '-':
725 /* default parameter, do nothing */
726 break;
727 default:
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300728 tuner_warn("pal= argument not recognised\n");
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700729 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700732 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
733 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200734 case 'b':
735 case 'B':
736 case 'g':
737 case 'G':
738 case 'h':
739 case 'H':
740 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300741 t->std = V4L2_STD_SECAM_B |
742 V4L2_STD_SECAM_G |
743 V4L2_STD_SECAM_H;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200744 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700745 case 'd':
746 case 'D':
747 case 'k':
748 case 'K':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300749 tuner_dbg("insmod fixup: SECAM => SECAM-DK\n");
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700750 t->std = V4L2_STD_SECAM_DK;
751 break;
752 case 'l':
753 case 'L':
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300754 if ((secam[1] == 'C') || (secam[1] == 'c')) {
755 tuner_dbg("insmod fixup: SECAM => SECAM-L'\n");
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800756 t->std = V4L2_STD_SECAM_LC;
757 } else {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300758 tuner_dbg("insmod fixup: SECAM => SECAM-L\n");
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800759 t->std = V4L2_STD_SECAM_L;
760 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700761 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700762 case '-':
763 /* default parameter, do nothing */
764 break;
765 default:
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300766 tuner_warn("secam= argument not recognised\n");
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700767 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700768 }
769 }
770
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200771 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
772 switch (ntsc[0]) {
773 case 'm':
774 case 'M':
775 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
776 t->std = V4L2_STD_NTSC_M;
777 break;
778 case 'j':
779 case 'J':
780 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
781 t->std = V4L2_STD_NTSC_M_JP;
782 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200783 case 'k':
784 case 'K':
785 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
786 t->std = V4L2_STD_NTSC_M_KR;
787 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200788 case '-':
789 /* default parameter, do nothing */
790 break;
791 default:
792 tuner_info("ntsc= argument not recognised\n");
793 break;
794 }
795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return 0;
797}
798
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300799/*
800 * Functions that are specific for Radio mode
801 */
802
803static void set_radio_freq(struct i2c_client *c, unsigned int freq)
804{
805 struct tuner *t = to_tuner(i2c_get_clientdata(c));
806 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
807
808 struct analog_parameters params = {
809 .mode = t->mode,
810 .audmode = t->audmode,
811 .std = t->std
812 };
813
814 if (t->type == UNSET) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300815 tuner_warn("tuner type not set\n");
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300816 return;
817 }
818 if (NULL == analog_ops->set_params) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300819 tuner_warn("tuner has no way to set radio frequency\n");
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300820 return;
821 }
822 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300823 tuner_dbg("radio freq (%d.%02d) out of range (%d-%d)\n",
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300824 freq / 16000, freq % 16000 * 100 / 16000,
825 radio_range[0], radio_range[1]);
826 /* V4L2 spec: if the freq is not possible then the closest
827 possible value should be selected */
828 if (freq < radio_range[0] * 16000)
829 freq = radio_range[0] * 16000;
830 else
831 freq = radio_range[1] * 16000;
832 }
833 params.frequency = freq;
834 tuner_dbg("radio freq set to %d.%02d\n",
835 freq / 16000, freq % 16000 * 100 / 16000);
836 t->radio_freq = freq;
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300837 t->standby = false;
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300838
839 analog_ops->set_params(&t->fe, &params);
840}
841
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300842/**
843 * check_mode - Verify if tuner supports the requested mode
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300844 * @t: a pointer to the module's internal struct_tuner
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300845 *
846 * This function checks if the tuner is capable of tuning analog TV,
847 * digital TV or radio, depending on what the caller wants. If the
848 * tuner can't support that mode, it returns -EINVAL. Otherwise, it
849 * returns 0.
850 * This function is needed for boards that have a separate tuner for
851 * radio (like devices with tea5767).
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300852 */
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300853static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300854{
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300855 if ((1 << mode & t->mode_mask) == 0)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300856 return -EINVAL;
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300857
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300858 return 0;
859}
860
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300861/**
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300862 * set_mode_freq - Switch tuner to other mode.
863 * @client: struct i2c_client pointer
864 * @t: a pointer to the module's internal struct_tuner
865 * @mode: enum v4l2_type (radio or TV)
866 * @freq: frequency to set (0 means to use the previous one)
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300867 *
868 * If tuner doesn't support the needed mode (radio or TV), prints a
869 * debug message and returns -EINVAL, changing internal state to T_STANDBY.
870 * Otherwise, changes the state and sets frequency to the last value, if
871 * the tuner can sleep or if it supports both Radio and TV.
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300872 */
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300873static int set_mode_freq(struct i2c_client *client, struct tuner *t,
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300874 enum v4l2_tuner_type mode, unsigned int freq)
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300875{
876 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
877
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300878 if (mode != t->mode) {
879 if (check_mode(t, mode) == -EINVAL) {
880 tuner_dbg("Tuner doesn't support mode %d. "
881 "Putting tuner to sleep\n", mode);
882 t->standby = true;
883 if (analog_ops->standby)
884 analog_ops->standby(&t->fe);
885 return -EINVAL;
886 }
887 t->mode = mode;
888 tuner_dbg("Changing to mode %d\n", mode);
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300889 }
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300890 if (t->mode == V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300891 if (freq)
892 t->radio_freq = freq;
893 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300894 } else {
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300895 if (freq)
896 t->tv_freq = freq;
897 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300898 }
899
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300900 return 0;
901}
902
Mauro Carvalho Chehabe2d25a22011-02-04 10:09:07 -0300903/*
904 * Functions that should be broken into separate radio/TV functions
905 */
906
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300907static void set_freq(struct i2c_client *c, unsigned long freq)
908{
909 struct tuner *t = to_tuner(i2c_get_clientdata(c));
910
911 switch (t->mode) {
912 case V4L2_TUNER_RADIO:
913 set_radio_freq(c, freq);
914 break;
915 case V4L2_TUNER_ANALOG_TV:
916 case V4L2_TUNER_DIGITAL_TV:
917 set_tv_freq(c, freq);
918 break;
919 default:
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300920 tuner_dbg("freq set: unknown mode: 0x%04x!\n", t->mode);
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300921 }
922}
923
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300924/**
925 * tuner_status - Dumps the current tuner status at dmesg
926 * @fe: pointer to struct dvb_frontend
927 *
928 * This callback is used only for driver debug purposes, answering to
929 * VIDIOC_LOG_STATUS. No changes should happen on this call.
930 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300931static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200932{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300933 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200934 unsigned long freq, freq_fraction;
Michael Krufkya07c8772008-04-29 03:54:19 -0300935 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
936 struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200937 const char *p;
938
939 switch (t->mode) {
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300940 case V4L2_TUNER_RADIO:
941 p = "radio";
942 break;
943 case V4L2_TUNER_DIGITAL_TV:
944 p = "digital TV";
945 break;
946 case V4L2_TUNER_ANALOG_TV:
947 default:
948 p = "analog TV";
949 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200950 }
951 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200952 freq = t->radio_freq / 16000;
953 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200954 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200955 freq = t->tv_freq / 16;
956 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200957 }
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300958 tuner_info("Tuner mode: %s%s\n", p,
959 t->standby ? " on standby mode" : "");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200960 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300961 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200962 if (t->mode != V4L2_TUNER_RADIO)
Mauro Carvalho Chehab7d275bf2011-02-04 11:28:00 -0300963 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300964 if (fe_tuner_ops->get_status) {
965 u32 tuner_status;
966
967 fe_tuner_ops->get_status(&t->fe, &tuner_status);
968 if (tuner_status & TUNER_STATUS_LOCKED)
969 tuner_info("Tuner is locked.\n");
970 if (tuner_status & TUNER_STATUS_STEREO)
971 tuner_info("Stereo: yes\n");
972 }
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300973 if (analog_ops->has_signal)
974 tuner_info("Signal strength: %d\n",
975 analog_ops->has_signal(fe));
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200976}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200977
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300978/**
979 * tuner_s_power - controls the power state of the tuner
980 * @sd: pointer to struct v4l2_subdev
981 * @on: a zero value puts the tuner to sleep
982 */
Laurent Pinchart622b8282009-10-05 10:48:17 -0300983static int tuner_s_power(struct v4l2_subdev *sd, int on)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300984{
985 struct tuner *t = to_tuner(sd);
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300986 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300988 /* FIXME: Why this function don't wake the tuner if on != 0 ? */
Laurent Pinchart622b8282009-10-05 10:48:17 -0300989 if (on)
990 return 0;
991
Mauro Carvalho Chehab16a5e532008-12-20 07:17:10 -0300992 tuner_dbg("Putting tuner to sleep\n");
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -0300993 t->standby = true;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -0300994 if (analog_ops->standby)
995 analog_ops->standby(&t->fe);
996 return 0;
997}
998
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -0300999/* ---------------------------------------------------------------------- */
1000
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -03001001static int tuner_s_radio(struct v4l2_subdev *sd)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001002{
1003 struct tuner *t = to_tuner(sd);
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -03001004 struct i2c_client *client = v4l2_get_subdevdata(sd);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -03001005
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001006 if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001007 return 0;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001008 return 0;
1009}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -07001010
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001011/* --- v4l ioctls --- */
1012/* take care: bttv does userspace copying, we'll get a
1013 kernel pointer here... */
1014static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1015{
1016 struct tuner *t = to_tuner(sd);
1017 struct i2c_client *client = v4l2_get_subdevdata(sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001019 if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001020 return 0;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001021
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001022 t->std = std;
1023 tuner_fixup_std(t);
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001024
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001025 return 0;
1026}
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001027
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001028static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
1029{
1030 struct tuner *t = to_tuner(sd);
1031 struct i2c_client *client = v4l2_get_subdevdata(sd);
Michael Krufkye18f9442007-08-21 01:25:48 -03001032
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001033 if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001034 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036 return 0;
1037}
1038
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001039static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
1040{
1041 struct tuner *t = to_tuner(sd);
1042 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
1043
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001044 if (check_mode(t, f->type) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001045 return 0;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001046 f->type = t->mode;
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001047 if (fe_tuner_ops->get_frequency && !t->standby) {
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001048 u32 abs_freq;
1049
1050 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
1051 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
Julia Lawall75b697f2009-08-01 16:48:41 -03001052 DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
1053 DIV_ROUND_CLOSEST(abs_freq, 62500);
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001054 } else {
1055 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
1056 t->radio_freq : t->tv_freq;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001057 }
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001058 return 0;
1059}
1060
1061static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1062{
1063 struct tuner *t = to_tuner(sd);
1064 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
1065 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
1066
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001067 if (check_mode(t, vt->type) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001068 return 0;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001069 vt->type = t->mode;
1070 if (analog_ops->get_afc)
1071 vt->afc = analog_ops->get_afc(&t->fe);
1072 if (t->mode == V4L2_TUNER_ANALOG_TV)
1073 vt->capability |= V4L2_TUNER_CAP_NORM;
1074 if (t->mode != V4L2_TUNER_RADIO) {
1075 vt->rangelow = tv_range[0] * 16;
1076 vt->rangehigh = tv_range[1] * 16;
1077 return 0;
1078 }
1079
1080 /* radio mode */
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001081 vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001082 if (fe_tuner_ops->get_status) {
1083 u32 tuner_status;
1084
1085 fe_tuner_ops->get_status(&t->fe, &tuner_status);
1086 vt->rxsubchans =
1087 (tuner_status & TUNER_STATUS_STEREO) ?
1088 V4L2_TUNER_SUB_STEREO :
1089 V4L2_TUNER_SUB_MONO;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001090 }
1091 if (analog_ops->has_signal)
1092 vt->signal = analog_ops->has_signal(&t->fe);
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001093 vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001094 vt->audmode = t->audmode;
1095 vt->rangelow = radio_range[0] * 16000;
1096 vt->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001097
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001098 return 0;
1099}
1100
1101static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1102{
1103 struct tuner *t = to_tuner(sd);
1104 struct i2c_client *client = v4l2_get_subdevdata(sd);
1105
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001106 if (set_mode_freq(client, t, vt->type, 0) == -EINVAL)
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001107 return 0;
1108
Mauro Carvalho Chehabcbde6892011-02-04 10:42:09 -03001109 if (t->mode == V4L2_TUNER_RADIO)
1110 t->audmode = vt->audmode;
1111
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001112 return 0;
1113}
1114
1115static int tuner_log_status(struct v4l2_subdev *sd)
1116{
1117 struct tuner *t = to_tuner(sd);
1118 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
1119
1120 if (analog_ops->tuner_status)
1121 analog_ops->tuner_status(&t->fe);
1122 return 0;
1123}
1124
Jean Delvare21b48a72007-03-12 19:20:15 -03001125static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001127 struct tuner *t = to_tuner(i2c_get_clientdata(c));
Mauro Carvalho Chehabe2f63d92011-02-04 11:15:21 -03001128 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001130 tuner_dbg("suspend\n");
Mauro Carvalho Chehabe2f63d92011-02-04 11:15:21 -03001131
1132 if (!t->standby && analog_ops->standby)
1133 analog_ops->standby(&t->fe);
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return 0;
1136}
1137
Jean Delvare21b48a72007-03-12 19:20:15 -03001138static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001140 struct tuner *t = to_tuner(i2c_get_clientdata(c));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001142 tuner_dbg("resume\n");
Mauro Carvalho Chehabe2f63d92011-02-04 11:15:21 -03001143
1144 if (!t->standby)
1145 set_mode_freq(c, t, t->type, 0);
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 return 0;
1148}
1149
Hans Verkuil75b4c262009-04-01 03:32:22 -03001150static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
1151{
1152 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1153
1154 /* TUNER_SET_CONFIG is still called by tuner-simple.c, so we have
1155 to handle it here.
1156 There must be a better way of doing this... */
1157 switch (cmd) {
1158 case TUNER_SET_CONFIG:
1159 return tuner_s_config(sd, arg);
1160 }
1161 return -ENOIOCTLCMD;
1162}
1163
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001164/* ----------------------------------------------------------------------- */
1165
1166static const struct v4l2_subdev_core_ops tuner_core_ops = {
1167 .log_status = tuner_log_status,
Hans Verkuilf41737e2009-04-01 03:52:39 -03001168 .s_std = tuner_s_std,
Laurent Pinchart622b8282009-10-05 10:48:17 -03001169 .s_power = tuner_s_power,
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001170};
1171
1172static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
Hans Verkuile8a4a9e2008-11-24 18:21:40 -03001173 .s_radio = tuner_s_radio,
1174 .g_tuner = tuner_g_tuner,
1175 .s_tuner = tuner_s_tuner,
1176 .s_frequency = tuner_s_frequency,
1177 .g_frequency = tuner_g_frequency,
1178 .s_type_addr = tuner_s_type_addr,
1179 .s_config = tuner_s_config,
1180};
1181
1182static const struct v4l2_subdev_ops tuner_ops = {
1183 .core = &tuner_core_ops,
1184 .tuner = &tuner_tuner_ops,
1185};
1186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187/* ----------------------------------------------------------------------- */
1188
Jean Delvareaf294862008-05-18 20:49:40 +02001189/* This driver supports many devices and the idea is to let the driver
1190 detect which device is present. So rather than listing all supported
1191 devices here, we pretend to support a single, fake device type. */
1192static const struct i2c_device_id tuner_id[] = {
1193 { "tuner", }, /* autodetect */
1194 { }
1195};
1196MODULE_DEVICE_TABLE(i2c, tuner_id);
1197
Hans Verkuil02a20982010-09-15 15:36:23 -03001198static struct i2c_driver tuner_driver = {
1199 .driver = {
1200 .owner = THIS_MODULE,
1201 .name = "tuner",
1202 },
1203 .probe = tuner_probe,
1204 .remove = tuner_remove,
1205 .command = tuner_command,
1206 .suspend = tuner_suspend,
1207 .resume = tuner_resume,
1208 .id_table = tuner_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209};
1210
Hans Verkuil02a20982010-09-15 15:36:23 -03001211static __init int init_tuner(void)
1212{
1213 return i2c_add_driver(&tuner_driver);
1214}
1215
1216static __exit void exit_tuner(void)
1217{
1218 i2c_del_driver(&tuner_driver);
1219}
1220
1221module_init(init_tuner);
1222module_exit(exit_tuner);
1223
Mauro Carvalho Chehab9f3f71e2011-02-03 23:32:07 -03001224MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
1225MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
1226MODULE_LICENSE("GPL");