Commit e89b60d0 authored by Alexandre Belloni's avatar Alexandre Belloni

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
...@@ -439,6 +439,7 @@ config RTC_DRV_PCF8523 ...@@ -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
......
...@@ -10,6 +10,8 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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
......
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