blob: e56a41941489590cd1eb9bdc0daaa6eb39f0f78c [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 Krufky4e9154b2007-10-21 19:39:50 -030081static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq)
Michael Krufkye18f9442007-08-21 01:25:48 -030082{
Michael Krufky4e9154b2007-10-21 19:39:50 -030083 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
84 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -030085
86 struct analog_parameters params = {
87 .frequency = freq,
88 .mode = t->mode,
89 .audmode = t->audmode,
90 .std = t->std
91 };
92
93 if (NULL == fe_tuner_ops->set_analog_params) {
94 tuner_warn("Tuner frontend module has no way to set freq\n");
95 return;
96 }
Michael Krufky4e9154b2007-10-21 19:39:50 -030097 fe_tuner_ops->set_analog_params(fe, &params);
Michael Krufkye18f9442007-08-21 01:25:48 -030098}
99
Michael Krufky4e9154b2007-10-21 19:39:50 -0300100static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300101{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300102 if (fe->ops.tuner_ops.release)
103 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300104
Michael Krufky4e9154b2007-10-21 19:39:50 -0300105 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300106
107 /* DO NOT kfree(fe->analog_demod_priv)
108 *
109 * If we are in this function, analog_demod_priv contains a pointer
110 * to struct tuner *t. This will be kfree'd in tuner_detach().
111 *
112 * Otherwise, fe->ops.analog_demod_ops->release will
113 * handle the cleanup for analog demodulator modules.
114 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300115 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300116}
117
Michael Krufky4e9154b2007-10-21 19:39:50 -0300118static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300119{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300120 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300121
122 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300123 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300124}
125
Michael Krufky4e9154b2007-10-21 19:39:50 -0300126static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300127{
Michael Krufky14196832007-10-14 18:11:53 -0300128 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300129
Michael Krufky4e9154b2007-10-21 19:39:50 -0300130 if (fe->ops.tuner_ops.get_rf_strength)
131 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300132
133 return strength;
134}
135
Michael Krufky4e9154b2007-10-21 19:39:50 -0300136static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300137
138static struct analog_tuner_ops tuner_core_ops = {
139 .set_tv_freq = fe_set_freq,
140 .set_radio_freq = fe_set_freq,
141 .standby = fe_standby,
142 .release = fe_release,
143 .has_signal = fe_has_signal,
144 .tuner_status = tuner_status
145};
146
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700147/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148static void set_tv_freq(struct i2c_client *c, unsigned int freq)
149{
150 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300151 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700154 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 return;
156 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300157 if ((NULL == ops) || (NULL == ops->set_tv_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700158 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 return;
160 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700161 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
162 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
163 freq / 16, freq % 16 * 100 / 16, tv_range[0],
164 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200165 /* V4L2 spec: if the freq is not possible then the closest
166 possible value should be selected */
167 if (freq < tv_range[0] * 16)
168 freq = tv_range[0] * 16;
169 else
170 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
Michael Krufky4e9154b2007-10-21 19:39:50 -0300172 ops->set_tv_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
175static void set_radio_freq(struct i2c_client *c, unsigned int freq)
176{
177 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300178 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700181 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 return;
183 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300184 if ((NULL == ops) || (NULL == ops->set_radio_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700185 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 return;
187 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200188 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700189 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
190 freq / 16000, freq % 16000 * 100 / 16000,
191 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200192 /* V4L2 spec: if the freq is not possible then the closest
193 possible value should be selected */
194 if (freq < radio_range[0] * 16000)
195 freq = radio_range[0] * 16000;
196 else
197 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700199
Michael Krufky4e9154b2007-10-21 19:39:50 -0300200 ops->set_radio_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
203static void set_freq(struct i2c_client *c, unsigned long freq)
204{
205 struct tuner *t = i2c_get_clientdata(c);
206
207 switch (t->mode) {
208 case V4L2_TUNER_RADIO:
209 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700210 freq / 16000, freq % 16000 * 100 / 16000);
211 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200212 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 break;
214 case V4L2_TUNER_ANALOG_TV:
215 case V4L2_TUNER_DIGITAL_TV:
216 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700217 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200219 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300221 default:
222 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
Michael Krufky293197c2007-08-28 17:20:42 -0300226static void tuner_i2c_address_check(struct tuner *t)
227{
228 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300229 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300230 return;
231
232 tuner_warn("====================== WARNING! ======================\n");
233 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
234 tuner_warn("will soon be dropped. This message indicates that your\n");
235 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300236 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300237 tuner_warn("To ensure continued support for your device, please\n");
238 tuner_warn("send a copy of this message, along with full dmesg\n");
239 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
240 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
241 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300242 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300243 tuners[t->type].name);
244 tuner_warn("====================== WARNING! ======================\n");
245}
246
Michael Krufky4adad282007-08-27 21:59:08 -0300247static void attach_simple_tuner(struct tuner *t)
248{
249 struct simple_tuner_config cfg = {
250 .type = t->type,
251 .tun = &tuners[t->type]
252 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300253 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300254}
255
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700256static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300257 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300258 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300261 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300262 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700263 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700265 if (type == UNSET || type == TUNER_ABSENT) {
266 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 return;
268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700270 if (type >= tuner_count) {
271 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
272 return;
273 }
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300276 t->config = new_config;
277 if (tuner_callback != NULL) {
278 tuner_dbg("defining GPIO callback\n");
279 t->tuner_callback = tuner_callback;
280 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300281
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300282 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300283 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
284
285 return;
286 }
287
Michael Krufkyb2083192007-05-29 22:54:06 -0300288 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300289 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300290 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 switch (t->type) {
293 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300294 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 break;
296 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300297 {
Michael Krufky8c125f2c2007-10-27 02:00:57 -0300298 tda829x_attach(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300299 break;
300 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700301 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300302 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700303 t->type = TUNER_ABSENT;
304 t->mode_mask = T_UNINITIALIZED;
305 return;
306 }
307 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700308 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300309 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300310 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300311 t->type = TUNER_ABSENT;
312 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300313 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300314 }
315 t->mode_mask = T_RADIO;
316 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700317 case TUNER_PHILIPS_FMD1216ME_MK3:
318 buffer[0] = 0x0b;
319 buffer[1] = 0xdc;
320 buffer[2] = 0x9c;
321 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700322 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700323 mdelay(1);
324 buffer[2] = 0x86;
325 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700326 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300327 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700328 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800329 case TUNER_PHILIPS_TD1316:
330 buffer[0] = 0x0b;
331 buffer[1] = 0xdc;
332 buffer[2] = 0x86;
333 buffer[3] = 0xa4;
334 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300335 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200336 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300337 case TUNER_XC2028:
338 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300339 struct xc2028_config cfg = {
340 .i2c_adap = t->i2c->adapter,
341 .i2c_addr = t->i2c->addr,
342 .video_dev = c->adapter->algo_data,
343 .callback = t->tuner_callback,
344 };
345 if (!xc2028_attach(&t->fe, &cfg)) {
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300346 t->type = TUNER_ABSENT;
347 t->mode_mask = T_UNINITIALIZED;
348 return;
349 }
350 break;
351 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300352 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300353 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300354 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300356 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 break;
358 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700359
Michael Krufkye2be32a2007-10-21 14:35:21 -0300360 ops = t->fe.ops.analog_demod_ops;
361
Michael Krufky1dde7a42007-10-21 13:40:56 -0300362 if (((NULL == ops) ||
363 ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) &&
364 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300365 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
366 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300367
Michael Krufky1dde7a42007-10-21 13:40:56 -0300368 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300369 t->fe.analog_demod_priv = t;
Michael Krufkye18f9442007-08-21 01:25:48 -0300370 }
371
Michael Krufky49427442007-10-30 09:44:12 -0300372 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300373
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700374 if (t->mode_mask == T_UNINITIALIZED)
375 t->mode_mask = new_mode_mask;
376
Hans Verkuil27487d42006-01-15 15:04:52 -0200377 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700378 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100379 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700380 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300381 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700384/*
385 * This function apply tuner config to tuner specified
386 * by tun_setup structure. I addr is unset, then admin status
387 * and tun addr status is more precise then current status,
388 * it's applied. Otherwise status and type are applied only to
389 * tuner with exactly the same addr.
390*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700391
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700392static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700393{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700394 struct tuner *t = i2c_get_clientdata(c);
395
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300396 tuner_dbg("set addr for type %i\n", t->type);
397
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300398 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
399 (t->mode_mask & tun_setup->mode_mask))) ||
400 (tun_setup->addr == c->addr)) {
401 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300402 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700403 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700404}
405
406static inline int check_mode(struct tuner *t, char *cmd)
407{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700408 if ((1 << t->mode & t->mode_mask) == 0) {
409 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700410 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700411
412 switch (t->mode) {
413 case V4L2_TUNER_RADIO:
414 tuner_dbg("Cmd %s accepted for radio\n", cmd);
415 break;
416 case V4L2_TUNER_ANALOG_TV:
417 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
418 break;
419 case V4L2_TUNER_DIGITAL_TV:
420 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
421 break;
422 }
423 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700424}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700425
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700426/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427static int tuner_fixup_std(struct tuner *t)
428{
429 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300431 case '6':
432 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
433 t->std = V4L2_STD_PAL_60;
434 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 case 'b':
436 case 'B':
437 case 'g':
438 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700439 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 t->std = V4L2_STD_PAL_BG;
441 break;
442 case 'i':
443 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700444 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 t->std = V4L2_STD_PAL_I;
446 break;
447 case 'd':
448 case 'D':
449 case 'k':
450 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700451 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 t->std = V4L2_STD_PAL_DK;
453 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700454 case 'M':
455 case 'm':
456 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
457 t->std = V4L2_STD_PAL_M;
458 break;
459 case 'N':
460 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200461 if (pal[1] == 'c' || pal[1] == 'C') {
462 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
463 t->std = V4L2_STD_PAL_Nc;
464 } else {
465 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
466 t->std = V4L2_STD_PAL_N;
467 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700468 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700469 case '-':
470 /* default parameter, do nothing */
471 break;
472 default:
473 tuner_warn ("pal= argument not recognised\n");
474 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
476 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700477 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
478 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200479 case 'b':
480 case 'B':
481 case 'g':
482 case 'G':
483 case 'h':
484 case 'H':
485 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
486 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
487 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700488 case 'd':
489 case 'D':
490 case 'k':
491 case 'K':
492 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
493 t->std = V4L2_STD_SECAM_DK;
494 break;
495 case 'l':
496 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800497 if ((secam[1]=='C')||(secam[1]=='c')) {
498 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
499 t->std = V4L2_STD_SECAM_LC;
500 } else {
501 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
502 t->std = V4L2_STD_SECAM_L;
503 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700504 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700505 case '-':
506 /* default parameter, do nothing */
507 break;
508 default:
509 tuner_warn ("secam= argument not recognised\n");
510 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700511 }
512 }
513
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200514 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
515 switch (ntsc[0]) {
516 case 'm':
517 case 'M':
518 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
519 t->std = V4L2_STD_NTSC_M;
520 break;
521 case 'j':
522 case 'J':
523 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
524 t->std = V4L2_STD_NTSC_M_JP;
525 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200526 case 'k':
527 case 'K':
528 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
529 t->std = V4L2_STD_NTSC_M_KR;
530 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200531 case '-':
532 /* default parameter, do nothing */
533 break;
534 default:
535 tuner_info("ntsc= argument not recognised\n");
536 break;
537 }
538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return 0;
540}
541
Michael Krufky4e9154b2007-10-21 19:39:50 -0300542static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200543{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300544 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200545 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300546 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300547 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200548 const char *p;
549
550 switch (t->mode) {
551 case V4L2_TUNER_RADIO: p = "radio"; break;
552 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
553 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
554 default: p = "undefined"; break;
555 }
556 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200557 freq = t->radio_freq / 16000;
558 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200559 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200560 freq = t->tv_freq / 16;
561 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200562 }
563 tuner_info("Tuner mode: %s\n", p);
564 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300565 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200566 if (t->mode != V4L2_TUNER_RADIO)
567 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300568 if (fe_tuner_ops->get_status) {
569 u32 tuner_status;
570
571 fe_tuner_ops->get_status(&t->fe, &tuner_status);
572 if (tuner_status & TUNER_STATUS_LOCKED)
573 tuner_info("Tuner is locked.\n");
574 if (tuner_status & TUNER_STATUS_STEREO)
575 tuner_info("Stereo: yes\n");
576 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300577 if (ops) {
578 if (ops->has_signal)
579 tuner_info("Signal strength: %d\n",
580 ops->has_signal(fe));
581 if (ops->is_stereo)
582 tuner_info("Stereo: %s\n",
583 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200584 }
585}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587/* ---------------------------------------------------------------------- */
588
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700589/*
590 * Switch tuner to other mode. If tuner support both tv and radio,
591 * set another frequency to some value (This is needed for some pal
592 * tuners to avoid locking). Otherwise, just put second tuner in
593 * standby mode.
594 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700596static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
597{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300598 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
599
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800600 if (mode == t->mode)
601 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700602
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800603 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700604
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800605 if (check_mode(t, cmd) == EINVAL) {
606 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300607 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300608 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800609 return EINVAL;
610 }
611 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700612}
613
614#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800615 tuner_dbg("switching to v4l2\n"); \
616 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700617
618static inline int check_v4l2(struct tuner *t)
619{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300620 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
621 TV, v4l1 for radio), until that is fixed this code is disabled.
622 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
623 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700624 return 0;
625}
626
627static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
629 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300630 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300631 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Hans Verkuilf9195de2006-01-11 19:01:01 -0200633 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300634 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200635
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700636 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700638 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300639 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 -0700640 ((struct tuner_setup *)arg)->type,
641 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300642 ((struct tuner_setup *)arg)->mode_mask,
643 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700644
645 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700646 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200648 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
649 == EINVAL)
650 return 0;
651 if (t->radio_freq)
652 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700654 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200655 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
656 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300657 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300658 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300659 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200660 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300661#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700662 case VIDIOCSAUDIO:
663 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
664 return 0;
665 if (check_v4l2(t) == EINVAL)
666 return 0;
667
668 /* Should be implemented, since bttv calls it */
669 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700672 {
673 static const v4l2_std_id map[] = {
674 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
675 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
676 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
677 [4 /* bttv */ ] = V4L2_STD_PAL_M,
678 [5 /* bttv */ ] = V4L2_STD_PAL_N,
679 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
680 };
681 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700683 if (check_v4l2(t) == EINVAL)
684 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700685
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700686 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700689 if (vc->norm < ARRAY_SIZE(map))
690 t->std = map[vc->norm];
691 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200692 if (t->tv_freq)
693 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700694 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700695 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700696 case VIDIOCSFREQ:
697 {
698 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700699
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700700 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
701 return 0;
702 if (check_v4l2(t) == EINVAL)
703 return 0;
704
705 set_freq(client, *v);
706 return 0;
707 }
708 case VIDIOCGTUNER:
709 {
710 struct video_tuner *vt = arg;
711
712 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
713 return 0;
714 if (check_v4l2(t) == EINVAL)
715 return 0;
716
717 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300718 if (fe_tuner_ops->get_status) {
719 u32 tuner_status;
720
721 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300722 if (tuner_status & TUNER_STATUS_STEREO)
723 vt->flags |= VIDEO_TUNER_STEREO_ON;
724 else
725 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300726 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300727 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300728 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300729 vt->flags |=
730 VIDEO_TUNER_STEREO_ON;
731 else
732 vt->flags &=
733 ~VIDEO_TUNER_STEREO_ON;
734 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700735 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300736 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300737 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300738
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700739 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
740
741 vt->rangelow = radio_range[0] * 16000;
742 vt->rangehigh = radio_range[1] * 16000;
743
744 } else {
745 vt->rangelow = tv_range[0] * 16;
746 vt->rangehigh = tv_range[1] * 16;
747 }
748
749 return 0;
750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700752 {
753 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700755 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
756 return 0;
757 if (check_v4l2(t) == EINVAL)
758 return 0;
759
Michael Krufkye18f9442007-08-21 01:25:48 -0300760 if (V4L2_TUNER_RADIO == t->mode) {
761 if (fe_tuner_ops->get_status) {
762 u32 tuner_status;
763
764 fe_tuner_ops->get_status(&t->fe, &tuner_status);
765 va->mode = (tuner_status & TUNER_STATUS_STEREO)
766 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300767 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300768 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300769 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
770 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700771 return 0;
772 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300773#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300774 case TUNER_SET_CONFIG:
775 {
776 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
777 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300779 if (t->type != cfg->tuner)
780 break;
781
782 if (t->type == TUNER_TDA9887) {
783 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300784 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300785 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300786 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300787
788 if (NULL == fe_tuner_ops->set_config) {
789 tuner_warn("Tuner frontend module has no way to "
790 "set config\n");
791 break;
792 }
793 fe_tuner_ops->set_config(&t->fe, cfg->priv);
794
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300795 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300796 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300797 /* --- v4l ioctls --- */
798 /* take care: bttv does userspace copying, we'll get a
799 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700801 {
802 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700804 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
805 == EINVAL)
806 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700807
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700808 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700810 t->std = *id;
811 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200812 if (t->tv_freq)
813 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700814 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700815 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700816 case VIDIOC_S_FREQUENCY:
817 {
818 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700819
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300820 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
821 == EINVAL)
822 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700823 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200824 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700825
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700826 break;
827 }
828 case VIDIOC_G_FREQUENCY:
829 {
830 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700831
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700832 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
833 return 0;
834 switch_v4l2();
835 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300836 if (fe_tuner_ops->get_frequency) {
837 u32 abs_freq;
838
839 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
840 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
841 (abs_freq * 2 + 125/2) / 125 :
842 (abs_freq + 62500/2) / 62500;
843 break;
844 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200845 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
846 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700847 break;
848 }
849 case VIDIOC_G_TUNER:
850 {
851 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700852
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700853 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
854 return 0;
855 switch_v4l2();
856
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200857 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300858 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300859 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300860 if (t->mode == V4L2_TUNER_ANALOG_TV)
861 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200862 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700863 tuner->rangelow = tv_range[0] * 16;
864 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200865 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700866 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200867
868 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200869 tuner->rxsubchans =
870 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300871 if (fe_tuner_ops->get_status) {
872 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200873
Michael Krufkye18f9442007-08-21 01:25:48 -0300874 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300875 tuner->rxsubchans =
876 (tuner_status & TUNER_STATUS_STEREO) ?
877 V4L2_TUNER_SUB_STEREO :
878 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300879 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300880 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300881 tuner->rxsubchans =
882 ops->is_stereo(&t->fe) ?
883 V4L2_TUNER_SUB_STEREO :
884 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300885 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300886 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300887 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300888 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200889 tuner->capability |=
890 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
891 tuner->audmode = t->audmode;
892 tuner->rangelow = radio_range[0] * 16000;
893 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700894 break;
895 }
896 case VIDIOC_S_TUNER:
897 {
898 struct v4l2_tuner *tuner = arg;
899
900 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
901 return 0;
902
903 switch_v4l2();
904
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200905 /* do nothing unless we're a radio tuner */
906 if (t->mode != V4L2_TUNER_RADIO)
907 break;
908 t->audmode = tuner->audmode;
909 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700910 break;
911 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200912 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300913 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300914 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200915 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917
918 return 0;
919}
920
Jean Delvare21b48a72007-03-12 19:20:15 -0300921static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300923 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300925 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 /* FIXME: power down ??? */
927 return 0;
928}
929
Jean Delvare21b48a72007-03-12 19:20:15 -0300930static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300932 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300934 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -0200935 if (V4L2_TUNER_RADIO == t->mode) {
936 if (t->radio_freq)
937 set_freq(c, t->radio_freq);
938 } else {
939 if (t->tv_freq)
940 set_freq(c, t->tv_freq);
941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 return 0;
943}
944
Hans Verkuil92de1f12007-11-04 10:53:09 -0300945/* ---------------------------------------------------------------------- */
946
947LIST_HEAD(tuner_list);
948
949/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300950 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -0300951 certain no other devices will be added/deleted at the same time, I2C
952 core protects against that. */
953static void tuner_lookup(struct i2c_adapter *adap,
954 struct tuner **radio, struct tuner **tv)
955{
956 struct tuner *pos;
957
958 *radio = NULL;
959 *tv = NULL;
960
961 list_for_each_entry(pos, &tuner_list, list) {
962 int mode_mask;
963
964 if (pos->i2c->adapter != adap ||
965 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
966 continue;
967
968 mode_mask = pos->mode_mask & ~T_STANDBY;
969 if (*radio == NULL && mode_mask == T_RADIO)
970 *radio = pos;
971 /* Note: currently TDA9887 is the only demod-only
972 device. If other devices appear then we need to
973 make this test more general. */
974 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
975 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
976 *tv = pos;
977 }
978}
979
980/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300981 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -0300982 */
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300983static int tuner_probe(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -0300984{
Hans Verkuil92de1f12007-11-04 10:53:09 -0300985 struct tuner *t;
986 struct tuner *radio;
987 struct tuner *tv;
988
Hans Verkuil92de1f12007-11-04 10:53:09 -0300989 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300990 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -0300991 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -0300992 t->i2c = client;
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300993 strlcpy(client->name, "(tuner unset)", sizeof(client->name));
Hans Verkuil92de1f12007-11-04 10:53:09 -0300994 i2c_set_clientdata(client, t);
995 t->type = UNSET;
996 t->audmode = V4L2_TUNER_MODE_STEREO;
997 t->mode_mask = T_UNINITIALIZED;
998
999 if (show_i2c) {
1000 unsigned char buffer[16];
1001 int i, rc;
1002
1003 memset(buffer, 0, sizeof(buffer));
1004 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1005 tuner_info("I2C RECV = ");
1006 for (i = 0; i < rc; i++)
1007 printk(KERN_CONT "%02x ", buffer[i]);
1008 printk("\n");
1009 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001010 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001011 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001012 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1013 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001014 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001015 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001016
1017 /* autodetection code based on the i2c addr */
1018 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001019 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001020 case 0x10:
1021 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1022 != EINVAL) {
1023 t->type = TUNER_TEA5761;
1024 t->mode_mask = T_RADIO;
1025 t->mode = T_STANDBY;
1026 /* Sets freq to FM range */
1027 t->radio_freq = 87.5 * 16000;
1028 tuner_lookup(t->i2c->adapter, &radio, &tv);
1029 if (tv)
1030 tv->mode_mask &= ~T_RADIO;
1031
1032 goto register_client;
1033 }
1034 break;
1035 case 0x42:
1036 case 0x43:
1037 case 0x4a:
1038 case 0x4b:
1039 /* If chip is not tda8290, don't register.
1040 since it can be tda9887*/
1041 if (tda829x_probe(t) == 0) {
1042 tuner_dbg("tda829x detected\n");
1043 } else {
1044 /* Default is being tda9887 */
1045 t->type = TUNER_TDA9887;
1046 t->mode_mask = T_RADIO | T_ANALOG_TV |
1047 T_DIGITAL_TV;
1048 t->mode = T_STANDBY;
1049 goto register_client;
1050 }
1051 break;
1052 case 0x60:
1053 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1054 != EINVAL) {
1055 t->type = TUNER_TEA5767;
1056 t->mode_mask = T_RADIO;
1057 t->mode = T_STANDBY;
1058 /* Sets freq to FM range */
1059 t->radio_freq = 87.5 * 16000;
1060 tuner_lookup(t->i2c->adapter, &radio, &tv);
1061 if (tv)
1062 tv->mode_mask &= ~T_RADIO;
1063
1064 goto register_client;
1065 }
1066 break;
1067 }
1068 }
1069
1070 /* Initializes only the first TV tuner on this adapter. Why only the
1071 first? Because there are some devices (notably the ones with TI
1072 tuners) that have more than one i2c address for the *same* device.
1073 Experience shows that, except for just one case, the first
1074 address is the right one. The exception is a Russian tuner
1075 (ACORP_Y878F). So, the desired behavior is just to enable the
1076 first found TV tuner. */
1077 tuner_lookup(t->i2c->adapter, &radio, &tv);
1078 if (tv == NULL) {
1079 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1080 if (radio == NULL)
1081 t->mode_mask |= T_RADIO;
1082 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1083 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1084 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1085 }
1086
1087 /* Should be just before return */
1088register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001089 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1090 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001091
1092 /* Sets a default mode */
1093 if (t->mode_mask & T_ANALOG_TV) {
1094 t->mode = T_ANALOG_TV;
1095 } else if (t->mode_mask & T_RADIO) {
1096 t->mode = T_RADIO;
1097 } else {
1098 t->mode = T_DIGITAL_TV;
1099 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001100 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001101 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001102 return 0;
1103}
1104
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001105static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001106{
1107 if (0 != addr) {
1108 normal_i2c[0] = addr;
1109 normal_i2c[1] = I2C_CLIENT_END;
1110 }
1111
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001112 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1113 return 0;
1114
Hans Verkuil92de1f12007-11-04 10:53:09 -03001115 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1116 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1117 * and an RTC at 0x6f which can get corrupted if probed.
1118 */
1119 if ((adap->id == I2C_HW_B_CX2388x) ||
1120 (adap->id == I2C_HW_B_CX23885)) {
1121 unsigned int i = 0;
1122
1123 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1124 i += 2;
1125 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1126 ignore[i+0] = adap->nr;
1127 ignore[i+1] = 0x6b;
1128 ignore[i+2] = adap->nr;
1129 ignore[i+3] = 0x6f;
1130 ignore[i+4] = I2C_CLIENT_END;
1131 } else
1132 printk(KERN_WARNING "tuner: "
1133 "too many options specified "
1134 "in i2c probe ignore list!\n");
1135 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001136 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001137}
1138
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001139static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001140{
1141 struct tuner *t = i2c_get_clientdata(client);
1142 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001143
1144 if (ops && ops->release)
1145 ops->release(&t->fe);
1146
1147 list_del(&t->list);
1148 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001149 return 0;
1150}
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152/* ----------------------------------------------------------------------- */
1153
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001154static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1155 .name = "tuner",
1156 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001157 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001158 .probe = tuner_probe,
1159 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001160 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001161 .resume = tuner_resume,
1162 .legacy_probe = tuner_legacy_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163};
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166/*
1167 * Overrides for Emacs so that we follow Linus's tabbing style.
1168 * ---------------------------------------------------------------------------
1169 * Local variables:
1170 * c-basic-offset: 8
1171 * End:
1172 */