summaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-rs5c348.c
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@bootlin.com>2018-09-24 11:05:09 -0400
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2018-09-28 08:21:03 -0400
commit1654a2b06b936c5e123978e6d9523b022a2a5aa1 (patch)
tree95ad57c2125f6e4f9a260543893b2d72d1a374eb /drivers/rtc/rtc-rs5c348.c
parent2d7be4ed7addcaae8eba6ae8cdee83e2f7d39059 (diff)
rtc: rs5c348: report error when time is invalid
Instead of resetting the RTC to an bogus valid time, let userspace know that the time is invalid when XSTP is set. Reset XSTP when setting the time again. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Diffstat (limited to 'drivers/rtc/rtc-rs5c348.c')
-rw-r--r--drivers/rtc/rtc-rs5c348.c43
1 files changed, 21 insertions, 22 deletions
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 7b9c7dc5b309..6582be707bd0 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -66,6 +66,17 @@ rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
66 u8 txbuf[5+7], *txp; 66 u8 txbuf[5+7], *txp;
67 int ret; 67 int ret;
68 68
69 ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
70 if (ret < 0)
71 return ret;
72 if (ret & RS5C348_BIT_XSTP) {
73 txbuf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
74 txbuf[1] = 0;
75 ret = spi_write_then_read(spi, txbuf, 2, NULL, 0);
76 if (ret < 0)
77 return ret;
78 }
79
69 /* Transfer 5 bytes before writing SEC. This gives 31us for carry. */ 80 /* Transfer 5 bytes before writing SEC. This gives 31us for carry. */
70 txp = txbuf; 81 txp = txbuf;
71 txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ 82 txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
@@ -102,6 +113,16 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
102 u8 txbuf[5], rxbuf[7]; 113 u8 txbuf[5], rxbuf[7];
103 int ret; 114 int ret;
104 115
116 ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
117 if (ret < 0)
118 return ret;
119 if (ret & RS5C348_BIT_VDET)
120 dev_warn(&spi->dev, "voltage-low detected.\n");
121 if (ret & RS5C348_BIT_XSTP) {
122 dev_warn(&spi->dev, "oscillator-stop detected.\n");
123 return -EINVAL;
124 }
125
105 /* Transfer 5 byte befores reading SEC. This gives 31us for carry. */ 126 /* Transfer 5 byte befores reading SEC. This gives 31us for carry. */
106 txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ 127 txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
107 txbuf[1] = 0; /* dummy */ 128 txbuf[1] = 0; /* dummy */
@@ -165,28 +186,6 @@ static int rs5c348_probe(struct spi_device *spi)
165 dev_info(&spi->dev, "spiclk %u KHz.\n", 186 dev_info(&spi->dev, "spiclk %u KHz.\n",
166 (spi->max_speed_hz + 500) / 1000); 187 (spi->max_speed_hz + 500) / 1000);
167 188
168 /* turn RTC on if it was not on */
169 ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
170 if (ret < 0)
171 return ret;
172 if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
173 u8 buf[2];
174 struct rtc_time tm;
175 if (ret & RS5C348_BIT_VDET)
176 dev_warn(&spi->dev, "voltage-low detected.\n");
177 if (ret & RS5C348_BIT_XSTP)
178 dev_warn(&spi->dev, "oscillator-stop detected.\n");
179 rtc_time_to_tm(0, &tm); /* 1970/1/1 */
180 ret = rs5c348_rtc_set_time(&spi->dev, &tm);
181 if (ret < 0)
182 return ret;
183 buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
184 buf[1] = 0;
185 ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
186 if (ret < 0)
187 return ret;
188 }
189
190 ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1)); 189 ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
191 if (ret < 0) 190 if (ret < 0)
192 return ret; 191 return ret;