提交 d1016581 编写于 作者: A Antti Palosaari 提交者: Mauro Carvalho Chehab

[media] rtl2832: convert to regmap API

Use regmap to cover register access routines.
Signed-off-by: NAntti Palosaari <crope@iki.fi>
Signed-off-by: NMauro Carvalho Chehab <mchehab@osg.samsung.com>
上级 de0a5f11
...@@ -452,6 +452,7 @@ config DVB_RTL2830 ...@@ -452,6 +452,7 @@ config DVB_RTL2830
config DVB_RTL2832 config DVB_RTL2832
tristate "Realtek RTL2832 DVB-T" tristate "Realtek RTL2832 DVB-T"
depends on DVB_CORE && I2C && I2C_MUX depends on DVB_CORE && I2C && I2C_MUX
select REGMAP
default m if !MEDIA_SUBDRV_AUTOSELECT default m if !MEDIA_SUBDRV_AUTOSELECT
help help
Say Y when you want to support this frontend. Say Y when you want to support this frontend.
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include "dvb_math.h" #include "dvb_math.h"
#include <linux/bitops.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) #define REG_MASK(b) (BIT(b + 1) - 1)
static const struct rtl2832_reg_entry registers[] = { static const struct rtl2832_reg_entry registers[] = {
...@@ -156,103 +154,53 @@ 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}, [DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0},
}; };
/* write multiple hardware registers */ /* Our regmap is bypassing I2C adapter lock, thus we do it! */
static int rtl2832_wr(struct rtl2832_dev *dev, u8 reg, u8 *val, int len) 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; 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)) { i2c_lock_adapter(client->adapter);
dev_warn(&client->dev, "i2c wr reg=%04x: len=%d is too big!\n", ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
reg, len); i2c_unlock_adapter(client->adapter);
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;
}
return ret; return ret;
} }
/* read multiple hardware registers */ int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
static int rtl2832_rd(struct rtl2832_dev *dev, u8 reg, u8 *val, int len) unsigned int mask, unsigned int val)
{ {
struct i2c_client *client = dev->client; struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = val,
}
};
ret = i2c_transfer(dev->i2c_adapter, msg, 2); i2c_lock_adapter(client->adapter);
if (ret == 2) { ret = regmap_update_bits(dev->regmap, reg, mask, val);
ret = 0; i2c_unlock_adapter(client->adapter);
} else {
dev_warn(&client->dev, "i2c rd failed=%d reg=%02x len=%d\n",
ret, reg, len);
ret = -EREMOTEIO;
}
return ret; return ret;
} }
/* write multiple registers */ int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg, void *val,
static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, size_t val_count)
int len)
{ {
struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret; int ret;
/* switch bank if needed */ i2c_lock_adapter(client->adapter);
if (page != dev->page) { ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
ret = rtl2832_wr(dev, 0x00, &page, 1); i2c_unlock_adapter(client->adapter);
if (ret)
return ret; return ret;
}
dev->page = page; /* write multiple registers */
} static int rtl2832_wr_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len)
return rtl2832_wr(dev, reg, val, len); {
return rtl2832_bulk_write(dev->client, page << 8 | reg, val, len);
} }
/* read multiple registers */ /* read multiple registers */
static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, static int rtl2832_rd_regs(struct rtl2832_dev *dev, u8 reg, u8 page, u8 *val, int len)
int len)
{ {
int ret; return rtl2832_bulk_read(dev->client, page << 8 | reg, val, len);
/* 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);
} }
/* write single register */ /* write single register */
...@@ -385,7 +333,6 @@ static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) ...@@ -385,7 +333,6 @@ static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
return ret; return ret;
} }
static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
{ {
struct rtl2832_dev *dev = fe->demodulator_priv; struct rtl2832_dev *dev = fe->demodulator_priv;
...@@ -897,44 +844,22 @@ static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber) ...@@ -897,44 +844,22 @@ static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
} }
/* /*
* Delay mechanism to avoid unneeded I2C gate open / close. Gate close is * I2C gate/mux/repeater logic
* delayed here a little bit in order to see if there is sequence of I2C * 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. * 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) static void rtl2832_i2c_gate_work(struct work_struct *work)
{ {
struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work);
struct rtl2832_dev, i2c_gate_work.work);
struct i2c_client *client = dev->client; struct i2c_client *client = dev->client;
int ret; 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 */ /* close gate */
buf[0] = 0x00; ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
buf[1] = 0x01; if (ret)
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)
goto err; goto err;
dev->i2c_gate_state = false; dev->i2c_gate_state = false;
...@@ -950,58 +875,24 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) ...@@ -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 rtl2832_dev *dev = mux_priv;
struct i2c_client *client = dev->client; struct i2c_client *client = dev->client;
int ret; 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 */ /* 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) if (dev->i2c_gate_state == chan_id)
return 0; return 0;
/* select reg bank 1 */ /*
buf[0] = 0x00; * chan_id 1 is muxed adapter demod provides and chan_id 0 is demod
buf[1] = 0x01; * itself. We need open gate when request is for chan_id 1. On that case
ret = __i2c_transfer(client->adapter, msg, 1); * I2C adapter lock is already taken and due to that we will use
if (ret != 1) * regmap_update_bits() which does not lock again I2C adapter.
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;
if (chan_id == 1) if (chan_id == 1)
buf[1] = 0x18; /* open */ ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
else else
buf[1] = 0x10; /* close */ ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
if (ret)
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1)
goto err; goto err;
dev->i2c_gate_state = chan_id; dev->i2c_gate_state = chan_id;
...@@ -1009,7 +900,7 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) ...@@ -1009,7 +900,7 @@ static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
return 0; return 0;
err: err:
dev_dbg(&client->dev, "failed=%d\n", ret); dev_dbg(&client->dev, "failed=%d\n", ret);
return -EREMOTEIO; return ret;
} }
static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
...@@ -1060,6 +951,91 @@ static struct dvb_frontend_ops rtl2832_ops = { ...@@ -1060,6 +951,91 @@ static struct dvb_frontend_ops rtl2832_ops = {
.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl, .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) static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
{ {
struct rtl2832_dev *dev = i2c_get_clientdata(client); struct rtl2832_dev *dev = i2c_get_clientdata(client);
...@@ -1142,6 +1118,30 @@ static int rtl2832_probe(struct i2c_client *client, ...@@ -1142,6 +1118,30 @@ static int rtl2832_probe(struct i2c_client *client,
struct rtl2832_dev *dev; struct rtl2832_dev *dev;
int ret; int ret;
u8 tmp; 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"); dev_dbg(&client->dev, "\n");
...@@ -1153,6 +1153,7 @@ static int rtl2832_probe(struct i2c_client *client, ...@@ -1153,6 +1153,7 @@ static int rtl2832_probe(struct i2c_client *client,
} }
/* setup the state */ /* setup the state */
i2c_set_clientdata(client, dev);
dev->client = client; dev->client = client;
dev->pdata = client->dev.platform_data; dev->pdata = client->dev.platform_data;
if (pdata->config) { if (pdata->config) {
...@@ -1161,12 +1162,19 @@ static int rtl2832_probe(struct i2c_client *client, ...@@ -1161,12 +1162,19 @@ static int rtl2832_probe(struct i2c_client *client,
} }
dev->sleeping = true; dev->sleeping = true;
INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work); INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
/* create regmap */
dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
&regmap_config);
if (IS_ERR(dev->regmap)) {
ret = PTR_ERR(dev->regmap);
goto err_kfree;
}
/* create muxed i2c adapter for demod itself */ /* create muxed i2c adapter for demod itself */
dev->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, dev, 0, 0, 0, dev->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, dev, 0, 0, 0,
rtl2832_select, NULL); rtl2832_select, NULL);
if (dev->i2c_adapter == NULL) { if (dev->i2c_adapter == NULL) {
ret = -ENODEV; ret = -ENODEV;
goto err_kfree; goto err_regmap_exit;
} }
/* check if the demod is there */ /* check if the demod is there */
...@@ -1185,7 +1193,6 @@ static int rtl2832_probe(struct i2c_client *client, ...@@ -1185,7 +1193,6 @@ static int rtl2832_probe(struct i2c_client *client,
/* create dvb_frontend */ /* create dvb_frontend */
memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
dev->fe.demodulator_priv = dev; dev->fe.demodulator_priv = dev;
i2c_set_clientdata(client, dev);
/* setup callbacks */ /* setup callbacks */
pdata->get_dvb_frontend = rtl2832_get_dvb_frontend; pdata->get_dvb_frontend = rtl2832_get_dvb_frontend;
...@@ -1197,6 +1204,8 @@ static int rtl2832_probe(struct i2c_client *client, ...@@ -1197,6 +1204,8 @@ static int rtl2832_probe(struct i2c_client *client,
return 0; return 0;
err_i2c_del_mux_adapter: err_i2c_del_mux_adapter:
i2c_del_mux_adapter(dev->i2c_adapter); i2c_del_mux_adapter(dev->i2c_adapter);
err_regmap_exit:
regmap_exit(dev->regmap);
err_kfree: err_kfree:
kfree(dev); kfree(dev);
err: err:
...@@ -1216,6 +1225,8 @@ static int rtl2832_remove(struct i2c_client *client) ...@@ -1216,6 +1225,8 @@ static int rtl2832_remove(struct i2c_client *client)
i2c_del_mux_adapter(dev->i2c_adapter); i2c_del_mux_adapter(dev->i2c_adapter);
regmap_exit(dev->regmap);
kfree(dev); kfree(dev);
return 0; return 0;
......
...@@ -24,18 +24,18 @@ ...@@ -24,18 +24,18 @@
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "rtl2832.h" #include "rtl2832.h"
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/regmap.h>
struct rtl2832_dev { struct rtl2832_dev {
struct rtl2832_platform_data *pdata; struct rtl2832_platform_data *pdata;
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap;
struct i2c_adapter *i2c_adapter; struct i2c_adapter *i2c_adapter;
struct i2c_adapter *i2c_adapter_tuner; struct i2c_adapter *i2c_adapter_tuner;
struct dvb_frontend fe; struct dvb_frontend fe;
bool i2c_gate_state; bool i2c_gate_state;
bool sleeping; bool sleeping;
u8 page; /* active register page */
struct delayed_work i2c_gate_work; struct delayed_work i2c_gate_work;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册