blob: 4f2bd2dd15c7048ac82b1ee405845b569a8ab08e [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>
Michael Krufky8218b0b2007-06-26 13:12:08 -030022#include "tuner-driver.h"
Michael Krufky96c0b7c2007-08-27 21:23:08 -030023#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030024#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030025#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030026#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030027#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030028#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030029#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#define UNSET (-1U)
32
Michael Krufky241020d2007-10-30 09:46:10 -030033#define PREFIX "tuner "
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* standard i2c insmod options */
36static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030037#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030038 0x10,
39#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080040 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070041 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
42 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 I2C_CLIENT_END
44};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046I2C_CLIENT_INSMOD;
47
48/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070049static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070050static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070051static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070052
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/* insmod options used at runtime => read/write */
Hans Verkuilf9195de2006-01-11 19:01:01 -020054int tuner_debug = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070056static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static unsigned int radio_range[2] = { 65, 108 };
58
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020059static char pal[] = "--";
60static char secam[] = "--";
61static char ntsc[] = "-";
62
Hans Verkuilf9195de2006-01-11 19:01:01 -020063
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020064module_param(addr, int, 0444);
65module_param(no_autodetect, int, 0444);
66module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020067module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020068module_param_string(pal, pal, sizeof(pal), 0644);
69module_param_string(secam, secam, sizeof(secam), 0644);
70module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070071module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072module_param_array(radio_range, int, NULL, 0644);
73
74MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
75MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
76MODULE_LICENSE("GPL");
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static struct i2c_driver driver;
79static struct i2c_client client_template;
80
81/* ---------------------------------------------------------------------- */
82
Michael Krufky4e9154b2007-10-21 19:39:50 -030083static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq)
Michael Krufkye18f9442007-08-21 01:25:48 -030084{
Michael Krufky4e9154b2007-10-21 19:39:50 -030085 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
86 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -030087
88 struct analog_parameters params = {
89 .frequency = freq,
90 .mode = t->mode,
91 .audmode = t->audmode,
92 .std = t->std
93 };
94
95 if (NULL == fe_tuner_ops->set_analog_params) {
96 tuner_warn("Tuner frontend module has no way to set freq\n");
97 return;
98 }
Michael Krufky4e9154b2007-10-21 19:39:50 -030099 fe_tuner_ops->set_analog_params(fe, &params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300100}
101
Michael Krufky4e9154b2007-10-21 19:39:50 -0300102static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300103{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300104 if (fe->ops.tuner_ops.release)
105 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300106
Michael Krufky4e9154b2007-10-21 19:39:50 -0300107 fe->ops.analog_demod_ops = NULL;
Michael Krufky4524c1a2007-10-22 18:15:39 -0300108
109 /* DO NOT kfree(fe->analog_demod_priv)
110 *
111 * If we are in this function, analog_demod_priv contains a pointer
112 * to struct tuner *t. This will be kfree'd in tuner_detach().
113 *
114 * Otherwise, fe->ops.analog_demod_ops->release will
115 * handle the cleanup for analog demodulator modules.
116 */
Michael Krufky4e9154b2007-10-21 19:39:50 -0300117 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300118}
119
Michael Krufky4e9154b2007-10-21 19:39:50 -0300120static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300121{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300122 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300123
124 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300125 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300126}
127
Michael Krufky4e9154b2007-10-21 19:39:50 -0300128static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300129{
Michael Krufky14196832007-10-14 18:11:53 -0300130 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300131
Michael Krufky4e9154b2007-10-21 19:39:50 -0300132 if (fe->ops.tuner_ops.get_rf_strength)
133 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300134
135 return strength;
136}
137
Michael Krufky4e9154b2007-10-21 19:39:50 -0300138static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300139
140static struct analog_tuner_ops tuner_core_ops = {
141 .set_tv_freq = fe_set_freq,
142 .set_radio_freq = fe_set_freq,
143 .standby = fe_standby,
144 .release = fe_release,
145 .has_signal = fe_has_signal,
146 .tuner_status = tuner_status
147};
148
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700149/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void set_tv_freq(struct i2c_client *c, unsigned int freq)
151{
152 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300153 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700156 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 return;
158 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300159 if ((NULL == ops) || (NULL == ops->set_tv_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700160 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return;
162 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700163 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
164 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
165 freq / 16, freq % 16 * 100 / 16, tv_range[0],
166 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200167 /* V4L2 spec: if the freq is not possible then the closest
168 possible value should be selected */
169 if (freq < tv_range[0] * 16)
170 freq = tv_range[0] * 16;
171 else
172 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Michael Krufky4e9154b2007-10-21 19:39:50 -0300174 ops->set_tv_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177static void set_radio_freq(struct i2c_client *c, unsigned int freq)
178{
179 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300180 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700183 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 return;
185 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300186 if ((NULL == ops) || (NULL == ops->set_radio_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700187 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return;
189 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200190 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700191 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
192 freq / 16000, freq % 16000 * 100 / 16000,
193 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200194 /* V4L2 spec: if the freq is not possible then the closest
195 possible value should be selected */
196 if (freq < radio_range[0] * 16000)
197 freq = radio_range[0] * 16000;
198 else
199 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700201
Michael Krufky4e9154b2007-10-21 19:39:50 -0300202 ops->set_radio_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205static void set_freq(struct i2c_client *c, unsigned long freq)
206{
207 struct tuner *t = i2c_get_clientdata(c);
208
209 switch (t->mode) {
210 case V4L2_TUNER_RADIO:
211 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700212 freq / 16000, freq % 16000 * 100 / 16000);
213 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200214 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 break;
216 case V4L2_TUNER_ANALOG_TV:
217 case V4L2_TUNER_DIGITAL_TV:
218 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700219 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200221 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300223 default:
224 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Michael Krufky293197c2007-08-28 17:20:42 -0300228static void tuner_i2c_address_check(struct tuner *t)
229{
230 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300231 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300232 return;
233
234 tuner_warn("====================== WARNING! ======================\n");
235 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
236 tuner_warn("will soon be dropped. This message indicates that your\n");
237 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300238 t->i2c->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300239 tuner_warn("To ensure continued support for your device, please\n");
240 tuner_warn("send a copy of this message, along with full dmesg\n");
241 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
242 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
243 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300244 t->i2c->adapter->name, t->i2c->addr, t->type,
Michael Krufky293197c2007-08-28 17:20:42 -0300245 tuners[t->type].name);
246 tuner_warn("====================== WARNING! ======================\n");
247}
248
Michael Krufky4adad282007-08-27 21:59:08 -0300249static void attach_simple_tuner(struct tuner *t)
250{
251 struct simple_tuner_config cfg = {
252 .type = t->type,
253 .tun = &tuners[t->type]
254 };
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300255 simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
Michael Krufky4adad282007-08-27 21:59:08 -0300256}
257
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700258static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300259 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300260 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
262 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300263 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300264 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700265 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700267 if (type == UNSET || type == TUNER_ABSENT) {
268 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700272 if (type >= tuner_count) {
273 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
274 return;
275 }
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300278 t->config = new_config;
279 if (tuner_callback != NULL) {
280 tuner_dbg("defining GPIO callback\n");
281 t->tuner_callback = tuner_callback;
282 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300283
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300284 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300285 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
286
287 return;
288 }
289
Michael Krufkyb2083192007-05-29 22:54:06 -0300290 /* discard private data, in case set_type() was previously called */
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300291 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300292 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 switch (t->type) {
295 case TUNER_MT2032:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300296 microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 break;
298 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300299 {
Michael Krufky8c125f2c2007-10-27 02:00:57 -0300300 tda829x_attach(t);
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300301 break;
302 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700303 case TUNER_TEA5767:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300304 if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700305 t->type = TUNER_ABSENT;
306 t->mode_mask = T_UNINITIALIZED;
307 return;
308 }
309 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700310 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300311 case TUNER_TEA5761:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300312 if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300313 t->type = TUNER_ABSENT;
314 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300315 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300316 }
317 t->mode_mask = T_RADIO;
318 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700319 case TUNER_PHILIPS_FMD1216ME_MK3:
320 buffer[0] = 0x0b;
321 buffer[1] = 0xdc;
322 buffer[2] = 0x9c;
323 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700324 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700325 mdelay(1);
326 buffer[2] = 0x86;
327 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700328 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300329 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700330 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800331 case TUNER_PHILIPS_TD1316:
332 buffer[0] = 0x0b;
333 buffer[1] = 0xdc;
334 buffer[2] = 0x86;
335 buffer[3] = 0xa4;
336 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300337 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200338 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300339 case TUNER_XC2028:
340 {
341 int rc=xc2028_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
342 &c->dev, c->adapter->algo_data,
343 t->tuner_callback);
344 if (rc<0) {
345 t->type = TUNER_ABSENT;
346 t->mode_mask = T_UNINITIALIZED;
347 return;
348 }
349 break;
350 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300351 case TUNER_TDA9887:
Michael Krufky31c95842007-10-21 20:48:48 -0300352 tda9887_attach(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300355 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 break;
357 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700358
Michael Krufkye2be32a2007-10-21 14:35:21 -0300359 ops = t->fe.ops.analog_demod_ops;
360
Michael Krufky1dde7a42007-10-21 13:40:56 -0300361 if (((NULL == ops) ||
362 ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) &&
363 (fe_tuner_ops->set_analog_params)) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300364 strlcpy(t->i2c->name, fe_tuner_ops->info.name,
365 sizeof(t->i2c->name));
Michael Krufkye18f9442007-08-21 01:25:48 -0300366
Michael Krufky1dde7a42007-10-21 13:40:56 -0300367 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300368 t->fe.analog_demod_priv = t;
Michael Krufkye18f9442007-08-21 01:25:48 -0300369 }
370
Michael Krufky49427442007-10-30 09:44:12 -0300371 tuner_dbg("type set to %s\n", t->i2c->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300372
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700373 if (t->mode_mask == T_UNINITIALIZED)
374 t->mode_mask = new_mode_mask;
375
Hans Verkuil27487d42006-01-15 15:04:52 -0200376 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700377 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100378 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700379 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300380 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700383/*
384 * This function apply tuner config to tuner specified
385 * by tun_setup structure. I addr is unset, then admin status
386 * and tun addr status is more precise then current status,
387 * it's applied. Otherwise status and type are applied only to
388 * tuner with exactly the same addr.
389*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700390
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700391static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700392{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700393 struct tuner *t = i2c_get_clientdata(c);
394
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300395 tuner_dbg("set addr for type %i\n", t->type);
396
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300397 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
398 (t->mode_mask & tun_setup->mode_mask))) ||
399 (tun_setup->addr == c->addr)) {
400 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300401 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700402 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700403}
404
405static inline int check_mode(struct tuner *t, char *cmd)
406{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700407 if ((1 << t->mode & t->mode_mask) == 0) {
408 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700409 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700410
411 switch (t->mode) {
412 case V4L2_TUNER_RADIO:
413 tuner_dbg("Cmd %s accepted for radio\n", cmd);
414 break;
415 case V4L2_TUNER_ANALOG_TV:
416 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
417 break;
418 case V4L2_TUNER_DIGITAL_TV:
419 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
420 break;
421 }
422 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700423}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700424
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700425/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426static int tuner_fixup_std(struct tuner *t)
427{
428 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300430 case '6':
431 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
432 t->std = V4L2_STD_PAL_60;
433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 case 'b':
435 case 'B':
436 case 'g':
437 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700438 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 t->std = V4L2_STD_PAL_BG;
440 break;
441 case 'i':
442 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700443 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 t->std = V4L2_STD_PAL_I;
445 break;
446 case 'd':
447 case 'D':
448 case 'k':
449 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700450 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 t->std = V4L2_STD_PAL_DK;
452 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700453 case 'M':
454 case 'm':
455 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
456 t->std = V4L2_STD_PAL_M;
457 break;
458 case 'N':
459 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200460 if (pal[1] == 'c' || pal[1] == 'C') {
461 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
462 t->std = V4L2_STD_PAL_Nc;
463 } else {
464 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
465 t->std = V4L2_STD_PAL_N;
466 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700467 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700468 case '-':
469 /* default parameter, do nothing */
470 break;
471 default:
472 tuner_warn ("pal= argument not recognised\n");
473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
475 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700476 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
477 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200478 case 'b':
479 case 'B':
480 case 'g':
481 case 'G':
482 case 'h':
483 case 'H':
484 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
485 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
486 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700487 case 'd':
488 case 'D':
489 case 'k':
490 case 'K':
491 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
492 t->std = V4L2_STD_SECAM_DK;
493 break;
494 case 'l':
495 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800496 if ((secam[1]=='C')||(secam[1]=='c')) {
497 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
498 t->std = V4L2_STD_SECAM_LC;
499 } else {
500 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
501 t->std = V4L2_STD_SECAM_L;
502 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700503 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700504 case '-':
505 /* default parameter, do nothing */
506 break;
507 default:
508 tuner_warn ("secam= argument not recognised\n");
509 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700510 }
511 }
512
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200513 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
514 switch (ntsc[0]) {
515 case 'm':
516 case 'M':
517 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
518 t->std = V4L2_STD_NTSC_M;
519 break;
520 case 'j':
521 case 'J':
522 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
523 t->std = V4L2_STD_NTSC_M_JP;
524 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200525 case 'k':
526 case 'K':
527 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
528 t->std = V4L2_STD_NTSC_M_KR;
529 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200530 case '-':
531 /* default parameter, do nothing */
532 break;
533 default:
534 tuner_info("ntsc= argument not recognised\n");
535 break;
536 }
537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return 0;
539}
540
Michael Krufky4e9154b2007-10-21 19:39:50 -0300541static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200542{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300543 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200544 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300545 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300546 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200547 const char *p;
548
549 switch (t->mode) {
550 case V4L2_TUNER_RADIO: p = "radio"; break;
551 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
552 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
553 default: p = "undefined"; break;
554 }
555 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200556 freq = t->radio_freq / 16000;
557 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200558 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200559 freq = t->tv_freq / 16;
560 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200561 }
562 tuner_info("Tuner mode: %s\n", p);
563 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300564 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200565 if (t->mode != V4L2_TUNER_RADIO)
566 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300567 if (fe_tuner_ops->get_status) {
568 u32 tuner_status;
569
570 fe_tuner_ops->get_status(&t->fe, &tuner_status);
571 if (tuner_status & TUNER_STATUS_LOCKED)
572 tuner_info("Tuner is locked.\n");
573 if (tuner_status & TUNER_STATUS_STEREO)
574 tuner_info("Stereo: yes\n");
575 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300576 if (ops) {
577 if (ops->has_signal)
578 tuner_info("Signal strength: %d\n",
579 ops->has_signal(fe));
580 if (ops->is_stereo)
581 tuner_info("Stereo: %s\n",
582 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200583 }
584}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586/* ---------------------------------------------------------------------- */
587
Hans Verkuil159ffe72007-11-04 10:42:42 -0300588LIST_HEAD(tuner_list);
589
590/* Search for existing radio and/or TV tuners on the given I2C adapter.
591 Note that when this function is called from tuner_attach you can be
592 certain no other devices will be added/deleted at the same time, I2C
593 core protects against that. */
594static void tuner_lookup(struct i2c_adapter *adap,
595 struct tuner **radio, struct tuner **tv)
596{
597 struct tuner *pos;
598
599 *radio = NULL;
600 *tv = NULL;
601
602 list_for_each_entry(pos, &tuner_list, list) {
603 int mode_mask;
604
605 if (pos->i2c->adapter != adap ||
606 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
607 continue;
608
609 mode_mask = pos->mode_mask & ~T_STANDBY;
610 if (*radio == NULL && mode_mask == T_RADIO)
611 *radio = pos;
612 /* Note: currently TDA9887 is the only demod-only
613 device. If other devices appear then we need to
614 make this test more general. */
615 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
616 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
617 *tv = pos;
618 }
619}
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700620
621/* During client attach, set_type is called by adapter's attach_inform callback.
622 set_type must then be completed by tuner_attach.
623 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
625{
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300626 struct i2c_client *client;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 struct tuner *t;
Hans Verkuil159ffe72007-11-04 10:42:42 -0300628 struct tuner *radio;
629 struct tuner *tv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300631 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
632 if (NULL == client)
633 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Panagiotis Issaris74081872006-01-11 19:40:56 -0200635 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300636 if (NULL == t) {
637 kfree(client);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700638 return -ENOMEM;
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300639 }
640 t->i2c = client;
641 client_template.adapter = adap;
642 client_template.addr = addr;
643 memcpy(client, &client_template, sizeof(struct i2c_client));
644 i2c_set_clientdata(client, t);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700645 t->type = UNSET;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700646 t->audmode = V4L2_TUNER_MODE_STEREO;
647 t->mode_mask = T_UNINITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700649 if (show_i2c) {
650 unsigned char buffer[16];
651 int i,rc;
652
653 memset(buffer, 0, sizeof(buffer));
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300654 rc = i2c_master_recv(client, buffer, sizeof(buffer));
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800655 tuner_info("I2C RECV = ");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700656 for (i=0;i<rc;i++)
657 printk("%02x ",buffer[i]);
658 printk("\n");
659 }
Michael Hunoldc28089a2006-11-28 08:14:44 -0300660 /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
661 if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
662 return -ENODEV;
663
Markus Rechberger257c6452006-01-23 17:11:11 -0200664 /* autodetection code based on the i2c addr */
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700665 if (!no_autodetect) {
Mauro Carvalho Chehab13dd38d2005-11-08 21:37:57 -0800666 switch (addr) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300667 case 0x10:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300668 if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300669 t->type = TUNER_TEA5761;
670 t->mode_mask = T_RADIO;
671 t->mode = T_STANDBY;
672 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
Hans Verkuil159ffe72007-11-04 10:42:42 -0300673 tuner_lookup(t->i2c->adapter, &radio, &tv);
674 if (tv)
675 tv->mode_mask &= ~T_RADIO;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300676
677 goto register_client;
678 }
679 break;
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800680 case 0x42:
681 case 0x43:
682 case 0x4a:
683 case 0x4b:
684 /* If chip is not tda8290, don't register.
685 since it can be tda9887*/
Michael Krufkyf1f32842007-11-03 22:14:54 -0300686 if (tda829x_probe(t) == 0) {
687 tuner_dbg("tda829x detected\n");
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300688 } else {
689 /* Default is being tda9887 */
690 t->type = TUNER_TDA9887;
691 t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
692 t->mode = T_STANDBY;
693 goto register_client;
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800694 }
695 break;
Mauro Carvalho Chehab13dd38d2005-11-08 21:37:57 -0800696 case 0x60:
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300697 if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) {
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700698 t->type = TUNER_TEA5767;
699 t->mode_mask = T_RADIO;
700 t->mode = T_STANDBY;
Hans Verkuil27487d42006-01-15 15:04:52 -0200701 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
Hans Verkuil159ffe72007-11-04 10:42:42 -0300702 tuner_lookup(t->i2c->adapter, &radio, &tv);
703 if (tv)
704 tv->mode_mask &= ~T_RADIO;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700705
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800706 goto register_client;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700707 }
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800708 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700709 }
710 }
711
Hans Verkuil159ffe72007-11-04 10:42:42 -0300712 /* Initializes only the first TV tuner on this adapter. Why only the
713 first? Because there are some devices (notably the ones with TI
714 tuners) that have more than one i2c address for the *same* device.
715 Experience shows that, except for just one case, the first
716 address is the right one. The exception is a Russian tuner
717 (ACORP_Y878F). So, the desired behavior is just to enable the
718 first found TV tuner. */
719 tuner_lookup(t->i2c->adapter, &radio, &tv);
720 if (tv == NULL) {
721 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
722 if (radio == NULL)
723 t->mode_mask |= T_RADIO;
724 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
Hans Verkuil27487d42006-01-15 15:04:52 -0200725 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
726 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700727 }
728
729 /* Should be just before return */
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800730register_client:
731 tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300732
733 /* Sets a default mode */
734 if (t->mode_mask & T_ANALOG_TV) {
735 t->mode = T_ANALOG_TV;
736 } else if (t->mode_mask & T_RADIO) {
737 t->mode = T_RADIO;
738 } else {
739 t->mode = T_DIGITAL_TV;
740 }
741
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300742 i2c_attach_client (client);
743 set_type (client,t->type, t->mode_mask, t->config, t->tuner_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return 0;
745}
746
747static int tuner_probe(struct i2c_adapter *adap)
748{
749 if (0 != addr) {
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -0700750 normal_i2c[0] = addr;
751 normal_i2c[1] = I2C_CLIENT_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Michael Krufkya1dec512007-08-24 01:13:07 -0300754 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
755 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
756 * and an RTC at 0x6f which can get corrupted if probed.
757 */
Michael Krufky9bc37ca2007-09-08 15:17:13 -0300758 if ((adap->id == I2C_HW_B_CX2388x) ||
759 (adap->id == I2C_HW_B_CX23885)) {
Michael Krufkya1dec512007-08-24 01:13:07 -0300760 unsigned int i = 0;
761
762 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
763 i += 2;
764 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
765 ignore[i+0] = adap->nr;
766 ignore[i+1] = 0x6b;
767 ignore[i+2] = adap->nr;
768 ignore[i+3] = 0x6f;
769 ignore[i+4] = I2C_CLIENT_END;
770 } else
771 printk(KERN_WARNING "tuner: "
772 "too many options specified "
773 "in i2c probe ignore list!\n");
774 }
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (adap->class & I2C_CLASS_TV_ANALOG)
777 return i2c_probe(adap, &addr_data, tuner_attach);
778 return 0;
779}
780
781static int tuner_detach(struct i2c_client *client)
782{
783 struct tuner *t = i2c_get_clientdata(client);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300784 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700785 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300787 err = i2c_detach_client(t->i2c);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700788 if (err) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700789 tuner_warn
790 ("Client deregistration failed, client not detached.\n");
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700791 return err;
792 }
793
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300794 if (ops && ops->release)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300795 ops->release(&t->fe);
Michael Krufky16f29162007-10-21 15:22:25 -0300796
Hans Verkuil159ffe72007-11-04 10:42:42 -0300797 list_del(&t->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 kfree(t);
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300799 kfree(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return 0;
801}
802
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700803/*
804 * Switch tuner to other mode. If tuner support both tv and radio,
805 * set another frequency to some value (This is needed for some pal
806 * tuners to avoid locking). Otherwise, just put second tuner in
807 * standby mode.
808 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700810static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
811{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300812 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
813
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800814 if (mode == t->mode)
815 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700816
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800817 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700818
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800819 if (check_mode(t, cmd) == EINVAL) {
820 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300821 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300822 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800823 return EINVAL;
824 }
825 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700826}
827
828#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800829 tuner_dbg("switching to v4l2\n"); \
830 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700831
832static inline int check_v4l2(struct tuner *t)
833{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300834 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
835 TV, v4l1 for radio), until that is fixed this code is disabled.
836 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
837 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700838 return 0;
839}
840
841static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300844 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300845 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Hans Verkuilf9195de2006-01-11 19:01:01 -0200847 if (tuner_debug>1)
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300848 v4l_i2c_print_ioctl(client,cmd);
Michael Krufky5e453dc2006-01-09 15:32:31 -0200849
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700850 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700852 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300853 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 -0700854 ((struct tuner_setup *)arg)->type,
855 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300856 ((struct tuner_setup *)arg)->mode_mask,
857 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700858
859 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700860 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200862 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
863 == EINVAL)
864 return 0;
865 if (t->radio_freq)
866 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700868 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200869 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
870 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300871 t->mode = T_STANDBY;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300872 if (ops && ops->standby)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300873 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200874 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300875#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700876 case VIDIOCSAUDIO:
877 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
878 return 0;
879 if (check_v4l2(t) == EINVAL)
880 return 0;
881
882 /* Should be implemented, since bttv calls it */
883 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700884 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700886 {
887 static const v4l2_std_id map[] = {
888 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
889 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
890 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
891 [4 /* bttv */ ] = V4L2_STD_PAL_M,
892 [5 /* bttv */ ] = V4L2_STD_PAL_N,
893 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
894 };
895 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700897 if (check_v4l2(t) == EINVAL)
898 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700899
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700900 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
901 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700903 if (vc->norm < ARRAY_SIZE(map))
904 t->std = map[vc->norm];
905 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200906 if (t->tv_freq)
907 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700908 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700909 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700910 case VIDIOCSFREQ:
911 {
912 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700913
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700914 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
915 return 0;
916 if (check_v4l2(t) == EINVAL)
917 return 0;
918
919 set_freq(client, *v);
920 return 0;
921 }
922 case VIDIOCGTUNER:
923 {
924 struct video_tuner *vt = arg;
925
926 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
927 return 0;
928 if (check_v4l2(t) == EINVAL)
929 return 0;
930
931 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300932 if (fe_tuner_ops->get_status) {
933 u32 tuner_status;
934
935 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300936 if (tuner_status & TUNER_STATUS_STEREO)
937 vt->flags |= VIDEO_TUNER_STEREO_ON;
938 else
939 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300940 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300941 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300942 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300943 vt->flags |=
944 VIDEO_TUNER_STEREO_ON;
945 else
946 vt->flags &=
947 ~VIDEO_TUNER_STEREO_ON;
948 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700949 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300950 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300951 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300952
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700953 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
954
955 vt->rangelow = radio_range[0] * 16000;
956 vt->rangehigh = radio_range[1] * 16000;
957
958 } else {
959 vt->rangelow = tv_range[0] * 16;
960 vt->rangehigh = tv_range[1] * 16;
961 }
962
963 return 0;
964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700966 {
967 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700969 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
970 return 0;
971 if (check_v4l2(t) == EINVAL)
972 return 0;
973
Michael Krufkye18f9442007-08-21 01:25:48 -0300974 if (V4L2_TUNER_RADIO == t->mode) {
975 if (fe_tuner_ops->get_status) {
976 u32 tuner_status;
977
978 fe_tuner_ops->get_status(&t->fe, &tuner_status);
979 va->mode = (tuner_status & TUNER_STATUS_STEREO)
980 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -0300981 } else if (ops && ops->is_stereo)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300982 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300983 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
984 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700985 return 0;
986 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300987#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300988 case TUNER_SET_CONFIG:
989 {
990 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
991 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300993 if (t->type != cfg->tuner)
994 break;
995
996 if (t->type == TUNER_TDA9887) {
997 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300998 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300999 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -03001000 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -03001001
1002 if (NULL == fe_tuner_ops->set_config) {
1003 tuner_warn("Tuner frontend module has no way to "
1004 "set config\n");
1005 break;
1006 }
1007 fe_tuner_ops->set_config(&t->fe, cfg->priv);
1008
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -03001009 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -03001010 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -03001011 /* --- v4l ioctls --- */
1012 /* take care: bttv does userspace copying, we'll get a
1013 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001015 {
1016 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001018 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
1019 == EINVAL)
1020 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -07001021
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001022 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001024 t->std = *id;
1025 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -02001026 if (t->tv_freq)
1027 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001028 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -07001029 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001030 case VIDIOC_S_FREQUENCY:
1031 {
1032 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001033
Hans Verkuil4f725cb2006-06-24 09:47:56 -03001034 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
1035 == EINVAL)
1036 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001037 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -02001038 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001039
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001040 break;
1041 }
1042 case VIDIOC_G_FREQUENCY:
1043 {
1044 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001045
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001046 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
1047 return 0;
1048 switch_v4l2();
1049 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -03001050 if (fe_tuner_ops->get_frequency) {
1051 u32 abs_freq;
1052
1053 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
1054 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
1055 (abs_freq * 2 + 125/2) / 125 :
1056 (abs_freq + 62500/2) / 62500;
1057 break;
1058 }
Hans Verkuil27487d42006-01-15 15:04:52 -02001059 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
1060 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001061 break;
1062 }
1063 case VIDIOC_G_TUNER:
1064 {
1065 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -07001066
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001067 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
1068 return 0;
1069 switch_v4l2();
1070
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001071 tuner->type = t->mode;
Michael Krufkyaf3b0f32007-10-22 18:03:29 -03001072 if (ops && ops->get_afc)
Michael Krufky4e9154b2007-10-21 19:39:50 -03001073 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -03001074 if (t->mode == V4L2_TUNER_ANALOG_TV)
1075 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001076 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001077 tuner->rangelow = tv_range[0] * 16;
1078 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001079 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001080 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001081
1082 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001083 tuner->rxsubchans =
1084 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001085 if (fe_tuner_ops->get_status) {
1086 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001087
Michael Krufkye18f9442007-08-21 01:25:48 -03001088 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -03001089 tuner->rxsubchans =
1090 (tuner_status & TUNER_STATUS_STEREO) ?
1091 V4L2_TUNER_SUB_STEREO :
1092 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001093 } else {
Michael Krufkyaf3b0f32007-10-22 18:03:29 -03001094 if (ops && ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -03001095 tuner->rxsubchans =
1096 ops->is_stereo(&t->fe) ?
1097 V4L2_TUNER_SUB_STEREO :
1098 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001099 }
Michael Krufkye18f9442007-08-21 01:25:48 -03001100 }
Michael Krufkyaf3b0f32007-10-22 18:03:29 -03001101 if (ops && ops->has_signal)
Michael Krufky4e9154b2007-10-21 19:39:50 -03001102 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001103 tuner->capability |=
1104 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
1105 tuner->audmode = t->audmode;
1106 tuner->rangelow = radio_range[0] * 16000;
1107 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001108 break;
1109 }
1110 case VIDIOC_S_TUNER:
1111 {
1112 struct v4l2_tuner *tuner = arg;
1113
1114 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
1115 return 0;
1116
1117 switch_v4l2();
1118
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001119 /* do nothing unless we're a radio tuner */
1120 if (t->mode != V4L2_TUNER_RADIO)
1121 break;
1122 t->audmode = tuner->audmode;
1123 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001124 break;
1125 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001126 case VIDIOC_LOG_STATUS:
Michael Krufkyaf3b0f32007-10-22 18:03:29 -03001127 if (ops && ops->tuner_status)
Michael Krufky4e9154b2007-10-21 19:39:50 -03001128 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001129 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
1131
1132 return 0;
1133}
1134
Jean Delvare21b48a72007-03-12 19:20:15 -03001135static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001137 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001139 tuner_dbg ("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 /* FIXME: power down ??? */
1141 return 0;
1142}
1143
Jean Delvare21b48a72007-03-12 19:20:15 -03001144static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001146 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001148 tuner_dbg ("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -02001149 if (V4L2_TUNER_RADIO == t->mode) {
1150 if (t->radio_freq)
1151 set_freq(c, t->radio_freq);
1152 } else {
1153 if (t->tv_freq)
1154 set_freq(c, t->tv_freq);
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return 0;
1157}
1158
1159/* ----------------------------------------------------------------------- */
1160
1161static struct i2c_driver driver = {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001162 .id = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001163 .attach_adapter = tuner_probe,
1164 .detach_client = tuner_detach,
1165 .command = tuner_command,
Jean Delvare21b48a72007-03-12 19:20:15 -03001166 .suspend = tuner_suspend,
1167 .resume = tuner_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 .driver = {
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001169 .name = "tuner",
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001170 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001172static struct i2c_client client_template = {
Jean Delvarefae91e72005-08-15 19:57:04 +02001173 .name = "(tuner unset)",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001174 .driver = &driver,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175};
1176
1177static int __init tuner_init_module(void)
1178{
1179 return i2c_add_driver(&driver);
1180}
1181
1182static void __exit tuner_cleanup_module(void)
1183{
1184 i2c_del_driver(&driver);
1185}
1186
1187module_init(tuner_init_module);
1188module_exit(tuner_cleanup_module);
1189
1190/*
1191 * Overrides for Emacs so that we follow Linus's tabbing style.
1192 * ---------------------------------------------------------------------------
1193 * Local variables:
1194 * c-basic-offset: 8
1195 * End:
1196 */