blob: 9134b997ef239bc0e12b755a063b91c4c3f8d157 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * i2c tv tuner chip device driver
4 * core core, i.e. kernel interfaces, registering and so on
5 */
6
7#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/string.h>
10#include <linux/timer.h>
11#include <linux/delay.h>
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/poll.h>
15#include <linux/i2c.h>
16#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/init.h>
Michael Krufkyffbb8072007-08-21 01:14:12 -030018#include <linux/videodev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <media/tuner.h>
Michael Krufky4adad282007-08-27 21:59:08 -030020#include <media/tuner-types.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020021#include <media/v4l2-common.h>
Hans Verkuil9dd659d2007-11-04 11:03:36 -030022#include <media/v4l2-i2c-drv-legacy.h>
Michael Krufky8218b0b2007-06-26 13:12:08 -030023#include "tuner-driver.h"
Michael Krufky96c0b7c2007-08-27 21:23:08 -030024#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030025#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030026#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030027#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030028#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030029#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030030#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#define UNSET (-1U)
33
Hans Verkuil9dd659d2007-11-04 11:03:36 -030034#define PREFIX t->i2c->driver->driver.name
Michael Krufky241020d2007-10-30 09:46:10 -030035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/* standard i2c insmod options */
37static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030038#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030039 0x10,
40#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080041 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070042 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
43 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 I2C_CLIENT_END
45};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047I2C_CLIENT_INSMOD;
48
49/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070050static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070051static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070052static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/* insmod options used at runtime => read/write */
Michael Krufkyab166052007-12-09 02:26:48 -030055static int tuner_debug;
56
57#define tuner_warn(fmt, arg...) do { \
58 printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
59 i2c_adapter_id(t->i2c->adapter), \
60 t->i2c->addr, ##arg); \
61 } while (0)
62
63#define tuner_info(fmt, arg...) do { \
64 printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
65 i2c_adapter_id(t->i2c->adapter), \
66 t->i2c->addr, ##arg); \
67 } while (0)
68
69#define tuner_err(fmt, arg...) do { \
70 printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
71 i2c_adapter_id(t->i2c->adapter), \
72 t->i2c->addr, ##arg); \
73 } while (0)
74
75#define tuner_dbg(fmt, arg...) do { \
76 if (tuner_debug) \
77 printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
78 i2c_adapter_id(t->i2c->adapter), \
79 t->i2c->addr, ##arg); \
80 } while (0)
81
82/* ------------------------------------------------------------------------ */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070084static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static unsigned int radio_range[2] = { 65, 108 };
86
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020087static char pal[] = "--";
88static char secam[] = "--";
89static char ntsc[] = "-";
90
Hans Verkuilf9195de2006-01-11 19:01:01 -020091
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020092module_param(addr, int, 0444);
93module_param(no_autodetect, int, 0444);
94module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020095module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020096module_param_string(pal, pal, sizeof(pal), 0644);
97module_param_string(secam, secam, sizeof(secam), 0644);
98module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070099module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100module_param_array(radio_range, int, NULL, 0644);
101
102MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
103MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
104MODULE_LICENSE("GPL");
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/* ---------------------------------------------------------------------- */
107
Michael Krufkyc7919d52007-12-08 17:06:30 -0300108static void fe_set_params(struct dvb_frontend *fe,
109 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -0300110{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300111 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
112 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -0300113
Michael Krufkye18f9442007-08-21 01:25:48 -0300114 if (NULL == fe_tuner_ops->set_analog_params) {
115 tuner_warn("Tuner frontend module has no way to set freq\n");
116 return;
117 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300118 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300119}
120
Michael Krufky4e9154b2007-10-21 19:39:50 -0300121static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300122{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300123 if (fe->ops.tuner_ops.release)
124 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300125
Michael Krufky4e9154b2007-10-21 19:39:50 -0300126 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300127
128 /* DO NOT kfree(fe->analog_demod_priv)
129 *
130 * If we are in this function, analog_demod_priv contains a pointer
131 * to struct tuner *t. This will be kfree'd in tuner_detach().
132 *
133 * Otherwise, fe->ops.analog_demod_ops->release will
134 * handle the cleanup for analog demodulator modules.
135 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300136 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300137}
138
Michael Krufky4e9154b2007-10-21 19:39:50 -0300139static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300140{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300141 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300142
143 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300144 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300145}
146
Michael Krufky4e9154b2007-10-21 19:39:50 -0300147static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300148{
Michael Krufky14196832007-10-14 18:11:53 -0300149 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300150
Michael Krufky4e9154b2007-10-21 19:39:50 -0300151 if (fe->ops.tuner_ops.get_rf_strength)
152 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300153
154 return strength;
155}
156
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300157static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
158{
159 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
160 struct tuner *t = fe->analog_demod_priv;
161
162 if (fe_tuner_ops->set_config)
163 return fe_tuner_ops->set_config(fe, priv_cfg);
164
165 tuner_warn("Tuner frontend module has no way to set config\n");
166
167 return 0;
168}
169
Michael Krufky4e9154b2007-10-21 19:39:50 -0300170static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300171
172static struct analog_tuner_ops tuner_core_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300173 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300174 .standby = fe_standby,
175 .release = fe_release,
176 .has_signal = fe_has_signal,
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300177 .set_config = fe_set_config,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300178 .tuner_status = tuner_status
179};
180
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700181/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static void set_tv_freq(struct i2c_client *c, unsigned int freq)
183{
184 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300185 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Michael Krufkyc7919d52007-12-08 17:06:30 -0300187 struct analog_parameters params = {
188 .mode = t->mode,
189 .audmode = t->audmode,
190 .std = t->std
191 };
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700194 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 return;
196 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300197 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700198 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 return;
200 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700201 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
202 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
203 freq / 16, freq % 16 * 100 / 16, tv_range[0],
204 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200205 /* V4L2 spec: if the freq is not possible then the closest
206 possible value should be selected */
207 if (freq < tv_range[0] * 16)
208 freq = tv_range[0] * 16;
209 else
210 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300212 params.frequency = freq;
213
214 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
216
217static void set_radio_freq(struct i2c_client *c, unsigned int freq)
218{
219 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300220 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Michael Krufkyc7919d52007-12-08 17:06:30 -0300222 struct analog_parameters params = {
223 .mode = t->mode,
224 .audmode = t->audmode,
225 .std = t->std
226 };
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700229 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 return;
231 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300232 if ((NULL == ops) || (NULL == ops->set_params)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700233 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 return;
235 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200236 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700237 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
238 freq / 16000, freq % 16000 * 100 / 16000,
239 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200240 /* V4L2 spec: if the freq is not possible then the closest
241 possible value should be selected */
242 if (freq < radio_range[0] * 16000)
243 freq = radio_range[0] * 16000;
244 else
245 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300247 params.frequency = freq;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700248
Michael Krufkyc7919d52007-12-08 17:06:30 -0300249 ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
251
252static void set_freq(struct i2c_client *c, unsigned long freq)
253{
254 struct tuner *t = i2c_get_clientdata(c);
255
256 switch (t->mode) {
257 case V4L2_TUNER_RADIO:
258 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700259 freq / 16000, freq % 16000 * 100 / 16000);
260 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200261 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 break;
263 case V4L2_TUNER_ANALOG_TV:
264 case V4L2_TUNER_DIGITAL_TV:
265 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700266 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200268 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300270 default:
271 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273}
274
Michael Krufky293197c2007-08-28 17:20:42 -0300275static void tuner_i2c_address_check(struct tuner *t)
276{
277 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300278 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300279 return;
280
281 tuner_warn("====================== WARNING! ======================\n");
282 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
283 tuner_warn("will soon be dropped. This message indicates that your\n");
284 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300285 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300286 tuner_warn("To ensure continued support for your device, please\n");
287 tuner_warn("send a copy of this message, along with full dmesg\n");
288 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
289 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
290 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300291 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300292 tuners[t->type].name);
293 tuner_warn("====================== WARNING! ======================\n");
294}
295
Michael Krufky4adad282007-08-27 21:59:08 -0300296static void attach_simple_tuner(struct tuner *t)
297{
298 struct simple_tuner_config cfg = {
299 .type = t->type,
300 .tun = &tuners[t->type]
301 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300302 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300303}
304
Michael Krufkyab166052007-12-09 02:26:48 -0300305static void attach_tda829x(struct tuner *t)
306{
307 struct tda829x_config cfg = {
308 .lna_cfg = &t->config,
309 .tuner_callback = t->tuner_callback,
310 };
311 tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
312}
313
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700314static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300315 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300316 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300319 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300320 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700321 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700323 if (type == UNSET || type == TUNER_ABSENT) {
324 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return;
326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700328 if (type >= tuner_count) {
329 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
330 return;
331 }
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300334 t->config = new_config;
335 if (tuner_callback != NULL) {
336 tuner_dbg("defining GPIO callback\n");
337 t->tuner_callback = tuner_callback;
338 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300339
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300340 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300341 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
342
343 return;
344 }
345
Michael Krufkyb2083192007-05-29 22:54:06 -0300346 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300347 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300348 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 switch (t->type) {
351 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300352 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 break;
354 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300355 {
Michael Krufkyab166052007-12-09 02:26:48 -0300356 attach_tda829x(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300357 break;
358 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700359 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300360 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700361 t->type = TUNER_ABSENT;
362 t->mode_mask = T_UNINITIALIZED;
363 return;
364 }
365 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700366 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300367 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300368 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300369 t->type = TUNER_ABSENT;
370 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300371 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300372 }
373 t->mode_mask = T_RADIO;
374 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700375 case TUNER_PHILIPS_FMD1216ME_MK3:
376 buffer[0] = 0x0b;
377 buffer[1] = 0xdc;
378 buffer[2] = 0x9c;
379 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700380 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700381 mdelay(1);
382 buffer[2] = 0x86;
383 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700384 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300385 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700386 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800387 case TUNER_PHILIPS_TD1316:
388 buffer[0] = 0x0b;
389 buffer[1] = 0xdc;
390 buffer[2] = 0x86;
391 buffer[3] = 0xa4;
392 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300393 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200394 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300395 case TUNER_XC2028:
396 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300397 struct xc2028_config cfg = {
398 .i2c_adap = t->i2c->adapter,
399 .i2c_addr = t->i2c->addr,
400 .video_dev = c->adapter->algo_data,
401 .callback = t->tuner_callback,
402 };
403 if (!xc2028_attach(&t->fe, &cfg)) {
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300404 t->type = TUNER_ABSENT;
405 t->mode_mask = T_UNINITIALIZED;
406 return;
407 }
408 break;
409 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300410 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300411 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300412 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300414 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
416 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700417
Michael Krufkye2be32a2007-10-21 14:35:21 -0300418 ops = t->fe.ops.analog_demod_ops;
419
Michael Krufkyc7919d52007-12-08 17:06:30 -0300420 if (((NULL == ops) || (NULL == ops->set_params)) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300421 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300422 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
423 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300424
Michael Krufky1dde7a42007-10-21 13:40:56 -0300425 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300426 t->fe.analog_demod_priv = t;
Michael Krufkya55db8c2007-12-09 13:52:51 -0300427 } else {
428 strlcpy(t->i2c->name, ops->info.name,
429 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300430 }
431
Michael Krufky49427442007-10-30 09:44:12 -0300432 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300433
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700434 if (t->mode_mask == T_UNINITIALIZED)
435 t->mode_mask = new_mode_mask;
436
Hans Verkuil27487d42006-01-15 15:04:52 -0200437 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700438 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100439 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700440 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300441 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700444/*
445 * This function apply tuner config to tuner specified
446 * by tun_setup structure. I addr is unset, then admin status
447 * and tun addr status is more precise then current status,
448 * it's applied. Otherwise status and type are applied only to
449 * tuner with exactly the same addr.
450*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700451
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700452static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700453{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700454 struct tuner *t = i2c_get_clientdata(c);
455
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300456 tuner_dbg("set addr for type %i\n", t->type);
457
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300458 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
459 (t->mode_mask & tun_setup->mode_mask))) ||
460 (tun_setup->addr == c->addr)) {
461 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300462 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700463 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700464}
465
466static inline int check_mode(struct tuner *t, char *cmd)
467{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700468 if ((1 << t->mode & t->mode_mask) == 0) {
469 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700470 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700471
472 switch (t->mode) {
473 case V4L2_TUNER_RADIO:
474 tuner_dbg("Cmd %s accepted for radio\n", cmd);
475 break;
476 case V4L2_TUNER_ANALOG_TV:
477 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
478 break;
479 case V4L2_TUNER_DIGITAL_TV:
480 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
481 break;
482 }
483 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700484}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700485
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700486/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487static int tuner_fixup_std(struct tuner *t)
488{
489 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300491 case '6':
492 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
493 t->std = V4L2_STD_PAL_60;
494 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 case 'b':
496 case 'B':
497 case 'g':
498 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700499 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 t->std = V4L2_STD_PAL_BG;
501 break;
502 case 'i':
503 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700504 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 t->std = V4L2_STD_PAL_I;
506 break;
507 case 'd':
508 case 'D':
509 case 'k':
510 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700511 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 t->std = V4L2_STD_PAL_DK;
513 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700514 case 'M':
515 case 'm':
516 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
517 t->std = V4L2_STD_PAL_M;
518 break;
519 case 'N':
520 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200521 if (pal[1] == 'c' || pal[1] == 'C') {
522 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
523 t->std = V4L2_STD_PAL_Nc;
524 } else {
525 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
526 t->std = V4L2_STD_PAL_N;
527 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700528 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700529 case '-':
530 /* default parameter, do nothing */
531 break;
532 default:
533 tuner_warn ("pal= argument not recognised\n");
534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
536 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700537 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
538 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200539 case 'b':
540 case 'B':
541 case 'g':
542 case 'G':
543 case 'h':
544 case 'H':
545 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
546 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
547 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700548 case 'd':
549 case 'D':
550 case 'k':
551 case 'K':
552 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
553 t->std = V4L2_STD_SECAM_DK;
554 break;
555 case 'l':
556 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800557 if ((secam[1]=='C')||(secam[1]=='c')) {
558 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
559 t->std = V4L2_STD_SECAM_LC;
560 } else {
561 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
562 t->std = V4L2_STD_SECAM_L;
563 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700564 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700565 case '-':
566 /* default parameter, do nothing */
567 break;
568 default:
569 tuner_warn ("secam= argument not recognised\n");
570 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700571 }
572 }
573
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200574 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
575 switch (ntsc[0]) {
576 case 'm':
577 case 'M':
578 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
579 t->std = V4L2_STD_NTSC_M;
580 break;
581 case 'j':
582 case 'J':
583 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
584 t->std = V4L2_STD_NTSC_M_JP;
585 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200586 case 'k':
587 case 'K':
588 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
589 t->std = V4L2_STD_NTSC_M_KR;
590 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200591 case '-':
592 /* default parameter, do nothing */
593 break;
594 default:
595 tuner_info("ntsc= argument not recognised\n");
596 break;
597 }
598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 0;
600}
601
Michael Krufky4e9154b2007-10-21 19:39:50 -0300602static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200603{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300604 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200605 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300606 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300607 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200608 const char *p;
609
610 switch (t->mode) {
611 case V4L2_TUNER_RADIO: p = "radio"; break;
612 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
613 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
614 default: p = "undefined"; break;
615 }
616 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200617 freq = t->radio_freq / 16000;
618 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200619 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200620 freq = t->tv_freq / 16;
621 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200622 }
623 tuner_info("Tuner mode: %s\n", p);
624 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300625 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200626 if (t->mode != V4L2_TUNER_RADIO)
627 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300628 if (fe_tuner_ops->get_status) {
629 u32 tuner_status;
630
631 fe_tuner_ops->get_status(&t->fe, &tuner_status);
632 if (tuner_status & TUNER_STATUS_LOCKED)
633 tuner_info("Tuner is locked.\n");
634 if (tuner_status & TUNER_STATUS_STEREO)
635 tuner_info("Stereo: yes\n");
636 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300637 if (ops) {
638 if (ops->has_signal)
639 tuner_info("Signal strength: %d\n",
640 ops->has_signal(fe));
641 if (ops->is_stereo)
642 tuner_info("Stereo: %s\n",
643 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200644 }
645}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647/* ---------------------------------------------------------------------- */
648
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700649/*
650 * Switch tuner to other mode. If tuner support both tv and radio,
651 * set another frequency to some value (This is needed for some pal
652 * tuners to avoid locking). Otherwise, just put second tuner in
653 * standby mode.
654 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700656static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
657{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300658 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
659
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800660 if (mode == t->mode)
661 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700662
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800663 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700664
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800665 if (check_mode(t, cmd) == EINVAL) {
666 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300667 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300668 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800669 return EINVAL;
670 }
671 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700672}
673
674#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800675 tuner_dbg("switching to v4l2\n"); \
676 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700677
678static inline int check_v4l2(struct tuner *t)
679{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300680 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
681 TV, v4l1 for radio), until that is fixed this code is disabled.
682 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
683 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700684 return 0;
685}
686
687static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300690 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300691 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Hans Verkuilf9195de2006-01-11 19:01:01 -0200693 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300694 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200695
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700696 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700698 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300699 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 -0700700 ((struct tuner_setup *)arg)->type,
701 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300702 ((struct tuner_setup *)arg)->mode_mask,
703 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700704
705 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700706 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200708 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
709 == EINVAL)
710 return 0;
711 if (t->radio_freq)
712 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700714 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200715 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
716 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300717 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300718 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300719 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200720 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300721#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700722 case VIDIOCSAUDIO:
723 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
724 return 0;
725 if (check_v4l2(t) == EINVAL)
726 return 0;
727
728 /* Should be implemented, since bttv calls it */
729 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700730 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700732 {
733 static const v4l2_std_id map[] = {
734 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
735 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
736 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
737 [4 /* bttv */ ] = V4L2_STD_PAL_M,
738 [5 /* bttv */ ] = V4L2_STD_PAL_N,
739 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
740 };
741 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700743 if (check_v4l2(t) == EINVAL)
744 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700745
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700746 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
747 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700749 if (vc->norm < ARRAY_SIZE(map))
750 t->std = map[vc->norm];
751 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200752 if (t->tv_freq)
753 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700754 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700755 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700756 case VIDIOCSFREQ:
757 {
758 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700759
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700760 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
761 return 0;
762 if (check_v4l2(t) == EINVAL)
763 return 0;
764
765 set_freq(client, *v);
766 return 0;
767 }
768 case VIDIOCGTUNER:
769 {
770 struct video_tuner *vt = arg;
771
772 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
773 return 0;
774 if (check_v4l2(t) == EINVAL)
775 return 0;
776
777 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300778 if (fe_tuner_ops->get_status) {
779 u32 tuner_status;
780
781 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300782 if (tuner_status & TUNER_STATUS_STEREO)
783 vt->flags |= VIDEO_TUNER_STEREO_ON;
784 else
785 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300786 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300787 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300788 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300789 vt->flags |=
790 VIDEO_TUNER_STEREO_ON;
791 else
792 vt->flags &=
793 ~VIDEO_TUNER_STEREO_ON;
794 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700795 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300796 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300797 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300798
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700799 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
800
801 vt->rangelow = radio_range[0] * 16000;
802 vt->rangehigh = radio_range[1] * 16000;
803
804 } else {
805 vt->rangelow = tv_range[0] * 16;
806 vt->rangehigh = tv_range[1] * 16;
807 }
808
809 return 0;
810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700812 {
813 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700815 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
816 return 0;
817 if (check_v4l2(t) == EINVAL)
818 return 0;
819
Michael Krufkye18f9442007-08-21 01:25:48 -0300820 if (V4L2_TUNER_RADIO == t->mode) {
821 if (fe_tuner_ops->get_status) {
822 u32 tuner_status;
823
824 fe_tuner_ops->get_status(&t->fe, &tuner_status);
825 va->mode = (tuner_status & TUNER_STATUS_STEREO)
826 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300827 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300828 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300829 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
830 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700831 return 0;
832 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300833#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300834 case TUNER_SET_CONFIG:
835 {
836 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
837 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300839 if (t->type != cfg->tuner)
840 break;
841
842 if (t->type == TUNER_TDA9887) {
843 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300844 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300845 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300846 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300847
848 if (NULL == fe_tuner_ops->set_config) {
849 tuner_warn("Tuner frontend module has no way to "
850 "set config\n");
851 break;
852 }
853 fe_tuner_ops->set_config(&t->fe, cfg->priv);
854
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300855 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300856 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300857 /* --- v4l ioctls --- */
858 /* take care: bttv does userspace copying, we'll get a
859 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700861 {
862 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700864 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
865 == EINVAL)
866 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700867
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700868 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700870 t->std = *id;
871 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200872 if (t->tv_freq)
873 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700874 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700875 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700876 case VIDIOC_S_FREQUENCY:
877 {
878 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700879
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300880 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
881 == EINVAL)
882 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700883 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200884 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700885
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700886 break;
887 }
888 case VIDIOC_G_FREQUENCY:
889 {
890 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700891
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700892 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
893 return 0;
894 switch_v4l2();
895 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300896 if (fe_tuner_ops->get_frequency) {
897 u32 abs_freq;
898
899 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
900 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
901 (abs_freq * 2 + 125/2) / 125 :
902 (abs_freq + 62500/2) / 62500;
903 break;
904 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200905 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
906 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700907 break;
908 }
909 case VIDIOC_G_TUNER:
910 {
911 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700912
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700913 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
914 return 0;
915 switch_v4l2();
916
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200917 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300918 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300919 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300920 if (t->mode == V4L2_TUNER_ANALOG_TV)
921 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200922 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700923 tuner->rangelow = tv_range[0] * 16;
924 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200925 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700926 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200927
928 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200929 tuner->rxsubchans =
930 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300931 if (fe_tuner_ops->get_status) {
932 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200933
Michael Krufkye18f9442007-08-21 01:25:48 -0300934 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300935 tuner->rxsubchans =
936 (tuner_status & TUNER_STATUS_STEREO) ?
937 V4L2_TUNER_SUB_STEREO :
938 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300939 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300940 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300941 tuner->rxsubchans =
942 ops->is_stereo(&t->fe) ?
943 V4L2_TUNER_SUB_STEREO :
944 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300945 }
Michael Krufkye18f9442007-08-21 01:25:48 -0300946 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300947 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300948 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200949 tuner->capability |=
950 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
951 tuner->audmode = t->audmode;
952 tuner->rangelow = radio_range[0] * 16000;
953 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700954 break;
955 }
956 case VIDIOC_S_TUNER:
957 {
958 struct v4l2_tuner *tuner = arg;
959
960 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
961 return 0;
962
963 switch_v4l2();
964
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200965 /* do nothing unless we're a radio tuner */
966 if (t->mode != V4L2_TUNER_RADIO)
967 break;
968 t->audmode = tuner->audmode;
969 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700970 break;
971 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200972 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300973 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300974 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -0200975 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977
978 return 0;
979}
980
Jean Delvare21b48a72007-03-12 19:20:15 -0300981static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300983 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300985 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 /* FIXME: power down ??? */
987 return 0;
988}
989
Jean Delvare21b48a72007-03-12 19:20:15 -0300990static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300992 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Hans Verkuil9dd659d2007-11-04 11:03:36 -0300994 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -0200995 if (V4L2_TUNER_RADIO == t->mode) {
996 if (t->radio_freq)
997 set_freq(c, t->radio_freq);
998 } else {
999 if (t->tv_freq)
1000 set_freq(c, t->tv_freq);
1001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return 0;
1003}
1004
Hans Verkuil92de1f12007-11-04 10:53:09 -03001005/* ---------------------------------------------------------------------- */
1006
1007LIST_HEAD(tuner_list);
1008
1009/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001010 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -03001011 certain no other devices will be added/deleted at the same time, I2C
1012 core protects against that. */
1013static void tuner_lookup(struct i2c_adapter *adap,
1014 struct tuner **radio, struct tuner **tv)
1015{
1016 struct tuner *pos;
1017
1018 *radio = NULL;
1019 *tv = NULL;
1020
1021 list_for_each_entry(pos, &tuner_list, list) {
1022 int mode_mask;
1023
1024 if (pos->i2c->adapter != adap ||
1025 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
1026 continue;
1027
1028 mode_mask = pos->mode_mask & ~T_STANDBY;
1029 if (*radio == NULL && mode_mask == T_RADIO)
1030 *radio = pos;
1031 /* Note: currently TDA9887 is the only demod-only
1032 device. If other devices appear then we need to
1033 make this test more general. */
1034 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
1035 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
1036 *tv = pos;
1037 }
1038}
1039
1040/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001041 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -03001042 */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001043static int tuner_probe(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001044{
Hans Verkuil92de1f12007-11-04 10:53:09 -03001045 struct tuner *t;
1046 struct tuner *radio;
1047 struct tuner *tv;
1048
Hans Verkuil92de1f12007-11-04 10:53:09 -03001049 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001050 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001051 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001052 t->i2c = client;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001053 strlcpy(client->name, "(tuner unset)", sizeof(client->name));
Hans Verkuil92de1f12007-11-04 10:53:09 -03001054 i2c_set_clientdata(client, t);
1055 t->type = UNSET;
1056 t->audmode = V4L2_TUNER_MODE_STEREO;
1057 t->mode_mask = T_UNINITIALIZED;
1058
1059 if (show_i2c) {
1060 unsigned char buffer[16];
1061 int i, rc;
1062
1063 memset(buffer, 0, sizeof(buffer));
1064 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1065 tuner_info("I2C RECV = ");
1066 for (i = 0; i < rc; i++)
1067 printk(KERN_CONT "%02x ", buffer[i]);
1068 printk("\n");
1069 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001070 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001071 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001072 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1073 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001074 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001075 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001076
1077 /* autodetection code based on the i2c addr */
1078 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001079 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001080 case 0x10:
1081 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
1082 != EINVAL) {
1083 t->type = TUNER_TEA5761;
1084 t->mode_mask = T_RADIO;
1085 t->mode = T_STANDBY;
1086 /* Sets freq to FM range */
1087 t->radio_freq = 87.5 * 16000;
1088 tuner_lookup(t->i2c->adapter, &radio, &tv);
1089 if (tv)
1090 tv->mode_mask &= ~T_RADIO;
1091
1092 goto register_client;
1093 }
1094 break;
1095 case 0x42:
1096 case 0x43:
1097 case 0x4a:
1098 case 0x4b:
1099 /* If chip is not tda8290, don't register.
1100 since it can be tda9887*/
Michael Krufkyab166052007-12-09 02:26:48 -03001101 if (tda829x_probe(t->i2c->adapter,
1102 t->i2c->addr) == 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001103 tuner_dbg("tda829x detected\n");
1104 } else {
1105 /* Default is being tda9887 */
1106 t->type = TUNER_TDA9887;
1107 t->mode_mask = T_RADIO | T_ANALOG_TV |
1108 T_DIGITAL_TV;
1109 t->mode = T_STANDBY;
1110 goto register_client;
1111 }
1112 break;
1113 case 0x60:
1114 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
1115 != EINVAL) {
1116 t->type = TUNER_TEA5767;
1117 t->mode_mask = T_RADIO;
1118 t->mode = T_STANDBY;
1119 /* Sets freq to FM range */
1120 t->radio_freq = 87.5 * 16000;
1121 tuner_lookup(t->i2c->adapter, &radio, &tv);
1122 if (tv)
1123 tv->mode_mask &= ~T_RADIO;
1124
1125 goto register_client;
1126 }
1127 break;
1128 }
1129 }
1130
1131 /* Initializes only the first TV tuner on this adapter. Why only the
1132 first? Because there are some devices (notably the ones with TI
1133 tuners) that have more than one i2c address for the *same* device.
1134 Experience shows that, except for just one case, the first
1135 address is the right one. The exception is a Russian tuner
1136 (ACORP_Y878F). So, the desired behavior is just to enable the
1137 first found TV tuner. */
1138 tuner_lookup(t->i2c->adapter, &radio, &tv);
1139 if (tv == NULL) {
1140 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1141 if (radio == NULL)
1142 t->mode_mask |= T_RADIO;
1143 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1144 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1145 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1146 }
1147
1148 /* Should be just before return */
1149register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001150 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1151 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001152
1153 /* Sets a default mode */
1154 if (t->mode_mask & T_ANALOG_TV) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001155 t->mode = V4L2_TUNER_ANALOG_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001156 } else if (t->mode_mask & T_RADIO) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001157 t->mode = V4L2_TUNER_RADIO;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001158 } else {
Michael Krufky864a6b82007-12-09 17:21:54 -03001159 t->mode = V4L2_TUNER_DIGITAL_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001160 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001161 set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001162 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001163 return 0;
1164}
1165
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001166static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001167{
1168 if (0 != addr) {
1169 normal_i2c[0] = addr;
1170 normal_i2c[1] = I2C_CLIENT_END;
1171 }
1172
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001173 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1174 return 0;
1175
Hans Verkuil92de1f12007-11-04 10:53:09 -03001176 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1177 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1178 * and an RTC at 0x6f which can get corrupted if probed.
1179 */
1180 if ((adap->id == I2C_HW_B_CX2388x) ||
1181 (adap->id == I2C_HW_B_CX23885)) {
1182 unsigned int i = 0;
1183
1184 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1185 i += 2;
1186 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1187 ignore[i+0] = adap->nr;
1188 ignore[i+1] = 0x6b;
1189 ignore[i+2] = adap->nr;
1190 ignore[i+3] = 0x6f;
1191 ignore[i+4] = I2C_CLIENT_END;
1192 } else
1193 printk(KERN_WARNING "tuner: "
1194 "too many options specified "
1195 "in i2c probe ignore list!\n");
1196 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001197 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001198}
1199
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001200static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001201{
1202 struct tuner *t = i2c_get_clientdata(client);
1203 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001204
1205 if (ops && ops->release)
1206 ops->release(&t->fe);
1207
1208 list_del(&t->list);
1209 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001210 return 0;
1211}
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213/* ----------------------------------------------------------------------- */
1214
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001215static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1216 .name = "tuner",
1217 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001218 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001219 .probe = tuner_probe,
1220 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001221 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001222 .resume = tuner_resume,
1223 .legacy_probe = tuner_legacy_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224};
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227/*
1228 * Overrides for Emacs so that we follow Linus's tabbing style.
1229 * ---------------------------------------------------------------------------
1230 * Local variables:
1231 * c-basic-offset: 8
1232 * End:
1233 */