blob: 59e67c92575839b8ef3030f635d447be40a41cdc [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>
Michael Krufkyffbb8072007-08-21 01:14:12 -030018#include <linux/videodev.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>
Michael Krufky5e453dc2006-01-09 15:32:31 -020021#include <media/v4l2-common.h>
Hans Verkuil9dd659d2007-11-04 11:03:36 -030022#include <media/v4l2-i2c-drv-legacy.h>
Michael Krufky8218b0b2007-06-26 13:12:08 -030023#include "tuner-driver.h"
Michael Krufky96c0b7c2007-08-27 21:23:08 -030024#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030025#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030026#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030027#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030028#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030029#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030030#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#define UNSET (-1U)
33
Hans Verkuil9dd659d2007-11-04 11:03:36 -030034#define PREFIX t->i2c->driver->driver.name
Michael Krufky241020d2007-10-30 09:46:10 -030035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/* standard i2c insmod options */
37static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030038#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030039 0x10,
40#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080041 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070042 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
43 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 I2C_CLIENT_END
45};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047I2C_CLIENT_INSMOD;
48
49/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070050static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070051static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070052static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/* insmod options used at runtime => read/write */
Michael Krufkyab166052007-12-09 02:26:48 -030055static int tuner_debug;
56
57#define tuner_warn(fmt, arg...) do { \
58 printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
59 i2c_adapter_id(t->i2c->adapter), \
60 t->i2c->addr, ##arg); \
61 } while (0)
62
63#define tuner_info(fmt, arg...) do { \
64 printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
65 i2c_adapter_id(t->i2c->adapter), \
66 t->i2c->addr, ##arg); \
67 } while (0)
68
69#define tuner_err(fmt, arg...) do { \
70 printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
71 i2c_adapter_id(t->i2c->adapter), \
72 t->i2c->addr, ##arg); \
73 } while (0)
74
75#define tuner_dbg(fmt, arg...) do { \
76 if (tuner_debug) \
77 printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
78 i2c_adapter_id(t->i2c->adapter), \
79 t->i2c->addr, ##arg); \
80 } while (0)
81
82/* ------------------------------------------------------------------------ */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070084static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static unsigned int radio_range[2] = { 65, 108 };
86
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020087static char pal[] = "--";
88static char secam[] = "--";
89static char ntsc[] = "-";
90
Hans Verkuilf9195de2006-01-11 19:01:01 -020091
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020092module_param(addr, int, 0444);
93module_param(no_autodetect, int, 0444);
94module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020095module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020096module_param_string(pal, pal, sizeof(pal), 0644);
97module_param_string(secam, secam, sizeof(secam), 0644);
98module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070099module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100module_param_array(radio_range, int, NULL, 0644);
101
102MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
103MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
104MODULE_LICENSE("GPL");
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/* ---------------------------------------------------------------------- */
107
Michael Krufkyc7919d52007-12-08 17:06:30 -0300108static void fe_set_params(struct dvb_frontend *fe,
109 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -0300110{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300111 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
112 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -0300113
Michael Krufkye18f9442007-08-21 01:25:48 -0300114 if (NULL == fe_tuner_ops->set_analog_params) {
115 tuner_warn("Tuner frontend module has no way to set freq\n");
116 return;
117 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300118 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300119}
120
Michael Krufky4e9154b2007-10-21 19:39:50 -0300121static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300122{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300123 if (fe->ops.tuner_ops.release)
124 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300125
Michael Krufky4e9154b2007-10-21 19:39:50 -0300126 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300127
128 /* DO NOT kfree(fe->analog_demod_priv)
129 *
130 * If we are in this function, analog_demod_priv contains a pointer
131 * to struct tuner *t. This will be kfree'd in tuner_detach().
132 *
133 * Otherwise, fe->ops.analog_demod_ops->release will
134 * handle the cleanup for analog demodulator modules.
135 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300136 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300137}
138
Michael Krufky4e9154b2007-10-21 19:39:50 -0300139static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300140{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300141 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300142
143 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300144 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300145}
146
Michael Krufky4e9154b2007-10-21 19:39:50 -0300147static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300148{
Michael Krufky14196832007-10-14 18:11:53 -0300149 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300150
Michael Krufky4e9154b2007-10-21 19:39:50 -0300151 if (fe->ops.tuner_ops.get_rf_strength)
152 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300153
154 return strength;
155}
156
Michael Krufky4e9154b2007-10-21 19:39:50 -0300157static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300158
159static struct analog_tuner_ops tuner_core_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300160 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300161 .standby = fe_standby,
162 .release = fe_release,
163 .has_signal = fe_has_signal,
164 .tuner_status = tuner_status
165};
166
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700167/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168static void set_tv_freq(struct i2c_client *c, unsigned int freq)
169{
170 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300171 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Michael Krufkyc7919d52007-12-08 17:06:30 -0300173 struct analog_parameters params = {
174 .mode = t->mode,
175 .audmode = t->audmode,
176 .std = t->std
177 };
178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700180 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return;
182 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300183 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700184 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 return;
186 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700187 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
188 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
189 freq / 16, freq % 16 * 100 / 16, tv_range[0],
190 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200191 /* V4L2 spec: if the freq is not possible then the closest
192 possible value should be selected */
193 if (freq < tv_range[0] * 16)
194 freq = tv_range[0] * 16;
195 else
196 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300198 params.frequency = freq;
199
200 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
203static void set_radio_freq(struct i2c_client *c, unsigned int freq)
204{
205 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300206 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Michael Krufkyc7919d52007-12-08 17:06:30 -0300208 struct analog_parameters params = {
209 .mode = t->mode,
210 .audmode = t->audmode,
211 .std = t->std
212 };
213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700215 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 return;
217 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300218 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700219 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return;
221 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200222 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700223 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
224 freq / 16000, freq % 16000 * 100 / 16000,
225 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200226 /* V4L2 spec: if the freq is not possible then the closest
227 possible value should be selected */
228 if (freq < radio_range[0] * 16000)
229 freq = radio_range[0] * 16000;
230 else
231 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300233 params.frequency = freq;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700234
Michael Krufkyc7919d52007-12-08 17:06:30 -0300235 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
238static void set_freq(struct i2c_client *c, unsigned long freq)
239{
240 struct tuner *t = i2c_get_clientdata(c);
241
242 switch (t->mode) {
243 case V4L2_TUNER_RADIO:
244 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700245 freq / 16000, freq % 16000 * 100 / 16000);
246 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200247 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 break;
249 case V4L2_TUNER_ANALOG_TV:
250 case V4L2_TUNER_DIGITAL_TV:
251 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700252 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200254 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300256 default:
257 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
Michael Krufky293197c2007-08-28 17:20:42 -0300261static void tuner_i2c_address_check(struct tuner *t)
262{
263 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300264 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300265 return;
266
267 tuner_warn("====================== WARNING! ======================\n");
268 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
269 tuner_warn("will soon be dropped. This message indicates that your\n");
270 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300271 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300272 tuner_warn("To ensure continued support for your device, please\n");
273 tuner_warn("send a copy of this message, along with full dmesg\n");
274 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
275 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
276 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300277 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300278 tuners[t->type].name);
279 tuner_warn("====================== WARNING! ======================\n");
280}
281
Michael Krufky4adad282007-08-27 21:59:08 -0300282static void attach_simple_tuner(struct tuner *t)
283{
284 struct simple_tuner_config cfg = {
285 .type = t->type,
286 .tun = &tuners[t->type]
287 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300288 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300289}
290
Michael Krufkyab166052007-12-09 02:26:48 -0300291static void attach_tda829x(struct tuner *t)
292{
293 struct tda829x_config cfg = {
294 .lna_cfg = &t->config,
295 .tuner_callback = t->tuner_callback,
296 };
297 tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
298}
299
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700300static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300301 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300302 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300305 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300306 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700307 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700309 if (type == UNSET || type == TUNER_ABSENT) {
310 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return;
312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700314 if (type >= tuner_count) {
315 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
316 return;
317 }
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300320 t->config = new_config;
321 if (tuner_callback != NULL) {
322 tuner_dbg("defining GPIO callback\n");
323 t->tuner_callback = tuner_callback;
324 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300325
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300326 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300327 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
328
329 return;
330 }
331
Michael Krufkyb2083192007-05-29 22:54:06 -0300332 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300333 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300334 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 switch (t->type) {
337 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300338 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 break;
340 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300341 {
Michael Krufkyab166052007-12-09 02:26:48 -0300342 attach_tda829x(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300343 break;
344 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700345 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300346 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700347 t->type = TUNER_ABSENT;
348 t->mode_mask = T_UNINITIALIZED;
349 return;
350 }
351 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700352 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300353 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300354 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300355 t->type = TUNER_ABSENT;
356 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300357 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300358 }
359 t->mode_mask = T_RADIO;
360 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700361 case TUNER_PHILIPS_FMD1216ME_MK3:
362 buffer[0] = 0x0b;
363 buffer[1] = 0xdc;
364 buffer[2] = 0x9c;
365 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700366 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700367 mdelay(1);
368 buffer[2] = 0x86;
369 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700370 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300371 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700372 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800373 case TUNER_PHILIPS_TD1316:
374 buffer[0] = 0x0b;
375 buffer[1] = 0xdc;
376 buffer[2] = 0x86;
377 buffer[3] = 0xa4;
378 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300379 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200380 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300381 case TUNER_XC2028:
382 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300383 struct xc2028_config cfg = {
384 .i2c_adap = t->i2c->adapter,
385 .i2c_addr = t->i2c->addr,
386 .video_dev = c->adapter->algo_data,
387 .callback = t->tuner_callback,
388 };
389 if (!xc2028_attach(&t->fe, &cfg)) {
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300390 t->type = TUNER_ABSENT;
391 t->mode_mask = T_UNINITIALIZED;
392 return;
393 }
394 break;
395 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300396 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300397 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300398 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300400 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
402 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700403
Michael Krufkye2be32a2007-10-21 14:35:21 -0300404 ops = t->fe.ops.analog_demod_ops;
405
Michael Krufkyc7919d52007-12-08 17:06:30 -0300406 if (((NULL == ops) || (NULL == ops->set_params)) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300407 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300408 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
409 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300410
Michael Krufky1dde7a42007-10-21 13:40:56 -0300411 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300412 t->fe.analog_demod_priv = t;
Michael Krufkya55db8c2007-12-09 13:52:51 -0300413 } else {
414 strlcpy(t->i2c->name, ops->info.name,
415 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300416 }
417
Michael Krufky49427442007-10-30 09:44:12 -0300418 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300419
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700420 if (t->mode_mask == T_UNINITIALIZED)
421 t->mode_mask = new_mode_mask;
422
Hans Verkuil27487d42006-01-15 15:04:52 -0200423 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700424 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100425 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700426 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300427 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700430/*
431 * This function apply tuner config to tuner specified
432 * by tun_setup structure. I addr is unset, then admin status
433 * and tun addr status is more precise then current status,
434 * it's applied. Otherwise status and type are applied only to
435 * tuner with exactly the same addr.
436*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700437
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700438static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700439{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700440 struct tuner *t = i2c_get_clientdata(c);
441
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300442 tuner_dbg("set addr for type %i\n", t->type);
443
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300444 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
445 (t->mode_mask & tun_setup->mode_mask))) ||
446 (tun_setup->addr == c->addr)) {
447 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300448 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700449 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700450}
451
452static inline int check_mode(struct tuner *t, char *cmd)
453{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700454 if ((1 << t->mode & t->mode_mask) == 0) {
455 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700456 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700457
458 switch (t->mode) {
459 case V4L2_TUNER_RADIO:
460 tuner_dbg("Cmd %s accepted for radio\n", cmd);
461 break;
462 case V4L2_TUNER_ANALOG_TV:
463 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
464 break;
465 case V4L2_TUNER_DIGITAL_TV:
466 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
467 break;
468 }
469 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700470}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700471
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700472/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473static int tuner_fixup_std(struct tuner *t)
474{
475 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300477 case '6':
478 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
479 t->std = V4L2_STD_PAL_60;
480 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 case 'b':
482 case 'B':
483 case 'g':
484 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700485 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 t->std = V4L2_STD_PAL_BG;
487 break;
488 case 'i':
489 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700490 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 t->std = V4L2_STD_PAL_I;
492 break;
493 case 'd':
494 case 'D':
495 case 'k':
496 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700497 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 t->std = V4L2_STD_PAL_DK;
499 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700500 case 'M':
501 case 'm':
502 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
503 t->std = V4L2_STD_PAL_M;
504 break;
505 case 'N':
506 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200507 if (pal[1] == 'c' || pal[1] == 'C') {
508 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
509 t->std = V4L2_STD_PAL_Nc;
510 } else {
511 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
512 t->std = V4L2_STD_PAL_N;
513 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700514 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700515 case '-':
516 /* default parameter, do nothing */
517 break;
518 default:
519 tuner_warn ("pal= argument not recognised\n");
520 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
522 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700523 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
524 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200525 case 'b':
526 case 'B':
527 case 'g':
528 case 'G':
529 case 'h':
530 case 'H':
531 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
532 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
533 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700534 case 'd':
535 case 'D':
536 case 'k':
537 case 'K':
538 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
539 t->std = V4L2_STD_SECAM_DK;
540 break;
541 case 'l':
542 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800543 if ((secam[1]=='C')||(secam[1]=='c')) {
544 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
545 t->std = V4L2_STD_SECAM_LC;
546 } else {
547 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
548 t->std = V4L2_STD_SECAM_L;
549 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700550 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700551 case '-':
552 /* default parameter, do nothing */
553 break;
554 default:
555 tuner_warn ("secam= argument not recognised\n");
556 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700557 }
558 }
559
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200560 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
561 switch (ntsc[0]) {
562 case 'm':
563 case 'M':
564 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
565 t->std = V4L2_STD_NTSC_M;
566 break;
567 case 'j':
568 case 'J':
569 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
570 t->std = V4L2_STD_NTSC_M_JP;
571 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200572 case 'k':
573 case 'K':
574 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
575 t->std = V4L2_STD_NTSC_M_KR;
576 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200577 case '-':
578 /* default parameter, do nothing */
579 break;
580 default:
581 tuner_info("ntsc= argument not recognised\n");
582 break;
583 }
584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return 0;
586}
587
Michael Krufky4e9154b2007-10-21 19:39:50 -0300588static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200589{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300590 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200591 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300592 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300593 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200594 const char *p;
595
596 switch (t->mode) {
597 case V4L2_TUNER_RADIO: p = "radio"; break;
598 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
599 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
600 default: p = "undefined"; break;
601 }
602 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200603 freq = t->radio_freq / 16000;
604 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200605 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200606 freq = t->tv_freq / 16;
607 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200608 }
609 tuner_info("Tuner mode: %s\n", p);
610 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300611 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200612 if (t->mode != V4L2_TUNER_RADIO)
613 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300614 if (fe_tuner_ops->get_status) {
615 u32 tuner_status;
616
617 fe_tuner_ops->get_status(&t->fe, &tuner_status);
618 if (tuner_status & TUNER_STATUS_LOCKED)
619 tuner_info("Tuner is locked.\n");
620 if (tuner_status & TUNER_STATUS_STEREO)
621 tuner_info("Stereo: yes\n");
622 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300623 if (ops) {
624 if (ops->has_signal)
625 tuner_info("Signal strength: %d\n",
626 ops->has_signal(fe));
627 if (ops->is_stereo)
628 tuner_info("Stereo: %s\n",
629 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200630 }
631}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633/* ---------------------------------------------------------------------- */
634
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700635/*
636 * Switch tuner to other mode. If tuner support both tv and radio,
637 * set another frequency to some value (This is needed for some pal
638 * tuners to avoid locking). Otherwise, just put second tuner in
639 * standby mode.
640 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700642static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
643{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300644 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
645
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800646 if (mode == t->mode)
647 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700648
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800649 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700650
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800651 if (check_mode(t, cmd) == EINVAL) {
652 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300653 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300654 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800655 return EINVAL;
656 }
657 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700658}
659
660#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800661 tuner_dbg("switching to v4l2\n"); \
662 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700663
664static inline int check_v4l2(struct tuner *t)
665{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300666 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
667 TV, v4l1 for radio), until that is fixed this code is disabled.
668 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
669 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700670 return 0;
671}
672
673static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300676 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300677 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Hans Verkuilf9195de2006-01-11 19:01:01 -0200679 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300680 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200681
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700682 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700684 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300685 tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700686 ((struct tuner_setup *)arg)->type,
687 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300688 ((struct tuner_setup *)arg)->mode_mask,
689 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700690
691 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700692 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200694 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
695 == EINVAL)
696 return 0;
697 if (t->radio_freq)
698 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700700 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200701 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
702 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300703 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300704 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300705 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200706 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300707#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700708 case VIDIOCSAUDIO:
709 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
710 return 0;
711 if (check_v4l2(t) == EINVAL)
712 return 0;
713
714 /* Should be implemented, since bttv calls it */
715 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700716 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700718 {
719 static const v4l2_std_id map[] = {
720 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
721 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
722 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
723 [4 /* bttv */ ] = V4L2_STD_PAL_M,
724 [5 /* bttv */ ] = V4L2_STD_PAL_N,
725 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
726 };
727 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700729 if (check_v4l2(t) == EINVAL)
730 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700731
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700732 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700735 if (vc->norm < ARRAY_SIZE(map))
736 t->std = map[vc->norm];
737 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200738 if (t->tv_freq)
739 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700740 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700741 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700742 case VIDIOCSFREQ:
743 {
744 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700745
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700746 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
747 return 0;
748 if (check_v4l2(t) == EINVAL)
749 return 0;
750
751 set_freq(client, *v);
752 return 0;
753 }
754 case VIDIOCGTUNER:
755 {
756 struct video_tuner *vt = arg;
757
758 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
759 return 0;
760 if (check_v4l2(t) == EINVAL)
761 return 0;
762
763 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300764 if (fe_tuner_ops->get_status) {
765 u32 tuner_status;
766
767 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300768 if (tuner_status & TUNER_STATUS_STEREO)
769 vt->flags |= VIDEO_TUNER_STEREO_ON;
770 else
771 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300772 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300773 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300774 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300775 vt->flags |=
776 VIDEO_TUNER_STEREO_ON;
777 else
778 vt->flags &=
779 ~VIDEO_TUNER_STEREO_ON;
780 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700781 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300782 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300783 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300784
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700785 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
786
787 vt->rangelow = radio_range[0] * 16000;
788 vt->rangehigh = radio_range[1] * 16000;
789
790 } else {
791 vt->rangelow = tv_range[0] * 16;
792 vt->rangehigh = tv_range[1] * 16;
793 }
794
795 return 0;
796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700798 {
799 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700801 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
802 return 0;
803 if (check_v4l2(t) == EINVAL)
804 return 0;
805
Michael Krufkye18f9442007-08-21 01:25:48 -0300806 if (V4L2_TUNER_RADIO == t->mode) {
807 if (fe_tuner_ops->get_status) {
808 u32 tuner_status;
809
810 fe_tuner_ops->get_status(&t->fe, &tuner_status);
811 va->mode = (tuner_status & TUNER_STATUS_STEREO)
812 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300813 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300814 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300815 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
816 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700817 return 0;
818 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300819#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300820 case TUNER_SET_CONFIG:
821 {
822 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
823 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300825 if (t->type != cfg->tuner)
826 break;
827
828 if (t->type == TUNER_TDA9887) {
829 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300830 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300831 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300832 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300833
834 if (NULL == fe_tuner_ops->set_config) {
835 tuner_warn("Tuner frontend module has no way to "
836 "set config\n");
837 break;
838 }
839 fe_tuner_ops->set_config(&t->fe, cfg->priv);
840
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300841 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300842 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300843 /* --- v4l ioctls --- */
844 /* take care: bttv does userspace copying, we'll get a
845 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700847 {
848 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700850 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
851 == EINVAL)
852 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700853
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700854 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700856 t->std = *id;
857 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200858 if (t->tv_freq)
859 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700860 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700861 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700862 case VIDIOC_S_FREQUENCY:
863 {
864 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700865
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300866 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
867 == EINVAL)
868 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700869 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200870 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700871
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700872 break;
873 }
874 case VIDIOC_G_FREQUENCY:
875 {
876 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700877
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700878 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
879 return 0;
880 switch_v4l2();
881 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300882 if (fe_tuner_ops->get_frequency) {
883 u32 abs_freq;
884
885 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
886 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
887 (abs_freq * 2 + 125/2) / 125 :
888 (abs_freq + 62500/2) / 62500;
889 break;
890 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200891 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
892 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700893 break;
894 }
895 case VIDIOC_G_TUNER:
896 {
897 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700898
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700899 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
900 return 0;
901 switch_v4l2();
902
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200903 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300904 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300905 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300906 if (t->mode == V4L2_TUNER_ANALOG_TV)
907 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200908 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700909 tuner->rangelow = tv_range[0] * 16;
910 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200911 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700912 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200913
914 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200915 tuner->rxsubchans =
916 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300917 if (fe_tuner_ops->get_status) {
918 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200919
Michael Krufkye18f9442007-08-21 01:25:48 -0300920 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300921 tuner->rxsubchans =
922 (tuner_status & TUNER_STATUS_STEREO) ?
923 V4L2_TUNER_SUB_STEREO :
924 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300925 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300926 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300927 tuner->rxsubchans =
928 ops->is_stereo(&t->fe) ?
929 V4L2_TUNER_SUB_STEREO :
930 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300931 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300932 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300933 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300934 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200935 tuner->capability |=
936 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
937 tuner->audmode = t->audmode;
938 tuner->rangelow = radio_range[0] * 16000;
939 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700940 break;
941 }
942 case VIDIOC_S_TUNER:
943 {
944 struct v4l2_tuner *tuner = arg;
945
946 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
947 return 0;
948
949 switch_v4l2();
950
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200951 /* do nothing unless we're a radio tuner */
952 if (t->mode != V4L2_TUNER_RADIO)
953 break;
954 t->audmode = tuner->audmode;
955 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700956 break;
957 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200958 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300959 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300960 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200961 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 }
963
964 return 0;
965}
966
Jean Delvare21b48a72007-03-12 19:20:15 -0300967static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300969 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300971 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 /* FIXME: power down ??? */
973 return 0;
974}
975
Jean Delvare21b48a72007-03-12 19:20:15 -0300976static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300978 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300980 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -0200981 if (V4L2_TUNER_RADIO == t->mode) {
982 if (t->radio_freq)
983 set_freq(c, t->radio_freq);
984 } else {
985 if (t->tv_freq)
986 set_freq(c, t->tv_freq);
987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return 0;
989}
990
Hans Verkuil92de1f12007-11-04 10:53:09 -0300991/* ---------------------------------------------------------------------- */
992
993LIST_HEAD(tuner_list);
994
995/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300996 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -0300997 certain no other devices will be added/deleted at the same time, I2C
998 core protects against that. */
999static void tuner_lookup(struct i2c_adapter *adap,
1000 struct tuner **radio, struct tuner **tv)
1001{
1002 struct tuner *pos;
1003
1004 *radio = NULL;
1005 *tv = NULL;
1006
1007 list_for_each_entry(pos, &tuner_list, list) {
1008 int mode_mask;
1009
1010 if (pos->i2c->adapter != adap ||
1011 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
1012 continue;
1013
1014 mode_mask = pos->mode_mask & ~T_STANDBY;
1015 if (*radio == NULL && mode_mask == T_RADIO)
1016 *radio = pos;
1017 /* Note: currently TDA9887 is the only demod-only
1018 device. If other devices appear then we need to
1019 make this test more general. */
1020 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
1021 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
1022 *tv = pos;
1023 }
1024}
1025
1026/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001027 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -03001028 */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001029static int tuner_probe(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001030{
Hans Verkuil92de1f12007-11-04 10:53:09 -03001031 struct tuner *t;
1032 struct tuner *radio;
1033 struct tuner *tv;
1034
Hans Verkuil92de1f12007-11-04 10:53:09 -03001035 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001036 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001037 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001038 t->i2c = client;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001039 strlcpy(client->name, "(tuner unset)", sizeof(client->name));
Hans Verkuil92de1f12007-11-04 10:53:09 -03001040 i2c_set_clientdata(client, t);
1041 t->type = UNSET;
1042 t->audmode = V4L2_TUNER_MODE_STEREO;
1043 t->mode_mask = T_UNINITIALIZED;
1044
1045 if (show_i2c) {
1046 unsigned char buffer[16];
1047 int i, rc;
1048
1049 memset(buffer, 0, sizeof(buffer));
1050 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1051 tuner_info("I2C RECV = ");
1052 for (i = 0; i < rc; i++)
1053 printk(KERN_CONT "%02x ", buffer[i]);
1054 printk("\n");
1055 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001056 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001057 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001058 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1059 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001060 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001061 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001062
1063 /* autodetection code based on the i2c addr */
1064 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001065 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001066 case 0x10:
1067 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1068 != EINVAL) {
1069 t->type = TUNER_TEA5761;
1070 t->mode_mask = T_RADIO;
1071 t->mode = T_STANDBY;
1072 /* Sets freq to FM range */
1073 t->radio_freq = 87.5 * 16000;
1074 tuner_lookup(t->i2c->adapter, &radio, &tv);
1075 if (tv)
1076 tv->mode_mask &= ~T_RADIO;
1077
1078 goto register_client;
1079 }
1080 break;
1081 case 0x42:
1082 case 0x43:
1083 case 0x4a:
1084 case 0x4b:
1085 /* If chip is not tda8290, don't register.
1086 since it can be tda9887*/
Michael Krufkyab166052007-12-09 02:26:48 -03001087 if (tda829x_probe(t->i2c->adapter,
1088 t->i2c->addr) == 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001089 tuner_dbg("tda829x detected\n");
1090 } else {
1091 /* Default is being tda9887 */
1092 t->type = TUNER_TDA9887;
1093 t->mode_mask = T_RADIO | T_ANALOG_TV |
1094 T_DIGITAL_TV;
1095 t->mode = T_STANDBY;
1096 goto register_client;
1097 }
1098 break;
1099 case 0x60:
1100 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1101 != EINVAL) {
1102 t->type = TUNER_TEA5767;
1103 t->mode_mask = T_RADIO;
1104 t->mode = T_STANDBY;
1105 /* Sets freq to FM range */
1106 t->radio_freq = 87.5 * 16000;
1107 tuner_lookup(t->i2c->adapter, &radio, &tv);
1108 if (tv)
1109 tv->mode_mask &= ~T_RADIO;
1110
1111 goto register_client;
1112 }
1113 break;
1114 }
1115 }
1116
1117 /* Initializes only the first TV tuner on this adapter. Why only the
1118 first? Because there are some devices (notably the ones with TI
1119 tuners) that have more than one i2c address for the *same* device.
1120 Experience shows that, except for just one case, the first
1121 address is the right one. The exception is a Russian tuner
1122 (ACORP_Y878F). So, the desired behavior is just to enable the
1123 first found TV tuner. */
1124 tuner_lookup(t->i2c->adapter, &radio, &tv);
1125 if (tv == NULL) {
1126 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1127 if (radio == NULL)
1128 t->mode_mask |= T_RADIO;
1129 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1130 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1131 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1132 }
1133
1134 /* Should be just before return */
1135register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001136 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1137 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001138
1139 /* Sets a default mode */
1140 if (t->mode_mask & T_ANALOG_TV) {
1141 t->mode = T_ANALOG_TV;
1142 } else if (t->mode_mask & T_RADIO) {
1143 t->mode = T_RADIO;
1144 } else {
1145 t->mode = T_DIGITAL_TV;
1146 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001147 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001148 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001149 return 0;
1150}
1151
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001152static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001153{
1154 if (0 != addr) {
1155 normal_i2c[0] = addr;
1156 normal_i2c[1] = I2C_CLIENT_END;
1157 }
1158
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001159 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1160 return 0;
1161
Hans Verkuil92de1f12007-11-04 10:53:09 -03001162 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1163 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1164 * and an RTC at 0x6f which can get corrupted if probed.
1165 */
1166 if ((adap->id == I2C_HW_B_CX2388x) ||
1167 (adap->id == I2C_HW_B_CX23885)) {
1168 unsigned int i = 0;
1169
1170 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1171 i += 2;
1172 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1173 ignore[i+0] = adap->nr;
1174 ignore[i+1] = 0x6b;
1175 ignore[i+2] = adap->nr;
1176 ignore[i+3] = 0x6f;
1177 ignore[i+4] = I2C_CLIENT_END;
1178 } else
1179 printk(KERN_WARNING "tuner: "
1180 "too many options specified "
1181 "in i2c probe ignore list!\n");
1182 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001183 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001184}
1185
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001186static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001187{
1188 struct tuner *t = i2c_get_clientdata(client);
1189 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001190
1191 if (ops && ops->release)
1192 ops->release(&t->fe);
1193
1194 list_del(&t->list);
1195 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001196 return 0;
1197}
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199/* ----------------------------------------------------------------------- */
1200
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001201static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1202 .name = "tuner",
1203 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001204 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001205 .probe = tuner_probe,
1206 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001207 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001208 .resume = tuner_resume,
1209 .legacy_probe = tuner_legacy_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210};
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213/*
1214 * Overrides for Emacs so that we follow Linus's tabbing style.
1215 * ---------------------------------------------------------------------------
1216 * Local variables:
1217 * c-basic-offset: 8
1218 * End:
1219 */