rtc: rv3028: factorize EERD bit handling

Both rv3028_eeprom_write and rv3028_eeprom_read enable EERD before sending
commands to the EEPROM and restore it afterwards. Factorize this code.

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20201009153101.721149-3-alexandre.belloni@bootlin.com
This commit is contained in:
Alexandre Belloni 2020-10-09 17:31:00 +02:00
parent c1efae1432
commit de0ad60e79

View File

@ -171,6 +171,44 @@ static const struct attribute_group rv3028_attr_group = {
.attrs = rv3028_attrs,
};
static int rv3028_exit_eerd(struct rv3028_data *rv3028, u32 eerd)
{
if (eerd)
return 0;
return regmap_update_bits(rv3028->regmap, RV3028_CTRL1, RV3028_CTRL1_EERD, 0);
}
static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd)
{
u32 ctrl1, status;
int ret;
ret = regmap_read(rv3028->regmap, RV3028_CTRL1, &ctrl1);
if (ret)
return ret;
*eerd = ctrl1 & RV3028_CTRL1_EERD;
if (*eerd)
return 0;
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
if (ret)
return ret;
ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
if (ret) {
rv3028_exit_eerd(rv3028, *eerd);
return ret;
}
return 0;
}
static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
{
struct rv3028_data *rv3028 = dev_id;
@ -451,49 +489,36 @@ static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
u32 status, ctrl1;
int i, ret, err;
struct rv3028_data *rv3028 = priv;
u32 status, eerd;
int i, ret;
u8 *buf = val;
ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
ret = rv3028_enter_eerd(rv3028, &eerd);
if (ret)
return ret;
if (!(ctrl1 & RV3028_CTRL1_EERD)) {
ret = regmap_update_bits(priv, RV3028_CTRL1,
RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
if (ret)
return ret;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
}
for (i = 0; i < bytes; i++) {
ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_DATA, buf[i]);
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_DATA, buf[i]);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD,
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
RV3028_EEPROM_CMD_WRITE);
if (ret)
goto restore_eerd;
usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
@ -502,13 +527,7 @@ static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
}
restore_eerd:
if (!(ctrl1 & RV3028_CTRL1_EERD))
{
err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
0);
if (err && !ret)
ret = err;
}
rv3028_exit_eerd(rv3028, eerd);
return ret;
}
@ -516,63 +535,44 @@ restore_eerd:
static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
u32 status, ctrl1, data;
int i, ret, err;
struct rv3028_data *rv3028 = priv;
u32 status, eerd, data;
int i, ret;
u8 *buf = val;
ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
ret = rv3028_enter_eerd(rv3028, &eerd);
if (ret)
return ret;
if (!(ctrl1 & RV3028_CTRL1_EERD)) {
ret = regmap_update_bits(priv, RV3028_CTRL1,
RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
if (ret)
return ret;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
}
for (i = 0; i < bytes; i++) {
ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD,
ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD,
RV3028_EEPROM_CMD_READ);
if (ret)
goto restore_eerd;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
ret = regmap_read(priv, RV3028_EEPROM_DATA, &data);
ret = regmap_read(rv3028->regmap, RV3028_EEPROM_DATA, &data);
if (ret)
goto restore_eerd;
buf[i] = data;
}
restore_eerd:
if (!(ctrl1 & RV3028_CTRL1_EERD))
{
err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
0);
if (err && !ret)
ret = err;
}
rv3028_exit_eerd(rv3028, eerd);
return ret;
}
@ -834,7 +834,7 @@ static int rv3028_probe(struct i2c_client *client)
nvmem_cfg.priv = rv3028->regmap;
rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
eeprom_cfg.priv = rv3028->regmap;
eeprom_cfg.priv = rv3028;
rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
rv3028->rtc->max_user_freq = 1;