Commit 0d981f81 authored by Chris DeBruin's avatar Chris DeBruin Committed by Alexandre Belloni

rtc: pcf85063: Add support for the PCF85063A device

The current rtc-pcf85063 driver only supports the PCF85063TP device.
Using the existing driver on a PCF85063A will result in the time being
set correctly into the RTC, but the RTC is held in the stopped state.
Therefore, the time will no longer advance and no error is indicated.

The PCF85063A device has a bigger memory map than the PCF85063TP.
The existing driver make use of an address rollover condition,
but the rollover point is different in the two devices.
Signed-off-by: default avatarChris DeBruin <cdeb5783@gmail.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent c421ce72
...@@ -16,6 +16,16 @@ ...@@ -16,6 +16,16 @@
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/module.h> #include <linux/module.h>
/*
* Information for this driver was pulled from the following datasheets.
*
* http://www.nxp.com/documents/data_sheet/PCF85063A.pdf
* http://www.nxp.com/documents/data_sheet/PCF85063TP.pdf
*
* PCF85063A -- Rev. 6 — 18 November 2015
* PCF85063TP -- Rev. 4 — 6 May 2015
*/
#define PCF85063_REG_CTRL1 0x00 /* status */ #define PCF85063_REG_CTRL1 0x00 /* status */
#define PCF85063_REG_CTRL1_STOP BIT(5) #define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01 #define PCF85063_REG_CTRL2 0x01
...@@ -55,6 +65,22 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) ...@@ -55,6 +65,22 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
return 0; return 0;
} }
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
{
s32 ret;
/* start the clock */
ctrl1 &= PCF85063_REG_CTRL1_STOP;
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
if (ret < 0) {
dev_err(&client->dev, "Failing to start the clock\n");
return -EIO;
}
return 0;
}
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{ {
int rc; int rc;
...@@ -94,7 +120,8 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -94,7 +120,8 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{ {
int rc; int rc;
u8 regs[8]; u8 regs[7];
u8 ctrl1;
if ((tm->tm_year < 100) || (tm->tm_year > 199)) if ((tm->tm_year < 100) || (tm->tm_year > 199))
return -EINVAL; return -EINVAL;
...@@ -103,7 +130,7 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -103,7 +130,7 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
* 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, &regs[7]); rc = pcf85063_stop_clock(client, &ctrl1);
if (rc != 0) if (rc != 0)
return rc; return rc;
...@@ -125,13 +152,6 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -125,13 +152,6 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */ /* year and century */
regs[6] = bin2bcd(tm->tm_year - 100); regs[6] = bin2bcd(tm->tm_year - 100);
/*
* after all time/date registers are written, let the 'address auto
* increment' feature wrap around and write register CTRL1 to re-enable
* the clock divider chain again
*/
regs[7] &= ~PCF85063_REG_CTRL1_STOP;
/* write all registers at once */ /* write all registers at once */
rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC, rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
sizeof(regs), regs); sizeof(regs), regs);
...@@ -140,6 +160,15 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -140,6 +160,15 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return rc; return rc;
} }
/*
* Write the control register as a separate action since the size of
* the register space is different between the PCF85063TP and
* PCF85063A devices. The rollover point can not be used.
*/
rc = pcf85063_start_clock(client, ctrl1);
if (rc != 0)
return rc;
return 0; return 0;
} }
......
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