diff options
Diffstat (limited to 'drivers/media/dvb-frontends')
-rw-r--r-- | drivers/media/dvb-frontends/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832.c | 329 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832_priv.h | 4 |
3 files changed, 173 insertions, 161 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 0e126345692..bb76727d924 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -452,6 +452,7 @@ config DVB_RTL2830 config DVB_RTL2832 tristate "Realtek RTL2832 DVB-T" depends on DVB_CORE && I2C && I2C_MUX + select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 31240bbce8f..5d7ea23f02f 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -22,8 +22,6 @@ #include "dvb_math.h" #include <linux/bitops.h> -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 #define REG_MASK(b) (BIT(b + 1) - 1) static const struct rtl2832_reg_entry registers[] = { @@ -156,103 +154,53 @@ static const struct rtl2832_reg_entry registers[] = { [DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0}, }; -/* write multiple hardware registers */ -static int rtl2832_wr(struct rtl2832_dev *dev, u8 reg, u8 *val, int len) +/* Our regmap is bypassing I2C adapter lock, thus we do it! */ +int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg, + const void *val, size_t val_count) { - struct i2c_client *client = dev->client; + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = client->addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - if (1 + len > sizeof(buf)) { - dev_warn(&client->dev, "i2c wr reg=%04x: len=%d is too big!\n", - reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(dev->i2c_adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c wr failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_write(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); return ret; } -/* read multiple hardware registers */ -static int rtl2832_rd(struct rtl2832_dev *dev, u8 reg, u8 *val, int len) +int rtl2832_update_bits(struct i2c_client *client, unsigned int reg, + unsigned int mask, unsigned int val) { - struct i2c_client *client = dev->client; + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - ret = i2c_transfer(dev->i2c_adapter, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c rd failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_update_bits(dev->regmap, reg, mask, val); + i2c_unlock_adapter(client->adapter); return ret; } -/* write multiple registers */ -static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, - int len) +int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg, void *val, + size_t val_count) { + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - /* switch bank if needed */ - if (page != dev->page) { - ret = rtl2832_wr(dev, 0x00, &page, 1); - if (ret) - return ret; + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_read(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); + return ret; +} - dev->page = page; - } - return rtl2832_wr(dev, reg, val, len); +/* write multiple registers */ +static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len) +{ + return rtl2832_bulk_write(dev->client, page << 8 | reg, val, len); } /* read multiple registers */ -static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, - int len) +static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len) { - int ret; - - /* switch bank if needed */ - if (page != dev->page) { - ret = rtl2832_wr(dev, 0x00, &page, 1); - if (ret) - return ret; - - dev->page = page; - } - return rtl2832_rd(dev, reg, val, len); + return rtl2832_bulk_read(dev->client, page << 8 | reg, val, len); } /* write single register */ @@ -385,7 +333,6 @@ err: return ret; } - static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) { struct rtl2832_dev *dev = fe->demodulator_priv; @@ -897,44 +844,22 @@ err: } /* - * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is - * delayed here a little bit in order to see if there is sequence of I2C + * I2C gate/mux/repeater logic + * We must use unlocked __i2c_transfer() here (through regmap) because of I2C + * adapter lock is already taken by tuner driver. + * There is delay mechanism to avoid unneeded I2C gate open / close. Gate close + * is delayed here a little bit in order to see if there is sequence of I2C * messages sent to same I2C bus. - * We must use unlocked version of __i2c_transfer() in order to avoid deadlock - * as lock is already taken by calling muxed i2c_transfer(). */ static void rtl2832_i2c_gate_work(struct work_struct *work) { - struct rtl2832_dev *dev = container_of(work, - struct rtl2832_dev, i2c_gate_work.work); + struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work); struct i2c_client *client = dev->client; int ret; - u8 buf[2]; - struct i2c_msg msg[1] = { - { - .addr = client->addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - - dev_dbg(&client->dev, "\n"); - /* select reg bank 1 */ - buf[0] = 0x00; - buf[1] = 0x01; - ret = __i2c_transfer(client->adapter, msg, 1); - if (ret != 1) - goto err; - - dev->page = 1; - - /* close I2C repeater gate */ - buf[0] = 0x01; - buf[1] = 0x10; - ret = __i2c_transfer(client->adapter, msg, 1); - if (ret != 1) + /* close gate */ + ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00); + if (ret) goto err; dev->i2c_gate_state = false; @@ -950,58 +875,24 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) struct rtl2832_dev *dev = mux_priv; struct i2c_client *client = dev->client; int ret; - u8 buf[2], val; - struct i2c_msg msg[1] = { - { - .addr = client->addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - struct i2c_msg msg_rd[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = "\x01", - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = &val, - } - }; /* terminate possible gate closing */ - cancel_delayed_work_sync(&dev->i2c_gate_work); + cancel_delayed_work(&dev->i2c_gate_work); if (dev->i2c_gate_state == chan_id) return 0; - /* select reg bank 1 */ - buf[0] = 0x00; - buf[1] = 0x01; - ret = __i2c_transfer(client->adapter, msg, 1); - if (ret != 1) - goto err; - - dev->page = 1; - - /* we must read that register, otherwise there will be errors */ - ret = __i2c_transfer(client->adapter, msg_rd, 2); - if (ret != 2) - goto err; - - /* open or close I2C repeater gate */ - buf[0] = 0x01; + /* + * chan_id 1 is muxed adapter demod provides and chan_id 0 is demod + * itself. We need open gate when request is for chan_id 1. On that case + * I2C adapter lock is already taken and due to that we will use + * regmap_update_bits() which does not lock again I2C adapter. + */ if (chan_id == 1) - buf[1] = 0x18; /* open */ + ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08); else - buf[1] = 0x10; /* close */ - - ret = __i2c_transfer(client->adapter, msg, 1); - if (ret != 1) + ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00); + if (ret) goto err; dev->i2c_gate_state = chan_id; @@ -1009,11 +900,11 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); - return -EREMOTEIO; + return ret; } static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, - u32 chan_id) + u32 chan_id) { struct rtl2832_dev *dev = mux_priv; @@ -1060,6 +951,91 @@ static struct dvb_frontend_ops rtl2832_ops = { .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl, }; +/* + * We implement own I2C access routines for regmap in order to get manual access + * to I2C adapter lock, which is needed for I2C mux adapter. + */ +static int rtl2832_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = reg_size, + .buf = (u8 *)reg_buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = val_size, + .buf = val_buf, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + dev_warn(&client->dev, "i2c reg read failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2832_regmap_write(void *context, const void *data, size_t count) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = count, + .buf = (u8 *)data, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2832_regmap_gather_write(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) +{ + struct i2c_client *client = context; + int ret; + u8 buf[256]; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 1 + val_len, + .buf = buf, + } + }; + + buf[0] = *(u8 const *)reg; + memcpy(&buf[1], val, val_len); + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client) { struct rtl2832_dev *dev = i2c_get_clientdata(client); @@ -1142,6 +1118,30 @@ static int rtl2832_probe(struct i2c_client *client, struct rtl2832_dev *dev; int ret; u8 tmp; + static const struct regmap_bus regmap_bus = { + .read = rtl2832_regmap_read, + .write = rtl2832_regmap_write, + .gather_write = rtl2832_regmap_gather_write, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, + }; + static const struct regmap_range_cfg regmap_range_cfg[] = { + { + .selector_reg = 0x00, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + .range_min = 0 * 0x100, + .range_max = 5 * 0x100, + }, + }; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 5 * 0x100, + .ranges = regmap_range_cfg, + .num_ranges = ARRAY_SIZE(regmap_range_cfg), + }; dev_dbg(&client->dev, "\n"); @@ -1153,6 +1153,7 @@ static int rtl2832_probe(struct i2c_client *client, } /* setup the state */ + i2c_set_clientdata(client, dev); dev->client = client; dev->pdata = client->dev.platform_data; if (pdata->config) { @@ -1161,12 +1162,19 @@ static int rtl2832_probe(struct i2c_client *client, } dev->sleeping = true; INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work); + /* create regmap */ + dev->regmap = regmap_init(&client->dev, ®map_bus, client, + ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } /* create muxed i2c adapter for demod itself */ dev->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, dev, 0, 0, 0, rtl2832_select, NULL); if (dev->i2c_adapter == NULL) { ret = -ENODEV; - goto err_kfree; + goto err_regmap_exit; } /* check if the demod is there */ @@ -1185,7 +1193,6 @@ static int rtl2832_probe(struct i2c_client *client, /* create dvb_frontend */ memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); dev->fe.demodulator_priv = dev; - i2c_set_clientdata(client, dev); /* setup callbacks */ pdata->get_dvb_frontend = rtl2832_get_dvb_frontend; @@ -1197,6 +1204,8 @@ static int rtl2832_probe(struct i2c_client *client, return 0; err_i2c_del_mux_adapter: i2c_del_mux_adapter(dev->i2c_adapter); +err_regmap_exit: + regmap_exit(dev->regmap); err_kfree: kfree(dev); err: @@ -1216,6 +1225,8 @@ static int rtl2832_remove(struct i2c_client *client) i2c_del_mux_adapter(dev->i2c_adapter); + regmap_exit(dev->regmap); + kfree(dev); return 0; diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 89953324192..eacd4e4d8ea 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -24,18 +24,18 @@ #include "dvb_frontend.h" #include "rtl2832.h" #include <linux/i2c-mux.h> +#include <linux/regmap.h> struct rtl2832_dev { struct rtl2832_platform_data *pdata; struct i2c_client *client; + struct regmap *regmap; struct i2c_adapter *i2c_adapter; struct i2c_adapter *i2c_adapter_tuner; struct dvb_frontend fe; bool i2c_gate_state; bool sleeping; - - u8 page; /* active register page */ struct delayed_work i2c_gate_work; }; |