From e4a7e3f741f797d93d97a153b0f6a862d19a1304 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 24 Jan 2022 17:01:29 -0500 Subject: [PATCH] regulator/rpi-panel-attiny: Use two transactions for I2C read The I2C to the Atmel is very fussy, and locks up easily on Pi0-3 particularly on reads. If running at 100kHz on Pi3, reading the ID register generally locks up the Atmel, but splitting the register select write and read into two transactions is reliable. Signed-off-by: Dave Stevenson Signed-off-by: Detlev Casanova Link: https://lore.kernel.org/r/20220124220129.158891-10-detlev.casanova@collabora.com Signed-off-by: Mark Brown --- drivers/regulator/rpi-panel-attiny-regulator.c | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 6e408a4..f7df0f4 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -250,6 +250,39 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) mutex_unlock(&state->lock); } +static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) +{ + struct i2c_msg msgs[1]; + u8 addr_buf[1] = { reg }; + u8 data_buf[1] = { 0, }; + int ret; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + usleep_range(5000, 10000); + + /* Read data from register */ + msgs[0].addr = client->addr; + msgs[0].flags = I2C_M_RD; + msgs[0].len = 1; + msgs[0].buf = data_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *buf = data_buf[0]; + return 0; +} + /* * I2C driver interface functions */ @@ -280,7 +313,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c, goto error; } - ret = regmap_read(regmap, REG_ID, &data); + ret = attiny_i2c_read(i2c, REG_ID, &data); if (ret < 0) { dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); goto error; -- 2.7.4