blob: f22c41bb97ef8000caf750aca60d399894492f9d [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
Michael Krufkyf7f427e2007-12-16 22:02:26 -030036struct tuner {
37 /* device */
38 struct dvb_frontend fe;
39 struct i2c_client *i2c;
40 struct list_head list;
41 unsigned int using_v4l2:1;
42
43 /* keep track of the current settings */
44 v4l2_std_id std;
45 unsigned int tv_freq;
46 unsigned int radio_freq;
47 unsigned int audmode;
48
49 unsigned int mode;
50 unsigned int mode_mask; /* Combination of allowable modes */
51
52 unsigned int type; /* chip type id */
53 unsigned int config;
54 int (*tuner_callback) (void *dev, int command, int arg);
55};
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/* standard i2c insmod options */
58static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030059#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030060 0x10,
61#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080062 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070063 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
64 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 I2C_CLIENT_END
66};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068I2C_CLIENT_INSMOD;
69
70/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070071static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070072static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070073static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* insmod options used at runtime => read/write */
Michael Krufkyab166052007-12-09 02:26:48 -030076static int tuner_debug;
77
78#define tuner_warn(fmt, arg...) do { \
79 printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
80 i2c_adapter_id(t->i2c->adapter), \
81 t->i2c->addr, ##arg); \
82 } while (0)
83
84#define tuner_info(fmt, arg...) do { \
85 printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
86 i2c_adapter_id(t->i2c->adapter), \
87 t->i2c->addr, ##arg); \
88 } while (0)
89
90#define tuner_err(fmt, arg...) do { \
91 printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
92 i2c_adapter_id(t->i2c->adapter), \
93 t->i2c->addr, ##arg); \
94 } while (0)
95
96#define tuner_dbg(fmt, arg...) do { \
97 if (tuner_debug) \
98 printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
99 i2c_adapter_id(t->i2c->adapter), \
100 t->i2c->addr, ##arg); \
101 } while (0)
102
103/* ------------------------------------------------------------------------ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700105static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static unsigned int radio_range[2] = { 65, 108 };
107
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200108static char pal[] = "--";
109static char secam[] = "--";
110static char ntsc[] = "-";
111
Hans Verkuilf9195de2006-01-11 19:01:01 -0200112
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200113module_param(addr, int, 0444);
114module_param(no_autodetect, int, 0444);
115module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -0200116module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200117module_param_string(pal, pal, sizeof(pal), 0644);
118module_param_string(secam, secam, sizeof(secam), 0644);
119module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700120module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121module_param_array(radio_range, int, NULL, 0644);
122
123MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
124MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
125MODULE_LICENSE("GPL");
126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127/* ---------------------------------------------------------------------- */
128
Michael Krufkyc7919d52007-12-08 17:06:30 -0300129static void fe_set_params(struct dvb_frontend *fe,
130 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -0300131{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300132 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
133 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -0300134
Michael Krufkye18f9442007-08-21 01:25:48 -0300135 if (NULL == fe_tuner_ops->set_analog_params) {
136 tuner_warn("Tuner frontend module has no way to set freq\n");
137 return;
138 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300139 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300140}
141
Michael Krufky4e9154b2007-10-21 19:39:50 -0300142static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300143{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300144 if (fe->ops.tuner_ops.release)
145 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300146
Michael Krufky4e9154b2007-10-21 19:39:50 -0300147 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300148
149 /* DO NOT kfree(fe->analog_demod_priv)
150 *
151 * If we are in this function, analog_demod_priv contains a pointer
152 * to struct tuner *t. This will be kfree'd in tuner_detach().
153 *
154 * Otherwise, fe->ops.analog_demod_ops->release will
155 * handle the cleanup for analog demodulator modules.
156 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300157 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300158}
159
Michael Krufky4e9154b2007-10-21 19:39:50 -0300160static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300161{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300162 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300163
164 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300165 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300166}
167
Michael Krufky4e9154b2007-10-21 19:39:50 -0300168static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300169{
Michael Krufky14196832007-10-14 18:11:53 -0300170 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300171
Michael Krufky4e9154b2007-10-21 19:39:50 -0300172 if (fe->ops.tuner_ops.get_rf_strength)
173 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300174
175 return strength;
176}
177
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300178static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
179{
180 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
181 struct tuner *t = fe->analog_demod_priv;
182
183 if (fe_tuner_ops->set_config)
184 return fe_tuner_ops->set_config(fe, priv_cfg);
185
186 tuner_warn("Tuner frontend module has no way to set config\n");
187
188 return 0;
189}
190
Michael Krufky4e9154b2007-10-21 19:39:50 -0300191static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300192
193static struct analog_tuner_ops tuner_core_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300194 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300195 .standby = fe_standby,
196 .release = fe_release,
197 .has_signal = fe_has_signal,
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300198 .set_config = fe_set_config,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300199 .tuner_status = tuner_status
200};
201
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700202/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static void set_tv_freq(struct i2c_client *c, unsigned int freq)
204{
205 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300206 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Michael Krufkyc7919d52007-12-08 17:06:30 -0300208 struct analog_parameters params = {
209 .mode = t->mode,
210 .audmode = t->audmode,
211 .std = t->std
212 };
213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700215 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 return;
217 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300218 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700219 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return;
221 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700222 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
223 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
224 freq / 16, freq % 16 * 100 / 16, tv_range[0],
225 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200226 /* V4L2 spec: if the freq is not possible then the closest
227 possible value should be selected */
228 if (freq < tv_range[0] * 16)
229 freq = tv_range[0] * 16;
230 else
231 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300233 params.frequency = freq;
234
235 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
238static void set_radio_freq(struct i2c_client *c, unsigned int freq)
239{
240 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300241 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Michael Krufkyc7919d52007-12-08 17:06:30 -0300243 struct analog_parameters params = {
244 .mode = t->mode,
245 .audmode = t->audmode,
246 .std = t->std
247 };
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700250 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 return;
252 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300253 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700254 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return;
256 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200257 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700258 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
259 freq / 16000, freq % 16000 * 100 / 16000,
260 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200261 /* V4L2 spec: if the freq is not possible then the closest
262 possible value should be selected */
263 if (freq < radio_range[0] * 16000)
264 freq = radio_range[0] * 16000;
265 else
266 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300268 params.frequency = freq;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700269
Michael Krufkyc7919d52007-12-08 17:06:30 -0300270 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
273static void set_freq(struct i2c_client *c, unsigned long freq)
274{
275 struct tuner *t = i2c_get_clientdata(c);
276
277 switch (t->mode) {
278 case V4L2_TUNER_RADIO:
279 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700280 freq / 16000, freq % 16000 * 100 / 16000);
281 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200282 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 break;
284 case V4L2_TUNER_ANALOG_TV:
285 case V4L2_TUNER_DIGITAL_TV:
286 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700287 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200289 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300291 default:
292 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Michael Krufky293197c2007-08-28 17:20:42 -0300296static void tuner_i2c_address_check(struct tuner *t)
297{
298 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300299 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300300 return;
301
302 tuner_warn("====================== WARNING! ======================\n");
303 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
304 tuner_warn("will soon be dropped. This message indicates that your\n");
305 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300306 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300307 tuner_warn("To ensure continued support for your device, please\n");
308 tuner_warn("send a copy of this message, along with full dmesg\n");
309 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
310 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
311 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300312 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300313 tuners[t->type].name);
314 tuner_warn("====================== WARNING! ======================\n");
315}
316
Michael Krufky4adad282007-08-27 21:59:08 -0300317static void attach_simple_tuner(struct tuner *t)
318{
319 struct simple_tuner_config cfg = {
320 .type = t->type,
321 .tun = &tuners[t->type]
322 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300323 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300324}
325
Michael Krufkyab166052007-12-09 02:26:48 -0300326static void attach_tda829x(struct tuner *t)
327{
328 struct tda829x_config cfg = {
329 .lna_cfg = &t->config,
330 .tuner_callback = t->tuner_callback,
331 };
332 tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
333}
334
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700335static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300336 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300337 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300340 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300341 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700342 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700344 if (type == UNSET || type == TUNER_ABSENT) {
345 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return;
347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700349 if (type >= tuner_count) {
350 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
351 return;
352 }
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300355 t->config = new_config;
356 if (tuner_callback != NULL) {
357 tuner_dbg("defining GPIO callback\n");
358 t->tuner_callback = tuner_callback;
359 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300360
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300361 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300362 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
363
364 return;
365 }
366
Michael Krufkyb2083192007-05-29 22:54:06 -0300367 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300368 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300369 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 switch (t->type) {
372 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300373 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 break;
375 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300376 {
Michael Krufkyab166052007-12-09 02:26:48 -0300377 attach_tda829x(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300378 break;
379 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700380 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300381 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700382 t->type = TUNER_ABSENT;
383 t->mode_mask = T_UNINITIALIZED;
384 return;
385 }
386 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700387 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300388 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300389 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300390 t->type = TUNER_ABSENT;
391 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300392 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300393 }
394 t->mode_mask = T_RADIO;
395 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700396 case TUNER_PHILIPS_FMD1216ME_MK3:
397 buffer[0] = 0x0b;
398 buffer[1] = 0xdc;
399 buffer[2] = 0x9c;
400 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700401 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700402 mdelay(1);
403 buffer[2] = 0x86;
404 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700405 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300406 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700407 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800408 case TUNER_PHILIPS_TD1316:
409 buffer[0] = 0x0b;
410 buffer[1] = 0xdc;
411 buffer[2] = 0x86;
412 buffer[3] = 0xa4;
413 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300414 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200415 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300416 case TUNER_XC2028:
417 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300418 struct xc2028_config cfg = {
419 .i2c_adap = t->i2c->adapter,
420 .i2c_addr = t->i2c->addr,
421 .video_dev = c->adapter->algo_data,
422 .callback = t->tuner_callback,
423 };
424 if (!xc2028_attach(&t->fe, &cfg)) {
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300425 t->type = TUNER_ABSENT;
426 t->mode_mask = T_UNINITIALIZED;
427 return;
428 }
429 break;
430 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300431 case TUNER_TDA9887:
Michael Krufky8ca40832007-12-16 20:11:46 -0300432 tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300435 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 break;
437 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700438
Michael Krufkye2be32a2007-10-21 14:35:21 -0300439 ops = t->fe.ops.analog_demod_ops;
440
Michael Krufkyc7919d52007-12-08 17:06:30 -0300441 if (((NULL == ops) || (NULL == ops->set_params)) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300442 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300443 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
444 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300445
Michael Krufky1dde7a42007-10-21 13:40:56 -0300446 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300447 t->fe.analog_demod_priv = t;
Michael Krufkya55db8c2007-12-09 13:52:51 -0300448 } else {
449 strlcpy(t->i2c->name, ops->info.name,
450 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300451 }
452
Michael Krufky49427442007-10-30 09:44:12 -0300453 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300454
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700455 if (t->mode_mask == T_UNINITIALIZED)
456 t->mode_mask = new_mode_mask;
457
Hans Verkuil27487d42006-01-15 15:04:52 -0200458 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700459 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100460 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700461 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300462 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700465/*
466 * This function apply tuner config to tuner specified
467 * by tun_setup structure. I addr is unset, then admin status
468 * and tun addr status is more precise then current status,
469 * it's applied. Otherwise status and type are applied only to
470 * tuner with exactly the same addr.
471*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700472
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700473static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700474{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700475 struct tuner *t = i2c_get_clientdata(c);
476
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300477 tuner_dbg("set addr for type %i\n", t->type);
478
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300479 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
480 (t->mode_mask & tun_setup->mode_mask))) ||
481 (tun_setup->addr == c->addr)) {
482 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300483 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700484 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700485}
486
487static inline int check_mode(struct tuner *t, char *cmd)
488{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700489 if ((1 << t->mode & t->mode_mask) == 0) {
490 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700491 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700492
493 switch (t->mode) {
494 case V4L2_TUNER_RADIO:
495 tuner_dbg("Cmd %s accepted for radio\n", cmd);
496 break;
497 case V4L2_TUNER_ANALOG_TV:
498 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
499 break;
500 case V4L2_TUNER_DIGITAL_TV:
501 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
502 break;
503 }
504 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700505}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700506
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700507/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508static int tuner_fixup_std(struct tuner *t)
509{
510 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300512 case '6':
513 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
514 t->std = V4L2_STD_PAL_60;
515 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 case 'b':
517 case 'B':
518 case 'g':
519 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700520 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 t->std = V4L2_STD_PAL_BG;
522 break;
523 case 'i':
524 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700525 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 t->std = V4L2_STD_PAL_I;
527 break;
528 case 'd':
529 case 'D':
530 case 'k':
531 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700532 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 t->std = V4L2_STD_PAL_DK;
534 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700535 case 'M':
536 case 'm':
537 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
538 t->std = V4L2_STD_PAL_M;
539 break;
540 case 'N':
541 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200542 if (pal[1] == 'c' || pal[1] == 'C') {
543 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
544 t->std = V4L2_STD_PAL_Nc;
545 } else {
546 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
547 t->std = V4L2_STD_PAL_N;
548 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700549 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700550 case '-':
551 /* default parameter, do nothing */
552 break;
553 default:
554 tuner_warn ("pal= argument not recognised\n");
555 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
557 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700558 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
559 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200560 case 'b':
561 case 'B':
562 case 'g':
563 case 'G':
564 case 'h':
565 case 'H':
566 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
567 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
568 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700569 case 'd':
570 case 'D':
571 case 'k':
572 case 'K':
573 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
574 t->std = V4L2_STD_SECAM_DK;
575 break;
576 case 'l':
577 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800578 if ((secam[1]=='C')||(secam[1]=='c')) {
579 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
580 t->std = V4L2_STD_SECAM_LC;
581 } else {
582 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
583 t->std = V4L2_STD_SECAM_L;
584 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700585 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700586 case '-':
587 /* default parameter, do nothing */
588 break;
589 default:
590 tuner_warn ("secam= argument not recognised\n");
591 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700592 }
593 }
594
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200595 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
596 switch (ntsc[0]) {
597 case 'm':
598 case 'M':
599 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
600 t->std = V4L2_STD_NTSC_M;
601 break;
602 case 'j':
603 case 'J':
604 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
605 t->std = V4L2_STD_NTSC_M_JP;
606 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200607 case 'k':
608 case 'K':
609 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
610 t->std = V4L2_STD_NTSC_M_KR;
611 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200612 case '-':
613 /* default parameter, do nothing */
614 break;
615 default:
616 tuner_info("ntsc= argument not recognised\n");
617 break;
618 }
619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
621}
622
Michael Krufky4e9154b2007-10-21 19:39:50 -0300623static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200624{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300625 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200626 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300627 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300628 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200629 const char *p;
630
631 switch (t->mode) {
632 case V4L2_TUNER_RADIO: p = "radio"; break;
633 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
634 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
635 default: p = "undefined"; break;
636 }
637 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200638 freq = t->radio_freq / 16000;
639 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200640 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200641 freq = t->tv_freq / 16;
642 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200643 }
644 tuner_info("Tuner mode: %s\n", p);
645 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300646 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200647 if (t->mode != V4L2_TUNER_RADIO)
648 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300649 if (fe_tuner_ops->get_status) {
650 u32 tuner_status;
651
652 fe_tuner_ops->get_status(&t->fe, &tuner_status);
653 if (tuner_status & TUNER_STATUS_LOCKED)
654 tuner_info("Tuner is locked.\n");
655 if (tuner_status & TUNER_STATUS_STEREO)
656 tuner_info("Stereo: yes\n");
657 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300658 if (ops) {
659 if (ops->has_signal)
660 tuner_info("Signal strength: %d\n",
661 ops->has_signal(fe));
662 if (ops->is_stereo)
663 tuner_info("Stereo: %s\n",
664 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200665 }
666}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668/* ---------------------------------------------------------------------- */
669
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700670/*
671 * Switch tuner to other mode. If tuner support both tv and radio,
672 * set another frequency to some value (This is needed for some pal
673 * tuners to avoid locking). Otherwise, just put second tuner in
674 * standby mode.
675 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700677static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
678{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300679 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
680
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800681 if (mode == t->mode)
682 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700683
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800684 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700685
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800686 if (check_mode(t, cmd) == EINVAL) {
687 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300688 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300689 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800690 return EINVAL;
691 }
692 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700693}
694
695#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800696 tuner_dbg("switching to v4l2\n"); \
697 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700698
699static inline int check_v4l2(struct tuner *t)
700{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300701 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
702 TV, v4l1 for radio), until that is fixed this code is disabled.
703 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
704 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700705 return 0;
706}
707
708static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300711 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300712 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Hans Verkuilf9195de2006-01-11 19:01:01 -0200714 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300715 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200716
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700717 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700719 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300720 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 -0700721 ((struct tuner_setup *)arg)->type,
722 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300723 ((struct tuner_setup *)arg)->mode_mask,
724 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700725
726 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700727 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200729 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
730 == EINVAL)
731 return 0;
732 if (t->radio_freq)
733 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700735 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200736 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
737 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300738 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300739 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300740 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200741 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300742#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700743 case VIDIOCSAUDIO:
744 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
745 return 0;
746 if (check_v4l2(t) == EINVAL)
747 return 0;
748
749 /* Should be implemented, since bttv calls it */
750 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700751 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700753 {
754 static const v4l2_std_id map[] = {
755 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
756 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
757 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
758 [4 /* bttv */ ] = V4L2_STD_PAL_M,
759 [5 /* bttv */ ] = V4L2_STD_PAL_N,
760 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
761 };
762 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700764 if (check_v4l2(t) == EINVAL)
765 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700766
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700767 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
768 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700770 if (vc->norm < ARRAY_SIZE(map))
771 t->std = map[vc->norm];
772 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200773 if (t->tv_freq)
774 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700775 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700776 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700777 case VIDIOCSFREQ:
778 {
779 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700780
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700781 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
782 return 0;
783 if (check_v4l2(t) == EINVAL)
784 return 0;
785
786 set_freq(client, *v);
787 return 0;
788 }
789 case VIDIOCGTUNER:
790 {
791 struct video_tuner *vt = arg;
792
793 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
794 return 0;
795 if (check_v4l2(t) == EINVAL)
796 return 0;
797
798 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300799 if (fe_tuner_ops->get_status) {
800 u32 tuner_status;
801
802 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300803 if (tuner_status & TUNER_STATUS_STEREO)
804 vt->flags |= VIDEO_TUNER_STEREO_ON;
805 else
806 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300807 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300808 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300809 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300810 vt->flags |=
811 VIDEO_TUNER_STEREO_ON;
812 else
813 vt->flags &=
814 ~VIDEO_TUNER_STEREO_ON;
815 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700816 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300817 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300818 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300819
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700820 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
821
822 vt->rangelow = radio_range[0] * 16000;
823 vt->rangehigh = radio_range[1] * 16000;
824
825 } else {
826 vt->rangelow = tv_range[0] * 16;
827 vt->rangehigh = tv_range[1] * 16;
828 }
829
830 return 0;
831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700833 {
834 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700836 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
837 return 0;
838 if (check_v4l2(t) == EINVAL)
839 return 0;
840
Michael Krufkye18f9442007-08-21 01:25:48 -0300841 if (V4L2_TUNER_RADIO == t->mode) {
842 if (fe_tuner_ops->get_status) {
843 u32 tuner_status;
844
845 fe_tuner_ops->get_status(&t->fe, &tuner_status);
846 va->mode = (tuner_status & TUNER_STATUS_STEREO)
847 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300848 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300849 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300850 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
851 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700852 return 0;
853 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300854#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300855 case TUNER_SET_CONFIG:
856 {
Michael Krufky710401b2007-12-16 19:53:32 -0300857 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300858 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300860 if (t->type != cfg->tuner)
861 break;
862
Michael Krufky710401b2007-12-16 19:53:32 -0300863 if ((NULL == ops) || (NULL == ops->set_config)) {
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300864 tuner_warn("Tuner frontend module has no way to "
865 "set config\n");
866 break;
867 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300868
Michael Krufky710401b2007-12-16 19:53:32 -0300869 ops->set_config(&t->fe, cfg->priv);
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300870 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300871 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300872 /* --- v4l ioctls --- */
873 /* take care: bttv does userspace copying, we'll get a
874 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700876 {
877 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700879 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
880 == EINVAL)
881 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700882
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700883 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700885 t->std = *id;
886 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200887 if (t->tv_freq)
888 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700889 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700890 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700891 case VIDIOC_S_FREQUENCY:
892 {
893 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700894
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300895 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
896 == EINVAL)
897 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700898 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200899 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700900
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700901 break;
902 }
903 case VIDIOC_G_FREQUENCY:
904 {
905 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700906
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700907 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
908 return 0;
909 switch_v4l2();
910 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300911 if (fe_tuner_ops->get_frequency) {
912 u32 abs_freq;
913
914 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
915 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
916 (abs_freq * 2 + 125/2) / 125 :
917 (abs_freq + 62500/2) / 62500;
918 break;
919 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200920 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
921 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700922 break;
923 }
924 case VIDIOC_G_TUNER:
925 {
926 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700927
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700928 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
929 return 0;
930 switch_v4l2();
931
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200932 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300933 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300934 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300935 if (t->mode == V4L2_TUNER_ANALOG_TV)
936 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200937 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700938 tuner->rangelow = tv_range[0] * 16;
939 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200940 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700941 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200942
943 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200944 tuner->rxsubchans =
945 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300946 if (fe_tuner_ops->get_status) {
947 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200948
Michael Krufkye18f9442007-08-21 01:25:48 -0300949 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300950 tuner->rxsubchans =
951 (tuner_status & TUNER_STATUS_STEREO) ?
952 V4L2_TUNER_SUB_STEREO :
953 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300954 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300955 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300956 tuner->rxsubchans =
957 ops->is_stereo(&t->fe) ?
958 V4L2_TUNER_SUB_STEREO :
959 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300960 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300961 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300962 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300963 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200964 tuner->capability |=
965 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
966 tuner->audmode = t->audmode;
967 tuner->rangelow = radio_range[0] * 16000;
968 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700969 break;
970 }
971 case VIDIOC_S_TUNER:
972 {
973 struct v4l2_tuner *tuner = arg;
974
975 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
976 return 0;
977
978 switch_v4l2();
979
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200980 /* do nothing unless we're a radio tuner */
981 if (t->mode != V4L2_TUNER_RADIO)
982 break;
983 t->audmode = tuner->audmode;
984 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700985 break;
986 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200987 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300988 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300989 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200990 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 }
992
993 return 0;
994}
995
Jean Delvare21b48a72007-03-12 19:20:15 -0300996static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300998 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001000 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 /* FIXME: power down ??? */
1002 return 0;
1003}
1004
Jean Delvare21b48a72007-03-12 19:20:15 -03001005static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001007 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001009 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -02001010 if (V4L2_TUNER_RADIO == t->mode) {
1011 if (t->radio_freq)
1012 set_freq(c, t->radio_freq);
1013 } else {
1014 if (t->tv_freq)
1015 set_freq(c, t->tv_freq);
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return 0;
1018}
1019
Hans Verkuil92de1f12007-11-04 10:53:09 -03001020/* ---------------------------------------------------------------------- */
1021
1022LIST_HEAD(tuner_list);
1023
1024/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001025 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -03001026 certain no other devices will be added/deleted at the same time, I2C
1027 core protects against that. */
1028static void tuner_lookup(struct i2c_adapter *adap,
1029 struct tuner **radio, struct tuner **tv)
1030{
1031 struct tuner *pos;
1032
1033 *radio = NULL;
1034 *tv = NULL;
1035
1036 list_for_each_entry(pos, &tuner_list, list) {
1037 int mode_mask;
1038
1039 if (pos->i2c->adapter != adap ||
1040 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
1041 continue;
1042
1043 mode_mask = pos->mode_mask & ~T_STANDBY;
1044 if (*radio == NULL && mode_mask == T_RADIO)
1045 *radio = pos;
1046 /* Note: currently TDA9887 is the only demod-only
1047 device. If other devices appear then we need to
1048 make this test more general. */
1049 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
1050 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
1051 *tv = pos;
1052 }
1053}
1054
1055/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001056 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -03001057 */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001058static int tuner_probe(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001059{
Hans Verkuil92de1f12007-11-04 10:53:09 -03001060 struct tuner *t;
1061 struct tuner *radio;
1062 struct tuner *tv;
1063
Hans Verkuil92de1f12007-11-04 10:53:09 -03001064 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001065 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001066 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001067 t->i2c = client;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001068 strlcpy(client->name, "(tuner unset)", sizeof(client->name));
Hans Verkuil92de1f12007-11-04 10:53:09 -03001069 i2c_set_clientdata(client, t);
1070 t->type = UNSET;
1071 t->audmode = V4L2_TUNER_MODE_STEREO;
1072 t->mode_mask = T_UNINITIALIZED;
1073
1074 if (show_i2c) {
1075 unsigned char buffer[16];
1076 int i, rc;
1077
1078 memset(buffer, 0, sizeof(buffer));
1079 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1080 tuner_info("I2C RECV = ");
1081 for (i = 0; i < rc; i++)
1082 printk(KERN_CONT "%02x ", buffer[i]);
1083 printk("\n");
1084 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001085 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001086 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001087 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1088 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001089 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001090 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001091
1092 /* autodetection code based on the i2c addr */
1093 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001094 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001095 case 0x10:
1096 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1097 != EINVAL) {
1098 t->type = TUNER_TEA5761;
1099 t->mode_mask = T_RADIO;
1100 t->mode = T_STANDBY;
1101 /* Sets freq to FM range */
1102 t->radio_freq = 87.5 * 16000;
1103 tuner_lookup(t->i2c->adapter, &radio, &tv);
1104 if (tv)
1105 tv->mode_mask &= ~T_RADIO;
1106
1107 goto register_client;
1108 }
1109 break;
1110 case 0x42:
1111 case 0x43:
1112 case 0x4a:
1113 case 0x4b:
1114 /* If chip is not tda8290, don't register.
1115 since it can be tda9887*/
Michael Krufkyab166052007-12-09 02:26:48 -03001116 if (tda829x_probe(t->i2c->adapter,
1117 t->i2c->addr) == 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001118 tuner_dbg("tda829x detected\n");
1119 } else {
1120 /* Default is being tda9887 */
1121 t->type = TUNER_TDA9887;
1122 t->mode_mask = T_RADIO | T_ANALOG_TV |
1123 T_DIGITAL_TV;
1124 t->mode = T_STANDBY;
1125 goto register_client;
1126 }
1127 break;
1128 case 0x60:
1129 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1130 != EINVAL) {
1131 t->type = TUNER_TEA5767;
1132 t->mode_mask = T_RADIO;
1133 t->mode = T_STANDBY;
1134 /* Sets freq to FM range */
1135 t->radio_freq = 87.5 * 16000;
1136 tuner_lookup(t->i2c->adapter, &radio, &tv);
1137 if (tv)
1138 tv->mode_mask &= ~T_RADIO;
1139
1140 goto register_client;
1141 }
1142 break;
1143 }
1144 }
1145
1146 /* Initializes only the first TV tuner on this adapter. Why only the
1147 first? Because there are some devices (notably the ones with TI
1148 tuners) that have more than one i2c address for the *same* device.
1149 Experience shows that, except for just one case, the first
1150 address is the right one. The exception is a Russian tuner
1151 (ACORP_Y878F). So, the desired behavior is just to enable the
1152 first found TV tuner. */
1153 tuner_lookup(t->i2c->adapter, &radio, &tv);
1154 if (tv == NULL) {
1155 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1156 if (radio == NULL)
1157 t->mode_mask |= T_RADIO;
1158 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1159 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1160 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1161 }
1162
1163 /* Should be just before return */
1164register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001165 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1166 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001167
1168 /* Sets a default mode */
1169 if (t->mode_mask & T_ANALOG_TV) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001170 t->mode = V4L2_TUNER_ANALOG_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001171 } else if (t->mode_mask & T_RADIO) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001172 t->mode = V4L2_TUNER_RADIO;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001173 } else {
Michael Krufky864a6b82007-12-09 17:21:54 -03001174 t->mode = V4L2_TUNER_DIGITAL_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001175 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001176 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001177 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001178 return 0;
1179}
1180
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001181static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001182{
1183 if (0 != addr) {
1184 normal_i2c[0] = addr;
1185 normal_i2c[1] = I2C_CLIENT_END;
1186 }
1187
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001188 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1189 return 0;
1190
Hans Verkuil92de1f12007-11-04 10:53:09 -03001191 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1192 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1193 * and an RTC at 0x6f which can get corrupted if probed.
1194 */
1195 if ((adap->id == I2C_HW_B_CX2388x) ||
1196 (adap->id == I2C_HW_B_CX23885)) {
1197 unsigned int i = 0;
1198
1199 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1200 i += 2;
1201 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1202 ignore[i+0] = adap->nr;
1203 ignore[i+1] = 0x6b;
1204 ignore[i+2] = adap->nr;
1205 ignore[i+3] = 0x6f;
1206 ignore[i+4] = I2C_CLIENT_END;
1207 } else
1208 printk(KERN_WARNING "tuner: "
1209 "too many options specified "
1210 "in i2c probe ignore list!\n");
1211 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001212 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001213}
1214
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001215static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001216{
1217 struct tuner *t = i2c_get_clientdata(client);
1218 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001219
1220 if (ops && ops->release)
1221 ops->release(&t->fe);
1222
1223 list_del(&t->list);
1224 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001225 return 0;
1226}
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228/* ----------------------------------------------------------------------- */
1229
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001230static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1231 .name = "tuner",
1232 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001233 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001234 .probe = tuner_probe,
1235 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001236 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001237 .resume = tuner_resume,
1238 .legacy_probe = tuner_legacy_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239};
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242/*
1243 * Overrides for Emacs so that we follow Linus's tabbing style.
1244 * ---------------------------------------------------------------------------
1245 * Local variables:
1246 * c-basic-offset: 8
1247 * End:
1248 */