Commit b8341e1d authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b6198ade
...@@ -915,7 +915,7 @@ static int vidioc_log_status (struct file *file, void *priv) ...@@ -915,7 +915,7 @@ static int vidioc_log_status (struct file *file, void *priv)
snprintf(name, sizeof(name), "%s/2", core->name); snprintf(name, sizeof(name), "%s/2", core->name);
printk("%s/2: ============ START LOG STATUS ============\n", printk("%s/2: ============ START LOG STATUS ============\n",
core->name); core->name);
cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL); call_all(core, core, log_status);
cx2341x_log_status(&dev->params, name); cx2341x_log_status(&dev->params, name);
printk("%s/2: ============= END LOG STATUS =============\n", printk("%s/2: ============= END LOG STATUS =============\n",
core->name); core->name);
...@@ -970,7 +970,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, ...@@ -970,7 +970,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
f->type = V4L2_TUNER_ANALOG_TV; f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = core->freq; f->frequency = core->freq;
cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); call_all(core, tuner, g_frequency, f);
return 0; return 0;
} }
......
...@@ -732,6 +732,8 @@ static const struct cx88_board cx88_boards[] = { ...@@ -732,6 +732,8 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET, .radio_type = UNSET,
.tuner_addr = ADDR_UNSET, .tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET,
/* Some variants use a tda9874 and so need the tvaudio module. */
.audio_chip = V4L2_IDENT_TVAUDIO,
.input = {{ .input = {{
.type = CX88_VMUX_TELEVISION, .type = CX88_VMUX_TELEVISION,
.vmux = 0, .vmux = 0,
...@@ -2985,7 +2987,7 @@ static void cx88_card_setup(struct cx88_core *core) ...@@ -2985,7 +2987,7 @@ static void cx88_card_setup(struct cx88_core *core)
tea5767_cfg.tuner = TUNER_TEA5767; tea5767_cfg.tuner = TUNER_TEA5767;
tea5767_cfg.priv = &ctl; tea5767_cfg.priv = &ctl;
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); call_all(core, tuner, s_config, &tea5767_cfg);
break; break;
} }
case CX88_BOARD_TEVII_S420: case CX88_BOARD_TEVII_S420:
...@@ -3010,7 +3012,7 @@ static void cx88_card_setup(struct cx88_core *core) ...@@ -3010,7 +3012,7 @@ static void cx88_card_setup(struct cx88_core *core)
tun_setup.type = core->board.radio_type; tun_setup.type = core->board.radio_type;
tun_setup.addr = core->board.radio_addr; tun_setup.addr = core->board.radio_addr;
tun_setup.tuner_callback = cx88_tuner_callback; 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; mode_mask &= ~T_RADIO;
} }
...@@ -3020,7 +3022,7 @@ static void cx88_card_setup(struct cx88_core *core) ...@@ -3020,7 +3022,7 @@ static void cx88_card_setup(struct cx88_core *core)
tun_setup.addr = core->board.tuner_addr; tun_setup.addr = core->board.tuner_addr;
tun_setup.tuner_callback = cx88_tuner_callback; 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) { if (core->board.tda9887_conf) {
...@@ -3029,7 +3031,7 @@ static void cx88_card_setup(struct cx88_core *core) ...@@ -3029,7 +3031,7 @@ static void cx88_card_setup(struct cx88_core *core)
tda9887_cfg.tuner = TUNER_TDA9887; tda9887_cfg.tuner = TUNER_TDA9887;
tda9887_cfg.priv = &core->board.tda9887_conf; 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) { if (core->board.tuner_type == TUNER_XC2028) {
...@@ -3045,9 +3047,9 @@ static void cx88_card_setup(struct cx88_core *core) ...@@ -3045,9 +3047,9 @@ static void cx88_card_setup(struct cx88_core *core)
xc2028_cfg.priv = &ctl; xc2028_cfg.priv = &ctl;
info_printk(core, "Asking xc2028/3028 to load firmware %s\n", info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
ctl.fname); 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) ...@@ -3202,8 +3204,30 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
cx88_i2c_init(core, pci); cx88_i2c_init(core, pci);
/* load tuner module, if needed */ /* load tuner module, if needed */
if (TUNER_ABSENT != core->board.tuner_type) if (TUNER_ABSENT != core->board.tuner_type) {
request_module("tuner"); 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_card_setup(core);
cx88_ir_init(core, pci); cx88_ir_init(core, pci);
......
...@@ -991,7 +991,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) ...@@ -991,7 +991,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
set_tvaudio(core); set_tvaudio(core);
// tell i2c chips // tell i2c chips
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm); call_all(core, tuner, s_std, norm);
// done // done
return 0; return 0;
...@@ -1059,8 +1059,11 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) ...@@ -1059,8 +1059,11 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
mutex_lock(&devlist); mutex_lock(&devlist);
cx88_ir_fini(core); 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); i2c_del_adapter(&core->i2c_adap);
}
list_del(&core->devlist); list_del(&core->devlist);
iounmap(core->lmmio); iounmap(core->lmmio);
cx88_devcount--; cx88_devcount--;
......
...@@ -1168,7 +1168,7 @@ static int dvb_register(struct cx8802_dev *dev) ...@@ -1168,7 +1168,7 @@ static int dvb_register(struct cx8802_dev *dev)
fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */ /* 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 */ /* register everything */
return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
......
...@@ -97,39 +97,6 @@ static int cx8800_bit_getsda(void *data) ...@@ -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 = { static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.setsda = cx8800_bit_setsda, .setsda = cx8800_bit_setsda,
.setscl = cx8800_bit_setscl, .setscl = cx8800_bit_setscl,
...@@ -175,17 +142,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) ...@@ -175,17 +142,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo)); 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; core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
core->i2c_adap.owner = THIS_MODULE; core->i2c_adap.owner = THIS_MODULE;
core->i2c_adap.id = I2C_HW_B_CX2388x; 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.udelay = i2c_udelay;
core->i2c_algo.data = core; core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev); 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) ...@@ -224,8 +185,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
EXPORT_SYMBOL(cx88_call_i2c_clients);
/* /*
* Local variables: * Local variables:
* c-basic-offset: 8 * c-basic-offset: 8
......
...@@ -431,8 +431,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) ...@@ -431,8 +431,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
struct v4l2_routing route; struct v4l2_routing route;
route.input = INPUT(input).audioroute; route.input = INPUT(input).audioroute;
cx88_call_i2c_clients(core, call_all(core, audio, s_routing, &route);
VIDIOC_INT_S_AUDIO_ROUTING, &route);
} }
/* cx2388's C-ADC is connected to the tuner only. /* cx2388's C-ADC is connected to the tuner only.
When used with S-Video, that ADC is busy dealing with When used with S-Video, that ADC is busy dealing with
...@@ -827,8 +826,7 @@ static int video_open(struct file *file) ...@@ -827,8 +826,7 @@ static int video_open(struct file *file)
struct v4l2_routing route; struct v4l2_routing route;
route.input = core->board.radio.audioroute; route.input = core->board.radio.audioroute;
cx88_call_i2c_clients(core, call_all(core, audio, s_routing, &route);
VIDIOC_INT_S_AUDIO_ROUTING, &route);
} }
/* "I2S ADC mode" */ /* "I2S ADC mode" */
core->tvaudio = WW_I2SADC; core->tvaudio = WW_I2SADC;
...@@ -839,7 +837,7 @@ static int video_open(struct file *file) ...@@ -839,7 +837,7 @@ static int video_open(struct file *file)
cx88_set_tvaudio(core); cx88_set_tvaudio(core);
cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); 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(); unlock_kernel();
...@@ -933,7 +931,7 @@ static int video_release(struct file *file) ...@@ -933,7 +931,7 @@ static int video_release(struct file *file)
kfree(fh); kfree(fh);
if(atomic_dec_and_test(&dev->core->users)) 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; return 0;
} }
...@@ -1395,7 +1393,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, ...@@ -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->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = core->freq; f->frequency = core->freq;
cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); call_all(core, tuner, g_frequency, f);
return 0; return 0;
} }
...@@ -1411,7 +1409,7 @@ int cx88_set_freq (struct cx88_core *core, ...@@ -1411,7 +1409,7 @@ int cx88_set_freq (struct cx88_core *core,
mutex_lock(&core->lock); mutex_lock(&core->lock);
core->freq = f->frequency; core->freq = f->frequency;
cx88_newstation(core); 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 */ /* When changing channels it is required to reset TVAUDIO */
msleep (10); msleep (10);
...@@ -1493,7 +1491,7 @@ static int radio_g_tuner (struct file *file, void *priv, ...@@ -1493,7 +1491,7 @@ static int radio_g_tuner (struct file *file, void *priv,
strcpy(t->name, "Radio"); strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO; t->type = V4L2_TUNER_RADIO;
cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); call_all(core, tuner, g_tuner, t);
return 0; return 0;
} }
...@@ -1527,7 +1525,7 @@ static int radio_s_tuner (struct file *file, void *priv, ...@@ -1527,7 +1525,7 @@ static int radio_s_tuner (struct file *file, void *priv,
if (0 != t->index) if (0 != t->index)
return -EINVAL; return -EINVAL;
cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); call_all(core, tuner, s_tuner, t);
return 0; return 0;
} }
...@@ -1884,12 +1882,30 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, ...@@ -1884,12 +1882,30 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* load and configure helper modules */ /* load and configure helper modules */
if (core->board.audio_chip == V4L2_IDENT_WM8775) 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) { switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: 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"); request_module("rtc-isl1208");
core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info);
}
/* break intentionally omitted */ /* break intentionally omitted */
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
request_module("ir-kbd-i2c"); request_module("ir-kbd-i2c");
......
...@@ -328,6 +328,7 @@ struct cx88_core { ...@@ -328,6 +328,7 @@ struct cx88_core {
/* config info -- analog */ /* config info -- analog */
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
struct i2c_client *i2c_rtc;
unsigned int boardnr; unsigned int boardnr;
struct cx88_board board; struct cx88_board board;
...@@ -371,6 +372,17 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) ...@@ -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); 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 cx8800_dev;
struct cx8802_dev; struct cx8802_dev;
...@@ -616,8 +628,6 @@ extern struct videobuf_queue_ops cx8800_vbi_qops; ...@@ -616,8 +628,6 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
/* cx88-i2c.c */ /* cx88-i2c.c */
extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); 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);
/* ----------------------------------------------------------- */ /* ----------------------------------------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment