diff options
Diffstat (limited to 'drivers/rtc/rtc-isl12057.c')
-rw-r--r-- | drivers/rtc/rtc-isl12057.c | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index 455b601d731d..6e1fcfb5d7e6 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */ | 41 | #define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */ |
42 | #define ISL12057_REG_RTC_DT 0x04 /* Date */ | 42 | #define ISL12057_REG_RTC_DT 0x04 /* Date */ |
43 | #define ISL12057_REG_RTC_MO 0x05 /* Month */ | 43 | #define ISL12057_REG_RTC_MO 0x05 /* Month */ |
44 | #define ISL12057_REG_RTC_MO_CEN BIT(7) /* Century bit */ | ||
44 | #define ISL12057_REG_RTC_YR 0x06 /* Year */ | 45 | #define ISL12057_REG_RTC_YR 0x06 /* Year */ |
45 | #define ISL12057_RTC_SEC_LEN 7 | 46 | #define ISL12057_RTC_SEC_LEN 7 |
46 | 47 | ||
@@ -88,7 +89,7 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) | |||
88 | tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); | 89 | tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); |
89 | 90 | ||
90 | if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ | 91 | if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ |
91 | tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f); | 92 | tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x1f); |
92 | if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) | 93 | if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) |
93 | tm->tm_hour += 12; | 94 | tm->tm_hour += 12; |
94 | } else { /* 24 hour mode */ | 95 | } else { /* 24 hour mode */ |
@@ -97,26 +98,37 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) | |||
97 | 98 | ||
98 | tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); | 99 | tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); |
99 | tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ | 100 | tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ |
100 | tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */ | 101 | tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO] & 0x1f) - 1; /* ditto */ |
101 | tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; | 102 | tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; |
103 | |||
104 | /* Check if years register has overflown from 99 to 00 */ | ||
105 | if (regs[ISL12057_REG_RTC_MO] & ISL12057_REG_RTC_MO_CEN) | ||
106 | tm->tm_year += 100; | ||
102 | } | 107 | } |
103 | 108 | ||
104 | static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) | 109 | static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) |
105 | { | 110 | { |
111 | u8 century_bit; | ||
112 | |||
106 | /* | 113 | /* |
107 | * The clock has an 8 bit wide bcd-coded register for the year. | 114 | * The clock has an 8 bit wide bcd-coded register for the year. |
115 | * It also has a century bit encoded in MO flag which provides | ||
116 | * information about overflow of year register from 99 to 00. | ||
108 | * tm_year is an offset from 1900 and we are interested in the | 117 | * tm_year is an offset from 1900 and we are interested in the |
109 | * 2000-2099 range, so any value less than 100 is invalid. | 118 | * 2000-2199 range, so any value less than 100 or larger than |
119 | * 299 is invalid. | ||
110 | */ | 120 | */ |
111 | if (tm->tm_year < 100) | 121 | if (tm->tm_year < 100 || tm->tm_year > 299) |
112 | return -EINVAL; | 122 | return -EINVAL; |
113 | 123 | ||
124 | century_bit = (tm->tm_year > 199) ? ISL12057_REG_RTC_MO_CEN : 0; | ||
125 | |||
114 | regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); | 126 | regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); |
115 | regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); | 127 | regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); |
116 | regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ | 128 | regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ |
117 | regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); | 129 | regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); |
118 | regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1); | 130 | regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1) | century_bit; |
119 | regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100); | 131 | regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year % 100); |
120 | regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); | 132 | regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); |
121 | 133 | ||
122 | return 0; | 134 | return 0; |
@@ -152,17 +164,33 @@ static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
152 | { | 164 | { |
153 | struct isl12057_rtc_data *data = dev_get_drvdata(dev); | 165 | struct isl12057_rtc_data *data = dev_get_drvdata(dev); |
154 | u8 regs[ISL12057_RTC_SEC_LEN]; | 166 | u8 regs[ISL12057_RTC_SEC_LEN]; |
167 | unsigned int sr; | ||
155 | int ret; | 168 | int ret; |
156 | 169 | ||
157 | mutex_lock(&data->lock); | 170 | mutex_lock(&data->lock); |
171 | ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr); | ||
172 | if (ret) { | ||
173 | dev_err(dev, "%s: unable to read oscillator status flag (%d)\n", | ||
174 | __func__, ret); | ||
175 | goto out; | ||
176 | } else { | ||
177 | if (sr & ISL12057_REG_SR_OSF) { | ||
178 | ret = -ENODATA; | ||
179 | goto out; | ||
180 | } | ||
181 | } | ||
182 | |||
158 | ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, | 183 | ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, |
159 | ISL12057_RTC_SEC_LEN); | 184 | ISL12057_RTC_SEC_LEN); |
185 | if (ret) | ||
186 | dev_err(dev, "%s: unable to read RTC time section (%d)\n", | ||
187 | __func__, ret); | ||
188 | |||
189 | out: | ||
160 | mutex_unlock(&data->lock); | 190 | mutex_unlock(&data->lock); |
161 | 191 | ||
162 | if (ret) { | 192 | if (ret) |
163 | dev_err(dev, "%s: RTC read failed\n", __func__); | ||
164 | return ret; | 193 | return ret; |
165 | } | ||
166 | 194 | ||
167 | isl12057_rtc_regs_to_tm(tm, regs); | 195 | isl12057_rtc_regs_to_tm(tm, regs); |
168 | 196 | ||
@@ -182,10 +210,24 @@ static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
182 | mutex_lock(&data->lock); | 210 | mutex_lock(&data->lock); |
183 | ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, | 211 | ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, |
184 | ISL12057_RTC_SEC_LEN); | 212 | ISL12057_RTC_SEC_LEN); |
185 | mutex_unlock(&data->lock); | 213 | if (ret) { |
214 | dev_err(dev, "%s: unable to write RTC time section (%d)\n", | ||
215 | __func__, ret); | ||
216 | goto out; | ||
217 | } | ||
186 | 218 | ||
187 | if (ret) | 219 | /* |
188 | dev_err(dev, "%s: RTC write failed\n", __func__); | 220 | * Now that RTC time has been updated, let's clear oscillator |
221 | * failure flag, if needed. | ||
222 | */ | ||
223 | ret = regmap_update_bits(data->regmap, ISL12057_REG_SR, | ||
224 | ISL12057_REG_SR_OSF, 0); | ||
225 | if (ret < 0) | ||
226 | dev_err(dev, "%s: unable to clear osc. failure bit (%d)\n", | ||
227 | __func__, ret); | ||
228 | |||
229 | out: | ||
230 | mutex_unlock(&data->lock); | ||
189 | 231 | ||
190 | return ret; | 232 | return ret; |
191 | } | 233 | } |
@@ -203,15 +245,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) | |||
203 | ret = regmap_update_bits(regmap, ISL12057_REG_INT, | 245 | ret = regmap_update_bits(regmap, ISL12057_REG_INT, |
204 | ISL12057_REG_INT_EOSC, 0); | 246 | ISL12057_REG_INT_EOSC, 0); |
205 | if (ret < 0) { | 247 | if (ret < 0) { |
206 | dev_err(dev, "Unable to enable oscillator\n"); | 248 | dev_err(dev, "%s: unable to enable oscillator (%d)\n", |
207 | return ret; | 249 | __func__, ret); |
208 | } | ||
209 | |||
210 | /* Clear oscillator failure bit if needed */ | ||
211 | ret = regmap_update_bits(regmap, ISL12057_REG_SR, | ||
212 | ISL12057_REG_SR_OSF, 0); | ||
213 | if (ret < 0) { | ||
214 | dev_err(dev, "Unable to clear oscillator failure bit\n"); | ||
215 | return ret; | 250 | return ret; |
216 | } | 251 | } |
217 | 252 | ||
@@ -219,7 +254,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) | |||
219 | ret = regmap_update_bits(regmap, ISL12057_REG_SR, | 254 | ret = regmap_update_bits(regmap, ISL12057_REG_SR, |
220 | ISL12057_REG_SR_A1F, 0); | 255 | ISL12057_REG_SR_A1F, 0); |
221 | if (ret < 0) { | 256 | if (ret < 0) { |
222 | dev_err(dev, "Unable to clear alarm bit\n"); | 257 | dev_err(dev, "%s: unable to clear alarm bit (%d)\n", |
258 | __func__, ret); | ||
223 | return ret; | 259 | return ret; |
224 | } | 260 | } |
225 | 261 | ||
@@ -253,7 +289,8 @@ static int isl12057_probe(struct i2c_client *client, | |||
253 | regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); | 289 | regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); |
254 | if (IS_ERR(regmap)) { | 290 | if (IS_ERR(regmap)) { |
255 | ret = PTR_ERR(regmap); | 291 | ret = PTR_ERR(regmap); |
256 | dev_err(dev, "regmap allocation failed: %d\n", ret); | 292 | dev_err(dev, "%s: regmap allocation failed (%d)\n", |
293 | __func__, ret); | ||
257 | return ret; | 294 | return ret; |
258 | } | 295 | } |
259 | 296 | ||