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

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.dk


Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 0a2abbfd
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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.
+25 −85
Original line number Original line Diff line number Diff line
@@ -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;


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,34 +98,19 @@ 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);
	buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min);
	buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min);
@@ -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 = {
	.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)
		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);