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:
parent
0a2abbfd85
commit
b1a1baa657
|
@ -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.
|
||||
|
|
|
@ -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, ®map_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);
|
||||
|
|
Loading…
Reference in New Issue