blob: 5f8bffc8209b4f60705fe7a5c22724d585ca3da2 [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 */
Hans Verkuilf9195de2006-01-11 19:01:01 -020055int tuner_debug = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070057static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static unsigned int radio_range[2] = { 65, 108 };
59
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020060static char pal[] = "--";
61static char secam[] = "--";
62static char ntsc[] = "-";
63
Hans Verkuilf9195de2006-01-11 19:01:01 -020064
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020065module_param(addr, int, 0444);
66module_param(no_autodetect, int, 0444);
67module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020068module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020069module_param_string(pal, pal, sizeof(pal), 0644);
70module_param_string(secam, secam, sizeof(secam), 0644);
71module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070072module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073module_param_array(radio_range, int, NULL, 0644);
74
75MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
76MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
77MODULE_LICENSE("GPL");
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/* ---------------------------------------------------------------------- */
80
Michael Krufkyc7919d52007-12-08 17:06:30 -030081static void fe_set_params(struct dvb_frontend *fe,
82 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -030083{
Michael Krufky4e9154b2007-10-21 19:39:50 -030084 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
85 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -030086
Michael Krufkye18f9442007-08-21 01:25:48 -030087 if (NULL == fe_tuner_ops->set_analog_params) {
88 tuner_warn("Tuner frontend module has no way to set freq\n");
89 return;
90 }
Michael Krufkyc7919d52007-12-08 17:06:30 -030091 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -030092}
93
Michael Krufky4e9154b2007-10-21 19:39:50 -030094static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -030095{
Michael Krufky4e9154b2007-10-21 19:39:50 -030096 if (fe->ops.tuner_ops.release)
97 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -030098
Michael Krufky4e9154b2007-10-21 19:39:50 -030099 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300100
101 /* DO NOT kfree(fe->analog_demod_priv)
102 *
103 * If we are in this function, analog_demod_priv contains a pointer
104 * to struct tuner *t. This will be kfree'd in tuner_detach().
105 *
106 * Otherwise, fe->ops.analog_demod_ops->release will
107 * handle the cleanup for analog demodulator modules.
108 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300109 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300110}
111
Michael Krufky4e9154b2007-10-21 19:39:50 -0300112static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300113{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300114 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300115
116 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300117 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300118}
119
Michael Krufky4e9154b2007-10-21 19:39:50 -0300120static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300121{
Michael Krufky14196832007-10-14 18:11:53 -0300122 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300123
Michael Krufky4e9154b2007-10-21 19:39:50 -0300124 if (fe->ops.tuner_ops.get_rf_strength)
125 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300126
127 return strength;
128}
129
Michael Krufky4e9154b2007-10-21 19:39:50 -0300130static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300131
132static struct analog_tuner_ops tuner_core_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300133 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300134 .standby = fe_standby,
135 .release = fe_release,
136 .has_signal = fe_has_signal,
137 .tuner_status = tuner_status
138};
139
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700140/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static void set_tv_freq(struct i2c_client *c, unsigned int freq)
142{
143 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300144 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Michael Krufkyc7919d52007-12-08 17:06:30 -0300146 struct analog_parameters params = {
147 .mode = t->mode,
148 .audmode = t->audmode,
149 .std = t->std
150 };
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700153 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 return;
155 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300156 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700157 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 return;
159 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700160 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
161 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
162 freq / 16, freq % 16 * 100 / 16, tv_range[0],
163 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200164 /* V4L2 spec: if the freq is not possible then the closest
165 possible value should be selected */
166 if (freq < tv_range[0] * 16)
167 freq = tv_range[0] * 16;
168 else
169 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300171 params.frequency = freq;
172
173 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
176static void set_radio_freq(struct i2c_client *c, unsigned int freq)
177{
178 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300179 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Michael Krufkyc7919d52007-12-08 17:06:30 -0300181 struct analog_parameters params = {
182 .mode = t->mode,
183 .audmode = t->audmode,
184 .std = t->std
185 };
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700188 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 return;
190 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300191 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700192 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 return;
194 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200195 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700196 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
197 freq / 16000, freq % 16000 * 100 / 16000,
198 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200199 /* V4L2 spec: if the freq is not possible then the closest
200 possible value should be selected */
201 if (freq < radio_range[0] * 16000)
202 freq = radio_range[0] * 16000;
203 else
204 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300206 params.frequency = freq;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700207
Michael Krufkyc7919d52007-12-08 17:06:30 -0300208 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
211static void set_freq(struct i2c_client *c, unsigned long freq)
212{
213 struct tuner *t = i2c_get_clientdata(c);
214
215 switch (t->mode) {
216 case V4L2_TUNER_RADIO:
217 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700218 freq / 16000, freq % 16000 * 100 / 16000);
219 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200220 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 break;
222 case V4L2_TUNER_ANALOG_TV:
223 case V4L2_TUNER_DIGITAL_TV:
224 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700225 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200227 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300229 default:
230 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
Michael Krufky293197c2007-08-28 17:20:42 -0300234static void tuner_i2c_address_check(struct tuner *t)
235{
236 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300237 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300238 return;
239
240 tuner_warn("====================== WARNING! ======================\n");
241 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
242 tuner_warn("will soon be dropped. This message indicates that your\n");
243 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300244 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300245 tuner_warn("To ensure continued support for your device, please\n");
246 tuner_warn("send a copy of this message, along with full dmesg\n");
247 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
248 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
249 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300250 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300251 tuners[t->type].name);
252 tuner_warn("====================== WARNING! ======================\n");
253}
254
Michael Krufky4adad282007-08-27 21:59:08 -0300255static void attach_simple_tuner(struct tuner *t)
256{
257 struct simple_tuner_config cfg = {
258 .type = t->type,
259 .tun = &tuners[t->type]
260 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300261 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300262}
263
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700264static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300265 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300266 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300269 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300270 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700271 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700273 if (type == UNSET || type == TUNER_ABSENT) {
274 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 return;
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700278 if (type >= tuner_count) {
279 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
280 return;
281 }
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300284 t->config = new_config;
285 if (tuner_callback != NULL) {
286 tuner_dbg("defining GPIO callback\n");
287 t->tuner_callback = tuner_callback;
288 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300289
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300290 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300291 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
292
293 return;
294 }
295
Michael Krufkyb2083192007-05-29 22:54:06 -0300296 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300297 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300298 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 switch (t->type) {
301 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300302 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 break;
304 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300305 {
Michael Krufky8c125f2c2007-10-27 02:00:57 -0300306 tda829x_attach(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300307 break;
308 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700309 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300310 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700311 t->type = TUNER_ABSENT;
312 t->mode_mask = T_UNINITIALIZED;
313 return;
314 }
315 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700316 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300317 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300318 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300319 t->type = TUNER_ABSENT;
320 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300321 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300322 }
323 t->mode_mask = T_RADIO;
324 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700325 case TUNER_PHILIPS_FMD1216ME_MK3:
326 buffer[0] = 0x0b;
327 buffer[1] = 0xdc;
328 buffer[2] = 0x9c;
329 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700330 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700331 mdelay(1);
332 buffer[2] = 0x86;
333 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700334 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300335 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700336 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800337 case TUNER_PHILIPS_TD1316:
338 buffer[0] = 0x0b;
339 buffer[1] = 0xdc;
340 buffer[2] = 0x86;
341 buffer[3] = 0xa4;
342 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300343 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200344 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300345 case TUNER_XC2028:
346 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300347 struct xc2028_config cfg = {
348 .i2c_adap = t->i2c->adapter,
349 .i2c_addr = t->i2c->addr,
350 .video_dev = c->adapter->algo_data,
351 .callback = t->tuner_callback,
352 };
353 if (!xc2028_attach(&t->fe, &cfg)) {
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300354 t->type = TUNER_ABSENT;
355 t->mode_mask = T_UNINITIALIZED;
356 return;
357 }
358 break;
359 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300360 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300361 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300362 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300364 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 break;
366 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700367
Michael Krufkye2be32a2007-10-21 14:35:21 -0300368 ops = t->fe.ops.analog_demod_ops;
369
Michael Krufkyc7919d52007-12-08 17:06:30 -0300370 if (((NULL == ops) || (NULL == ops->set_params)) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300371 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300372 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
373 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300374
Michael Krufky1dde7a42007-10-21 13:40:56 -0300375 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300376 t->fe.analog_demod_priv = t;
Michael Krufkye18f9442007-08-21 01:25:48 -0300377 }
378
Michael Krufky49427442007-10-30 09:44:12 -0300379 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300380
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700381 if (t->mode_mask == T_UNINITIALIZED)
382 t->mode_mask = new_mode_mask;
383
Hans Verkuil27487d42006-01-15 15:04:52 -0200384 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700385 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100386 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700387 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300388 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700391/*
392 * This function apply tuner config to tuner specified
393 * by tun_setup structure. I addr is unset, then admin status
394 * and tun addr status is more precise then current status,
395 * it's applied. Otherwise status and type are applied only to
396 * tuner with exactly the same addr.
397*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700398
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700399static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700400{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700401 struct tuner *t = i2c_get_clientdata(c);
402
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300403 tuner_dbg("set addr for type %i\n", t->type);
404
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300405 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
406 (t->mode_mask & tun_setup->mode_mask))) ||
407 (tun_setup->addr == c->addr)) {
408 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300409 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700410 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700411}
412
413static inline int check_mode(struct tuner *t, char *cmd)
414{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700415 if ((1 << t->mode & t->mode_mask) == 0) {
416 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700417 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700418
419 switch (t->mode) {
420 case V4L2_TUNER_RADIO:
421 tuner_dbg("Cmd %s accepted for radio\n", cmd);
422 break;
423 case V4L2_TUNER_ANALOG_TV:
424 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
425 break;
426 case V4L2_TUNER_DIGITAL_TV:
427 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
428 break;
429 }
430 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700431}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700432
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700433/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434static int tuner_fixup_std(struct tuner *t)
435{
436 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300438 case '6':
439 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
440 t->std = V4L2_STD_PAL_60;
441 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 case 'b':
443 case 'B':
444 case 'g':
445 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700446 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 t->std = V4L2_STD_PAL_BG;
448 break;
449 case 'i':
450 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700451 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 t->std = V4L2_STD_PAL_I;
453 break;
454 case 'd':
455 case 'D':
456 case 'k':
457 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700458 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 t->std = V4L2_STD_PAL_DK;
460 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700461 case 'M':
462 case 'm':
463 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
464 t->std = V4L2_STD_PAL_M;
465 break;
466 case 'N':
467 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200468 if (pal[1] == 'c' || pal[1] == 'C') {
469 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
470 t->std = V4L2_STD_PAL_Nc;
471 } else {
472 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
473 t->std = V4L2_STD_PAL_N;
474 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700475 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700476 case '-':
477 /* default parameter, do nothing */
478 break;
479 default:
480 tuner_warn ("pal= argument not recognised\n");
481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 }
483 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700484 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
485 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200486 case 'b':
487 case 'B':
488 case 'g':
489 case 'G':
490 case 'h':
491 case 'H':
492 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
493 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
494 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700495 case 'd':
496 case 'D':
497 case 'k':
498 case 'K':
499 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
500 t->std = V4L2_STD_SECAM_DK;
501 break;
502 case 'l':
503 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800504 if ((secam[1]=='C')||(secam[1]=='c')) {
505 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
506 t->std = V4L2_STD_SECAM_LC;
507 } else {
508 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
509 t->std = V4L2_STD_SECAM_L;
510 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700511 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700512 case '-':
513 /* default parameter, do nothing */
514 break;
515 default:
516 tuner_warn ("secam= argument not recognised\n");
517 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700518 }
519 }
520
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200521 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
522 switch (ntsc[0]) {
523 case 'm':
524 case 'M':
525 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
526 t->std = V4L2_STD_NTSC_M;
527 break;
528 case 'j':
529 case 'J':
530 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
531 t->std = V4L2_STD_NTSC_M_JP;
532 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200533 case 'k':
534 case 'K':
535 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
536 t->std = V4L2_STD_NTSC_M_KR;
537 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200538 case '-':
539 /* default parameter, do nothing */
540 break;
541 default:
542 tuner_info("ntsc= argument not recognised\n");
543 break;
544 }
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return 0;
547}
548
Michael Krufky4e9154b2007-10-21 19:39:50 -0300549static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200550{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300551 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200552 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300553 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300554 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200555 const char *p;
556
557 switch (t->mode) {
558 case V4L2_TUNER_RADIO: p = "radio"; break;
559 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
560 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
561 default: p = "undefined"; break;
562 }
563 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200564 freq = t->radio_freq / 16000;
565 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200566 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200567 freq = t->tv_freq / 16;
568 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200569 }
570 tuner_info("Tuner mode: %s\n", p);
571 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300572 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200573 if (t->mode != V4L2_TUNER_RADIO)
574 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300575 if (fe_tuner_ops->get_status) {
576 u32 tuner_status;
577
578 fe_tuner_ops->get_status(&t->fe, &tuner_status);
579 if (tuner_status & TUNER_STATUS_LOCKED)
580 tuner_info("Tuner is locked.\n");
581 if (tuner_status & TUNER_STATUS_STEREO)
582 tuner_info("Stereo: yes\n");
583 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300584 if (ops) {
585 if (ops->has_signal)
586 tuner_info("Signal strength: %d\n",
587 ops->has_signal(fe));
588 if (ops->is_stereo)
589 tuner_info("Stereo: %s\n",
590 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200591 }
592}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594/* ---------------------------------------------------------------------- */
595
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700596/*
597 * Switch tuner to other mode. If tuner support both tv and radio,
598 * set another frequency to some value (This is needed for some pal
599 * tuners to avoid locking). Otherwise, just put second tuner in
600 * standby mode.
601 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700603static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
604{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300605 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
606
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800607 if (mode == t->mode)
608 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700609
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800610 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700611
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800612 if (check_mode(t, cmd) == EINVAL) {
613 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300614 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300615 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800616 return EINVAL;
617 }
618 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700619}
620
621#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800622 tuner_dbg("switching to v4l2\n"); \
623 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700624
625static inline int check_v4l2(struct tuner *t)
626{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300627 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
628 TV, v4l1 for radio), until that is fixed this code is disabled.
629 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
630 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700631 return 0;
632}
633
634static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
636 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300637 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300638 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Hans Verkuilf9195de2006-01-11 19:01:01 -0200640 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300641 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200642
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700643 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700645 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300646 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 -0700647 ((struct tuner_setup *)arg)->type,
648 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300649 ((struct tuner_setup *)arg)->mode_mask,
650 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700651
652 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700653 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200655 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
656 == EINVAL)
657 return 0;
658 if (t->radio_freq)
659 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700661 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200662 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
663 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300664 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300665 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300666 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200667 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300668#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700669 case VIDIOCSAUDIO:
670 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
671 return 0;
672 if (check_v4l2(t) == EINVAL)
673 return 0;
674
675 /* Should be implemented, since bttv calls it */
676 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700677 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700679 {
680 static const v4l2_std_id map[] = {
681 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
682 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
683 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
684 [4 /* bttv */ ] = V4L2_STD_PAL_M,
685 [5 /* bttv */ ] = V4L2_STD_PAL_N,
686 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
687 };
688 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700690 if (check_v4l2(t) == EINVAL)
691 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700692
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700693 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
694 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700696 if (vc->norm < ARRAY_SIZE(map))
697 t->std = map[vc->norm];
698 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200699 if (t->tv_freq)
700 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700701 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700702 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700703 case VIDIOCSFREQ:
704 {
705 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700706
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700707 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
708 return 0;
709 if (check_v4l2(t) == EINVAL)
710 return 0;
711
712 set_freq(client, *v);
713 return 0;
714 }
715 case VIDIOCGTUNER:
716 {
717 struct video_tuner *vt = arg;
718
719 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
720 return 0;
721 if (check_v4l2(t) == EINVAL)
722 return 0;
723
724 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300725 if (fe_tuner_ops->get_status) {
726 u32 tuner_status;
727
728 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300729 if (tuner_status & TUNER_STATUS_STEREO)
730 vt->flags |= VIDEO_TUNER_STEREO_ON;
731 else
732 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300733 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300734 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300735 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300736 vt->flags |=
737 VIDEO_TUNER_STEREO_ON;
738 else
739 vt->flags &=
740 ~VIDEO_TUNER_STEREO_ON;
741 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700742 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300743 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300744 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300745
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700746 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
747
748 vt->rangelow = radio_range[0] * 16000;
749 vt->rangehigh = radio_range[1] * 16000;
750
751 } else {
752 vt->rangelow = tv_range[0] * 16;
753 vt->rangehigh = tv_range[1] * 16;
754 }
755
756 return 0;
757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700759 {
760 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700762 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
763 return 0;
764 if (check_v4l2(t) == EINVAL)
765 return 0;
766
Michael Krufkye18f9442007-08-21 01:25:48 -0300767 if (V4L2_TUNER_RADIO == t->mode) {
768 if (fe_tuner_ops->get_status) {
769 u32 tuner_status;
770
771 fe_tuner_ops->get_status(&t->fe, &tuner_status);
772 va->mode = (tuner_status & TUNER_STATUS_STEREO)
773 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300774 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300775 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300776 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
777 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700778 return 0;
779 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300780#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300781 case TUNER_SET_CONFIG:
782 {
783 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
784 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300786 if (t->type != cfg->tuner)
787 break;
788
789 if (t->type == TUNER_TDA9887) {
790 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300791 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300792 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300793 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300794
795 if (NULL == fe_tuner_ops->set_config) {
796 tuner_warn("Tuner frontend module has no way to "
797 "set config\n");
798 break;
799 }
800 fe_tuner_ops->set_config(&t->fe, cfg->priv);
801
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300802 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300803 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300804 /* --- v4l ioctls --- */
805 /* take care: bttv does userspace copying, we'll get a
806 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700808 {
809 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700811 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
812 == EINVAL)
813 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700814
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700815 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700817 t->std = *id;
818 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200819 if (t->tv_freq)
820 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700821 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700822 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700823 case VIDIOC_S_FREQUENCY:
824 {
825 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700826
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300827 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
828 == EINVAL)
829 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700830 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200831 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700832
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700833 break;
834 }
835 case VIDIOC_G_FREQUENCY:
836 {
837 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700838
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700839 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
840 return 0;
841 switch_v4l2();
842 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300843 if (fe_tuner_ops->get_frequency) {
844 u32 abs_freq;
845
846 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
847 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
848 (abs_freq * 2 + 125/2) / 125 :
849 (abs_freq + 62500/2) / 62500;
850 break;
851 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200852 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
853 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700854 break;
855 }
856 case VIDIOC_G_TUNER:
857 {
858 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700859
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700860 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
861 return 0;
862 switch_v4l2();
863
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200864 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300865 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300866 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300867 if (t->mode == V4L2_TUNER_ANALOG_TV)
868 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200869 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700870 tuner->rangelow = tv_range[0] * 16;
871 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200872 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700873 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200874
875 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200876 tuner->rxsubchans =
877 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300878 if (fe_tuner_ops->get_status) {
879 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200880
Michael Krufkye18f9442007-08-21 01:25:48 -0300881 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300882 tuner->rxsubchans =
883 (tuner_status & TUNER_STATUS_STEREO) ?
884 V4L2_TUNER_SUB_STEREO :
885 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300886 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300887 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300888 tuner->rxsubchans =
889 ops->is_stereo(&t->fe) ?
890 V4L2_TUNER_SUB_STEREO :
891 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300892 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300893 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300894 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300895 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200896 tuner->capability |=
897 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
898 tuner->audmode = t->audmode;
899 tuner->rangelow = radio_range[0] * 16000;
900 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700901 break;
902 }
903 case VIDIOC_S_TUNER:
904 {
905 struct v4l2_tuner *tuner = arg;
906
907 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
908 return 0;
909
910 switch_v4l2();
911
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200912 /* do nothing unless we're a radio tuner */
913 if (t->mode != V4L2_TUNER_RADIO)
914 break;
915 t->audmode = tuner->audmode;
916 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700917 break;
918 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200919 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300920 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300921 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200922 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
924
925 return 0;
926}
927
Jean Delvare21b48a72007-03-12 19:20:15 -0300928static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300930 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300932 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 /* FIXME: power down ??? */
934 return 0;
935}
936
Jean Delvare21b48a72007-03-12 19:20:15 -0300937static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300939 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300941 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -0200942 if (V4L2_TUNER_RADIO == t->mode) {
943 if (t->radio_freq)
944 set_freq(c, t->radio_freq);
945 } else {
946 if (t->tv_freq)
947 set_freq(c, t->tv_freq);
948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return 0;
950}
951
Hans Verkuil92de1f12007-11-04 10:53:09 -0300952/* ---------------------------------------------------------------------- */
953
954LIST_HEAD(tuner_list);
955
956/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300957 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -0300958 certain no other devices will be added/deleted at the same time, I2C
959 core protects against that. */
960static void tuner_lookup(struct i2c_adapter *adap,
961 struct tuner **radio, struct tuner **tv)
962{
963 struct tuner *pos;
964
965 *radio = NULL;
966 *tv = NULL;
967
968 list_for_each_entry(pos, &tuner_list, list) {
969 int mode_mask;
970
971 if (pos->i2c->adapter != adap ||
972 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
973 continue;
974
975 mode_mask = pos->mode_mask & ~T_STANDBY;
976 if (*radio == NULL && mode_mask == T_RADIO)
977 *radio = pos;
978 /* Note: currently TDA9887 is the only demod-only
979 device. If other devices appear then we need to
980 make this test more general. */
981 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
982 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
983 *tv = pos;
984 }
985}
986
987/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300988 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -0300989 */
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300990static int tuner_probe(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -0300991{
Hans Verkuil92de1f12007-11-04 10:53:09 -0300992 struct tuner *t;
993 struct tuner *radio;
994 struct tuner *tv;
995
Hans Verkuil92de1f12007-11-04 10:53:09 -0300996 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300997 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -0300998 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -0300999 t->i2c = client;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001000 strlcpy(client->name, "(tuner unset)", sizeof(client->name));
Hans Verkuil92de1f12007-11-04 10:53:09 -03001001 i2c_set_clientdata(client, t);
1002 t->type = UNSET;
1003 t->audmode = V4L2_TUNER_MODE_STEREO;
1004 t->mode_mask = T_UNINITIALIZED;
1005
1006 if (show_i2c) {
1007 unsigned char buffer[16];
1008 int i, rc;
1009
1010 memset(buffer, 0, sizeof(buffer));
1011 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1012 tuner_info("I2C RECV = ");
1013 for (i = 0; i < rc; i++)
1014 printk(KERN_CONT "%02x ", buffer[i]);
1015 printk("\n");
1016 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001017 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001018 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001019 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1020 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001021 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001022 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001023
1024 /* autodetection code based on the i2c addr */
1025 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001026 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001027 case 0x10:
1028 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1029 != EINVAL) {
1030 t->type = TUNER_TEA5761;
1031 t->mode_mask = T_RADIO;
1032 t->mode = T_STANDBY;
1033 /* Sets freq to FM range */
1034 t->radio_freq = 87.5 * 16000;
1035 tuner_lookup(t->i2c->adapter, &radio, &tv);
1036 if (tv)
1037 tv->mode_mask &= ~T_RADIO;
1038
1039 goto register_client;
1040 }
1041 break;
1042 case 0x42:
1043 case 0x43:
1044 case 0x4a:
1045 case 0x4b:
1046 /* If chip is not tda8290, don't register.
1047 since it can be tda9887*/
1048 if (tda829x_probe(t) == 0) {
1049 tuner_dbg("tda829x detected\n");
1050 } else {
1051 /* Default is being tda9887 */
1052 t->type = TUNER_TDA9887;
1053 t->mode_mask = T_RADIO | T_ANALOG_TV |
1054 T_DIGITAL_TV;
1055 t->mode = T_STANDBY;
1056 goto register_client;
1057 }
1058 break;
1059 case 0x60:
1060 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1061 != EINVAL) {
1062 t->type = TUNER_TEA5767;
1063 t->mode_mask = T_RADIO;
1064 t->mode = T_STANDBY;
1065 /* Sets freq to FM range */
1066 t->radio_freq = 87.5 * 16000;
1067 tuner_lookup(t->i2c->adapter, &radio, &tv);
1068 if (tv)
1069 tv->mode_mask &= ~T_RADIO;
1070
1071 goto register_client;
1072 }
1073 break;
1074 }
1075 }
1076
1077 /* Initializes only the first TV tuner on this adapter. Why only the
1078 first? Because there are some devices (notably the ones with TI
1079 tuners) that have more than one i2c address for the *same* device.
1080 Experience shows that, except for just one case, the first
1081 address is the right one. The exception is a Russian tuner
1082 (ACORP_Y878F). So, the desired behavior is just to enable the
1083 first found TV tuner. */
1084 tuner_lookup(t->i2c->adapter, &radio, &tv);
1085 if (tv == NULL) {
1086 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1087 if (radio == NULL)
1088 t->mode_mask |= T_RADIO;
1089 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1090 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1091 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1092 }
1093
1094 /* Should be just before return */
1095register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001096 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1097 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001098
1099 /* Sets a default mode */
1100 if (t->mode_mask & T_ANALOG_TV) {
1101 t->mode = T_ANALOG_TV;
1102 } else if (t->mode_mask & T_RADIO) {
1103 t->mode = T_RADIO;
1104 } else {
1105 t->mode = T_DIGITAL_TV;
1106 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001107 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001108 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001109 return 0;
1110}
1111
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001112static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001113{
1114 if (0 != addr) {
1115 normal_i2c[0] = addr;
1116 normal_i2c[1] = I2C_CLIENT_END;
1117 }
1118
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001119 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1120 return 0;
1121
Hans Verkuil92de1f12007-11-04 10:53:09 -03001122 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1123 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1124 * and an RTC at 0x6f which can get corrupted if probed.
1125 */
1126 if ((adap->id == I2C_HW_B_CX2388x) ||
1127 (adap->id == I2C_HW_B_CX23885)) {
1128 unsigned int i = 0;
1129
1130 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1131 i += 2;
1132 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1133 ignore[i+0] = adap->nr;
1134 ignore[i+1] = 0x6b;
1135 ignore[i+2] = adap->nr;
1136 ignore[i+3] = 0x6f;
1137 ignore[i+4] = I2C_CLIENT_END;
1138 } else
1139 printk(KERN_WARNING "tuner: "
1140 "too many options specified "
1141 "in i2c probe ignore list!\n");
1142 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001143 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001144}
1145
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001146static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001147{
1148 struct tuner *t = i2c_get_clientdata(client);
1149 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001150
1151 if (ops && ops->release)
1152 ops->release(&t->fe);
1153
1154 list_del(&t->list);
1155 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001156 return 0;
1157}
1158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159/* ----------------------------------------------------------------------- */
1160
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001161static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1162 .name = "tuner",
1163 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001164 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001165 .probe = tuner_probe,
1166 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001167 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001168 .resume = tuner_resume,
1169 .legacy_probe = tuner_legacy_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170};
1171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173/*
1174 * Overrides for Emacs so that we follow Linus's tabbing style.
1175 * ---------------------------------------------------------------------------
1176 * Local variables:
1177 * c-basic-offset: 8
1178 * End:
1179 */