rtc: isl12022: switch to using regmap API

The regmap abstraction allows us to avoid the private i2c transfer
helpers, and also offers some nice utility functions such as the
regmap_update_bits family.

While at it, simplify the code even more by not keeping track of
->write_enabled: rtc_set_time is not a hot path, so one extra i2c read
doesn't hurt (regmap_update_bits elides the write when the bits are
already as desired).

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Link: https://lore.kernel.org/r/20220921114624.3250848-9-linux@rasmusvillemoes.dk
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Rasmus Villemoes 2022-09-21 13:46:23 +02:00 committed by Alexandre Belloni
parent 0a2abbfd85
commit b1a1baa657
2 changed files with 26 additions and 85 deletions

View file

@ -423,6 +423,7 @@ config RTC_DRV_ISL1208
config RTC_DRV_ISL12022
tristate "Intersil ISL12022"
select REGMAP_I2C
help
If you say yes here you get support for the
Intersil ISL12022 RTC chip.

View file

@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
/* ISL register offsets */
#define ISL12022_REG_SC 0x00
@ -42,72 +43,21 @@ static struct i2c_driver isl12022_driver;
struct isl12022 {
struct rtc_device *rtc;
bool write_enabled; /* true if write enable is set */
struct regmap *regmap;
};
static int isl12022_read_regs(struct i2c_client *client, uint8_t reg,
uint8_t *data, size_t n)
{
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = data
}, /* setup read ptr */
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = n,
.buf = data
}
};
int ret;
data[0] = reg;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
dev_err(&client->dev, "%s: read error, ret=%d\n",
__func__, ret);
return -EIO;
}
return 0;
}
static int isl12022_write_reg(struct i2c_client *client,
uint8_t reg, uint8_t val)
{
uint8_t data[2] = { reg, val };
int err;
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
return -EIO;
}
return 0;
}
/*
* In the routines that deal directly with the isl12022 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
*/
static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
uint8_t buf[ISL12022_REG_INT + 1];
int ret;
ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf));
ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf));
if (ret)
return ret;
@ -148,33 +98,18 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl12022 *isl12022 = dev_get_drvdata(dev);
size_t i;
struct regmap *regmap = isl12022->regmap;
int ret;
uint8_t buf[ISL12022_REG_DW + 1];
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
if (!isl12022->write_enabled) {
ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1);
if (ret)
return ret;
/* Check if WRTC (write rtc enable) is set factory default is
* 0 (not set) */
if (!(buf[0] & ISL12022_INT_WRTC)) {
/* Set the write enable bit. */
ret = isl12022_write_reg(client,
ISL12022_REG_INT,
buf[0] | ISL12022_INT_WRTC);
if (ret)
return ret;
}
isl12022->write_enabled = true;
}
/* Ensure the write enable bit is set. */
ret = regmap_update_bits(regmap, ISL12022_REG_INT,
ISL12022_INT_WRTC, ISL12022_INT_WRTC);
if (ret)
return ret;
/* hours, minutes and seconds */
buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec);
@ -191,15 +126,8 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
/* write register's data */
for (i = 0; i < ARRAY_SIZE(buf); i++) {
ret = isl12022_write_reg(client, ISL12022_REG_SC + i,
buf[ISL12022_REG_SC + i]);
if (ret)
return -EIO;
}
return 0;
return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC,
buf, sizeof(buf));
}
static const struct rtc_class_ops isl12022_rtc_ops = {
@ -207,6 +135,12 @@ static const struct rtc_class_ops isl12022_rtc_ops = {
.set_time = isl12022_rtc_set_time,
};
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.use_single_write = true,
};
static int isl12022_probe(struct i2c_client *client)
{
struct isl12022 *isl12022;
@ -220,6 +154,12 @@ static int isl12022_probe(struct i2c_client *client)
return -ENOMEM;
dev_set_drvdata(&client->dev, isl12022);
isl12022->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(isl12022->regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(isl12022->regmap);
}
isl12022->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(isl12022->rtc))
return PTR_ERR(isl12022->rtc);