Commit 2ff4ba9e authored by Marek Vasut's avatar Marek Vasut Committed by Stephen Boyd

clk: rs9: Fix I2C accessors

Add custom I2C accessors to this driver, since the regular I2C regmap ones
do not generate the exact I2C transfers required by the chip. On I2C write,
it is mandatory to send transfer length first, on read the chip returns the
transfer length in first byte. Instead of always reading back 8 bytes, which
is the default and also the size of the entire register file, set BCP register
to 1 to read out 1 byte which is less wasteful.

Fixes: 892e0dde ("clk: rs9: Add Renesas 9-series PCIe clock generator driver")
Reported-by: default avatarAlexander Stein <alexander.stein@ew.tq-group.com>
Signed-off-by: default avatarMarek Vasut <marex@denx.de>
Link: https://lore.kernel.org/r/20220929195521.284497-1-marex@denx.deReviewed-by: default avatarAlexander Stein <alexander.stein@ew.tq-group.com>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 9abf2313
...@@ -90,13 +90,66 @@ static const struct regmap_access_table rs9_writeable_table = { ...@@ -90,13 +90,66 @@ static const struct regmap_access_table rs9_writeable_table = {
.n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges), .n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges),
}; };
static int rs9_regmap_i2c_write(void *context,
unsigned int reg, unsigned int val)
{
struct i2c_client *i2c = context;
const u8 data[3] = { reg, 1, val };
const int count = ARRAY_SIZE(data);
int ret;
ret = i2c_master_send(i2c, data, count);
if (ret == count)
return 0;
else if (ret < 0)
return ret;
else
return -EIO;
}
static int rs9_regmap_i2c_read(void *context,
unsigned int reg, unsigned int *val)
{
struct i2c_client *i2c = context;
struct i2c_msg xfer[2];
u8 txdata = reg;
u8 rxdata[2];
int ret;
xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = (void *)&txdata;
xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (void *)rxdata;
ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret < 0)
return ret;
if (ret != 2)
return -EIO;
/*
* Byte 0 is transfer length, which is always 1 due
* to BCP register programming to 1 in rs9_probe(),
* ignore it and use data from Byte 1.
*/
*val = rxdata[1];
return 0;
}
static const struct regmap_config rs9_regmap_config = { static const struct regmap_config rs9_regmap_config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.cache_type = REGCACHE_FLAT, .cache_type = REGCACHE_NONE,
.max_register = 0x8, .max_register = RS9_REG_BCP,
.rd_table = &rs9_readable_table, .rd_table = &rs9_readable_table,
.wr_table = &rs9_writeable_table, .wr_table = &rs9_writeable_table,
.reg_write = rs9_regmap_i2c_write,
.reg_read = rs9_regmap_i2c_read,
}; };
static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
...@@ -242,11 +295,17 @@ static int rs9_probe(struct i2c_client *client) ...@@ -242,11 +295,17 @@ static int rs9_probe(struct i2c_client *client)
return ret; return ret;
} }
rs9->regmap = devm_regmap_init_i2c(client, &rs9_regmap_config); rs9->regmap = devm_regmap_init(&client->dev, NULL,
client, &rs9_regmap_config);
if (IS_ERR(rs9->regmap)) if (IS_ERR(rs9->regmap))
return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap), return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap),
"Failed to allocate register map\n"); "Failed to allocate register map\n");
/* Always read back 1 Byte via I2C */
ret = regmap_write(rs9->regmap, RS9_REG_BCP, 1);
if (ret < 0)
return ret;
/* Register clock */ /* Register clock */
for (i = 0; i < rs9->chip_info->num_clks; i++) { for (i = 0; i < rs9->chip_info->num_clks; i++) {
snprintf(name, 5, "DIF%d", i); snprintf(name, 5, "DIF%d", i);
......
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