aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/rtc-s35390a.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 6507a01cf9ad..6c90c9f48cab 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -15,6 +15,7 @@
15#include <linux/bitrev.h> 15#include <linux/bitrev.h>
16#include <linux/bcd.h> 16#include <linux/bcd.h>
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/delay.h>
18 19
19#define S35390A_CMD_STATUS1 0 20#define S35390A_CMD_STATUS1 0
20#define S35390A_CMD_STATUS2 1 21#define S35390A_CMD_STATUS2 1
@@ -94,19 +95,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
94 return 0; 95 return 0;
95} 96}
96 97
97static int s35390a_reset(struct s35390a *s35390a) 98/*
99 * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
100 * To keep the information if an irq is pending, pass the value read from
101 * STATUS1 to the caller.
102 */
103static int s35390a_reset(struct s35390a *s35390a, char *status1)
98{ 104{
99 char buf[1]; 105 char buf;
106 int ret;
107 unsigned initcount = 0;
100 108
101 if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0) 109 ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
102 return -EIO; 110 if (ret < 0)
111 return ret;
103 112
104 if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD))) 113 if (*status1 & S35390A_FLAG_POC)
114 /*
115 * Do not communicate for 0.5 seconds since the power-on
116 * detection circuit is in operation.
117 */
118 msleep(500);
119 else if (!(*status1 & S35390A_FLAG_BLD))
120 /*
121 * If both POC and BLD are unset everything is fine.
122 */
105 return 0; 123 return 0;
106 124
107 buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H); 125 /*
108 buf[0] &= 0xf0; 126 * At least one of POC and BLD are set, so reinitialise chip. Keeping
109 return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)); 127 * this information in the hardware to know later that the time isn't
128 * valid is unfortunately not possible because POC and BLD are cleared
129 * on read. So the reset is best done now.
130 *
131 * The 24H bit is kept over reset, so set it already here.
132 */
133initialize:
134 *status1 = S35390A_FLAG_24H;
135 buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
136 ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
137
138 if (ret < 0)
139 return ret;
140
141 ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
142 if (ret < 0)
143 return ret;
144
145 if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
146 /* Try up to five times to reset the chip */
147 if (initcount < 5) {
148 ++initcount;
149 goto initialize;
150 } else
151 return -EIO;
152 }
153
154 return 1;
110} 155}
111 156
112static int s35390a_disable_test_mode(struct s35390a *s35390a) 157static int s35390a_disable_test_mode(struct s35390a *s35390a)
@@ -353,7 +398,7 @@ static int s35390a_probe(struct i2c_client *client,
353 unsigned int i; 398 unsigned int i;
354 struct s35390a *s35390a; 399 struct s35390a *s35390a;
355 struct rtc_time tm; 400 struct rtc_time tm;
356 char buf[1]; 401 char buf[1], status1;
357 402
358 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 403 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
359 err = -ENODEV; 404 err = -ENODEV;
@@ -382,7 +427,7 @@ static int s35390a_probe(struct i2c_client *client,
382 } 427 }
383 } 428 }
384 429
385 err = s35390a_reset(s35390a); 430 err = s35390a_reset(s35390a, &status1);
386 if (err < 0) { 431 if (err < 0) {
387 dev_err(&client->dev, "error resetting chip\n"); 432 dev_err(&client->dev, "error resetting chip\n");
388 goto exit_dummy; 433 goto exit_dummy;