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 | ||
