Commit b1a1baa6 authored by Rasmus Villemoes's avatar Rasmus Villemoes Committed by Alexandre Belloni

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: default avatarRasmus Villemoes <linux@rasmusvillemoes.dk>
Link: https://lore.kernel.org/r/20220921114624.3250848-9-linux@rasmusvillemoes.dkSigned-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 0a2abbfd
...@@ -423,6 +423,7 @@ config RTC_DRV_ISL1208 ...@@ -423,6 +423,7 @@ config RTC_DRV_ISL1208
config RTC_DRV_ISL12022 config RTC_DRV_ISL12022
tristate "Intersil ISL12022" tristate "Intersil ISL12022"
select REGMAP_I2C
help help
If you say yes here you get support for the If you say yes here you get support for the
Intersil ISL12022 RTC chip. Intersil ISL12022 RTC chip.
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/regmap.h>
/* ISL register offsets */ /* ISL register offsets */
#define ISL12022_REG_SC 0x00 #define ISL12022_REG_SC 0x00
...@@ -42,72 +43,21 @@ static struct i2c_driver isl12022_driver; ...@@ -42,72 +43,21 @@ static struct i2c_driver isl12022_driver;
struct isl12022 { struct isl12022 {
struct rtc_device *rtc; struct rtc_device *rtc;
struct regmap *regmap;
bool write_enabled; /* true if write enable is set */
}; };
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 * In the routines that deal directly with the isl12022 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. * 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) 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]; uint8_t buf[ISL12022_REG_INT + 1];
int ret; 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) if (ret)
return ret; return ret;
...@@ -148,33 +98,18 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -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) 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); struct isl12022 *isl12022 = dev_get_drvdata(dev);
size_t i; struct regmap *regmap = isl12022->regmap;
int ret; int ret;
uint8_t buf[ISL12022_REG_DW + 1]; uint8_t buf[ISL12022_REG_DW + 1];
dev_dbg(dev, "%s: %ptR\n", __func__, tm); dev_dbg(dev, "%s: %ptR\n", __func__, tm);
if (!isl12022->write_enabled) { /* Ensure the write enable bit is set. */
ret = regmap_update_bits(regmap, ISL12022_REG_INT,
ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1); ISL12022_INT_WRTC, ISL12022_INT_WRTC);
if (ret) if (ret)
return 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;
}
/* hours, minutes and seconds */ /* hours, minutes and seconds */
buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec); 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) ...@@ -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; buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
/* write register's data */ return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC,
for (i = 0; i < ARRAY_SIZE(buf); i++) { buf, sizeof(buf));
ret = isl12022_write_reg(client, ISL12022_REG_SC + i,
buf[ISL12022_REG_SC + i]);
if (ret)
return -EIO;
}
return 0;
} }
static const struct rtc_class_ops isl12022_rtc_ops = { static const struct rtc_class_ops isl12022_rtc_ops = {
...@@ -207,6 +135,12 @@ 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, .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) static int isl12022_probe(struct i2c_client *client)
{ {
struct isl12022 *isl12022; struct isl12022 *isl12022;
...@@ -220,6 +154,12 @@ static int isl12022_probe(struct i2c_client *client) ...@@ -220,6 +154,12 @@ static int isl12022_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
dev_set_drvdata(&client->dev, isl12022); 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); isl12022->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(isl12022->rtc)) if (IS_ERR(isl12022->rtc))
return PTR_ERR(isl12022->rtc); return PTR_ERR(isl12022->rtc);
......
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