V4L/DVB (11300): cx88: convert to v4l2_subdev.
Convert cx88 to use v4l2_subdev since the old i2c autoprobing mechanism will be removed. Added code to explicitly load tvaudio where needed. Also fix the rtc-isl1208 support: since that driver no longer supports autoprobing it has to be loaded using the new i2c API. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
b6198ade55
commit
b8341e1d2a
7 changed files with 80 additions and 68 deletions
|
@ -915,7 +915,7 @@ static int vidioc_log_status (struct file *file, void *priv)
|
|||
snprintf(name, sizeof(name), "%s/2", core->name);
|
||||
printk("%s/2: ============ START LOG STATUS ============\n",
|
||||
core->name);
|
||||
cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
|
||||
call_all(core, core, log_status);
|
||||
cx2341x_log_status(&dev->params, name);
|
||||
printk("%s/2: ============= END LOG STATUS =============\n",
|
||||
core->name);
|
||||
|
@ -970,7 +970,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
|
|||
|
||||
f->type = V4L2_TUNER_ANALOG_TV;
|
||||
f->frequency = core->freq;
|
||||
cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
|
||||
call_all(core, tuner, g_frequency, f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -732,6 +732,8 @@ static const struct cx88_board cx88_boards[] = {
|
|||
.radio_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
/* Some variants use a tda9874 and so need the tvaudio module. */
|
||||
.audio_chip = V4L2_IDENT_TVAUDIO,
|
||||
.input = {{
|
||||
.type = CX88_VMUX_TELEVISION,
|
||||
.vmux = 0,
|
||||
|
@ -2985,7 +2987,7 @@ static void cx88_card_setup(struct cx88_core *core)
|
|||
tea5767_cfg.tuner = TUNER_TEA5767;
|
||||
tea5767_cfg.priv = &ctl;
|
||||
|
||||
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
|
||||
call_all(core, tuner, s_config, &tea5767_cfg);
|
||||
break;
|
||||
}
|
||||
case CX88_BOARD_TEVII_S420:
|
||||
|
@ -3010,7 +3012,7 @@ static void cx88_card_setup(struct cx88_core *core)
|
|||
tun_setup.type = core->board.radio_type;
|
||||
tun_setup.addr = core->board.radio_addr;
|
||||
tun_setup.tuner_callback = cx88_tuner_callback;
|
||||
cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
|
||||
call_all(core, tuner, s_type_addr, &tun_setup);
|
||||
mode_mask &= ~T_RADIO;
|
||||
}
|
||||
|
||||
|
@ -3020,7 +3022,7 @@ static void cx88_card_setup(struct cx88_core *core)
|
|||
tun_setup.addr = core->board.tuner_addr;
|
||||
tun_setup.tuner_callback = cx88_tuner_callback;
|
||||
|
||||
cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
|
||||
call_all(core, tuner, s_type_addr, &tun_setup);
|
||||
}
|
||||
|
||||
if (core->board.tda9887_conf) {
|
||||
|
@ -3029,7 +3031,7 @@ static void cx88_card_setup(struct cx88_core *core)
|
|||
tda9887_cfg.tuner = TUNER_TDA9887;
|
||||
tda9887_cfg.priv = &core->board.tda9887_conf;
|
||||
|
||||
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
|
||||
call_all(core, tuner, s_config, &tda9887_cfg);
|
||||
}
|
||||
|
||||
if (core->board.tuner_type == TUNER_XC2028) {
|
||||
|
@ -3045,9 +3047,9 @@ static void cx88_card_setup(struct cx88_core *core)
|
|||
xc2028_cfg.priv = &ctl;
|
||||
info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
|
||||
ctl.fname);
|
||||
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
|
||||
call_all(core, tuner, s_config, &xc2028_cfg);
|
||||
}
|
||||
cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
|
||||
call_all(core, core, s_standby, 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
@ -3202,8 +3204,30 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
|
|||
cx88_i2c_init(core, pci);
|
||||
|
||||
/* load tuner module, if needed */
|
||||
if (TUNER_ABSENT != core->board.tuner_type)
|
||||
request_module("tuner");
|
||||
if (TUNER_ABSENT != core->board.tuner_type) {
|
||||
int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT);
|
||||
|
||||
/* I don't trust the radio_type as is stored in the card
|
||||
definitions, so we just probe for it.
|
||||
The radio_type is sometimes missing, or set to UNSET but
|
||||
later code configures a tea5767.
|
||||
*/
|
||||
v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner", "tuner",
|
||||
v4l2_i2c_tuner_addrs(ADDRS_RADIO));
|
||||
if (has_demod)
|
||||
v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
|
||||
"tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
||||
if (core->board.tuner_addr == ADDR_UNSET) {
|
||||
enum v4l2_i2c_tuner_type type =
|
||||
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
|
||||
|
||||
v4l2_i2c_new_probed_subdev(&core->i2c_adap, "tuner",
|
||||
"tuner", v4l2_i2c_tuner_addrs(type));
|
||||
} else {
|
||||
v4l2_i2c_new_subdev(&core->i2c_adap,
|
||||
"tuner", "tuner", core->board.tuner_addr);
|
||||
}
|
||||
}
|
||||
|
||||
cx88_card_setup(core);
|
||||
cx88_ir_init(core, pci);
|
||||
|
|
|
@ -991,7 +991,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
|
|||
set_tvaudio(core);
|
||||
|
||||
// tell i2c chips
|
||||
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
|
||||
call_all(core, tuner, s_std, norm);
|
||||
|
||||
// done
|
||||
return 0;
|
||||
|
@ -1059,8 +1059,11 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
|
|||
|
||||
mutex_lock(&devlist);
|
||||
cx88_ir_fini(core);
|
||||
if (0 == core->i2c_rc)
|
||||
if (0 == core->i2c_rc) {
|
||||
if (core->i2c_rtc)
|
||||
i2c_unregister_device(core->i2c_rtc);
|
||||
i2c_del_adapter(&core->i2c_adap);
|
||||
}
|
||||
list_del(&core->devlist);
|
||||
iounmap(core->lmmio);
|
||||
cx88_devcount--;
|
||||
|
|
|
@ -1168,7 +1168,7 @@ static int dvb_register(struct cx8802_dev *dev)
|
|||
fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
|
||||
|
||||
/* Put the analog decoder in standby to keep it quiet */
|
||||
cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
|
||||
call_all(core, core, s_standby, 0);
|
||||
|
||||
/* register everything */
|
||||
return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
|
||||
|
|
|
@ -97,39 +97,6 @@ static int cx8800_bit_getsda(void *data)
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int attach_inform(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
|
||||
struct cx88_core *core = to_core(v4l2_dev);
|
||||
|
||||
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
|
||||
client->driver->driver.name, client->addr, client->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int detach_inform(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter);
|
||||
struct cx88_core *core = to_core(v4l2_dev);
|
||||
|
||||
dprintk(1, "i2c detach [client=%s]\n", client->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
|
||||
{
|
||||
if (0 != core->i2c_rc)
|
||||
return;
|
||||
|
||||
if (core->gate_ctrl)
|
||||
core->gate_ctrl(core, 1);
|
||||
|
||||
i2c_clients_command(&core->i2c_adap, cmd, arg);
|
||||
|
||||
if (core->gate_ctrl)
|
||||
core->gate_ctrl(core, 0);
|
||||
}
|
||||
|
||||
static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
|
||||
.setsda = cx8800_bit_setsda,
|
||||
.setscl = cx8800_bit_setscl,
|
||||
|
@ -175,17 +142,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
|
|||
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
|
||||
sizeof(core->i2c_algo));
|
||||
|
||||
if (core->board.tuner_type != TUNER_ABSENT)
|
||||
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
|
||||
if (core->board.mpeg & CX88_MPEG_DVB)
|
||||
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
|
||||
|
||||
core->i2c_adap.dev.parent = &pci->dev;
|
||||
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
|
||||
core->i2c_adap.owner = THIS_MODULE;
|
||||
core->i2c_adap.id = I2C_HW_B_CX2388x;
|
||||
core->i2c_adap.client_register = attach_inform;
|
||||
core->i2c_adap.client_unregister = detach_inform;
|
||||
core->i2c_algo.udelay = i2c_udelay;
|
||||
core->i2c_algo.data = core;
|
||||
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
|
||||
|
@ -224,8 +185,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
EXPORT_SYMBOL(cx88_call_i2c_clients);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
|
|
|
@ -431,8 +431,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
|
|||
struct v4l2_routing route;
|
||||
|
||||
route.input = INPUT(input).audioroute;
|
||||
cx88_call_i2c_clients(core,
|
||||
VIDIOC_INT_S_AUDIO_ROUTING, &route);
|
||||
call_all(core, audio, s_routing, &route);
|
||||
}
|
||||
/* cx2388's C-ADC is connected to the tuner only.
|
||||
When used with S-Video, that ADC is busy dealing with
|
||||
|
@ -827,8 +826,7 @@ static int video_open(struct file *file)
|
|||
struct v4l2_routing route;
|
||||
|
||||
route.input = core->board.radio.audioroute;
|
||||
cx88_call_i2c_clients(core,
|
||||
VIDIOC_INT_S_AUDIO_ROUTING, &route);
|
||||
call_all(core, audio, s_routing, &route);
|
||||
}
|
||||
/* "I2S ADC mode" */
|
||||
core->tvaudio = WW_I2SADC;
|
||||
|
@ -839,7 +837,7 @@ static int video_open(struct file *file)
|
|||
cx88_set_tvaudio(core);
|
||||
cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
|
||||
}
|
||||
cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
|
||||
call_all(core, tuner, s_radio);
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
|
@ -933,7 +931,7 @@ static int video_release(struct file *file)
|
|||
kfree(fh);
|
||||
|
||||
if(atomic_dec_and_test(&dev->core->users))
|
||||
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
|
||||
call_all(dev->core, core, s_standby, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1395,7 +1393,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
|
|||
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
|
||||
f->frequency = core->freq;
|
||||
|
||||
cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
|
||||
call_all(core, tuner, g_frequency, f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1411,7 +1409,7 @@ int cx88_set_freq (struct cx88_core *core,
|
|||
mutex_lock(&core->lock);
|
||||
core->freq = f->frequency;
|
||||
cx88_newstation(core);
|
||||
cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
|
||||
call_all(core, tuner, s_frequency, f);
|
||||
|
||||
/* When changing channels it is required to reset TVAUDIO */
|
||||
msleep (10);
|
||||
|
@ -1493,7 +1491,7 @@ static int radio_g_tuner (struct file *file, void *priv,
|
|||
strcpy(t->name, "Radio");
|
||||
t->type = V4L2_TUNER_RADIO;
|
||||
|
||||
cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
|
||||
call_all(core, tuner, g_tuner, t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1525,7 @@ static int radio_s_tuner (struct file *file, void *priv,
|
|||
if (0 != t->index)
|
||||
return -EINVAL;
|
||||
|
||||
cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
|
||||
call_all(core, tuner, s_tuner, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1884,12 +1882,30 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
|
|||
/* load and configure helper modules */
|
||||
|
||||
if (core->board.audio_chip == V4L2_IDENT_WM8775)
|
||||
request_module("wm8775");
|
||||
v4l2_i2c_new_subdev(&core->i2c_adap,
|
||||
"wm8775", "wm8775", 0x36 >> 1);
|
||||
|
||||
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
|
||||
/* This probes for a tda9874 as is used on some
|
||||
Pixelview Ultra boards. */
|
||||
static const unsigned short i2c_addr[] = {
|
||||
0xb0 >> 1, I2C_CLIENT_END
|
||||
};
|
||||
|
||||
v4l2_i2c_new_probed_subdev(&core->i2c_adap,
|
||||
"tvaudio", "tvaudio", i2c_addr);
|
||||
}
|
||||
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
|
||||
static struct i2c_board_info rtc_info = {
|
||||
I2C_BOARD_INFO("isl1208", 0x6f)
|
||||
};
|
||||
|
||||
request_module("rtc-isl1208");
|
||||
core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
|
||||
}
|
||||
/* break intentionally omitted */
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
|
||||
request_module("ir-kbd-i2c");
|
||||
|
|
|
@ -328,6 +328,7 @@ struct cx88_core {
|
|||
|
||||
/* config info -- analog */
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct i2c_client *i2c_rtc;
|
||||
unsigned int boardnr;
|
||||
struct cx88_board board;
|
||||
|
||||
|
@ -371,6 +372,17 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
|
|||
return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
|
||||
}
|
||||
|
||||
#define call_all(core, o, f, args...) \
|
||||
do { \
|
||||
if (!core->i2c_rc) { \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 1); \
|
||||
v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct cx8800_dev;
|
||||
struct cx8802_dev;
|
||||
|
||||
|
@ -616,8 +628,6 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
|
|||
/* cx88-i2c.c */
|
||||
|
||||
extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
|
||||
extern void cx88_call_i2c_clients(struct cx88_core *core,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
|
Loading…
Reference in a new issue