blob: 3de03da28da086581fb46e065790659b7c7a2556 [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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#define UNSET (-1U)
31
32/* standard i2c insmod options */
33static unsigned short normal_i2c[] = {
Adrian Bunk04d934f2007-10-24 09:06:47 -030034#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -030035 0x10,
36#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -080037 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -070038 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
39 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 I2C_CLIENT_END
41};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070042
Linus Torvalds1da177e2005-04-16 15:20:36 -070043I2C_CLIENT_INSMOD;
44
45/* insmod options used at init time => read/only */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070046static unsigned int addr = 0;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -070047static unsigned int no_autodetect = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070048static unsigned int show_i2c = 0;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -070049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050/* insmod options used at runtime => read/write */
Hans Verkuilf9195de2006-01-11 19:01:01 -020051int tuner_debug = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070053static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070054static unsigned int radio_range[2] = { 65, 108 };
55
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020056static char pal[] = "--";
57static char secam[] = "--";
58static char ntsc[] = "-";
59
Hans Verkuilf9195de2006-01-11 19:01:01 -020060
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020061module_param(addr, int, 0444);
62module_param(no_autodetect, int, 0444);
63module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -020064module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -020065module_param_string(pal, pal, sizeof(pal), 0644);
66module_param_string(secam, secam, sizeof(secam), 0644);
67module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -070068module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069module_param_array(radio_range, int, NULL, 0644);
70
71MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
72MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
73MODULE_LICENSE("GPL");
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static struct i2c_driver driver;
76static struct i2c_client client_template;
77
78/* ---------------------------------------------------------------------- */
79
Michael Krufky4e9154b2007-10-21 19:39:50 -030080static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq)
Michael Krufkye18f9442007-08-21 01:25:48 -030081{
Michael Krufky4e9154b2007-10-21 19:39:50 -030082 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
83 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -030084
85 struct analog_parameters params = {
86 .frequency = freq,
87 .mode = t->mode,
88 .audmode = t->audmode,
89 .std = t->std
90 };
91
92 if (NULL == fe_tuner_ops->set_analog_params) {
93 tuner_warn("Tuner frontend module has no way to set freq\n");
94 return;
95 }
Michael Krufky4e9154b2007-10-21 19:39:50 -030096 fe_tuner_ops->set_analog_params(fe, &params);
Michael Krufkye18f9442007-08-21 01:25:48 -030097}
98
Michael Krufky4e9154b2007-10-21 19:39:50 -030099static void fe_release(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300100{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300101 if (fe->ops.tuner_ops.release)
102 fe->ops.tuner_ops.release(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300103
Michael Krufky4e9154b2007-10-21 19:39:50 -0300104 fe->ops.analog_demod_ops = NULL;
105 /* DO NOT kfree(t->fe.analog_demod_priv) */
106 fe->analog_demod_priv = NULL;
Michael Krufkye18f9442007-08-21 01:25:48 -0300107}
108
Michael Krufky4e9154b2007-10-21 19:39:50 -0300109static void fe_standby(struct dvb_frontend *fe)
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;
Michael Krufkye18f9442007-08-21 01:25:48 -0300112
113 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300114 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300115}
116
Michael Krufky4e9154b2007-10-21 19:39:50 -0300117static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300118{
Michael Krufky14196832007-10-14 18:11:53 -0300119 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300120
Michael Krufky4e9154b2007-10-21 19:39:50 -0300121 if (fe->ops.tuner_ops.get_rf_strength)
122 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300123
124 return strength;
125}
126
Michael Krufky4e9154b2007-10-21 19:39:50 -0300127static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300128
129static struct analog_tuner_ops tuner_core_ops = {
130 .set_tv_freq = fe_set_freq,
131 .set_radio_freq = fe_set_freq,
132 .standby = fe_standby,
133 .release = fe_release,
134 .has_signal = fe_has_signal,
135 .tuner_status = tuner_status
136};
137
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700138/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static void set_tv_freq(struct i2c_client *c, unsigned int freq)
140{
141 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300142 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700145 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return;
147 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300148 if ((NULL == ops) || (NULL == ops->set_tv_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700149 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 return;
151 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700152 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
153 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
154 freq / 16, freq % 16 * 100 / 16, tv_range[0],
155 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200156 /* V4L2 spec: if the freq is not possible then the closest
157 possible value should be selected */
158 if (freq < tv_range[0] * 16)
159 freq = tv_range[0] * 16;
160 else
161 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
Michael Krufky4e9154b2007-10-21 19:39:50 -0300163 ops->set_tv_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
166static void set_radio_freq(struct i2c_client *c, unsigned int freq)
167{
168 struct tuner *t = i2c_get_clientdata(c);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300169 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700172 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return;
174 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300175 if ((NULL == ops) || (NULL == ops->set_radio_freq)) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700176 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 return;
178 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200179 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700180 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
181 freq / 16000, freq % 16000 * 100 / 16000,
182 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200183 /* V4L2 spec: if the freq is not possible then the closest
184 possible value should be selected */
185 if (freq < radio_range[0] * 16000)
186 freq = radio_range[0] * 16000;
187 else
188 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700190
Michael Krufky4e9154b2007-10-21 19:39:50 -0300191 ops->set_radio_freq(&t->fe, freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
194static void set_freq(struct i2c_client *c, unsigned long freq)
195{
196 struct tuner *t = i2c_get_clientdata(c);
197
198 switch (t->mode) {
199 case V4L2_TUNER_RADIO:
200 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700201 freq / 16000, freq % 16000 * 100 / 16000);
202 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200203 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 break;
205 case V4L2_TUNER_ANALOG_TV:
206 case V4L2_TUNER_DIGITAL_TV:
207 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700208 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200210 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300212 default:
213 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
216
Michael Krufky293197c2007-08-28 17:20:42 -0300217static void tuner_i2c_address_check(struct tuner *t)
218{
219 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
220 ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
221 return;
222
223 tuner_warn("====================== WARNING! ======================\n");
224 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
225 tuner_warn("will soon be dropped. This message indicates that your\n");
226 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
227 t->i2c.name, t->i2c.addr);
228 tuner_warn("To ensure continued support for your device, please\n");
229 tuner_warn("send a copy of this message, along with full dmesg\n");
230 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
231 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
232 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
233 t->i2c.adapter->name, t->i2c.addr, t->type,
234 tuners[t->type].name);
235 tuner_warn("====================== WARNING! ======================\n");
236}
237
Michael Krufky4adad282007-08-27 21:59:08 -0300238static void attach_simple_tuner(struct tuner *t)
239{
240 struct simple_tuner_config cfg = {
241 .type = t->type,
242 .tun = &tuners[t->type]
243 };
244 simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
245}
246
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700247static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300248 unsigned int new_mode_mask, unsigned int new_config,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300249 int (*tuner_callback) (void *dev, int command,int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300252 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300253 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700254 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700256 if (type == UNSET || type == TUNER_ABSENT) {
257 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return;
259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700261 if (type >= tuner_count) {
262 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
263 return;
264 }
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300267 t->config = new_config;
268 if (tuner_callback != NULL) {
269 tuner_dbg("defining GPIO callback\n");
270 t->tuner_callback = tuner_callback;
271 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300272
273 /* This code detects calls by card attach_inform */
274 if (NULL == t->i2c.dev.driver) {
275 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
276
277 return;
278 }
279
Michael Krufkyb2083192007-05-29 22:54:06 -0300280 /* discard private data, in case set_type() was previously called */
Michael Krufky1dde7a42007-10-21 13:40:56 -0300281 if ((ops) && (ops->release))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300282 ops->release(&t->fe);
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 switch (t->type) {
285 case TUNER_MT2032:
Michael Krufky96c0b7c2007-08-27 21:23:08 -0300286 microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 break;
288 case TUNER_PHILIPS_TDA8290:
Michael Krufky910bb3e2007-08-27 21:22:20 -0300289 {
Michael Krufky746d97322007-08-25 19:08:45 -0300290 tda8290_attach(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
Michael Krufky910bb3e2007-08-27 21:22:20 -0300292 }
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300293 case TUNER_PHILIPS_TDA8295:
294 {
295 tda8295_attach(t);
296 break;
297 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700298 case TUNER_TEA5767:
Michael Krufky8d0936e2007-08-27 21:24:27 -0300299 if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700300 t->type = TUNER_ABSENT;
301 t->mode_mask = T_UNINITIALIZED;
302 return;
303 }
304 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700305 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300306 case TUNER_TEA5761:
Michael Krufky7ab10bf2007-08-27 21:23:40 -0300307 if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300308 t->type = TUNER_ABSENT;
309 t->mode_mask = T_UNINITIALIZED;
Adrian Bunk9ee476a2007-06-05 05:22:00 -0300310 return;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300311 }
312 t->mode_mask = T_RADIO;
313 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700314 case TUNER_PHILIPS_FMD1216ME_MK3:
315 buffer[0] = 0x0b;
316 buffer[1] = 0xdc;
317 buffer[2] = 0x9c;
318 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700319 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700320 mdelay(1);
321 buffer[2] = 0x86;
322 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700323 i2c_master_send(c, buffer, 4);
Michael Krufky4adad282007-08-27 21:59:08 -0300324 attach_simple_tuner(t);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700325 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800326 case TUNER_PHILIPS_TD1316:
327 buffer[0] = 0x0b;
328 buffer[1] = 0xdc;
329 buffer[2] = 0x86;
330 buffer[3] = 0xa4;
331 i2c_master_send(c,buffer,4);
Michael Krufky4adad282007-08-27 21:59:08 -0300332 attach_simple_tuner(t);
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200333 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300334 case TUNER_XC2028:
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -0300335 {
336 int rc=xc2028_attach(&t->fe, t->i2c.adapter, t->i2c.addr,
337 &c->dev, c->adapter->algo_data,
338 t->tuner_callback);
339 if (rc<0) {
340 t->type = TUNER_ABSENT;
341 t->mode_mask = T_UNINITIALIZED;
342 return;
343 }
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300344 break;
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -0300345 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300346 case TUNER_TDA9887:
Michael Krufkydb8a6952007-08-21 01:24:42 -0300347 tda9887_tuner_init(t);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 default:
Michael Krufky4adad282007-08-27 21:59:08 -0300350 attach_simple_tuner(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 break;
352 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700353
Michael Krufkye2be32a2007-10-21 14:35:21 -0300354 ops = t->fe.ops.analog_demod_ops;
355
Michael Krufky1dde7a42007-10-21 13:40:56 -0300356 if (((NULL == ops) ||
357 ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) &&
358 (fe_tuner_ops->set_analog_params)) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300359 strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
360
Michael Krufky1dde7a42007-10-21 13:40:56 -0300361 t->fe.ops.analog_demod_ops = &tuner_core_ops;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300362 t->fe.analog_demod_priv = t;
Michael Krufkye18f9442007-08-21 01:25:48 -0300363 }
364
365 tuner_info("type set to %s\n", t->i2c.name);
366
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700367 if (t->mode_mask == T_UNINITIALIZED)
368 t->mode_mask = new_mode_mask;
369
Hans Verkuil27487d42006-01-15 15:04:52 -0200370 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700371 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100372 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700373 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300374 tuner_i2c_address_check(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700377/*
378 * This function apply tuner config to tuner specified
379 * by tun_setup structure. I addr is unset, then admin status
380 * and tun addr status is more precise then current status,
381 * it's applied. Otherwise status and type are applied only to
382 * tuner with exactly the same addr.
383*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700384
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700385static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700386{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700387 struct tuner *t = i2c_get_clientdata(c);
388
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300389 tuner_dbg("set addr for type %i\n", t->type);
390
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300391 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
392 (t->mode_mask & tun_setup->mode_mask))) ||
393 (tun_setup->addr == c->addr)) {
394 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300395 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700396 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700397}
398
399static inline int check_mode(struct tuner *t, char *cmd)
400{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700401 if ((1 << t->mode & t->mode_mask) == 0) {
402 return EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700403 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700404
405 switch (t->mode) {
406 case V4L2_TUNER_RADIO:
407 tuner_dbg("Cmd %s accepted for radio\n", cmd);
408 break;
409 case V4L2_TUNER_ANALOG_TV:
410 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
411 break;
412 case V4L2_TUNER_DIGITAL_TV:
413 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
414 break;
415 }
416 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700417}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700418
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700419/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420static int tuner_fixup_std(struct tuner *t)
421{
422 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300424 case '6':
425 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
426 t->std = V4L2_STD_PAL_60;
427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 case 'b':
429 case 'B':
430 case 'g':
431 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700432 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 t->std = V4L2_STD_PAL_BG;
434 break;
435 case 'i':
436 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700437 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 t->std = V4L2_STD_PAL_I;
439 break;
440 case 'd':
441 case 'D':
442 case 'k':
443 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700444 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 t->std = V4L2_STD_PAL_DK;
446 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700447 case 'M':
448 case 'm':
449 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
450 t->std = V4L2_STD_PAL_M;
451 break;
452 case 'N':
453 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200454 if (pal[1] == 'c' || pal[1] == 'C') {
455 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
456 t->std = V4L2_STD_PAL_Nc;
457 } else {
458 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
459 t->std = V4L2_STD_PAL_N;
460 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700461 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700462 case '-':
463 /* default parameter, do nothing */
464 break;
465 default:
466 tuner_warn ("pal= argument not recognised\n");
467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700470 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
471 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200472 case 'b':
473 case 'B':
474 case 'g':
475 case 'G':
476 case 'h':
477 case 'H':
478 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
479 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
480 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700481 case 'd':
482 case 'D':
483 case 'k':
484 case 'K':
485 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
486 t->std = V4L2_STD_SECAM_DK;
487 break;
488 case 'l':
489 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800490 if ((secam[1]=='C')||(secam[1]=='c')) {
491 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
492 t->std = V4L2_STD_SECAM_LC;
493 } else {
494 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
495 t->std = V4L2_STD_SECAM_L;
496 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700497 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700498 case '-':
499 /* default parameter, do nothing */
500 break;
501 default:
502 tuner_warn ("secam= argument not recognised\n");
503 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700504 }
505 }
506
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200507 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
508 switch (ntsc[0]) {
509 case 'm':
510 case 'M':
511 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
512 t->std = V4L2_STD_NTSC_M;
513 break;
514 case 'j':
515 case 'J':
516 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
517 t->std = V4L2_STD_NTSC_M_JP;
518 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200519 case 'k':
520 case 'K':
521 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
522 t->std = V4L2_STD_NTSC_M_KR;
523 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200524 case '-':
525 /* default parameter, do nothing */
526 break;
527 default:
528 tuner_info("ntsc= argument not recognised\n");
529 break;
530 }
531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return 0;
533}
534
Michael Krufky4e9154b2007-10-21 19:39:50 -0300535static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200536{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300537 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200538 unsigned long freq, freq_fraction;
Michael Krufkye18f9442007-08-21 01:25:48 -0300539 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300540 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200541 const char *p;
542
543 switch (t->mode) {
544 case V4L2_TUNER_RADIO: p = "radio"; break;
545 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
546 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
547 default: p = "undefined"; break;
548 }
549 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200550 freq = t->radio_freq / 16000;
551 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200552 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200553 freq = t->tv_freq / 16;
554 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200555 }
556 tuner_info("Tuner mode: %s\n", p);
557 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300558 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200559 if (t->mode != V4L2_TUNER_RADIO)
560 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300561 if (fe_tuner_ops->get_status) {
562 u32 tuner_status;
563
564 fe_tuner_ops->get_status(&t->fe, &tuner_status);
565 if (tuner_status & TUNER_STATUS_LOCKED)
566 tuner_info("Tuner is locked.\n");
567 if (tuner_status & TUNER_STATUS_STEREO)
568 tuner_info("Stereo: yes\n");
569 }
Michael Krufky1b29ced2007-10-22 01:44:03 -0300570 if (ops) {
571 if (ops->has_signal)
572 tuner_info("Signal strength: %d\n",
573 ops->has_signal(fe));
574 if (ops->is_stereo)
575 tuner_info("Stereo: %s\n",
576 ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200577 }
578}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580/* ---------------------------------------------------------------------- */
581
Hans Verkuilba8fc392006-06-25 15:34:39 -0300582/* static vars: used only in tuner_attach and tuner_probe */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700583static unsigned default_mode_mask;
584
585/* During client attach, set_type is called by adapter's attach_inform callback.
586 set_type must then be completed by tuner_attach.
587 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
589{
590 struct tuner *t;
591
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700592 client_template.adapter = adap;
593 client_template.addr = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Panagiotis Issaris74081872006-01-11 19:40:56 -0200595 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700596 if (NULL == t)
597 return -ENOMEM;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700598 memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 i2c_set_clientdata(&t->i2c, t);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700600 t->type = UNSET;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700601 t->audmode = V4L2_TUNER_MODE_STEREO;
602 t->mode_mask = T_UNINITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700604 if (show_i2c) {
605 unsigned char buffer[16];
606 int i,rc;
607
608 memset(buffer, 0, sizeof(buffer));
609 rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800610 tuner_info("I2C RECV = ");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700611 for (i=0;i<rc;i++)
612 printk("%02x ",buffer[i]);
613 printk("\n");
614 }
Michael Hunoldc28089a2006-11-28 08:14:44 -0300615 /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
616 if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
617 return -ENODEV;
618
Markus Rechberger257c6452006-01-23 17:11:11 -0200619 /* autodetection code based on the i2c addr */
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700620 if (!no_autodetect) {
Mauro Carvalho Chehab13dd38d2005-11-08 21:37:57 -0800621 switch (addr) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300622 case 0x10:
Michael Krufky7ab10bf2007-08-27 21:23:40 -0300623 if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300624 t->type = TUNER_TEA5761;
625 t->mode_mask = T_RADIO;
626 t->mode = T_STANDBY;
627 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
628 default_mode_mask &= ~T_RADIO;
629
630 goto register_client;
631 }
632 break;
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800633 case 0x42:
634 case 0x43:
635 case 0x4a:
636 case 0x4b:
637 /* If chip is not tda8290, don't register.
638 since it can be tda9887*/
Michael Krufky746d97322007-08-25 19:08:45 -0300639 if (tda8290_probe(t) == 0) {
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300640 tuner_dbg("chip at addr %x is a tda8290\n", addr);
641 } else {
642 /* Default is being tda9887 */
643 t->type = TUNER_TDA9887;
644 t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
645 t->mode = T_STANDBY;
646 goto register_client;
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800647 }
648 break;
Mauro Carvalho Chehab13dd38d2005-11-08 21:37:57 -0800649 case 0x60:
Michael Krufky8d0936e2007-08-27 21:24:27 -0300650 if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700651 t->type = TUNER_TEA5767;
652 t->mode_mask = T_RADIO;
653 t->mode = T_STANDBY;
Hans Verkuil27487d42006-01-15 15:04:52 -0200654 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700655 default_mode_mask &= ~T_RADIO;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700656
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800657 goto register_client;
Mauro Carvalho Chehabc5287ba2005-07-15 03:56:28 -0700658 }
Hartmut Hackmann07345f52005-11-08 21:38:09 -0800659 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700660 }
661 }
662
663 /* Initializes only the first adapter found */
664 if (default_mode_mask != T_UNINITIALIZED) {
665 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
666 t->mode_mask = default_mode_mask;
Hans Verkuil27487d42006-01-15 15:04:52 -0200667 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
668 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700669 default_mode_mask = T_UNINITIALIZED;
670 }
671
672 /* Should be just before return */
Mauro Carvalho Chehab67678362005-11-08 21:38:02 -0800673register_client:
674 tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700675 i2c_attach_client (&t->i2c);
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300676 set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 return 0;
678}
679
680static int tuner_probe(struct i2c_adapter *adap)
681{
682 if (0 != addr) {
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -0700683 normal_i2c[0] = addr;
684 normal_i2c[1] = I2C_CLIENT_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Michael Krufkya1dec512007-08-24 01:13:07 -0300687 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
688 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
689 * and an RTC at 0x6f which can get corrupted if probed.
690 */
Michael Krufky9bc37ca2007-09-08 15:17:13 -0300691 if ((adap->id == I2C_HW_B_CX2388x) ||
692 (adap->id == I2C_HW_B_CX23885)) {
Michael Krufkya1dec512007-08-24 01:13:07 -0300693 unsigned int i = 0;
694
695 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
696 i += 2;
697 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
698 ignore[i+0] = adap->nr;
699 ignore[i+1] = 0x6b;
700 ignore[i+2] = adap->nr;
701 ignore[i+3] = 0x6f;
702 ignore[i+4] = I2C_CLIENT_END;
703 } else
704 printk(KERN_WARNING "tuner: "
705 "too many options specified "
706 "in i2c probe ignore list!\n");
707 }
708
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700709 default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 if (adap->class & I2C_CLASS_TV_ANALOG)
712 return i2c_probe(adap, &addr_data, tuner_attach);
713 return 0;
714}
715
716static int tuner_detach(struct i2c_client *client)
717{
718 struct tuner *t = i2c_get_clientdata(client);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300719 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700720 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700722 err = i2c_detach_client(&t->i2c);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700723 if (err) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700724 tuner_warn
725 ("Client deregistration failed, client not detached.\n");
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700726 return err;
727 }
728
Michael Krufky1dde7a42007-10-21 13:40:56 -0300729 if ((ops) && (ops->release))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300730 ops->release(&t->fe);
Michael Krufky16f29162007-10-21 15:22:25 -0300731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 kfree(t);
733 return 0;
734}
735
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700736/*
737 * Switch tuner to other mode. If tuner support both tv and radio,
738 * set another frequency to some value (This is needed for some pal
739 * tuners to avoid locking). Otherwise, just put second tuner in
740 * standby mode.
741 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700743static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
744{
Michael Krufky1dde7a42007-10-21 13:40:56 -0300745 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
746
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800747 if (mode == t->mode)
748 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700749
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800750 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700751
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800752 if (check_mode(t, cmd) == EINVAL) {
753 t->mode = T_STANDBY;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300754 if ((ops) && (ops->standby))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300755 ops->standby(&t->fe);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800756 return EINVAL;
757 }
758 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700759}
760
761#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800762 tuner_dbg("switching to v4l2\n"); \
763 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700764
765static inline int check_v4l2(struct tuner *t)
766{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300767 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
768 TV, v4l1 for radio), until that is fixed this code is disabled.
769 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
770 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700771 return 0;
772}
773
774static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300777 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300778 struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Hans Verkuilf9195de2006-01-11 19:01:01 -0200780 if (tuner_debug>1)
Michael Krufky5e453dc2006-01-09 15:32:31 -0200781 v4l_i2c_print_ioctl(&(t->i2c),cmd);
782
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700783 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700785 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300786 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 -0700787 ((struct tuner_setup *)arg)->type,
788 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300789 ((struct tuner_setup *)arg)->mode_mask,
790 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700791
792 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700793 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200795 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
796 == EINVAL)
797 return 0;
798 if (t->radio_freq)
799 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700801 case TUNER_SET_STANDBY:
Hans Verkuil27487d42006-01-15 15:04:52 -0200802 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
803 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300804 t->mode = T_STANDBY;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300805 if ((ops) && (ops->standby))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300806 ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200807 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300808#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700809 case VIDIOCSAUDIO:
810 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
811 return 0;
812 if (check_v4l2(t) == EINVAL)
813 return 0;
814
815 /* Should be implemented, since bttv calls it */
816 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700817 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700819 {
820 static const v4l2_std_id map[] = {
821 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
822 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
823 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
824 [4 /* bttv */ ] = V4L2_STD_PAL_M,
825 [5 /* bttv */ ] = V4L2_STD_PAL_N,
826 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
827 };
828 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700830 if (check_v4l2(t) == EINVAL)
831 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700832
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700833 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
834 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700836 if (vc->norm < ARRAY_SIZE(map))
837 t->std = map[vc->norm];
838 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200839 if (t->tv_freq)
840 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700841 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700842 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700843 case VIDIOCSFREQ:
844 {
845 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700846
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700847 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
848 return 0;
849 if (check_v4l2(t) == EINVAL)
850 return 0;
851
852 set_freq(client, *v);
853 return 0;
854 }
855 case VIDIOCGTUNER:
856 {
857 struct video_tuner *vt = arg;
858
859 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
860 return 0;
861 if (check_v4l2(t) == EINVAL)
862 return 0;
863
864 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300865 if (fe_tuner_ops->get_status) {
866 u32 tuner_status;
867
868 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300869 if (tuner_status & TUNER_STATUS_STEREO)
870 vt->flags |= VIDEO_TUNER_STEREO_ON;
871 else
872 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300873 } else {
Michael Krufky1dde7a42007-10-21 13:40:56 -0300874 if ((ops) && (ops->is_stereo)) {
Michael Krufky4e9154b2007-10-21 19:39:50 -0300875 if (ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300876 vt->flags |=
877 VIDEO_TUNER_STEREO_ON;
878 else
879 vt->flags &=
880 ~VIDEO_TUNER_STEREO_ON;
881 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700882 }
Michael Krufky1dde7a42007-10-21 13:40:56 -0300883 if ((ops) && (ops->has_signal))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300884 vt->signal = ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300885
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700886 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
887
888 vt->rangelow = radio_range[0] * 16000;
889 vt->rangehigh = radio_range[1] * 16000;
890
891 } else {
892 vt->rangelow = tv_range[0] * 16;
893 vt->rangehigh = tv_range[1] * 16;
894 }
895
896 return 0;
897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700899 {
900 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700902 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
903 return 0;
904 if (check_v4l2(t) == EINVAL)
905 return 0;
906
Michael Krufkye18f9442007-08-21 01:25:48 -0300907 if (V4L2_TUNER_RADIO == t->mode) {
908 if (fe_tuner_ops->get_status) {
909 u32 tuner_status;
910
911 fe_tuner_ops->get_status(&t->fe, &tuner_status);
912 va->mode = (tuner_status & TUNER_STATUS_STEREO)
913 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300914 } else if ((ops) && (ops->is_stereo))
Michael Krufky4e9154b2007-10-21 19:39:50 -0300915 va->mode = ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300916 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
917 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700918 return 0;
919 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300920#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300921 case TUNER_SET_CONFIG:
922 {
923 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
924 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300926 if (t->type != cfg->tuner)
927 break;
928
929 if (t->type == TUNER_TDA9887) {
930 t->tda9887_config = *(unsigned int *)cfg->priv;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300931 set_freq(client, t->tv_freq);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300932 break;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300933 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300934
935 if (NULL == fe_tuner_ops->set_config) {
936 tuner_warn("Tuner frontend module has no way to "
937 "set config\n");
938 break;
939 }
940 fe_tuner_ops->set_config(&t->fe, cfg->priv);
941
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300942 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300943 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300944 /* --- v4l ioctls --- */
945 /* take care: bttv does userspace copying, we'll get a
946 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700948 {
949 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700951 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
952 == EINVAL)
953 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700954
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700955 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700957 t->std = *id;
958 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200959 if (t->tv_freq)
960 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700961 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700962 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700963 case VIDIOC_S_FREQUENCY:
964 {
965 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700966
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300967 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
968 == EINVAL)
969 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700970 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200971 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700972
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700973 break;
974 }
975 case VIDIOC_G_FREQUENCY:
976 {
977 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700978
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700979 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
980 return 0;
981 switch_v4l2();
982 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300983 if (fe_tuner_ops->get_frequency) {
984 u32 abs_freq;
985
986 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
987 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
988 (abs_freq * 2 + 125/2) / 125 :
989 (abs_freq + 62500/2) / 62500;
990 break;
991 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200992 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
993 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700994 break;
995 }
996 case VIDIOC_G_TUNER:
997 {
998 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700999
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001000 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
1001 return 0;
1002 switch_v4l2();
1003
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001004 tuner->type = t->mode;
Michael Krufky1dde7a42007-10-21 13:40:56 -03001005 if ((ops) && (ops->get_afc))
Michael Krufky4e9154b2007-10-21 19:39:50 -03001006 tuner->afc = ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -03001007 if (t->mode == V4L2_TUNER_ANALOG_TV)
1008 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001009 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001010 tuner->rangelow = tv_range[0] * 16;
1011 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001012 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001013 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001014
1015 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001016 tuner->rxsubchans =
1017 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001018 if (fe_tuner_ops->get_status) {
1019 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001020
Michael Krufkye18f9442007-08-21 01:25:48 -03001021 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -03001022 tuner->rxsubchans =
1023 (tuner_status & TUNER_STATUS_STEREO) ?
1024 V4L2_TUNER_SUB_STEREO :
1025 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001026 } else {
Michael Krufky1dde7a42007-10-21 13:40:56 -03001027 if ((ops) && (ops->is_stereo)) {
Michael Krufky4e9154b2007-10-21 19:39:50 -03001028 tuner->rxsubchans =
1029 ops->is_stereo(&t->fe) ?
1030 V4L2_TUNER_SUB_STEREO :
1031 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001032 }
Michael Krufkye18f9442007-08-21 01:25:48 -03001033 }
Michael Krufky1dde7a42007-10-21 13:40:56 -03001034 if ((ops) && (ops->has_signal))
Michael Krufky4e9154b2007-10-21 19:39:50 -03001035 tuner->signal = ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001036 tuner->capability |=
1037 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
1038 tuner->audmode = t->audmode;
1039 tuner->rangelow = radio_range[0] * 16000;
1040 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001041 break;
1042 }
1043 case VIDIOC_S_TUNER:
1044 {
1045 struct v4l2_tuner *tuner = arg;
1046
1047 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
1048 return 0;
1049
1050 switch_v4l2();
1051
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001052 /* do nothing unless we're a radio tuner */
1053 if (t->mode != V4L2_TUNER_RADIO)
1054 break;
1055 t->audmode = tuner->audmode;
1056 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001057 break;
1058 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001059 case VIDIOC_LOG_STATUS:
Michael Krufky1dde7a42007-10-21 13:40:56 -03001060 if ((ops) && (ops->tuner_status))
Michael Krufky4e9154b2007-10-21 19:39:50 -03001061 ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001062 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064
1065 return 0;
1066}
1067
Jean Delvare21b48a72007-03-12 19:20:15 -03001068static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001070 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001072 tuner_dbg ("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 /* FIXME: power down ??? */
1074 return 0;
1075}
1076
Jean Delvare21b48a72007-03-12 19:20:15 -03001077static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001079 struct tuner *t = i2c_get_clientdata (c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001081 tuner_dbg ("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -02001082 if (V4L2_TUNER_RADIO == t->mode) {
1083 if (t->radio_freq)
1084 set_freq(c, t->radio_freq);
1085 } else {
1086 if (t->tv_freq)
1087 set_freq(c, t->tv_freq);
1088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return 0;
1090}
1091
1092/* ----------------------------------------------------------------------- */
1093
1094static struct i2c_driver driver = {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001095 .id = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001096 .attach_adapter = tuner_probe,
1097 .detach_client = tuner_detach,
1098 .command = tuner_command,
Jean Delvare21b48a72007-03-12 19:20:15 -03001099 .suspend = tuner_suspend,
1100 .resume = tuner_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 .driver = {
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001102 .name = "tuner",
Mauro Carvalho Chehabcab462f2006-01-09 15:53:26 -02001103 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001105static struct i2c_client client_template = {
Jean Delvarefae91e72005-08-15 19:57:04 +02001106 .name = "(tuner unset)",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001107 .driver = &driver,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108};
1109
1110static int __init tuner_init_module(void)
1111{
1112 return i2c_add_driver(&driver);
1113}
1114
1115static void __exit tuner_cleanup_module(void)
1116{
1117 i2c_del_driver(&driver);
1118}
1119
1120module_init(tuner_init_module);
1121module_exit(tuner_cleanup_module);
1122
1123/*
1124 * Overrides for Emacs so that we follow Linus's tabbing style.
1125 * ---------------------------------------------------------------------------
1126 * Local variables:
1127 * c-basic-offset: 8
1128 * End:
1129 */