diff options
-rw-r--r-- | drivers/rtc/rtc-s35390a.c | 65 |
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 | ||
97 | static 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 | */ | ||
103 | static 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 | */ | ||
133 | initialize: | ||
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 | ||
112 | static int s35390a_disable_test_mode(struct s35390a *s35390a) | 157 | static 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; |