From: Antti Palosaari Date: Tue, 26 Aug 2014 20:14:16 +0000 (-0300) Subject: [media] it913x: convert to I2C driver X-Git-Tag: v4.14-rc1~6092^2~593 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3b2a5e8c080da37be6135f44d236fe6b796666d9;p=platform%2Fkernel%2Flinux-rpi.git [media] it913x: convert to I2C driver Change the it913x driver to use the I2C high lever tuner binding model. As af9035 depends on it, add a code there to do the binding. [mchehab@osg.samsung.com: Merge 3 patches into one, because we don't want to break bisect due to the conversion] Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 4627925..72fefb7 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -23,10 +23,9 @@ #include "it913x_priv.h" struct it913x_state { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; + struct i2c_client *client; + struct dvb_frontend *fe; u8 chip_ver; - u8 tuner_type; u8 firmware_ver; u16 tun_xtal; u8 tun_fdiv; @@ -41,9 +40,9 @@ static int it913x_rd_regs(struct it913x_state *state, int ret; u8 b[3]; struct i2c_msg msg[2] = { - { .addr = state->i2c_addr, .flags = 0, + { .addr = state->client->addr, .flags = 0, .buf = b, .len = sizeof(b) }, - { .addr = state->i2c_addr, .flags = I2C_M_RD, + { .addr = state->client->addr, .flags = I2C_M_RD, .buf = data, .len = count } }; @@ -52,7 +51,7 @@ static int it913x_rd_regs(struct it913x_state *state, b[2] = (u8) reg & 0xff; b[0] |= 0x80; /* All reads from demodulator */ - ret = i2c_transfer(state->i2c_adap, msg, 2); + ret = i2c_transfer(state->client->adapter, msg, 2); return ret; } @@ -73,7 +72,7 @@ static int it913x_wr_regs(struct it913x_state *state, { u8 b[256]; struct i2c_msg msg[1] = { - { .addr = state->i2c_addr, .flags = 0, + { .addr = state->client->addr, .flags = 0, .buf = b, .len = 3 + count } }; int ret; @@ -86,7 +85,7 @@ static int it913x_wr_regs(struct it913x_state *state, if (pro == PRO_DMOD) b[0] |= 0x80; - ret = i2c_transfer(state->i2c_adap, msg, 1); + ret = i2c_transfer(state->client->adapter, msg, 1); if (ret < 0) return -EIO; @@ -191,8 +190,7 @@ static int it913x_init(struct dvb_frontend *fe) } state->tun_fn_min = state->tun_xtal * reg; state->tun_fn_min /= (state->tun_fdiv * nv_val); - dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, - state->tun_fn_min); + dev_dbg(&state->client->dev, "Tuner fn_min %d\n", state->tun_fn_min); if (state->chip_ver > 1) msleep(50); @@ -237,8 +235,8 @@ static int it9137_set_params(struct dvb_frontend *fe) else set_tuner = set_it9137_template; - dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", - __func__, frequency, bandwidth); + dev_dbg(&state->client->dev, "Tuner Frequency %d Bandwidth %d\n", + frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { l_band = 0; @@ -353,15 +351,13 @@ static int it9137_set_params(struct dvb_frontend *fe) set_tuner[3].reg[0] = temp_f & 0xff; set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; - dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", - __func__, temp_f); + dev_dbg(&state->client->dev, "High Frequency = %04x\n", temp_f); /* Lower frequency */ set_tuner[5].reg[0] = freq & 0xff; set_tuner[6].reg[0] = (freq >> 8) & 0xff; - dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", - __func__, freq); + dev_dbg(&state->client->dev, "low Frequency = %04x\n", freq); ret = it913x_script_loader(state, set_tuner); @@ -382,12 +378,6 @@ static int it913x_sleep(struct dvb_frontend *fe) return it913x_script_loader(state, it9137_tuner_off); } -static int it913x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - return 0; -} - static const struct dvb_tuner_ops it913x_tuner_ops = { .info = { .name = "ITE Tech IT913X", @@ -395,68 +385,91 @@ static const struct dvb_tuner_ops it913x_tuner_ops = { .frequency_max = 862000000, }, - .release = it913x_release, - .init = it913x_init, .sleep = it913x_sleep, .set_params = it9137_set_params, }; -struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) +static int it913x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct it913x_state *state = NULL; + struct it913x_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct it913x_state *state; int ret; + char *chip_ver_str; - /* allocate memory for the internal state */ state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->i2c_adap = i2c_adap; - state->i2c_addr = i2c_addr; - - switch (config) { - case AF9033_TUNER_IT9135_38: - case AF9033_TUNER_IT9135_51: - case AF9033_TUNER_IT9135_52: - state->chip_ver = 0x01; - break; - case AF9033_TUNER_IT9135_60: - case AF9033_TUNER_IT9135_61: - case AF9033_TUNER_IT9135_62: - state->chip_ver = 0x02; - break; - default: - dev_dbg(&i2c_adap->dev, - "%s: invalid config=%02x\n", __func__, config); - goto error; + if (state == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; } - state->tuner_type = config; + state->client = client; + state->fe = cfg->fe; + state->chip_ver = cfg->chip_ver; state->firmware_ver = 1; /* tuner RF initial */ ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); if (ret < 0) - goto error; + goto err; fe->tuner_priv = state; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, state); + + if (state->chip_ver == 1) + chip_ver_str = "AX"; + else if (state->chip_ver == 2) + chip_ver_str = "BX"; + else + chip_ver_str = "??"; + + dev_info(&state->client->dev, "ITE IT913X %s successfully attached\n", + chip_ver_str); + dev_dbg(&state->client->dev, "chip_ver=%02x\n", state->chip_ver); + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + kfree(state); - dev_info(&i2c_adap->dev, - "%s: ITE Tech IT913X successfully attached\n", - KBUILD_MODNAME); - dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", - __func__, config, state->chip_ver); + return ret; +} - return fe; -error: +static int it913x_remove(struct i2c_client *client) +{ + struct it913x_state *state = i2c_get_clientdata(client); + struct dvb_frontend *fe = state->fe; + + dev_dbg(&client->dev, "\n"); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; kfree(state); - return NULL; + + return 0; } -EXPORT_SYMBOL(it913x_attach); + +static const struct i2c_device_id it913x_id_table[] = { + {"it913x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, it913x_id_table); + +static struct i2c_driver it913x_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "it913x", + }, + .probe = it913x_probe, + .remove = it913x_remove, + .id_table = it913x_id_table, +}; + +module_i2c_driver(it913x_driver); MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h index 12dd36b..9789c4d 100644 --- a/drivers/media/tuners/it913x.h +++ b/drivers/media/tuners/it913x.h @@ -25,21 +25,22 @@ #include "dvb_frontend.h" -#if defined(CONFIG_MEDIA_TUNER_IT913X) || \ - (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) -extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config); -#else -static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif +/* + * I2C address + * 0x38, 0x3a, 0x3c, 0x3e + */ +struct it913x_config { + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; + + /* + * chip version + * 1 = IT9135 AX + * 2 = IT9135 BX + */ + u8 chip_ver:2; +}; #endif diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 781c98e..d624efd 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -24,7 +24,6 @@ #define IT913X_PRIV_H #include "it913x.h" -#include "af9033.h" #define PRO_LINK 0x0 #define PRO_DMOD 0x1 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f37cf7d..1a5b600 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -193,6 +193,93 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, return af9035_wr_regs(d, reg, &val, 1); } +static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr, + void *platform_data) +{ + int ret, num; + struct 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 < AF9035_I2C_CLIENT_MAX; num++) { + if (state->i2c_client[num] == NULL) + break; + } + + dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); + + if (num == AF9035_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 af9035_del_i2c_dev(struct dvb_usb_device *d) +{ + int num; + struct state *state = d_to_priv(d); + struct i2c_client *client; + + /* find last used client */ + num = AF9035_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; + return; +err: + dev_dbg(&d->udev->dev, "%s: failed\n", __func__); +} + static int af9035_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -1231,14 +1318,39 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: + { + struct it913x_config it913x_config = { + .fe = adap->fe[0], + .chip_ver = 1, + }; + + ret = af9035_add_i2c_dev(d, "it913x", + state->af9033_config[adap->id].i2c_addr, + &it913x_config); + if (ret) + goto err; + + fe = adap->fe[0]; + break; + } case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - /* attach tuner */ - fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap, + { + struct it913x_config it913x_config = { + .fe = adap->fe[0], + .chip_ver = 2, + }; + + ret = af9035_add_i2c_dev(d, "it913x", state->af9033_config[adap->id].i2c_addr, - state->af9033_config[0].tuner); + &it913x_config); + if (ret) + goto err; + + fe = adap->fe[0]; break; + } default: fe = NULL; } @@ -1303,6 +1415,19 @@ err: return ret; } +static void af9035_exit(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (state->i2c_client[1]) + af9035_del_i2c_dev(d); + + if (state->i2c_client[0]) + af9035_del_i2c_dev(d); +} + #if IS_ENABLED(CONFIG_RC_CORE) static int af9035_rc_query(struct dvb_usb_device *d) { @@ -1479,6 +1604,7 @@ static const struct dvb_usb_device_properties af9035_props = { .init = af9035_init, .get_rc_config = af9035_get_rc_config, .get_stream_config = af9035_get_stream_config, + .exit = af9035_exit, .get_adapter_count = af9035_get_adapter_count, .adapter = { diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 70ec9c9..0911c4fc 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -62,8 +62,9 @@ struct state { u8 dual_mode:1; u16 eeprom_addr; struct af9033_config af9033_config[2]; - struct af9033_ops ops; + #define AF9035_I2C_CLIENT_MAX 2 + struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX]; }; static const u32 clock_lut_af9035[] = {