* [PATCH v2] RTC/PCF85063: fix reading/setting time/date
@ 2016-02-09 10:57 ` Juergen Borleis
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
The PCF85063 RTC needs special treatment while setting or reading the
time/date:
- when reading the 7 time/date registers they are blocked from updating by
the 'one second' pulse internally. So reading all time/date registers
should happen in one turn to ensure reading is an atomic operation
- to let setting the time/date be an atomic operation as well, the clock
dividers must be kept in reset state to avoid a 'one second' pulse during
writing the 7 time/date registers
Changes from v1:
- using high level I2C access functions instead of the low level i2c_transfer()
to simplify the code
Comments are welcome
Juergen
Please keep me on CC since I'm not subscribed to the list.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [rtc-linux] [PATCH v2] RTC/PCF85063: fix reading/setting time/date
@ 2016-02-09 10:57 ` Juergen Borleis
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
The PCF85063 RTC needs special treatment while setting or reading the
time/date:
- when reading the 7 time/date registers they are blocked from updating by
the 'one second' pulse internally. So reading all time/date registers
should happen in one turn to ensure reading is an atomic operation
- to let setting the time/date be an atomic operation as well, the clock
dividers must be kept in reset state to avoid a 'one second' pulse during
writing the 7 time/date registers
Changes from v1:
- using high level I2C access functions instead of the low level i2c_transfer()
to simplify the code
Comments are welcome
Juergen
Please keep me on CC since I'm not subscribed to the list.
--
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/3] RTC/PCF85063: simplify code to read the current time
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
@ 2016-02-09 10:57 ` Juergen Borleis
-1 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
By using i2c_smbus_read_i2c_block_data() the code is now much simpler.
While at it: when reading the RTC's seconds register, all time/date registers
are frozen until the RTC's year register is read. So it is important to read
all time/date registers in one turn to not lose a second event. Make it more
clear why the read must happen in this way.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 47 +++++++++++++++++++++-------------------------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 63334cb..7f9caee 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -45,39 +45,34 @@ struct pcf85063 {
*/
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ int rc;
struct pcf85063 *pcf85063 = i2c_get_clientdata(client);
- unsigned char buf[13] = { PCF85063_REG_CTRL1 };
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = buf
- },
- {/* read status + date */
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 13,
- .buf = buf
- },
- };
-
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
+ u8 regs[7];
+
+ /*
+ * while reading, the time/date registers are blocked and not updated
+ * anymore until the access is finished. To not lose a second
+ * event, the access must be finished within one second. So, read all
+ * time/date registers in one turn.
+ */
+ rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc != sizeof(regs)) {
+ dev_err(&client->dev, "date/time register read error\n");
return -EIO;
}
- tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F);
- tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F);
- tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F);
- tm->tm_wday = buf[PCF85063_REG_DW] & 0x07;
- tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]);
+ tm->tm_sec = bcd2bin(regs[0] & 0x7F);
+ tm->tm_min = bcd2bin(regs[1] & 0x7F);
+ tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
+ tm->tm_mday = bcd2bin(regs[3] & 0x3F);
+ tm->tm_wday = regs[4] & 0x07;
+ tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = bcd2bin(regs[6]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
/* detect the polarity heuristically. see note above. */
- pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ?
+ pcf85063->c_polarity = (regs[5] & PCF85063_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
return rtc_valid_tm(tm);
--
2.7.0.rc3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [rtc-linux] [PATCH v2 1/3] RTC/PCF85063: simplify code to read the current time
@ 2016-02-09 10:57 ` Juergen Borleis
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
By using i2c_smbus_read_i2c_block_data() the code is now much simpler.
While at it: when reading the RTC's seconds register, all time/date registers
are frozen until the RTC's year register is read. So it is important to read
all time/date registers in one turn to not lose a second event. Make it more
clear why the read must happen in this way.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 47 +++++++++++++++++++++-------------------------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 63334cb..7f9caee 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -45,39 +45,34 @@ struct pcf85063 {
*/
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ int rc;
struct pcf85063 *pcf85063 = i2c_get_clientdata(client);
- unsigned char buf[13] = { PCF85063_REG_CTRL1 };
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = buf
- },
- {/* read status + date */
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 13,
- .buf = buf
- },
- };
-
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
+ u8 regs[7];
+
+ /*
+ * while reading, the time/date registers are blocked and not updated
+ * anymore until the access is finished. To not lose a second
+ * event, the access must be finished within one second. So, read all
+ * time/date registers in one turn.
+ */
+ rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc != sizeof(regs)) {
+ dev_err(&client->dev, "date/time register read error\n");
return -EIO;
}
- tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F);
- tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F);
- tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F);
- tm->tm_wday = buf[PCF85063_REG_DW] & 0x07;
- tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]);
+ tm->tm_sec = bcd2bin(regs[0] & 0x7F);
+ tm->tm_min = bcd2bin(regs[1] & 0x7F);
+ tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
+ tm->tm_mday = bcd2bin(regs[3] & 0x3F);
+ tm->tm_wday = regs[4] & 0x07;
+ tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = bcd2bin(regs[6]);
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
/* detect the polarity heuristically. see note above. */
- pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ?
+ pcf85063->c_polarity = (regs[5] & PCF85063_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
return rtc_valid_tm(tm);
--
2.7.0.rc3
--
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/3] RTC/PCF85063: fix time/date reading
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
@ 2016-02-09 10:57 ` Juergen Borleis
-1 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
Check if the RTC signals an invalid time/date (due to a battery power loss
for example). In this case ignore the time/date until it is really set again.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 7f9caee..e0343e6 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -22,6 +22,7 @@
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
+#define PCF85063_REG_SC_OS 0x80
#define PCF85063_REG_MN 0x05
#define PCF85063_REG_HR 0x06
#define PCF85063_REG_DM 0x07
@@ -62,6 +63,12 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
+ /* if the clock has lost its power it makes no sense to use its time */
+ if (regs[0] & PCF85063_REG_SC_OS) {
+ dev_warn(&client->dev, "Power loss detected, invalid time\n");
+ return -EINVAL;
+ }
+
tm->tm_sec = bcd2bin(regs[0] & 0x7F);
tm->tm_min = bcd2bin(regs[1] & 0x7F);
tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
--
2.7.0.rc3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [rtc-linux] [PATCH v2 2/3] RTC/PCF85063: fix time/date reading
@ 2016-02-09 10:57 ` Juergen Borleis
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
Check if the RTC signals an invalid time/date (due to a battery power loss
for example). In this case ignore the time/date until it is really set again.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 7f9caee..e0343e6 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -22,6 +22,7 @@
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
+#define PCF85063_REG_SC_OS 0x80
#define PCF85063_REG_MN 0x05
#define PCF85063_REG_HR 0x06
#define PCF85063_REG_DM 0x07
@@ -62,6 +63,12 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
+ /* if the clock has lost its power it makes no sense to use its time */
+ if (regs[0] & PCF85063_REG_SC_OS) {
+ dev_warn(&client->dev, "Power loss detected, invalid time\n");
+ return -EINVAL;
+ }
+
tm->tm_sec = bcd2bin(regs[0] & 0x7F);
tm->tm_min = bcd2bin(regs[1] & 0x7F);
tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
--
2.7.0.rc3
--
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 3/3] RTC/PCF85063: fix time/date setting
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
@ 2016-02-09 10:57 ` Juergen Borleis
-1 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
When setting a new time/date the RTC's clock must be stopped first, in
order to write the time/date registers in an atomic manner.
So, this change stops the clock first and then writes the time/date
registers and the clock control register (to re-enable the clock) in one
turn.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 78 ++++++++++++++++++++++++++++++++--------------
1 file changed, 55 insertions(+), 23 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index e0343e6..c5db231 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -19,6 +19,7 @@
#define DRV_VERSION "0.0.1"
#define PCF85063_REG_CTRL1 0x00 /* status */
+#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
@@ -40,6 +41,30 @@ struct pcf85063 {
int voltage_low; /* indicates if a low_voltage was detected */
};
+static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ /* stop the clock */
+ ret |= PCF85063_REG_CTRL1_STOP;
+
+ ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ *ctrl1 = ret;
+
+ return 0;
+}
+
/*
* In the routines that deal directly with the pcf85063 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
@@ -87,41 +112,48 @@ 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)
{
- int i = 0, err = 0;
- unsigned char buf[11];
+ int rc;
+ u8 regs[8];
- /* Control & status */
- buf[PCF85063_REG_CTRL1] = 0;
- buf[PCF85063_REG_CTRL2] = 5;
+ /*
+ * to accurately set the time, reset the divider chain and keep it in
+ * reset state until all time/date registers are written
+ */
+ rc = pcf85063_stop_clock(client, ®s[7]);
+ if (rc != 0)
+ return rc;
/* hours, minutes and seconds */
- buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
+ regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */
- buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min);
- buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour);
+ regs[1] = bin2bcd(tm->tm_min);
+ regs[2] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
- buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
+ regs[3] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
- buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
+ regs[4] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[5] = bin2bcd(tm->tm_mon + 1);
/* year and century */
- buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100);
-
- /* write register's data */
- for (i = 0; i < sizeof(buf); i++) {
- unsigned char data[2] = { i, buf[i] };
-
- 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;
- }
+ 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 */
+ rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc < 0) {
+ dev_err(&client->dev, "date/time register write error\n");
+ return rc;
}
return 0;
--
2.7.0.rc3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [rtc-linux] [PATCH v2 3/3] RTC/PCF85063: fix time/date setting
@ 2016-02-09 10:57 ` Juergen Borleis
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Borleis @ 2016-02-09 10:57 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
When setting a new time/date the RTC's clock must be stopped first, in
order to write the time/date registers in an atomic manner.
So, this change stops the clock first and then writes the time/date
registers and the clock control register (to re-enable the clock) in one
turn.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 78 ++++++++++++++++++++++++++++++++--------------
1 file changed, 55 insertions(+), 23 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index e0343e6..c5db231 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -19,6 +19,7 @@
#define DRV_VERSION "0.0.1"
#define PCF85063_REG_CTRL1 0x00 /* status */
+#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */
@@ -40,6 +41,30 @@ struct pcf85063 {
int voltage_low; /* indicates if a low_voltage was detected */
};
+static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ /* stop the clock */
+ ret |= PCF85063_REG_CTRL1_STOP;
+
+ ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ *ctrl1 = ret;
+
+ return 0;
+}
+
/*
* In the routines that deal directly with the pcf85063 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
@@ -87,41 +112,48 @@ 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)
{
- int i = 0, err = 0;
- unsigned char buf[11];
+ int rc;
+ u8 regs[8];
- /* Control & status */
- buf[PCF85063_REG_CTRL1] = 0;
- buf[PCF85063_REG_CTRL2] = 5;
+ /*
+ * to accurately set the time, reset the divider chain and keep it in
+ * reset state until all time/date registers are written
+ */
+ rc = pcf85063_stop_clock(client, ®s[7]);
+ if (rc != 0)
+ return rc;
/* hours, minutes and seconds */
- buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
+ regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */
- buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min);
- buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour);
+ regs[1] = bin2bcd(tm->tm_min);
+ regs[2] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
- buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
+ regs[3] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
- buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
+ regs[4] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[5] = bin2bcd(tm->tm_mon + 1);
/* year and century */
- buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100);
-
- /* write register's data */
- for (i = 0; i < sizeof(buf); i++) {
- unsigned char data[2] = { i, buf[i] };
-
- 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;
- }
+ 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 */
+ rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
+ sizeof(regs), regs);
+ if (rc < 0) {
+ dev_err(&client->dev, "date/time register write error\n");
+ return rc;
}
return 0;
--
2.7.0.rc3
--
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2] RTC/PCF85063: fix reading/setting time/date
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
@ 2016-02-23 23:04 ` Alexandre Belloni
-1 siblings, 0 replies; 10+ messages in thread
From: Alexandre Belloni @ 2016-02-23 23:04 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel, jbe
On 09/02/2016 at 11:57:24 +0100, Juergen Borleis wrote :
> The PCF85063 RTC needs special treatment while setting or reading the
> time/date:
>
> - when reading the 7 time/date registers they are blocked from updating by
> the 'one second' pulse internally. So reading all time/date registers
> should happen in one turn to ensure reading is an atomic operation
>
> - to let setting the time/date be an atomic operation as well, the clock
> dividers must be kept in reset state to avoid a 'one second' pulse during
> writing the 7 time/date registers
>
> Changes from v1:
>
> - using high level I2C access functions instead of the low level i2c_transfer()
> to simplify the code
>
All applied, thanks!
However, I found two interesting things in that driver. I'll send a
patch shortly, removing the useless century handling.
Also, I'm quite unsure about the year range handling. I have a patch but
I'm not sure about the RTC behaviour when the year goes from 99 to 00.
Can you check that works properly?
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* [rtc-linux] Re: [PATCH v2] RTC/PCF85063: fix reading/setting time/date
@ 2016-02-23 23:04 ` Alexandre Belloni
0 siblings, 0 replies; 10+ messages in thread
From: Alexandre Belloni @ 2016-02-23 23:04 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel, jbe
On 09/02/2016 at 11:57:24 +0100, Juergen Borleis wrote :
> The PCF85063 RTC needs special treatment while setting or reading the
> time/date:
>
> - when reading the 7 time/date registers they are blocked from updating by
> the 'one second' pulse internally. So reading all time/date registers
> should happen in one turn to ensure reading is an atomic operation
>
> - to let setting the time/date be an atomic operation as well, the clock
> dividers must be kept in reset state to avoid a 'one second' pulse during
> writing the 7 time/date registers
>
> Changes from v1:
>
> - using high level I2C access functions instead of the low level i2c_transfer()
> to simplify the code
>
All applied, thanks!
However, I found two interesting things in that driver. I'll send a
patch shortly, removing the useless century handling.
Also, I'm quite unsure about the year range handling. I have a patch but
I'm not sure about the RTC behaviour when the year goes from 99 to 00.
Can you check that works properly?
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
--
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-02-23 23:04 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-09 10:57 [PATCH v2] RTC/PCF85063: fix reading/setting time/date Juergen Borleis
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
2016-02-09 10:57 ` [PATCH v2 1/3] RTC/PCF85063: simplify code to read the current time Juergen Borleis
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
2016-02-09 10:57 ` [PATCH v2 2/3] RTC/PCF85063: fix time/date reading Juergen Borleis
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
2016-02-09 10:57 ` [PATCH v2 3/3] RTC/PCF85063: fix time/date setting Juergen Borleis
2016-02-09 10:57 ` [rtc-linux] " Juergen Borleis
2016-02-23 23:04 ` [PATCH v2] RTC/PCF85063: fix reading/setting time/date Alexandre Belloni
2016-02-23 23:04 ` [rtc-linux] " Alexandre Belloni
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.