[media] anysee: convert tda18212 tuner to I2C client

Used tda18212 tuner is implemented as I2C driver. Implement I2C
client to anysee and use it for tda18212.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
Antti Palosaari 2014-08-03 21:47:10 -03:00 committed by Mauro Carvalho Chehab
parent 3ab779c039
commit f80f2ae213
2 changed files with 150 additions and 34 deletions

View file

@ -332,7 +332,6 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
};
static struct tda18212_config anysee_tda18212_config = {
.i2c_address = (0xc0 >> 1),
.if_dvbt_6 = 4150,
.if_dvbt_7 = 4150,
.if_dvbt_8 = 4150,
@ -340,7 +339,6 @@ static struct tda18212_config anysee_tda18212_config = {
};
static struct tda18212_config anysee_tda18212_config2 = {
.i2c_address = 0x60 /* (0xc0 >> 1) */,
.if_dvbt_6 = 3550,
.if_dvbt_7 = 3700,
.if_dvbt_8 = 4150,
@ -632,6 +630,92 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
return ret;
}
static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
void *platform_data)
{
int ret, num;
struct anysee_state *state = d_to_priv(d);
struct i2c_client *client;
struct i2c_adapter *adapter = &d->i2c_adap;
struct i2c_board_info board_info = {
.addr = addr,
.platform_data = platform_data,
};
strlcpy(board_info.type, type, I2C_NAME_SIZE);
/* find first free client */
for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
if (state->i2c_client[num] == NULL)
break;
}
dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
if (num == ANYSEE_I2C_CLIENT_MAX) {
dev_err(&d->udev->dev, "%s: I2C client out of index\n",
KBUILD_MODNAME);
ret = -ENODEV;
goto err;
}
request_module(board_info.type);
/* register I2C device */
client = i2c_new_device(adapter, &board_info);
if (client == NULL || client->dev.driver == NULL) {
ret = -ENODEV;
goto err;
}
/* increase I2C driver usage count */
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
ret = -ENODEV;
goto err;
}
state->i2c_client[num] = client;
return 0;
err:
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static void anysee_del_i2c_dev(struct dvb_usb_device *d)
{
int num;
struct anysee_state *state = d_to_priv(d);
struct i2c_client *client;
/* find last used client */
num = ANYSEE_I2C_CLIENT_MAX;
while (num--) {
if (state->i2c_client[num] != NULL)
break;
}
dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
if (num == -1) {
dev_err(&d->udev->dev, "%s: I2C client out of index\n",
KBUILD_MODNAME);
goto err;
}
client = state->i2c_client[num];
/* decrease I2C driver usage count */
module_put(client->dev.driver->owner);
/* unregister I2C device */
i2c_unregister_device(client);
state->i2c_client[num] = NULL;
err:
dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
}
static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap_to_priv(adap);
@ -640,12 +724,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
u8 tmp;
struct i2c_msg msg[2] = {
{
.addr = anysee_tda18212_config.i2c_address,
.addr = 0x60,
.flags = 0,
.len = 1,
.buf = "\x00",
}, {
.addr = anysee_tda18212_config.i2c_address,
.addr = 0x60,
.flags = I2C_M_RD,
.len = 1,
.buf = &tmp,
@ -723,9 +807,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* probe TDA18212 */
tmp = 0;
ret = i2c_transfer(&d->i2c_adap, msg, 2);
if (ret == 2 && tmp == 0xc7)
if (ret == 2 && tmp == 0xc7) {
dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
__func__);
state->has_tda18212 = true;
}
else
tmp = 0;
@ -939,46 +1025,63 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
* fails attach old simple PLL. */
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
&anysee_tda18212_config);
if (state->has_tda18212) {
struct tda18212_config tda18212_config =
anysee_tda18212_config;
if (fe && adap->fe[1]) {
/* attach tuner for 2nd FE */
fe = dvb_attach(tda18212_attach, adap->fe[1],
&d->i2c_adap, &anysee_tda18212_config);
break;
} else if (fe) {
break;
}
tda18212_config.fe = adap->fe[0];
ret = anysee_add_i2c_dev(d, "tda18212", 0x60,
&tda18212_config);
if (ret)
goto err;
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
&d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
/* copy tuner ops for 2nd FE as tuner is shared */
if (adap->fe[1]) {
adap->fe[1]->tuner_priv =
adap->fe[0]->tuner_priv;
memcpy(&adap->fe[1]->ops.tuner_ops,
&adap->fe[0]->ops.tuner_ops,
sizeof(struct dvb_tuner_ops));
}
if (fe && adap->fe[1]) {
/* attach tuner for 2nd FE */
fe = dvb_attach(dvb_pll_attach, adap->fe[1],
return 0;
} else {
/* attach tuner */
fe = dvb_attach(dvb_pll_attach, adap->fe[0],
(0xc0 >> 1), &d->i2c_adap,
DVB_PLL_SAMSUNG_DTOS403IH102A);
if (fe && adap->fe[1]) {
/* attach tuner for 2nd FE */
fe = dvb_attach(dvb_pll_attach, adap->fe[1],
(0xc0 >> 1), &d->i2c_adap,
DVB_PLL_SAMSUNG_DTOS403IH102A);
}
}
break;
case ANYSEE_HW_508TC: /* 18 */
case ANYSEE_HW_508PTC: /* 21 */
{
/* E7 TC */
/* E7 PTC */
struct tda18212_config tda18212_config = anysee_tda18212_config;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
&anysee_tda18212_config);
tda18212_config.fe = adap->fe[0];
ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
if (ret)
goto err;
if (fe) {
/* attach tuner for 2nd FE */
fe = dvb_attach(tda18212_attach, adap->fe[1],
&d->i2c_adap, &anysee_tda18212_config);
/* copy tuner ops for 2nd FE as tuner is shared */
if (adap->fe[1]) {
adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
memcpy(&adap->fe[1]->ops.tuner_ops,
&adap->fe[0]->ops.tuner_ops,
sizeof(struct dvb_tuner_ops));
}
break;
return 0;
}
case ANYSEE_HW_508S2: /* 19 */
case ANYSEE_HW_508PS2: /* 22 */
/* E7 S2 */
@ -997,13 +1100,18 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
break;
case ANYSEE_HW_508T2C: /* 20 */
{
/* E7 T2C */
struct tda18212_config tda18212_config =
anysee_tda18212_config2;
/* attach tuner */
fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
&anysee_tda18212_config2);
tda18212_config.fe = adap->fe[0];
ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
if (ret)
goto err;
break;
return 0;
}
default:
fe = NULL;
}
@ -1012,7 +1120,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
ret = 0;
else
ret = -ENODEV;
err:
return ret;
}
@ -1270,6 +1378,11 @@ static int anysee_init(struct dvb_usb_device *d)
static void anysee_exit(struct dvb_usb_device *d)
{
struct anysee_state *state = d_to_priv(d);
if (state->i2c_client[0])
anysee_del_i2c_dev(d);
return anysee_ci_release(d);
}

View file

@ -55,8 +55,11 @@ struct anysee_state {
u8 buf[64];
u8 seq;
u8 hw; /* PCB ID */
#define ANYSEE_I2C_CLIENT_MAX 1
struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
u8 fe_id:1; /* frondend ID */
u8 has_ci:1;
u8 has_tda18212:1;
u8 ci_attached:1;
struct dvb_ca_en50221 ci;
unsigned long ci_cam_ready; /* jiffies */