X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Ftuner-core.c;h=183bbb9ba6ab873cff4aa066f1e3f525ddb62bc1;hb=e18f9444bda60a67e6feef00c354f8de0cdaeba7;hp=b6101bf446d4897e62d85e215ae27e290140087c;hpb=be6f655d03d2e166134da2ea3c9360c4fe008744;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index b6101bf..183bbb9 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -5,9 +5,7 @@ */ #include -#include #include -#include #include #include #include @@ -16,17 +14,19 @@ #include #include #include -#include #include - +#include #include #include -#include +#include "tuner-driver.h" #define UNSET (-1U) /* standard i2c insmod options */ static unsigned short normal_i2c[] = { +#ifdef CONFIG_TUNER_TEA5761 + 0x10, +#endif 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, @@ -41,7 +41,6 @@ static unsigned int no_autodetect = 0; static unsigned int show_i2c = 0; /* insmod options used at runtime => read/write */ -static unsigned int tuner_debug_old = 0; int tuner_debug = 0; static unsigned int tv_range[2] = { 44, 958 }; @@ -55,8 +54,6 @@ static char ntsc[] = "-"; module_param(addr, int, 0444); module_param(no_autodetect, int, 0444); module_param(show_i2c, int, 0444); -/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */ -module_param_named(tuner_debug,tuner_debug_old, int, 0444); module_param_named(debug,tuner_debug, int, 0644); module_param_string(pal, pal, sizeof(pal), 0644); module_param_string(secam, secam, sizeof(secam), 0644); @@ -73,6 +70,40 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ +static void fe_set_freq(struct tuner *t, unsigned int freq) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (NULL == fe_tuner_ops->set_analog_params) { + tuner_warn("Tuner frontend module has no way to set freq\n"); + return; + } + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); +} + +static void fe_release(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); +} + +static void fe_standby(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->sleep) + fe_tuner_ops->sleep(&t->fe); +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -82,7 +113,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->set_tv_freq) { + if (NULL == t->ops.set_tv_freq) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -97,7 +128,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->set_tv_freq(c, freq); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -108,7 +139,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->set_radio_freq) { + if (NULL == t->ops.set_radio_freq) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -124,7 +155,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->set_radio_freq(c, freq); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -148,10 +179,33 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +static void tuner_i2c_address_check(struct tuner *t) +{ + if ((t->type == UNSET || t->type == TUNER_ABSENT) || + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + return; + + tuner_warn("====================== WARNING! ======================\n"); + tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); + tuner_warn("will soon be dropped. This message indicates that your\n"); + tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", + t->i2c.name, t->i2c.addr); + tuner_warn("To ensure continued support for your device, please\n"); + tuner_warn("send a copy of this message, along with full dmesg\n"); + tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); + tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); + tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", + t->i2c.adapter->name, t->i2c.addr, t->type, + tuners[t->type].name); + tuner_warn("====================== WARNING! ======================\n"); +} + static void set_type(struct i2c_client *c, unsigned int type, - unsigned int new_mode_mask) + unsigned int new_mode_mask, unsigned int new_config, + int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -164,31 +218,53 @@ static void set_type(struct i2c_client *c, unsigned int type, return; } + t->type = type; + t->config = new_config; + if (tuner_callback != NULL) { + tuner_dbg("defining GPIO callback\n"); + t->tuner_callback = tuner_callback; + } + /* This code detects calls by card attach_inform */ if (NULL == t->i2c.dev.driver) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); - t->type=type; return; } - t->type = type; + /* discard private data, in case set_type() was previously called */ + if (t->ops.release) + t->ops.release(t); + else { + kfree(t->priv); + t->priv = NULL; + } switch (t->type) { case TUNER_MT2032: - microtune_init(c); + microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(c); + tda8290_init(t); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c) == EINVAL) { + if (tea5767_tuner_init(t) == EINVAL) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + t->mode_mask = T_RADIO; + break; +#ifdef CONFIG_TUNER_TEA5761 + case TUNER_TEA5761: + if (tea5761_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; } t->mode_mask = T_RADIO; break; +#endif case TUNER_PHILIPS_FMD1216ME_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; @@ -199,15 +275,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(c); - break; - case TUNER_LG_TDVS_H062F: - /* Set the Auxiliary Byte. */ - buffer[2] &= ~0x20; - buffer[2] |= 0x18; - buffer[3] = 0x20; - i2c_master_send(c, buffer, 4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -215,13 +283,27 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(c); + default_tuner_init(t); + break; + case TUNER_TDA9887: + tda9887_tuner_init(t); break; default: - default_tuner_init(c); + default_tuner_init(t); break; } + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + } + + tuner_info("type set to %s\n", t->i2c.name); + if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -229,6 +311,7 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); + tuner_i2c_address_check(t); } /* @@ -243,10 +326,13 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) { struct tuner *t = i2c_get_clientdata(c); - if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET && - (t->mode_mask & tun_setup->mode_mask)) || - tun_setup->addr == c->addr)) { - set_type(c, tun_setup->type, tun_setup->mode_mask); + tuner_dbg("set addr for type %i\n", t->type); + + if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && + (t->mode_mask & tun_setup->mode_mask))) || + (tun_setup->addr == c->addr)) { + set_type(c, tun_setup->type, tun_setup->mode_mask, + tun_setup->config, tun_setup->tuner_callback); } } @@ -275,6 +361,10 @@ static int tuner_fixup_std(struct tuner *t) { if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { + case '6': + tuner_dbg ("insmod fixup: PAL => PAL-60\n"); + t->std = V4L2_STD_PAL_60; + break; case 'b': case 'B': case 'g': @@ -382,10 +472,10 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) +static void tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); unsigned long freq, freq_fraction; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; const char *p; switch (t->mode) { @@ -403,19 +493,29 @@ static void tuner_status(struct i2c_client *client) } tuner_info("Tuner mode: %s\n", p); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); - tuner_info("Standard: 0x%08llx\n", t->std); - if (t->mode == V4L2_TUNER_RADIO) { - if (t->has_signal) { - tuner_info("Signal strength: %d\n", t->has_signal(client)); - } - if (t->is_stereo) { - tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); - } + tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); + if (t->mode != V4L2_TUNER_RADIO) + return; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_LOCKED) + tuner_info("Tuner is locked.\n"); + if (tuner_status & TUNER_STATUS_STEREO) + tuner_info("Stereo: yes\n"); + } + if (t->ops.has_signal) { + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); + } + if (t->ops.is_stereo) { + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); } } + /* ---------------------------------------------------------------------- */ -/* static var Used only in tuner_attach and tuner_probe */ +/* static vars: used only in tuner_attach and tuner_probe */ static unsigned default_mode_mask; /* During client attach, set_type is called by adapter's attach_inform callback. @@ -434,14 +534,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(&t->i2c, t); t->type = UNSET; - t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ t->audmode = V4L2_TUNER_MODE_STEREO; t->mode_mask = T_UNINITIALIZED; - if (tuner_debug_old) { - tuner_debug = tuner_debug_old; - printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n"); - printk(KERN_ERR "tuner: use the debug option instead.\n"); - } + t->ops.tuner_status = tuner_status; if (show_i2c) { unsigned char buffer[16]; @@ -454,23 +549,44 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) printk("%02x ",buffer[i]); printk("\n"); } + /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */ + if (adap->id == I2C_HW_SAA7146 && addr < 0x4a) + return -ENODEV; + /* autodetection code based on the i2c addr */ if (!no_autodetect) { switch (addr) { +#ifdef CONFIG_TUNER_TEA5761 + case 0x10: + if (tea5761_autodetection(t) != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + goto register_client; + } + break; +#endif case 0x42: case 0x43: case 0x4a: case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(&t->i2c) != 0) { - tuner_dbg("chip at addr %x is not a tda8290\n", addr); - kfree(t); - return 0; + if (tda8290_probe(t) == 0) { + tuner_dbg("chip at addr %x is a tda8290\n", addr); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; } break; case 0x60: - if (tea5767_autodetection(&t->i2c) != EINVAL) { + if (tea5767_autodetection(t) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -496,7 +612,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) register_client: tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); i2c_attach_client (&t->i2c); - set_type (&t->i2c,t->type, t->mode_mask); + set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); return 0; } @@ -526,6 +642,11 @@ static int tuner_detach(struct i2c_client *client) return err; } + if (t->ops.release) + t->ops.release(t); + else { + kfree(t->priv); + } kfree(t); return 0; } @@ -546,8 +667,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (t->standby) - t->standby (client); + if (t->ops.standby) + t->ops.standby(t); return EINVAL; } return 0; @@ -559,16 +680,17 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, static inline int check_v4l2(struct tuner *t) { - if (t->using_v4l2) { - tuner_dbg ("ignore v4l1 call\n"); - return EINVAL; - } + /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for + TV, v4l1 for radio), until that is fixed this code is disabled. + Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2) + first. */ return 0; } static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -576,10 +698,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { /* --- configuration --- */ case TUNER_SET_TYPE_ADDR: - tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", + tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", ((struct tuner_setup *)arg)->type, ((struct tuner_setup *)arg)->addr, - ((struct tuner_setup *)arg)->mode_mask); + ((struct tuner_setup *)arg)->mode_mask, + ((struct tuner_setup *)arg)->config); set_addr(client, (struct tuner_setup *)arg); break; @@ -593,9 +716,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) case TUNER_SET_STANDBY: if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; - if (t->standby) - t->standby (client); + t->mode = T_STANDBY; + if (t->ops.standby) + t->ops.standby(t); break; +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) return 0; @@ -605,9 +730,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* Should be implemented, since bttv calls it */ tuner_dbg("VIDIOCSAUDIO not implemented.\n"); break; - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ case VIDIOCSCHAN: { static const v4l2_std_id map[] = { @@ -655,15 +777,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - vt->signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) - vt->flags |= - VIDEO_TUNER_STEREO_ON; - else - vt->flags &= - ~VIDEO_TUNER_STEREO_ON; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; + vt->signal = tuner_status & TUNER_STATUS_LOCKED + ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); } vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -686,12 +820,31 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) - va->mode = t->is_stereo(client) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + if (V4L2_TUNER_RADIO == t->mode) { + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + va->mode = (tuner_status & TUNER_STATUS_STEREO) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } return 0; } +#endif + case TDA9887_SET_CONFIG: + if (t->type == TUNER_TDA9887) { + int *i = arg; + t->tda9887_config = *i; + set_freq(client, t->tv_freq); + } + break; + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ case VIDIOC_S_STD: { v4l2_std_id *id = arg; @@ -712,14 +865,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_frequency *f = arg; + if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") + == EINVAL) + return 0; switch_v4l2(); - if ((V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode) - || (V4L2_TUNER_DIGITAL_TV == f->type - && V4L2_TUNER_DIGITAL_TV != t->mode)) { - if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") - == EINVAL) - return 0; - } set_freq(client,f->frequency); break; @@ -732,6 +881,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); f->type = t->mode; + if (fe_tuner_ops->get_frequency) { + u32 abs_freq; + + fe_tuner_ops->get_frequency(&t->fe, &abs_freq); + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + (abs_freq * 2 + 125/2) / 125 : + (abs_freq + 62500/2) / 62500; + break; + } f->frequency = (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq; break; @@ -744,33 +902,40 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); - if (V4L2_TUNER_RADIO == t->mode) { - - if (t->has_signal) - tuner->signal = t->has_signal(client); - - if (t->is_stereo) { - if (t->is_stereo(client)) { - tuner->rxsubchans = - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_MONO; - } else { - tuner->rxsubchans = - V4L2_TUNER_SUB_MONO; - } - } - - tuner->capability |= - V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->type = t->mode; + if (t->ops.get_afc) + tuner->afc=t->ops.get_afc(t); + if (t->mode == V4L2_TUNER_ANALOG_TV) + tuner->capability |= V4L2_TUNER_CAP_NORM; + if (t->mode != V4L2_TUNER_RADIO) { + tuner->rangelow = tv_range[0] * 16; + tuner->rangehigh = tv_range[1] * 16; + break; + } - tuner->audmode = t->audmode; + /* radio mode */ + tuner->rxsubchans = + V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + if (fe_tuner_ops->get_status) { + u32 tuner_status; - tuner->rangelow = radio_range[0] * 16000; - tuner->rangehigh = radio_range[1] * 16000; + fe_tuner_ops->get_status(&t->fe, &tuner_status); + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; } else { - tuner->rangelow = tv_range[0] * 16; - tuner->rangehigh = tv_range[1] * 16; + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); } + tuner->capability |= + V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->audmode = t->audmode; + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; break; } case VIDIOC_S_TUNER: @@ -782,23 +947,24 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); - if (V4L2_TUNER_RADIO == t->mode) { - t->audmode = tuner->audmode; - set_radio_freq(client, t->radio_freq); - } + /* do nothing unless we're a radio tuner */ + if (t->mode != V4L2_TUNER_RADIO) + break; + t->audmode = tuner->audmode; + set_radio_freq(client, t->radio_freq); break; } case VIDIOC_LOG_STATUS: - tuner_status(client); + if (t->ops.tuner_status) + t->ops.tuner_status(t); break; } return 0; } -static int tuner_suspend(struct device *dev, pm_message_t state) +static int tuner_suspend(struct i2c_client *c, pm_message_t state) { - struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); tuner_dbg ("suspend\n"); @@ -806,9 +972,8 @@ static int tuner_suspend(struct device *dev, pm_message_t state) return 0; } -static int tuner_resume(struct device *dev) +static int tuner_resume(struct i2c_client *c) { - struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); tuner_dbg ("resume\n"); @@ -829,10 +994,10 @@ static struct i2c_driver driver = { .attach_adapter = tuner_probe, .detach_client = tuner_detach, .command = tuner_command, + .suspend = tuner_suspend, + .resume = tuner_resume, .driver = { .name = "tuner", - .suspend = tuner_suspend, - .resume = tuner_resume, }, }; static struct i2c_client client_template = {