blob: 4a7735c6c1a65e022c11689c8b6ef4b1a8f86406 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * i2c tv tuner chip device driver
4 * core core, i.e. kernel interfaces, registering and so on
5 */
6
7#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/string.h>
10#include <linux/timer.h>
11#include <linux/delay.h>
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/poll.h>
15#include <linux/i2c.h>
16#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/init.h>
Michael Krufkyffbb8072007-08-21 01:14:12 -030018#include <linux/videodev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <media/tuner.h>
Michael Krufky4adad282007-08-27 21:59:08 -030020#include <media/tuner-types.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020021#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030022#include <media/v4l2-ioctl.h>
Hans Verkuil9dd659d2007-11-04 11:03:36 -030023#include <media/v4l2-i2c-drv-legacy.h>
Michael Krufky96c0b7c2007-08-27 21:23:08 -030024#include "mt20xx.h"
Michael Krufky910bb3e2007-08-27 21:22:20 -030025#include "tda8290.h"
Michael Krufky7ab10bf2007-08-27 21:23:40 -030026#include "tea5761.h"
Michael Krufky8d0936e2007-08-27 21:24:27 -030027#include "tea5767.h"
Mauro Carvalho Chehab215b95b2007-10-23 15:24:06 -030028#include "tuner-xc2028.h"
Michael Krufky4adad282007-08-27 21:59:08 -030029#include "tuner-simple.h"
Michael Krufky31c95842007-10-21 20:48:48 -030030#include "tda9887.h"
Steven Toth27c685a2008-01-05 16:50:14 -030031#include "xc5000.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#define UNSET (-1U)
34
Hans Verkuil9dd659d2007-11-04 11:03:36 -030035#define PREFIX t->i2c->driver->driver.name
Michael Krufky241020d2007-10-30 09:46:10 -030036
Michael Krufkya07c8772008-04-29 03:54:19 -030037/** This macro allows us to probe dynamically, avoiding static links */
Mauro Carvalho Chehabff138172008-04-29 23:02:33 -030038#ifdef CONFIG_MEDIA_ATTACH
Michael Krufkya07c8772008-04-29 03:54:19 -030039#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
40 int __r = -EINVAL; \
41 typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
42 if (__a) { \
43 __r = (int) __a(ARGS); \
Andrew Mortona1355e52008-04-30 11:40:17 -030044 symbol_put(FUNCTION); \
Michael Krufkya07c8772008-04-29 03:54:19 -030045 } else { \
46 printk(KERN_ERR "TUNER: Unable to find " \
47 "symbol "#FUNCTION"()\n"); \
48 } \
Michael Krufkya07c8772008-04-29 03:54:19 -030049 __r; \
50})
51
52static void tuner_detach(struct dvb_frontend *fe)
53{
54 if (fe->ops.tuner_ops.release) {
55 fe->ops.tuner_ops.release(fe);
56 symbol_put_addr(fe->ops.tuner_ops.release);
57 }
58 if (fe->ops.analog_ops.release) {
59 fe->ops.analog_ops.release(fe);
60 symbol_put_addr(fe->ops.analog_ops.release);
61 }
62}
63#else
64#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
65 FUNCTION(ARGS); \
66})
67
68static void tuner_detach(struct dvb_frontend *fe)
69{
70 if (fe->ops.tuner_ops.release)
71 fe->ops.tuner_ops.release(fe);
72 if (fe->ops.analog_ops.release)
73 fe->ops.analog_ops.release(fe);
74}
75#endif
76
Michael Krufkyf7f427e2007-12-16 22:02:26 -030077struct tuner {
78 /* device */
79 struct dvb_frontend fe;
80 struct i2c_client *i2c;
81 struct list_head list;
82 unsigned int using_v4l2:1;
83
84 /* keep track of the current settings */
85 v4l2_std_id std;
86 unsigned int tv_freq;
87 unsigned int radio_freq;
88 unsigned int audmode;
89
90 unsigned int mode;
91 unsigned int mode_mask; /* Combination of allowable modes */
92
93 unsigned int type; /* chip type id */
94 unsigned int config;
Michael Krufky7271e602008-05-26 16:08:40 +020095 const char *name;
Michael Krufkyf7f427e2007-12-16 22:02:26 -030096};
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098/* standard i2c insmod options */
99static unsigned short normal_i2c[] = {
Mauro Carvalho Chehab149ef722008-04-29 21:38:46 -0300100#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300101 0x10,
102#endif
Hartmut Hackmannde48eeb2005-11-08 21:37:48 -0800103 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
Mauro Carvalho Chehabf5bec392005-06-23 22:05:13 -0700104 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
105 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 I2C_CLIENT_END
107};
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109I2C_CLIENT_INSMOD;
110
111/* insmod options used at init time => read/only */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300112static unsigned int addr;
113static unsigned int no_autodetect;
114static unsigned int show_i2c;
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/* insmod options used at runtime => read/write */
Michael Krufkyab166052007-12-09 02:26:48 -0300117static int tuner_debug;
118
119#define tuner_warn(fmt, arg...) do { \
120 printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
121 i2c_adapter_id(t->i2c->adapter), \
122 t->i2c->addr, ##arg); \
123 } while (0)
124
125#define tuner_info(fmt, arg...) do { \
126 printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
127 i2c_adapter_id(t->i2c->adapter), \
128 t->i2c->addr, ##arg); \
129 } while (0)
130
131#define tuner_err(fmt, arg...) do { \
132 printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
133 i2c_adapter_id(t->i2c->adapter), \
134 t->i2c->addr, ##arg); \
135 } while (0)
136
137#define tuner_dbg(fmt, arg...) do { \
138 if (tuner_debug) \
139 printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
140 i2c_adapter_id(t->i2c->adapter), \
141 t->i2c->addr, ##arg); \
142 } while (0)
143
144/* ------------------------------------------------------------------------ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700146static unsigned int tv_range[2] = { 44, 958 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static unsigned int radio_range[2] = { 65, 108 };
148
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200149static char pal[] = "--";
150static char secam[] = "--";
151static char ntsc[] = "-";
152
Hans Verkuilf9195de2006-01-11 19:01:01 -0200153
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200154module_param(addr, int, 0444);
155module_param(no_autodetect, int, 0444);
156module_param(show_i2c, int, 0444);
Hans Verkuilf9195de2006-01-11 19:01:01 -0200157module_param_named(debug,tuner_debug, int, 0644);
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200158module_param_string(pal, pal, sizeof(pal), 0644);
159module_param_string(secam, secam, sizeof(secam), 0644);
160module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700161module_param_array(tv_range, int, NULL, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162module_param_array(radio_range, int, NULL, 0644);
163
164MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
165MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
166MODULE_LICENSE("GPL");
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168/* ---------------------------------------------------------------------- */
169
Michael Krufkyc7919d52007-12-08 17:06:30 -0300170static void fe_set_params(struct dvb_frontend *fe,
171 struct analog_parameters *params)
Michael Krufkye18f9442007-08-21 01:25:48 -0300172{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300173 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
174 struct tuner *t = fe->analog_demod_priv;
Michael Krufkye18f9442007-08-21 01:25:48 -0300175
Michael Krufkye18f9442007-08-21 01:25:48 -0300176 if (NULL == fe_tuner_ops->set_analog_params) {
177 tuner_warn("Tuner frontend module has no way to set freq\n");
178 return;
179 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300180 fe_tuner_ops->set_analog_params(fe, params);
Michael Krufkye18f9442007-08-21 01:25:48 -0300181}
182
Michael Krufky4e9154b2007-10-21 19:39:50 -0300183static void fe_standby(struct dvb_frontend *fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300184{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300185 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
Michael Krufkye18f9442007-08-21 01:25:48 -0300186
187 if (fe_tuner_ops->sleep)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300188 fe_tuner_ops->sleep(fe);
Michael Krufkye18f9442007-08-21 01:25:48 -0300189}
190
Michael Krufky4e9154b2007-10-21 19:39:50 -0300191static int fe_has_signal(struct dvb_frontend *fe)
Michael Krufky1f5ef192007-08-31 17:38:02 -0300192{
Michael Krufky14196832007-10-14 18:11:53 -0300193 u16 strength = 0;
Michael Krufky1f5ef192007-08-31 17:38:02 -0300194
Michael Krufky4e9154b2007-10-21 19:39:50 -0300195 if (fe->ops.tuner_ops.get_rf_strength)
196 fe->ops.tuner_ops.get_rf_strength(fe, &strength);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300197
198 return strength;
199}
200
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300201static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
202{
203 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
204 struct tuner *t = fe->analog_demod_priv;
205
206 if (fe_tuner_ops->set_config)
207 return fe_tuner_ops->set_config(fe, priv_cfg);
208
209 tuner_warn("Tuner frontend module has no way to set config\n");
210
211 return 0;
212}
213
Michael Krufky4e9154b2007-10-21 19:39:50 -0300214static void tuner_status(struct dvb_frontend *fe);
Michael Krufky1dde7a42007-10-21 13:40:56 -0300215
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300216static struct analog_demod_ops tuner_core_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300217 .set_params = fe_set_params,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300218 .standby = fe_standby,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300219 .has_signal = fe_has_signal,
Michael Krufkyf1c9a282007-12-16 19:27:23 -0300220 .set_config = fe_set_config,
Michael Krufky1dde7a42007-10-21 13:40:56 -0300221 .tuner_status = tuner_status
222};
223
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700224/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225static void set_tv_freq(struct i2c_client *c, unsigned int freq)
226{
227 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300228 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Michael Krufkyc7919d52007-12-08 17:06:30 -0300230 struct analog_parameters params = {
231 .mode = t->mode,
232 .audmode = t->audmode,
233 .std = t->std
234 };
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700237 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return;
239 }
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300240 if (NULL == analog_ops->set_params) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700241 tuner_warn ("Tuner has no way to set tv freq\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return;
243 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700244 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
245 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
246 freq / 16, freq % 16 * 100 / 16, tv_range[0],
247 tv_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200248 /* V4L2 spec: if the freq is not possible then the closest
249 possible value should be selected */
250 if (freq < tv_range[0] * 16)
251 freq = tv_range[0] * 16;
252 else
253 freq = tv_range[1] * 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300255 params.frequency = freq;
256
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300257 analog_ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
260static void set_radio_freq(struct i2c_client *c, unsigned int freq)
261{
262 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300263 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Michael Krufkyc7919d52007-12-08 17:06:30 -0300265 struct analog_parameters params = {
266 .mode = t->mode,
267 .audmode = t->audmode,
268 .std = t->std
269 };
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (t->type == UNSET) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700272 tuner_warn ("tuner type not set\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return;
274 }
Mauro Carvalho Chehabe545d6e2008-01-05 16:37:04 -0300275 if (NULL == analog_ops->set_params) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700276 tuner_warn ("tuner has no way to set radio frequency\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return;
278 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200279 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700280 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
281 freq / 16000, freq % 16000 * 100 / 16000,
282 radio_range[0], radio_range[1]);
Hans Verkuil27487d42006-01-15 15:04:52 -0200283 /* V4L2 spec: if the freq is not possible then the closest
284 possible value should be selected */
285 if (freq < radio_range[0] * 16000)
286 freq = radio_range[0] * 16000;
287 else
288 freq = radio_range[1] * 16000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
Michael Krufkyc7919d52007-12-08 17:06:30 -0300290 params.frequency = freq;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700291
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300292 analog_ops->set_params(&t->fe, &params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
295static void set_freq(struct i2c_client *c, unsigned long freq)
296{
297 struct tuner *t = i2c_get_clientdata(c);
298
299 switch (t->mode) {
300 case V4L2_TUNER_RADIO:
301 tuner_dbg("radio freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700302 freq / 16000, freq % 16000 * 100 / 16000);
303 set_radio_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200304 t->radio_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 break;
306 case V4L2_TUNER_ANALOG_TV:
307 case V4L2_TUNER_DIGITAL_TV:
308 tuner_dbg("tv freq set to %lu.%02lu\n",
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700309 freq / 16, freq % 16 * 100 / 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 set_tv_freq(c, freq);
Hans Verkuil27487d42006-01-15 15:04:52 -0200311 t->tv_freq = freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 break;
Mauro Carvalho Chehab6cb45872007-10-02 11:57:03 -0300313 default:
314 tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
Michael Krufky293197c2007-08-28 17:20:42 -0300318static void tuner_i2c_address_check(struct tuner *t)
319{
320 if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300321 ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
Michael Krufky293197c2007-08-28 17:20:42 -0300322 return;
323
Michael Krufky16410022008-01-21 12:01:34 -0300324 /* We already know that the XC5000 can only be located at
325 * i2c address 0x61, 0x62, 0x63 or 0x64 */
326 if ((t->type == TUNER_XC5000) &&
327 ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
328 return;
329
Michael Krufky293197c2007-08-28 17:20:42 -0300330 tuner_warn("====================== WARNING! ======================\n");
331 tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
332 tuner_warn("will soon be dropped. This message indicates that your\n");
333 tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
Michael Krufky7271e602008-05-26 16:08:40 +0200334 t->name, t->i2c->addr);
Michael Krufky293197c2007-08-28 17:20:42 -0300335 tuner_warn("To ensure continued support for your device, please\n");
336 tuner_warn("send a copy of this message, along with full dmesg\n");
337 tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
338 tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
339 tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
Michael Krufky7271e602008-05-26 16:08:40 +0200340 t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
Michael Krufky293197c2007-08-28 17:20:42 -0300341 tuner_warn("====================== WARNING! ======================\n");
342}
343
Steven Toth27c685a2008-01-05 16:50:14 -0300344static struct xc5000_config xc5000_cfg;
345
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700346static void set_type(struct i2c_client *c, unsigned int type,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300347 unsigned int new_mode_mask, unsigned int new_config,
Michael Krufkyd7cba042008-09-12 13:31:45 -0300348 int (*tuner_callback) (void *dev, int component, int cmd, int arg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
350 struct tuner *t = i2c_get_clientdata(c);
Michael Krufkye18f9442007-08-21 01:25:48 -0300351 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300352 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700353 unsigned char buffer[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700355 if (type == UNSET || type == TUNER_ABSENT) {
356 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 t->type = type;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300361 t->config = new_config;
362 if (tuner_callback != NULL) {
363 tuner_dbg("defining GPIO callback\n");
Michael Krufkyd7cba042008-09-12 13:31:45 -0300364 t->fe.callback = tuner_callback;
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300365 }
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300366
Mauro Carvalho Chehab48aa3362007-10-29 11:33:18 -0300367 if (t->mode == T_UNINITIALIZED) {
Hartmut Hackmann80f90fb2007-04-27 12:31:18 -0300368 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
369
370 return;
371 }
372
Michael Krufkyb2083192007-05-29 22:54:06 -0300373 /* discard private data, in case set_type() was previously called */
Michael Krufkya07c8772008-04-29 03:54:19 -0300374 tuner_detach(&t->fe);
375 t->fe.analog_demod_priv = NULL;
Michael Krufkybe2b85a2007-06-04 14:40:27 -0300376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 switch (t->type) {
378 case TUNER_MT2032:
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300379 if (!dvb_attach(microtune_attach,
380 &t->fe, t->i2c->adapter, t->i2c->addr))
381 goto attach_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 break;
383 case TUNER_PHILIPS_TDA8290:
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300384 {
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300385 struct tda829x_config cfg = {
386 .lna_cfg = t->config,
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300387 };
388 if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
389 t->i2c->addr, &cfg))
390 goto attach_failed;
Michael Krufky5bea1cd2007-10-22 09:56:38 -0300391 break;
392 }
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700393 case TUNER_TEA5767:
Michael Krufkya07c8772008-04-29 03:54:19 -0300394 if (!dvb_attach(tea5767_attach, &t->fe,
395 t->i2c->adapter, t->i2c->addr))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300396 goto attach_failed;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700397 t->mode_mask = T_RADIO;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700398 break;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300399 case TUNER_TEA5761:
Michael Krufkya07c8772008-04-29 03:54:19 -0300400 if (!dvb_attach(tea5761_attach, &t->fe,
401 t->i2c->adapter, t->i2c->addr))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300402 goto attach_failed;
Mauro Carvalho Chehab8573a9e2007-04-08 01:09:11 -0300403 t->mode_mask = T_RADIO;
404 break;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700405 case TUNER_PHILIPS_FMD1216ME_MK3:
406 buffer[0] = 0x0b;
407 buffer[1] = 0xdc;
408 buffer[2] = 0x9c;
409 buffer[3] = 0x60;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700410 i2c_master_send(c, buffer, 4);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700411 mdelay(1);
412 buffer[2] = 0x86;
413 buffer[3] = 0x54;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700414 i2c_master_send(c, buffer, 4);
Michael Krufkya07c8772008-04-29 03:54:19 -0300415 if (!dvb_attach(simple_tuner_attach, &t->fe,
416 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300417 goto attach_failed;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700418 break;
Hartmut Hackmann93df3412005-11-08 21:36:31 -0800419 case TUNER_PHILIPS_TD1316:
420 buffer[0] = 0x0b;
421 buffer[1] = 0xdc;
422 buffer[2] = 0x86;
423 buffer[3] = 0xa4;
Michael Krufkya07c8772008-04-29 03:54:19 -0300424 i2c_master_send(c, buffer, 4);
425 if (!dvb_attach(simple_tuner_attach, &t->fe,
426 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300427 goto attach_failed;
Markus Rechbergerac272ed2006-01-23 17:11:09 -0200428 break;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300429 case TUNER_XC2028:
430 {
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300431 struct xc2028_config cfg = {
432 .i2c_adap = t->i2c->adapter,
433 .i2c_addr = t->i2c->addr,
Michel Ludwiga37b4c92007-11-16 07:46:14 -0300434 };
Michael Krufkya07c8772008-04-29 03:54:19 -0300435 if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300436 goto attach_failed;
Mauro Carvalho Chehab690c5442007-10-29 11:33:18 -0300437 break;
438 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300439 case TUNER_TDA9887:
Mauro Carvalho Chehab09fee5f2008-04-30 15:29:57 -0300440 if (!dvb_attach(tda9887_attach,
441 &t->fe, t->i2c->adapter, t->i2c->addr))
442 goto attach_failed;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300443 break;
Steven Toth27c685a2008-01-05 16:50:14 -0300444 case TUNER_XC5000:
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300445 {
446 struct dvb_tuner_ops *xc_tuner_ops;
447
Steven Toth27c685a2008-01-05 16:50:14 -0300448 xc5000_cfg.i2c_address = t->i2c->addr;
449 xc5000_cfg.if_khz = 5380;
Michael Krufkya07c8772008-04-29 03:54:19 -0300450 if (!dvb_attach(xc5000_attach,
Michael Krufky30650962008-09-06 14:56:58 -0300451 &t->fe, t->i2c->adapter, &xc5000_cfg))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300452 goto attach_failed;
453
Steven Toth27c685a2008-01-05 16:50:14 -0300454 xc_tuner_ops = &t->fe.ops.tuner_ops;
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300455 if (xc_tuner_ops->init)
Steven Toth27c685a2008-01-05 16:50:14 -0300456 xc_tuner_ops->init(&t->fe);
Steven Toth27c685a2008-01-05 16:50:14 -0300457 break;
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 default:
Michael Krufkya07c8772008-04-29 03:54:19 -0300460 if (!dvb_attach(simple_tuner_attach, &t->fe,
461 t->i2c->adapter, t->i2c->addr, t->type))
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300462 goto attach_failed;
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 break;
465 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700466
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300467 if ((NULL == analog_ops->set_params) &&
Michael Krufky1dde7a42007-10-21 13:40:56 -0300468 (fe_tuner_ops->set_analog_params)) {
Michael Krufkya07c8772008-04-29 03:54:19 -0300469
Michael Krufky7271e602008-05-26 16:08:40 +0200470 t->name = fe_tuner_ops->info.name;
Michael Krufkye18f9442007-08-21 01:25:48 -0300471
Michael Krufky4e9154b2007-10-21 19:39:50 -0300472 t->fe.analog_demod_priv = t;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300473 memcpy(analog_ops, &tuner_core_ops,
474 sizeof(struct analog_demod_ops));
Michael Krufkya07c8772008-04-29 03:54:19 -0300475
Michael Krufkya55db8c2007-12-09 13:52:51 -0300476 } else {
Michael Krufky7271e602008-05-26 16:08:40 +0200477 t->name = analog_ops->info.name;
Michael Krufkye18f9442007-08-21 01:25:48 -0300478 }
479
Michael Krufky7271e602008-05-26 16:08:40 +0200480 tuner_dbg("type set to %s\n", t->name);
Michael Krufkye18f9442007-08-21 01:25:48 -0300481
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700482 if (t->mode_mask == T_UNINITIALIZED)
483 t->mode_mask = new_mode_mask;
484
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300485 /* xc2028/3028 and xc5000 requires a firmware to be set-up later
486 trying to set a frequency here will just fail
487 FIXME: better to move set_freq to the tuner code. This is needed
488 on analog tuners for PLL to properly work
489 */
490 if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
491 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
492 t->radio_freq : t->tv_freq);
493
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700494 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
Laurent Riffard604f28e2005-11-26 20:43:39 +0100495 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700496 t->mode_mask);
Michael Krufky293197c2007-08-28 17:20:42 -0300497 tuner_i2c_address_check(t);
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300498 return;
499
500attach_failed:
501 tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
502 t->type = TUNER_ABSENT;
503 t->mode_mask = T_UNINITIALIZED;
504
505 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700508/*
509 * This function apply tuner config to tuner specified
510 * by tun_setup structure. I addr is unset, then admin status
511 * and tun addr status is more precise then current status,
512 * it's applied. Otherwise status and type are applied only to
513 * tuner with exactly the same addr.
514*/
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700515
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700516static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700517{
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700518 struct tuner *t = i2c_get_clientdata(c);
519
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300520 if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
521 (t->mode_mask & tun_setup->mode_mask))) ||
522 (tun_setup->addr == c->addr)) {
523 set_type(c, tun_setup->type, tun_setup->mode_mask,
Hartmut Hackmanncfeb8832007-04-27 12:31:17 -0300524 tun_setup->config, tun_setup->tuner_callback);
Mauro Carvalho Chehabb9ef6bb2008-04-26 11:29:34 -0300525 } else
526 tuner_dbg("set addr discarded for type %i, mask %x. "
527 "Asked to change tuner at addr 0x%02x, with mask %x\n",
528 t->type, t->mode_mask,
529 tun_setup->addr, tun_setup->mode_mask);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700530}
531
532static inline int check_mode(struct tuner *t, char *cmd)
533{
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700534 if ((1 << t->mode & t->mode_mask) == 0) {
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300535 return -EINVAL;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700536 }
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700537
538 switch (t->mode) {
539 case V4L2_TUNER_RADIO:
540 tuner_dbg("Cmd %s accepted for radio\n", cmd);
541 break;
542 case V4L2_TUNER_ANALOG_TV:
543 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
544 break;
545 case V4L2_TUNER_DIGITAL_TV:
546 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
547 break;
548 }
549 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700550}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700551
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700552/* get more precise norm info from insmod option */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553static int tuner_fixup_std(struct tuner *t)
554{
555 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 switch (pal[0]) {
Hans Verkuile71ced12006-12-11 15:51:43 -0300557 case '6':
558 tuner_dbg ("insmod fixup: PAL => PAL-60\n");
559 t->std = V4L2_STD_PAL_60;
560 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 case 'b':
562 case 'B':
563 case 'g':
564 case 'G':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700565 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 t->std = V4L2_STD_PAL_BG;
567 break;
568 case 'i':
569 case 'I':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700570 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 t->std = V4L2_STD_PAL_I;
572 break;
573 case 'd':
574 case 'D':
575 case 'k':
576 case 'K':
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700577 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 t->std = V4L2_STD_PAL_DK;
579 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700580 case 'M':
581 case 'm':
582 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
583 t->std = V4L2_STD_PAL_M;
584 break;
585 case 'N':
586 case 'n':
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200587 if (pal[1] == 'c' || pal[1] == 'C') {
588 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
589 t->std = V4L2_STD_PAL_Nc;
590 } else {
591 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
592 t->std = V4L2_STD_PAL_N;
593 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700594 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700595 case '-':
596 /* default parameter, do nothing */
597 break;
598 default:
599 tuner_warn ("pal= argument not recognised\n");
600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700603 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
604 switch (secam[0]) {
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200605 case 'b':
606 case 'B':
607 case 'g':
608 case 'G':
609 case 'h':
610 case 'H':
611 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
612 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
613 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700614 case 'd':
615 case 'D':
616 case 'k':
617 case 'K':
618 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
619 t->std = V4L2_STD_SECAM_DK;
620 break;
621 case 'l':
622 case 'L':
Mauro Carvalho Chehab800d3c62005-11-13 16:07:48 -0800623 if ((secam[1]=='C')||(secam[1]=='c')) {
624 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
625 t->std = V4L2_STD_SECAM_LC;
626 } else {
627 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
628 t->std = V4L2_STD_SECAM_L;
629 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700630 break;
Mauro Carvalho Chehab21d4df32005-09-09 13:03:59 -0700631 case '-':
632 /* default parameter, do nothing */
633 break;
634 default:
635 tuner_warn ("secam= argument not recognised\n");
636 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700637 }
638 }
639
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200640 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
641 switch (ntsc[0]) {
642 case 'm':
643 case 'M':
644 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
645 t->std = V4L2_STD_NTSC_M;
646 break;
647 case 'j':
648 case 'J':
649 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
650 t->std = V4L2_STD_NTSC_M_JP;
651 break;
Hans Verkuild97a11e2006-02-07 06:48:40 -0200652 case 'k':
653 case 'K':
654 tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
655 t->std = V4L2_STD_NTSC_M_KR;
656 break;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200657 case '-':
658 /* default parameter, do nothing */
659 break;
660 default:
661 tuner_info("ntsc= argument not recognised\n");
662 break;
663 }
664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return 0;
666}
667
Michael Krufky4e9154b2007-10-21 19:39:50 -0300668static void tuner_status(struct dvb_frontend *fe)
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200669{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300670 struct tuner *t = fe->analog_demod_priv;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200671 unsigned long freq, freq_fraction;
Michael Krufkya07c8772008-04-29 03:54:19 -0300672 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
673 struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200674 const char *p;
675
676 switch (t->mode) {
677 case V4L2_TUNER_RADIO: p = "radio"; break;
678 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
679 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
680 default: p = "undefined"; break;
681 }
682 if (t->mode == V4L2_TUNER_RADIO) {
Hans Verkuil27487d42006-01-15 15:04:52 -0200683 freq = t->radio_freq / 16000;
684 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200685 } else {
Hans Verkuil27487d42006-01-15 15:04:52 -0200686 freq = t->tv_freq / 16;
687 freq_fraction = (t->tv_freq % 16) * 100 / 16;
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200688 }
689 tuner_info("Tuner mode: %s\n", p);
690 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Mauro Carvalho Chehab4ae5c2e2006-03-25 15:53:38 -0300691 tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200692 if (t->mode != V4L2_TUNER_RADIO)
693 return;
Michael Krufkye18f9442007-08-21 01:25:48 -0300694 if (fe_tuner_ops->get_status) {
695 u32 tuner_status;
696
697 fe_tuner_ops->get_status(&t->fe, &tuner_status);
698 if (tuner_status & TUNER_STATUS_LOCKED)
699 tuner_info("Tuner is locked.\n");
700 if (tuner_status & TUNER_STATUS_STEREO)
701 tuner_info("Stereo: yes\n");
702 }
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300703 if (analog_ops->has_signal)
704 tuner_info("Signal strength: %d\n",
705 analog_ops->has_signal(fe));
706 if (analog_ops->is_stereo)
707 tuner_info("Stereo: %s\n",
708 analog_ops->is_stereo(fe) ? "yes" : "no");
Mauro Carvalho Chehab7e578192006-01-09 15:25:27 -0200709}
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711/* ---------------------------------------------------------------------- */
712
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700713/*
714 * Switch tuner to other mode. If tuner support both tv and radio,
715 * set another frequency to some value (This is needed for some pal
716 * tuners to avoid locking). Otherwise, just put second tuner in
717 * standby mode.
718 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700720static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
721{
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300722 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Michael Krufky1dde7a42007-10-21 13:40:56 -0300723
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800724 if (mode == t->mode)
725 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700726
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800727 t->mode = mode;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700728
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300729 if (check_mode(t, cmd) == -EINVAL) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800730 t->mode = T_STANDBY;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300731 if (analog_ops->standby)
732 analog_ops->standby(&t->fe);
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300733 return -EINVAL;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800734 }
735 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700736}
737
738#define switch_v4l2() if (!t->using_v4l2) \
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800739 tuner_dbg("switching to v4l2\n"); \
740 t->using_v4l2 = 1;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700741
742static inline int check_v4l2(struct tuner *t)
743{
Hans Verkuil3bbe5a82006-04-01 15:27:52 -0300744 /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
745 TV, v4l1 for radio), until that is fixed this code is disabled.
746 Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
747 first. */
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700748 return 0;
749}
750
751static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 struct tuner *t = i2c_get_clientdata(client);
Michael Krufkye18f9442007-08-21 01:25:48 -0300754 struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300755 struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Mauro Carvalho Chehab397be5c2008-04-26 14:04:10 -0300757 if (tuner_debug > 1) {
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300758 v4l_i2c_print_ioctl(client,cmd);
Mauro Carvalho Chehab397be5c2008-04-26 14:04:10 -0300759 printk("\n");
760 }
Michael Krufky5e453dc2006-01-09 15:32:31 -0200761
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700762 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 /* --- configuration --- */
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700764 case TUNER_SET_TYPE_ADDR:
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300765 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 -0700766 ((struct tuner_setup *)arg)->type,
767 ((struct tuner_setup *)arg)->addr,
Hartmut Hackmannde956c12007-04-27 12:31:12 -0300768 ((struct tuner_setup *)arg)->mode_mask,
769 ((struct tuner_setup *)arg)->config);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700770
771 set_addr(client, (struct tuner_setup *)arg);
Mauro Carvalho Chehab391cd722005-06-23 22:02:43 -0700772 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 case AUDC_SET_RADIO:
Hans Verkuil27487d42006-01-15 15:04:52 -0200774 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300775 == -EINVAL)
Hans Verkuil27487d42006-01-15 15:04:52 -0200776 return 0;
777 if (t->radio_freq)
778 set_freq(client, t->radio_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 break;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700780 case TUNER_SET_STANDBY:
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300781 if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
Hans Verkuil27487d42006-01-15 15:04:52 -0200782 return 0;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300783 t->mode = T_STANDBY;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300784 if (analog_ops->standby)
785 analog_ops->standby(&t->fe);
Hans Verkuil27487d42006-01-15 15:04:52 -0200786 break;
Mauro Carvalho Chehab17de9a42008-04-15 18:11:50 -0300787#ifdef CONFIG_VIDEO_ALLOW_V4L1
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700788 case VIDIOCSAUDIO:
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300789 if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700790 return 0;
Marcin Slusarz427aad62008-05-11 19:58:59 -0300791 if (check_v4l2(t) == -EINVAL)
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700792 return 0;
793
794 /* Should be implemented, since bttv calls it */
795 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
Mauro Carvalho Chehabfd3113e2005-07-31 22:34:43 -0700796 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 case VIDIOCSCHAN:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700798 {
799 static const v4l2_std_id map[] = {
800 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
801 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
802 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
803 [4 /* bttv */ ] = V4L2_STD_PAL_M,
804 [5 /* bttv */ ] = V4L2_STD_PAL_N,
805 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
806 };
807 struct video_channel *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Marcin Slusarz427aad62008-05-11 19:58:59 -0300809 if (check_v4l2(t) == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700810 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700811
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300812 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700813 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700815 if (vc->norm < ARRAY_SIZE(map))
816 t->std = map[vc->norm];
817 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200818 if (t->tv_freq)
819 set_tv_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700820 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700821 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700822 case VIDIOCSFREQ:
823 {
824 unsigned long *v = arg;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700825
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300826 if (check_mode(t, "VIDIOCSFREQ") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700827 return 0;
Marcin Slusarz427aad62008-05-11 19:58:59 -0300828 if (check_v4l2(t) == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700829 return 0;
830
831 set_freq(client, *v);
832 return 0;
833 }
834 case VIDIOCGTUNER:
835 {
836 struct video_tuner *vt = arg;
837
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300838 if (check_mode(t, "VIDIOCGTUNER") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700839 return 0;
Marcin Slusarz427aad62008-05-11 19:58:59 -0300840 if (check_v4l2(t) == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700841 return 0;
842
843 if (V4L2_TUNER_RADIO == t->mode) {
Michael Krufkye18f9442007-08-21 01:25:48 -0300844 if (fe_tuner_ops->get_status) {
845 u32 tuner_status;
846
847 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300848 if (tuner_status & TUNER_STATUS_STEREO)
849 vt->flags |= VIDEO_TUNER_STEREO_ON;
850 else
851 vt->flags &= ~VIDEO_TUNER_STEREO_ON;
Michael Krufkye18f9442007-08-21 01:25:48 -0300852 } else {
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300853 if (analog_ops->is_stereo) {
854 if (analog_ops->is_stereo(&t->fe))
Michael Krufkye18f9442007-08-21 01:25:48 -0300855 vt->flags |=
856 VIDEO_TUNER_STEREO_ON;
857 else
858 vt->flags &=
859 ~VIDEO_TUNER_STEREO_ON;
860 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700861 }
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300862 if (analog_ops->has_signal)
863 vt->signal =
864 analog_ops->has_signal(&t->fe);
Michael Krufky1f5ef192007-08-31 17:38:02 -0300865
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700866 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
867
868 vt->rangelow = radio_range[0] * 16000;
869 vt->rangehigh = radio_range[1] * 16000;
870
871 } else {
872 vt->rangelow = tv_range[0] * 16;
873 vt->rangehigh = tv_range[1] * 16;
874 }
875
876 return 0;
877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 case VIDIOCGAUDIO:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700879 {
880 struct video_audio *va = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300882 if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700883 return 0;
Marcin Slusarz427aad62008-05-11 19:58:59 -0300884 if (check_v4l2(t) == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700885 return 0;
886
Michael Krufkye18f9442007-08-21 01:25:48 -0300887 if (V4L2_TUNER_RADIO == t->mode) {
888 if (fe_tuner_ops->get_status) {
889 u32 tuner_status;
890
891 fe_tuner_ops->get_status(&t->fe, &tuner_status);
892 va->mode = (tuner_status & TUNER_STATUS_STEREO)
893 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300894 } else if (analog_ops->is_stereo)
895 va->mode = analog_ops->is_stereo(&t->fe)
Michael Krufkye18f9442007-08-21 01:25:48 -0300896 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
897 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700898 return 0;
899 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300900#endif
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300901 case TUNER_SET_CONFIG:
902 {
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300903 struct v4l2_priv_tun_config *cfg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300905 if (t->type != cfg->tuner)
906 break;
907
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300908 if (analog_ops->set_config) {
Michael Krufky67d52e22007-12-24 16:05:39 -0300909 analog_ops->set_config(&t->fe, cfg->priv);
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300910 break;
911 }
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300912
Michael Krufky67d52e22007-12-24 16:05:39 -0300913 tuner_dbg("Tuner frontend module has no way to set config\n");
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300914 break;
Mauro Carvalho Chehab7f171122007-10-18 19:56:47 -0300915 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -0300916 /* --- v4l ioctls --- */
917 /* take care: bttv does userspace copying, we'll get a
918 kernel pointer here... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 case VIDIOC_S_STD:
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700920 {
921 v4l2_std_id *id = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700923 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300924 == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700925 return 0;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700926
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700927 switch_v4l2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700929 t->std = *id;
930 tuner_fixup_std(t);
Hans Verkuil27487d42006-01-15 15:04:52 -0200931 if (t->tv_freq)
932 set_freq(client, t->tv_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700933 break;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700934 }
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700935 case VIDIOC_S_FREQUENCY:
936 {
937 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700938
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300939 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300940 == -EINVAL)
Hans Verkuil4f725cb2006-06-24 09:47:56 -0300941 return 0;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700942 switch_v4l2();
Hans Verkuil27487d42006-01-15 15:04:52 -0200943 set_freq(client,f->frequency);
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700944
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700945 break;
946 }
947 case VIDIOC_G_FREQUENCY:
948 {
949 struct v4l2_frequency *f = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700950
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300951 if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700952 return 0;
953 switch_v4l2();
954 f->type = t->mode;
Michael Krufkye18f9442007-08-21 01:25:48 -0300955 if (fe_tuner_ops->get_frequency) {
956 u32 abs_freq;
957
958 fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
959 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
960 (abs_freq * 2 + 125/2) / 125 :
961 (abs_freq + 62500/2) / 62500;
962 break;
963 }
Hans Verkuil27487d42006-01-15 15:04:52 -0200964 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
965 t->radio_freq : t->tv_freq;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700966 break;
967 }
968 case VIDIOC_G_TUNER:
969 {
970 struct v4l2_tuner *tuner = arg;
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700971
Marcin Slusarz4d3437d2008-05-26 14:03:02 -0300972 if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700973 return 0;
974 switch_v4l2();
975
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200976 tuner->type = t->mode;
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300977 if (analog_ops->get_afc)
978 tuner->afc = analog_ops->get_afc(&t->fe);
Hans Verkuilab4cecf2006-04-01 16:40:21 -0300979 if (t->mode == V4L2_TUNER_ANALOG_TV)
980 tuner->capability |= V4L2_TUNER_CAP_NORM;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200981 if (t->mode != V4L2_TUNER_RADIO) {
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700982 tuner->rangelow = tv_range[0] * 16;
983 tuner->rangehigh = tv_range[1] * 16;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200984 break;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -0700985 }
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200986
987 /* radio mode */
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200988 tuner->rxsubchans =
989 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300990 if (fe_tuner_ops->get_status) {
991 u32 tuner_status;
Hans Verkuil8a4b2752006-01-23 17:11:09 -0200992
Michael Krufkye18f9442007-08-21 01:25:48 -0300993 fe_tuner_ops->get_status(&t->fe, &tuner_status);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300994 tuner->rxsubchans =
995 (tuner_status & TUNER_STATUS_STEREO) ?
996 V4L2_TUNER_SUB_STEREO :
997 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -0300998 } else {
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300999 if (analog_ops->is_stereo) {
Michael Krufky4e9154b2007-10-21 19:39:50 -03001000 tuner->rxsubchans =
Michael Krufkybc3e5c72007-12-21 11:18:32 -03001001 analog_ops->is_stereo(&t->fe) ?
Michael Krufky4e9154b2007-10-21 19:39:50 -03001002 V4L2_TUNER_SUB_STEREO :
1003 V4L2_TUNER_SUB_MONO;
Michael Krufkye18f9442007-08-21 01:25:48 -03001004 }
Michael Krufkye18f9442007-08-21 01:25:48 -03001005 }
Michael Krufkybc3e5c72007-12-21 11:18:32 -03001006 if (analog_ops->has_signal)
1007 tuner->signal = analog_ops->has_signal(&t->fe);
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001008 tuner->capability |=
1009 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
1010 tuner->audmode = t->audmode;
1011 tuner->rangelow = radio_range[0] * 16000;
1012 tuner->rangehigh = radio_range[1] * 16000;
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001013 break;
1014 }
1015 case VIDIOC_S_TUNER:
1016 {
1017 struct v4l2_tuner *tuner = arg;
1018
Marcin Slusarz4d3437d2008-05-26 14:03:02 -03001019 if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001020 return 0;
1021
1022 switch_v4l2();
1023
Hans Verkuil8a4b2752006-01-23 17:11:09 -02001024 /* do nothing unless we're a radio tuner */
1025 if (t->mode != V4L2_TUNER_RADIO)
1026 break;
1027 t->audmode = tuner->audmode;
1028 set_radio_freq(client, t->radio_freq);
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001029 break;
1030 }
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001031 case VIDIOC_LOG_STATUS:
Michael Krufkybc3e5c72007-12-21 11:18:32 -03001032 if (analog_ops->tuner_status)
1033 analog_ops->tuner_status(&t->fe);
Hans Verkuilcd43c3f2006-01-09 15:25:15 -02001034 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 }
1036
1037 return 0;
1038}
1039
Jean Delvare21b48a72007-03-12 19:20:15 -03001040static int tuner_suspend(struct i2c_client *c, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001042 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001044 tuner_dbg("suspend\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 /* FIXME: power down ??? */
1046 return 0;
1047}
1048
Jean Delvare21b48a72007-03-12 19:20:15 -03001049static int tuner_resume(struct i2c_client *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050{
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001051 struct tuner *t = i2c_get_clientdata(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001053 tuner_dbg("resume\n");
Hans Verkuil27487d42006-01-15 15:04:52 -02001054 if (V4L2_TUNER_RADIO == t->mode) {
1055 if (t->radio_freq)
1056 set_freq(c, t->radio_freq);
1057 } else {
1058 if (t->tv_freq)
1059 set_freq(c, t->tv_freq);
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return 0;
1062}
1063
Hans Verkuil92de1f12007-11-04 10:53:09 -03001064/* ---------------------------------------------------------------------- */
1065
Adrian Bunkc52c4d02008-01-28 22:11:15 -03001066static LIST_HEAD(tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001067
1068/* Search for existing radio and/or TV tuners on the given I2C adapter.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001069 Note that when this function is called from tuner_probe you can be
Hans Verkuil92de1f12007-11-04 10:53:09 -03001070 certain no other devices will be added/deleted at the same time, I2C
1071 core protects against that. */
1072static void tuner_lookup(struct i2c_adapter *adap,
1073 struct tuner **radio, struct tuner **tv)
1074{
1075 struct tuner *pos;
1076
1077 *radio = NULL;
1078 *tv = NULL;
1079
1080 list_for_each_entry(pos, &tuner_list, list) {
1081 int mode_mask;
1082
1083 if (pos->i2c->adapter != adap ||
1084 pos->i2c->driver->id != I2C_DRIVERID_TUNER)
1085 continue;
1086
1087 mode_mask = pos->mode_mask & ~T_STANDBY;
1088 if (*radio == NULL && mode_mask == T_RADIO)
1089 *radio = pos;
1090 /* Note: currently TDA9887 is the only demod-only
1091 device. If other devices appear then we need to
1092 make this test more general. */
1093 else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
1094 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
1095 *tv = pos;
1096 }
1097}
1098
1099/* During client attach, set_type is called by adapter's attach_inform callback.
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001100 set_type must then be completed by tuner_probe.
Hans Verkuil92de1f12007-11-04 10:53:09 -03001101 */
Jean Delvared2653e92008-04-29 23:11:39 +02001102static int tuner_probe(struct i2c_client *client,
1103 const struct i2c_device_id *id)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001104{
Hans Verkuil92de1f12007-11-04 10:53:09 -03001105 struct tuner *t;
1106 struct tuner *radio;
1107 struct tuner *tv;
1108
Hans Verkuil92de1f12007-11-04 10:53:09 -03001109 t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001110 if (NULL == t)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001111 return -ENOMEM;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001112 t->i2c = client;
Michael Krufky7271e602008-05-26 16:08:40 +02001113 t->name = "(tuner unset)";
Hans Verkuil92de1f12007-11-04 10:53:09 -03001114 i2c_set_clientdata(client, t);
1115 t->type = UNSET;
1116 t->audmode = V4L2_TUNER_MODE_STEREO;
1117 t->mode_mask = T_UNINITIALIZED;
1118
1119 if (show_i2c) {
1120 unsigned char buffer[16];
1121 int i, rc;
1122
1123 memset(buffer, 0, sizeof(buffer));
1124 rc = i2c_master_recv(client, buffer, sizeof(buffer));
1125 tuner_info("I2C RECV = ");
1126 for (i = 0; i < rc; i++)
1127 printk(KERN_CONT "%02x ", buffer[i]);
1128 printk("\n");
1129 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001130 /* HACK: This test was added to avoid tuner to probe tda9840 and
Hans Verkuil92de1f12007-11-04 10:53:09 -03001131 tea6415c on the MXB card */
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001132 if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
1133 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001134 return -ENODEV;
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001135 }
Hans Verkuil92de1f12007-11-04 10:53:09 -03001136
1137 /* autodetection code based on the i2c addr */
1138 if (!no_autodetect) {
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001139 switch (client->addr) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001140 case 0x10:
Michael Krufkya07c8772008-04-29 03:54:19 -03001141 if (tuner_symbol_probe(tea5761_autodetection,
1142 t->i2c->adapter,
1143 t->i2c->addr) >= 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001144 t->type = TUNER_TEA5761;
1145 t->mode_mask = T_RADIO;
1146 t->mode = T_STANDBY;
1147 /* Sets freq to FM range */
1148 t->radio_freq = 87.5 * 16000;
1149 tuner_lookup(t->i2c->adapter, &radio, &tv);
1150 if (tv)
1151 tv->mode_mask &= ~T_RADIO;
1152
1153 goto register_client;
1154 }
Mauro Carvalho Chehab867e8352008-04-23 17:27:27 -03001155 return -ENODEV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001156 case 0x42:
1157 case 0x43:
1158 case 0x4a:
1159 case 0x4b:
1160 /* If chip is not tda8290, don't register.
1161 since it can be tda9887*/
Michael Krufkya07c8772008-04-29 03:54:19 -03001162 if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
Mauro Carvalho Chehabb538d282008-04-30 15:45:00 -03001163 t->i2c->addr) >= 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001164 tuner_dbg("tda829x detected\n");
1165 } else {
1166 /* Default is being tda9887 */
1167 t->type = TUNER_TDA9887;
1168 t->mode_mask = T_RADIO | T_ANALOG_TV |
1169 T_DIGITAL_TV;
1170 t->mode = T_STANDBY;
1171 goto register_client;
1172 }
1173 break;
1174 case 0x60:
Michael Krufkya07c8772008-04-29 03:54:19 -03001175 if (tuner_symbol_probe(tea5767_autodetection,
1176 t->i2c->adapter, t->i2c->addr)
Mauro Carvalho Chehabb538d282008-04-30 15:45:00 -03001177 >= 0) {
Hans Verkuil92de1f12007-11-04 10:53:09 -03001178 t->type = TUNER_TEA5767;
1179 t->mode_mask = T_RADIO;
1180 t->mode = T_STANDBY;
1181 /* Sets freq to FM range */
1182 t->radio_freq = 87.5 * 16000;
1183 tuner_lookup(t->i2c->adapter, &radio, &tv);
1184 if (tv)
1185 tv->mode_mask &= ~T_RADIO;
1186
1187 goto register_client;
1188 }
1189 break;
1190 }
1191 }
1192
1193 /* Initializes only the first TV tuner on this adapter. Why only the
1194 first? Because there are some devices (notably the ones with TI
1195 tuners) that have more than one i2c address for the *same* device.
1196 Experience shows that, except for just one case, the first
1197 address is the right one. The exception is a Russian tuner
1198 (ACORP_Y878F). So, the desired behavior is just to enable the
1199 first found TV tuner. */
1200 tuner_lookup(t->i2c->adapter, &radio, &tv);
1201 if (tv == NULL) {
1202 t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
1203 if (radio == NULL)
1204 t->mode_mask |= T_RADIO;
1205 tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
1206 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
1207 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
1208 }
1209
1210 /* Should be just before return */
1211register_client:
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001212 tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
1213 client->adapter->name);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001214
1215 /* Sets a default mode */
1216 if (t->mode_mask & T_ANALOG_TV) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001217 t->mode = V4L2_TUNER_ANALOG_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001218 } else if (t->mode_mask & T_RADIO) {
Michael Krufky864a6b82007-12-09 17:21:54 -03001219 t->mode = V4L2_TUNER_RADIO;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001220 } else {
Michael Krufky864a6b82007-12-09 17:21:54 -03001221 t->mode = V4L2_TUNER_DIGITAL_TV;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001222 }
Michael Krufkyd7cba042008-09-12 13:31:45 -03001223 set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001224 list_add_tail(&t->list, &tuner_list);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001225 return 0;
1226}
1227
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001228static int tuner_legacy_probe(struct i2c_adapter *adap)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001229{
1230 if (0 != addr) {
1231 normal_i2c[0] = addr;
1232 normal_i2c[1] = I2C_CLIENT_END;
1233 }
1234
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001235 if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
1236 return 0;
1237
Hans Verkuil92de1f12007-11-04 10:53:09 -03001238 /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
1239 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
1240 * and an RTC at 0x6f which can get corrupted if probed.
1241 */
1242 if ((adap->id == I2C_HW_B_CX2388x) ||
1243 (adap->id == I2C_HW_B_CX23885)) {
1244 unsigned int i = 0;
1245
1246 while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
1247 i += 2;
1248 if (i + 4 < I2C_CLIENT_MAX_OPTS) {
1249 ignore[i+0] = adap->nr;
1250 ignore[i+1] = 0x6b;
1251 ignore[i+2] = adap->nr;
1252 ignore[i+3] = 0x6f;
1253 ignore[i+4] = I2C_CLIENT_END;
1254 } else
1255 printk(KERN_WARNING "tuner: "
1256 "too many options specified "
1257 "in i2c probe ignore list!\n");
1258 }
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001259 return 1;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001260}
1261
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001262static int tuner_remove(struct i2c_client *client)
Hans Verkuil92de1f12007-11-04 10:53:09 -03001263{
1264 struct tuner *t = i2c_get_clientdata(client);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001265
Michael Krufkya07c8772008-04-29 03:54:19 -03001266 tuner_detach(&t->fe);
1267 t->fe.analog_demod_priv = NULL;
Hans Verkuil92de1f12007-11-04 10:53:09 -03001268
1269 list_del(&t->list);
1270 kfree(t);
Hans Verkuil92de1f12007-11-04 10:53:09 -03001271 return 0;
1272}
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274/* ----------------------------------------------------------------------- */
1275
Jean Delvareaf294862008-05-18 20:49:40 +02001276/* This driver supports many devices and the idea is to let the driver
1277 detect which device is present. So rather than listing all supported
1278 devices here, we pretend to support a single, fake device type. */
1279static const struct i2c_device_id tuner_id[] = {
1280 { "tuner", }, /* autodetect */
1281 { }
1282};
1283MODULE_DEVICE_TABLE(i2c, tuner_id);
1284
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001285static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1286 .name = "tuner",
1287 .driverid = I2C_DRIVERID_TUNER,
Mauro Carvalho Chehabf7ce3cc2005-07-12 13:58:55 -07001288 .command = tuner_command,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001289 .probe = tuner_probe,
1290 .remove = tuner_remove,
Jean Delvare21b48a72007-03-12 19:20:15 -03001291 .suspend = tuner_suspend,
Hans Verkuil9dd659d2007-11-04 11:03:36 -03001292 .resume = tuner_resume,
1293 .legacy_probe = tuner_legacy_probe,
Jean Delvareaf294862008-05-18 20:49:40 +02001294 .id_table = tuner_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295};
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297/*
1298 * Overrides for Emacs so that we follow Linus's tabbing style.
1299 * ---------------------------------------------------------------------------
1300 * Local variables:
1301 * c-basic-offset: 8
1302 * End:
1303 */