Commit e89b60d0 authored by Alexandre Belloni's avatar Alexandre Belloni
Browse files

rtc: pcf85063: switch to regmap



Switch to regmap to simplify register accesses and remove the need for
pcf85063_stop_clock/pcf85063_start_clock.

Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 802a779a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -439,6 +439,7 @@ config RTC_DRV_PCF8523


config RTC_DRV_PCF85063
config RTC_DRV_PCF85063
	tristate "NXP PCF85063"
	tristate "NXP PCF85063"
	select REGMAP_I2C
	help
	help
	  If you say yes here you get support for the PCF85063 RTC chip
	  If you say yes here you get support for the PCF85063 RTC chip


+61 −93
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@
#include <linux/bcd.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/rtc.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>


/*
/*
 * Information for this driver was pulled from the following datasheets.
 * Information for this driver was pulled from the following datasheets.
@@ -28,50 +30,14 @@
#define PCF85063_REG_SC			0x04 /* datetime */
#define PCF85063_REG_SC			0x04 /* datetime */
#define PCF85063_REG_SC_OS		0x80
#define PCF85063_REG_SC_OS		0x80


static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
struct pcf85063 {
{
	struct rtc_device	*rtc;
	int rc;
	struct regmap		*regmap;
	u8 reg;
};

	rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
	if (rc < 0) {
		dev_err(&client->dev, "Failing to stop the clock\n");
		return -EIO;
	}

	/* stop the clock */
	reg = rc | PCF85063_REG_CTRL1_STOP;

	rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg);
	if (rc < 0) {
		dev_err(&client->dev, "Failing to stop the clock\n");
		return -EIO;
	}

	*ctrl1 = reg;

	return 0;
}

static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
{
	int rc;

	/* start the clock */
	ctrl1 &= ~PCF85063_REG_CTRL1_STOP;

	rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
	if (rc < 0) {
		dev_err(&client->dev, "Failing to start the clock\n");
		return -EIO;
	}

	return 0;
}


static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
{
	struct i2c_client *client = to_i2c_client(dev);
	struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
	int rc;
	int rc;
	u8 regs[7];
	u8 regs[7];


@@ -81,16 +47,14 @@ static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm)
	 * event, the access must be finished within one second. So, read all
	 * event, the access must be finished within one second. So, read all
	 * time/date registers in one turn.
	 * time/date registers in one turn.
	 */
	 */
	rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC,
	rc = regmap_bulk_read(pcf85063->regmap, PCF85063_REG_SC, regs,
					   sizeof(regs), regs);
			      sizeof(regs));
	if (rc != sizeof(regs)) {
	if (rc)
		dev_err(&client->dev, "date/time register read error\n");
		return rc;
		return -EIO;
	}


	/* if the clock has lost its power it makes no sense to use its time */
	/* if the clock has lost its power it makes no sense to use its time */
	if (regs[0] & PCF85063_REG_SC_OS) {
	if (regs[0] & PCF85063_REG_SC_OS) {
		dev_warn(&client->dev, "Power loss detected, invalid time\n");
		dev_warn(&pcf85063->rtc->dev, "Power loss detected, invalid time\n");
		return -EINVAL;
		return -EINVAL;
	}
	}


@@ -108,17 +72,18 @@ static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm)


static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
{
	struct i2c_client *client = to_i2c_client(dev);
	struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
	int rc;
	int rc;
	u8 regs[7];
	u8 regs[7];
	u8 ctrl1;


	/*
	/*
	 * to accurately set the time, reset the divider chain and keep it in
	 * to accurately set the time, reset the divider chain and keep it in
	 * reset state until all time/date registers are written
	 * reset state until all time/date registers are written
	 */
	 */
	rc = pcf85063_stop_clock(client, &ctrl1);
	rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
	if (rc != 0)
				PCF85063_REG_CTRL1_STOP,
				PCF85063_REG_CTRL1_STOP);
	if (rc)
		return rc;
		return rc;


	/* hours, minutes and seconds */
	/* hours, minutes and seconds */
@@ -140,23 +105,18 @@ static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm)
	regs[6] = bin2bcd(tm->tm_year - 100);
	regs[6] = bin2bcd(tm->tm_year - 100);


	/* write all registers at once */
	/* write all registers at once */
	rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
	rc = regmap_bulk_write(pcf85063->regmap, PCF85063_REG_SC,
					    sizeof(regs), regs);
			       regs, sizeof(regs));
	if (rc < 0) {
	if (rc)
		dev_err(&client->dev, "date/time register write error\n");
		return rc;
		return rc;
	}


	/*
	/*
	 * Write the control register as a separate action since the size of
	 * Write the control register as a separate action since the size of
	 * the register space is different between the PCF85063TP and
	 * the register space is different between the PCF85063TP and
	 * PCF85063A devices.  The rollover point can not be used.
	 * PCF85063A devices.  The rollover point can not be used.
	 */
	 */
	rc = pcf85063_start_clock(client, ctrl1);
	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
	if (rc != 0)
				  PCF85063_REG_CTRL1_STOP, 0);
		return rc;

	return 0;
}
}


static const struct rtc_class_ops pcf85063_rtc_ops = {
static const struct rtc_class_ops pcf85063_rtc_ops = {
@@ -164,66 +124,74 @@ static const struct rtc_class_ops pcf85063_rtc_ops = {
	.set_time	= pcf85063_rtc_set_time
	.set_time	= pcf85063_rtc_set_time
};
};


static int pcf85063_load_capacitance(struct i2c_client *client)
static int pcf85063_load_capacitance(struct pcf85063 *pcf85063,
				     const struct device_node *np)
{
{
	u32 load;
	u32 load = 7000;
	int rc;
	u8 reg = 0;
	u8 reg;

	rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
	if (rc < 0)
		return rc;

	reg = rc;
	load = 7000;
	of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads",
			     &load);


	of_property_read_u32(np, "quartz-load-femtofarads", &load);
	switch (load) {
	switch (load) {
	default:
	default:
		dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
		dev_warn(&pcf85063->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
			 load);
			 load);
		/* fall through */
		/* fall through */
	case 7000:
	case 7000:
		reg &= ~PCF85063_REG_CTRL1_CAP_SEL;
		break;
		break;
	case 12500:
	case 12500:
		reg |= PCF85063_REG_CTRL1_CAP_SEL;
		reg = PCF85063_REG_CTRL1_CAP_SEL;
		break;
		break;
	}
	}


	rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg);
	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,

				  PCF85063_REG_CTRL1_CAP_SEL, reg);
	return rc;
}
}


static const struct regmap_config regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = 0x11,
};

static int pcf85063_probe(struct i2c_client *client)
static int pcf85063_probe(struct i2c_client *client)
{
{
	struct rtc_device *rtc;
	struct pcf85063 *pcf85063;
	unsigned int tmp;
	int err;
	int err;


	dev_dbg(&client->dev, "%s\n", __func__);
	dev_dbg(&client->dev, "%s\n", __func__);


	err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
	pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
	if (err < 0) {
				GFP_KERNEL);
	if (!pcf85063)
		return -ENOMEM;

	pcf85063->regmap = devm_regmap_init_i2c(client, &regmap_config);
	if (IS_ERR(pcf85063->regmap))
		return PTR_ERR(pcf85063->regmap);

	i2c_set_clientdata(client, pcf85063);

	err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp);
	if (err) {
		dev_err(&client->dev, "RTC chip is not present\n");
		dev_err(&client->dev, "RTC chip is not present\n");
		return err;
		return err;
	}
	}


	err = pcf85063_load_capacitance(client);
	pcf85063->rtc = devm_rtc_allocate_device(&client->dev);
	if (IS_ERR(pcf85063->rtc))
		return PTR_ERR(pcf85063->rtc);

	err = pcf85063_load_capacitance(pcf85063, client->dev.of_node);
	if (err < 0)
	if (err < 0)
		dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
		dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
			 err);
			 err);


	rtc = devm_rtc_allocate_device(&client->dev);
	pcf85063->rtc->ops = &pcf85063_rtc_ops;
	if (IS_ERR(rtc))
	pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
		return PTR_ERR(rtc);
	pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099;

	rtc->ops = &pcf85063_rtc_ops;
	rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
	rtc->range_max = RTC_TIMESTAMP_END_2099;


	return rtc_register_device(rtc);
	return rtc_register_device(pcf85063->rtc);
}
}


#ifdef CONFIG_OF
#ifdef CONFIG_OF