* [rtc-linux] [PATCH] RTC/PCF85063: fix reading/setting time/date
@ 2015-12-07 13:49 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 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:
- while 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
Patch 1 and 2 change reading the time/date. I have kept them separately for
easier review. Squasching both into one patch render it more or less
unreadable.
Patch 3 changes setting the time/date.
Comments are welcome
Juergen
Please keep me on CC as 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] 18+ messages in thread
* [PATCH 1/3] RTC/PCF85063: fix time/date reading (part 1)
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2015-12-07 13:49 ` Juergen Borleis
-1 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
When reading the seconds register, all time/date registers are frozen
until the year register is read. So, read all time/date registers in one
turn.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 63334cb..75f2866 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -39,6 +39,38 @@ struct pcf85063 {
int voltage_low; /* indicates if a low_voltage was detected */
};
+static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
+{
+ int rc;
+ u8 clk_ctrl = PCF85063_REG_SC;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .len = sizeof(clk_ctrl),
+ .buf = &clk_ctrl,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = size,
+ .buf = buf
+ },
+ };
+
+ /*
+ * 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_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (rc != ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "date/time register read error\n");
+ return -EIO;
+ }
+
+ 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.
--
2.6.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [rtc-linux] [PATCH 1/3] RTC/PCF85063: fix time/date reading (part 1)
@ 2015-12-07 13:49 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
When reading the seconds register, all time/date registers are frozen
until the year register is read. So, read all time/date registers in one
turn.
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
drivers/rtc/rtc-pcf85063.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 63334cb..75f2866 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -39,6 +39,38 @@ struct pcf85063 {
int voltage_low; /* indicates if a low_voltage was detected */
};
+static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
+{
+ int rc;
+ u8 clk_ctrl = PCF85063_REG_SC;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .len = sizeof(clk_ctrl),
+ .buf = &clk_ctrl,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = size,
+ .buf = buf
+ },
+ };
+
+ /*
+ * 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_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (rc != ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "date/time register read error\n");
+ return -EIO;
+ }
+
+ 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.
--
2.6.2
--
--
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] 18+ messages in thread
* [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2015-12-07 13:49 ` Juergen Borleis
-1 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
Use the function to read the whole time/date register in one turn and now
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 | 45 +++++++++++++++++++--------------------------
1 file changed, 19 insertions(+), 26 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 75f2866..abed934 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
@@ -77,39 +78,31 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
*/
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
- },
- };
+ u8 regs[7];
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
+ rc = pcf85063_read_time(client, regs, sizeof(regs));
+ if (rc < 0)
+ return rc;
+
+ /* 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(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.6.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [rtc-linux] [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
@ 2015-12-07 13:49 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 UTC (permalink / raw)
To: rtc-linux; +Cc: Alessandro Zummo, Alexandre Belloni, linux-kernel, kernel
Use the function to read the whole time/date register in one turn and now
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 | 45 +++++++++++++++++++--------------------------
1 file changed, 19 insertions(+), 26 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 75f2866..abed934 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
@@ -77,39 +78,31 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
*/
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
- },
- };
+ u8 regs[7];
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
+ rc = pcf85063_read_time(client, regs, sizeof(regs));
+ if (rc < 0)
+ return rc;
+
+ /* 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(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.6.2
--
--
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] 18+ messages in thread
* Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2015-12-20 11:35 ` Alexandre Belloni
-1 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2015-12-20 11:35 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel
Hi,
On 07/12/2015 at 14:49:33 +0100, Juergen Borleis wrote :
> Use the function to read the whole time/date register in one turn and now
> 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 | 45 +++++++++++++++++++--------------------------
> 1 file changed, 19 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> index 75f2866..abed934 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
> @@ -77,39 +78,31 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
> */
> 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
> - },
> - };
> + u8 regs[7];
>
> - /* read registers */
> - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
> - dev_err(&client->dev, "%s: read error\n", __func__);
> - return -EIO;
Isn't that already reading the time and date register in one block? I'd
say you are simply reading less registers. Also, maybe you could use
i2c_smbus_read_block_data?
> + rc = pcf85063_read_time(client, regs, sizeof(regs));
> + if (rc < 0)
> + return rc;
> +
> + /* 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;
> }
That part is more useful and as I understand it is what you are trying
to fix.
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 18+ messages in thread
* [rtc-linux] Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
@ 2015-12-20 11:35 ` Alexandre Belloni
0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2015-12-20 11:35 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel
Hi,
On 07/12/2015 at 14:49:33 +0100, Juergen Borleis wrote :
> Use the function to read the whole time/date register in one turn and now
> 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 | 45 +++++++++++++++++++--------------------------
> 1 file changed, 19 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> index 75f2866..abed934 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
> @@ -77,39 +78,31 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
> */
> 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
> - },
> - };
> + u8 regs[7];
>
> - /* read registers */
> - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
> - dev_err(&client->dev, "%s: read error\n", __func__);
> - return -EIO;
Isn't that already reading the time and date register in one block? I'd
say you are simply reading less registers. Also, maybe you could use
i2c_smbus_read_block_data?
> + rc = pcf85063_read_time(client, regs, sizeof(regs));
> + if (rc < 0)
> + return rc;
> +
> + /* 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;
> }
That part is more useful and as I understand it is what you are trying
to fix.
--
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] 18+ messages in thread
* Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2016-01-07 10:12 ` Juergen Borleis
-1 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2016-01-07 10:12 UTC (permalink / raw)
To: kernel; +Cc: rtc-linux, Alessandro Zummo, Alexandre Belloni, linux-kernel
Hi Alexandre,
(please keep me on CC...)
> [...]
> > - /* read registers */
> > - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
> > - dev_err(&client->dev, "%s: read error\n", __func__);
> > - return -EIO;
>
> Isn't that already reading the time and date register in one block? I'd
> say you are simply reading less registers. Also, maybe you could use
> i2c_smbus_read_block_data?
Its just a "try" to make the code more readable, by a named subfunction and
more comments why things must happen that way.
Will check for the suggested smbus function.
Regards,
Juergen
--
Pengutronix e.K. | Juergen Borleis |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 18+ messages in thread
* [rtc-linux] Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
@ 2016-01-07 10:12 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2016-01-07 10:12 UTC (permalink / raw)
To: kernel; +Cc: rtc-linux, Alessandro Zummo, Alexandre Belloni, linux-kernel
Hi Alexandre,
(please keep me on CC...)
> [...]
> > - /* read registers */
> > - if ((i2c_transfer(client->adapter, msgs, 2)) !=3D 2) {
> > - dev_err(&client->dev, "%s: read error\n", __func__);
> > - return -EIO;
>
> Isn't that already reading the time and date register in one block? I'd
> say you are simply reading less registers. Also, maybe you could use
> i2c_smbus_read_block_data?
Its just a "try" to make the code more readable, by a named subfunction and=
=20
more comments why things must happen that way.
Will check for the suggested smbus function.
Regards,
Juergen
=2D-=20
Pengutronix e.K. =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0| Juergen Borleis =A0 =A0 =A0 =A0 =A0 =A0 |
Industrial Linux Solutions =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| http://=
www.pengutronix.de/ =A0|
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
2016-01-07 10:12 ` [rtc-linux] " Juergen Borleis
@ 2016-01-21 0:04 ` Alexandre Belloni
-1 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2016-01-21 0:04 UTC (permalink / raw)
To: Juergen Borleis
Cc: kernel, rtc-linux, Alessandro Zummo, linux-kernel, Juergen Borleis
Hi Jurgen,
On 07/01/2016 at 11:12:52 +0100, Juergen Borleis wrote :
> Hi Alexandre,
>
> (please keep me on CC...)
>
I've just checked again and now I'm pretty sure you were in To:. Should
I also add you in Cc? Maybe you should check your filters ;)
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 18+ messages in thread
* [rtc-linux] Re: [PATCH 2/3] RTC/PCF85063: fix time/date reading (part II)
@ 2016-01-21 0:04 ` Alexandre Belloni
0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2016-01-21 0:04 UTC (permalink / raw)
To: Juergen Borleis
Cc: kernel, rtc-linux, Alessandro Zummo, linux-kernel, Juergen Borleis
Hi Jurgen,
On 07/01/2016 at 11:12:52 +0100, Juergen Borleis wrote :
> Hi Alexandre,
>
> (please keep me on CC...)
>
I've just checked again and now I'm pretty sure you were in To:. Should
I also add you in Cc? Maybe you should check your filters ;)
--
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] 18+ messages in thread
* [PATCH 3/3] RTC/PCF85063: fix time/date setting
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2015-12-07 13:49 ` Juergen Borleis
-1 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 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 | 96 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 73 insertions(+), 23 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index abed934..0150e93 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 */
@@ -72,6 +73,47 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
return 0;
}
+static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
+{
+ int rc;
+ u8 clk_ctrl[2] = { PCF85063_REG_CTRL1, };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .len = 1,
+ .buf = &clk_ctrl[0],
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &clk_ctrl[1],
+ }, {
+ .addr = client->addr,
+ .len = sizeof(clk_ctrl),
+ .buf = &clk_ctrl[0],
+ },
+ };
+
+ rc = i2c_transfer(client->adapter, &msgs[0], 2);
+ if (rc != 2) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ /* stop the clock */
+ clk_ctrl[1] |= PCF85063_REG_CTRL1_STOP;
+
+ rc = i2c_transfer(client->adapter, &msgs[2], 1);
+ if (rc != 1) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ *ctrl1 = clk_ctrl[1];
+
+ 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.
@@ -110,41 +152,49 @@ 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[9];
- /* 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[8]);
+ if (rc != 0)
+ return rc;
+ /* write start register */
+ regs[0] = PCF85063_REG_SC;
/* hours, minutes and seconds */
- buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
+ regs[1] = 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[2] = bin2bcd(tm->tm_min);
+ regs[3] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
- buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
+ regs[4] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
- buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
+ regs[5] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[6] = 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[7] = bin2bcd(tm->tm_year % 100);
+
+ /*
+ * after all time/date registers are written, let the address auto
+ * increment wrap around and write register CTRL1 to re-enable the
+ * clock divider chain again
+ */
+ regs[8] &= ~PCF85063_REG_CTRL1_STOP;
+
+ /* write all registers at once */
+ rc = i2c_master_send(client, regs, sizeof(regs));
+ if (rc != sizeof(regs)) {
+ dev_err(&client->dev, "date/time register write error\n");
+ return -EIO;
}
return 0;
--
2.6.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [rtc-linux] [PATCH 3/3] RTC/PCF85063: fix time/date setting
@ 2015-12-07 13:49 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2015-12-07 13:49 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 | 96 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 73 insertions(+), 23 deletions(-)
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index abed934..0150e93 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 */
@@ -72,6 +73,47 @@ static int pcf85063_read_time(struct i2c_client *client, u8 *buf, u16 size)
return 0;
}
+static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
+{
+ int rc;
+ u8 clk_ctrl[2] = { PCF85063_REG_CTRL1, };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .len = 1,
+ .buf = &clk_ctrl[0],
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &clk_ctrl[1],
+ }, {
+ .addr = client->addr,
+ .len = sizeof(clk_ctrl),
+ .buf = &clk_ctrl[0],
+ },
+ };
+
+ rc = i2c_transfer(client->adapter, &msgs[0], 2);
+ if (rc != 2) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ /* stop the clock */
+ clk_ctrl[1] |= PCF85063_REG_CTRL1_STOP;
+
+ rc = i2c_transfer(client->adapter, &msgs[2], 1);
+ if (rc != 1) {
+ dev_err(&client->dev, "Failing to stop the clock\n");
+ return -EIO;
+ }
+
+ *ctrl1 = clk_ctrl[1];
+
+ 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.
@@ -110,41 +152,49 @@ 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[9];
- /* 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[8]);
+ if (rc != 0)
+ return rc;
+ /* write start register */
+ regs[0] = PCF85063_REG_SC;
/* hours, minutes and seconds */
- buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F;
+ regs[1] = 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[2] = bin2bcd(tm->tm_min);
+ regs[3] = bin2bcd(tm->tm_hour);
/* Day of month, 1 - 31 */
- buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday);
+ regs[4] = bin2bcd(tm->tm_mday);
/* Day, 0 - 6 */
- buf[PCF85063_REG_DW] = tm->tm_wday & 0x07;
+ regs[5] = tm->tm_wday & 0x07;
/* month, 1 - 12 */
- buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[6] = 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[7] = bin2bcd(tm->tm_year % 100);
+
+ /*
+ * after all time/date registers are written, let the address auto
+ * increment wrap around and write register CTRL1 to re-enable the
+ * clock divider chain again
+ */
+ regs[8] &= ~PCF85063_REG_CTRL1_STOP;
+
+ /* write all registers at once */
+ rc = i2c_master_send(client, regs, sizeof(regs));
+ if (rc != sizeof(regs)) {
+ dev_err(&client->dev, "date/time register write error\n");
+ return -EIO;
}
return 0;
--
2.6.2
--
--
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] 18+ messages in thread
* Re: [PATCH 3/3] RTC/PCF85063: fix time/date setting
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2015-12-20 11:46 ` Alexandre Belloni
-1 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2015-12-20 11:46 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel
On 07/12/2015 at 14:49:34 +0100, Juergen Borleis wrote :
> 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.
>
I'd have the same comment for that patch. Using
i2c_smbus_write_byte_data and i2c_smbus_write_block_data would make the
code clearer and also more robust because it takes care of
retransmissions for example.
--
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply [flat|nested] 18+ messages in thread
* [rtc-linux] Re: [PATCH 3/3] RTC/PCF85063: fix time/date setting
@ 2015-12-20 11:46 ` Alexandre Belloni
0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Belloni @ 2015-12-20 11:46 UTC (permalink / raw)
To: Juergen Borleis; +Cc: rtc-linux, Alessandro Zummo, linux-kernel, kernel
On 07/12/2015 at 14:49:34 +0100, Juergen Borleis wrote :
> 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.
>
I'd have the same comment for that patch. Using
i2c_smbus_write_byte_data and i2c_smbus_write_block_data would make the
code clearer and also more robust because it takes care of
retransmissions for example.
--
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] 18+ messages in thread
* Re: [PATCH 3/3] RTC/PCF85063: fix time/date setting
2015-12-07 13:49 ` [rtc-linux] " Juergen Borleis
@ 2016-01-07 10:13 ` Juergen Borleis
-1 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2016-01-07 10:13 UTC (permalink / raw)
To: kernel; +Cc: rtc-linux, Alessandro Zummo, Alexandre Belloni, linux-kernel
Hi Alexandre,
sorry, missed your comment. Please keep me on CC since I'm not subscribed to
the list.
> > 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.
>
> I'd have the same comment for that patch. Using
> i2c_smbus_write_byte_data and i2c_smbus_write_block_data would make the
> code clearer and also more robust because it takes care of
> retransmissions for example.
Okay. Will have a look.
Regards,
Juergen
--
Pengutronix e.K. | Juergen Borleis |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply [flat|nested] 18+ messages in thread
* [rtc-linux] Re: [PATCH 3/3] RTC/PCF85063: fix time/date setting
@ 2016-01-07 10:13 ` Juergen Borleis
0 siblings, 0 replies; 18+ messages in thread
From: Juergen Borleis @ 2016-01-07 10:13 UTC (permalink / raw)
To: kernel; +Cc: rtc-linux, Alessandro Zummo, Alexandre Belloni, linux-kernel
Hi Alexandre,
sorry, missed your comment. Please keep me on CC since I'm not subscribed t=
o=20
the list.
> > 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.
>
> I'd have the same comment for that patch. Using
> i2c_smbus_write_byte_data and i2c_smbus_write_block_data would make the
> code clearer and also more robust because it takes care of
> retransmissions for example.
Okay. Will have a look.
Regards,
Juergen
=2D-=20
Pengutronix e.K. =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0| Juergen Borleis =A0 =A0 =A0 =A0 =A0 =A0 |
Industrial Linux Solutions =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| http://=
www.pengutronix.de/ =A0|
^ permalink raw reply [flat|nested] 18+ messages in thread