diff options
Diffstat (limited to 'drivers/rtc/rtc-s35390a.c')
| -rw-r--r-- | drivers/rtc/rtc-s35390a.c | 129 |
1 files changed, 127 insertions, 2 deletions
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index c9562ceedef3..8a092325188d 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #define S35390A_CMD_STATUS1 0 | 19 | #define S35390A_CMD_STATUS1 0 |
| 20 | #define S35390A_CMD_STATUS2 1 | 20 | #define S35390A_CMD_STATUS2 1 |
| 21 | #define S35390A_CMD_TIME1 2 | 21 | #define S35390A_CMD_TIME1 2 |
| 22 | #define S35390A_CMD_TIME2 3 | ||
| 23 | #define S35390A_CMD_INT2_REG1 5 | ||
| 22 | 24 | ||
| 23 | #define S35390A_BYTE_YEAR 0 | 25 | #define S35390A_BYTE_YEAR 0 |
| 24 | #define S35390A_BYTE_MONTH 1 | 26 | #define S35390A_BYTE_MONTH 1 |
| @@ -28,12 +30,23 @@ | |||
| 28 | #define S35390A_BYTE_MINS 5 | 30 | #define S35390A_BYTE_MINS 5 |
| 29 | #define S35390A_BYTE_SECS 6 | 31 | #define S35390A_BYTE_SECS 6 |
| 30 | 32 | ||
| 33 | #define S35390A_ALRM_BYTE_WDAY 0 | ||
| 34 | #define S35390A_ALRM_BYTE_HOURS 1 | ||
| 35 | #define S35390A_ALRM_BYTE_MINS 2 | ||
| 36 | |||
| 31 | #define S35390A_FLAG_POC 0x01 | 37 | #define S35390A_FLAG_POC 0x01 |
| 32 | #define S35390A_FLAG_BLD 0x02 | 38 | #define S35390A_FLAG_BLD 0x02 |
| 33 | #define S35390A_FLAG_24H 0x40 | 39 | #define S35390A_FLAG_24H 0x40 |
| 34 | #define S35390A_FLAG_RESET 0x80 | 40 | #define S35390A_FLAG_RESET 0x80 |
| 35 | #define S35390A_FLAG_TEST 0x01 | 41 | #define S35390A_FLAG_TEST 0x01 |
| 36 | 42 | ||
| 43 | #define S35390A_INT2_MODE_MASK 0xF0 | ||
| 44 | |||
| 45 | #define S35390A_INT2_MODE_NOINTR 0x00 | ||
| 46 | #define S35390A_INT2_MODE_FREQ 0x10 | ||
| 47 | #define S35390A_INT2_MODE_ALARM 0x40 | ||
| 48 | #define S35390A_INT2_MODE_PMIN_EDG 0x20 | ||
| 49 | |||
| 37 | static const struct i2c_device_id s35390a_id[] = { | 50 | static const struct i2c_device_id s35390a_id[] = { |
| 38 | { "s35390a", 0 }, | 51 | { "s35390a", 0 }, |
| 39 | { } | 52 | { } |
| @@ -50,7 +63,11 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) | |||
| 50 | { | 63 | { |
| 51 | struct i2c_client *client = s35390a->client[reg]; | 64 | struct i2c_client *client = s35390a->client[reg]; |
| 52 | struct i2c_msg msg[] = { | 65 | struct i2c_msg msg[] = { |
| 53 | { client->addr, 0, len, buf }, | 66 | { |
| 67 | .addr = client->addr, | ||
| 68 | .len = len, | ||
| 69 | .buf = buf | ||
| 70 | }, | ||
| 54 | }; | 71 | }; |
| 55 | 72 | ||
| 56 | if ((i2c_transfer(client->adapter, msg, 1)) != 1) | 73 | if ((i2c_transfer(client->adapter, msg, 1)) != 1) |
| @@ -63,7 +80,12 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) | |||
| 63 | { | 80 | { |
| 64 | struct i2c_client *client = s35390a->client[reg]; | 81 | struct i2c_client *client = s35390a->client[reg]; |
| 65 | struct i2c_msg msg[] = { | 82 | struct i2c_msg msg[] = { |
| 66 | { client->addr, I2C_M_RD, len, buf }, | 83 | { |
| 84 | .addr = client->addr, | ||
| 85 | .flags = I2C_M_RD, | ||
| 86 | .len = len, | ||
| 87 | .buf = buf | ||
| 88 | }, | ||
| 67 | }; | 89 | }; |
| 68 | 90 | ||
| 69 | if ((i2c_transfer(client->adapter, msg, 1)) != 1) | 91 | if ((i2c_transfer(client->adapter, msg, 1)) != 1) |
| @@ -184,6 +206,104 @@ static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
| 184 | return rtc_valid_tm(tm); | 206 | return rtc_valid_tm(tm); |
| 185 | } | 207 | } |
| 186 | 208 | ||
| 209 | static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) | ||
| 210 | { | ||
| 211 | struct s35390a *s35390a = i2c_get_clientdata(client); | ||
| 212 | char buf[3], sts = 0; | ||
| 213 | int err, i; | ||
| 214 | |||
| 215 | dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\ | ||
| 216 | "mon=%d, year=%d, wday=%d\n", __func__, alm->time.tm_sec, | ||
| 217 | alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday, | ||
| 218 | alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday); | ||
| 219 | |||
| 220 | /* disable interrupt */ | ||
| 221 | err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); | ||
| 222 | if (err < 0) | ||
| 223 | return err; | ||
| 224 | |||
| 225 | /* clear pending interrupt, if any */ | ||
| 226 | err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts)); | ||
| 227 | if (err < 0) | ||
| 228 | return err; | ||
| 229 | |||
| 230 | if (alm->enabled) | ||
| 231 | sts = S35390A_INT2_MODE_ALARM; | ||
| 232 | else | ||
| 233 | sts = S35390A_INT2_MODE_NOINTR; | ||
| 234 | |||
| 235 | /* This chip expects the bits of each byte to be in reverse order */ | ||
| 236 | sts = bitrev8(sts); | ||
| 237 | |||
| 238 | /* set interupt mode*/ | ||
| 239 | err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); | ||
| 240 | if (err < 0) | ||
| 241 | return err; | ||
| 242 | |||
| 243 | if (alm->time.tm_wday != -1) | ||
| 244 | buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80; | ||
| 245 | |||
| 246 | buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a, | ||
| 247 | alm->time.tm_hour) | 0x80; | ||
| 248 | buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80; | ||
| 249 | |||
| 250 | if (alm->time.tm_hour >= 12) | ||
| 251 | buf[S35390A_ALRM_BYTE_HOURS] |= 0x40; | ||
| 252 | |||
| 253 | for (i = 0; i < 3; ++i) | ||
| 254 | buf[i] = bitrev8(buf[i]); | ||
| 255 | |||
| 256 | err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf, | ||
| 257 | sizeof(buf)); | ||
| 258 | |||
| 259 | return err; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) | ||
| 263 | { | ||
| 264 | struct s35390a *s35390a = i2c_get_clientdata(client); | ||
| 265 | char buf[3], sts; | ||
| 266 | int i, err; | ||
| 267 | |||
| 268 | err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); | ||
| 269 | if (err < 0) | ||
| 270 | return err; | ||
| 271 | |||
| 272 | if (bitrev8(sts) != S35390A_INT2_MODE_ALARM) | ||
| 273 | return -EINVAL; | ||
| 274 | |||
| 275 | err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf)); | ||
| 276 | if (err < 0) | ||
| 277 | return err; | ||
| 278 | |||
| 279 | /* This chip returns the bits of each byte in reverse order */ | ||
| 280 | for (i = 0; i < 3; ++i) { | ||
| 281 | buf[i] = bitrev8(buf[i]); | ||
| 282 | buf[i] &= ~0x80; | ||
| 283 | } | ||
| 284 | |||
| 285 | alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]); | ||
| 286 | alm->time.tm_hour = s35390a_reg2hr(s35390a, | ||
| 287 | buf[S35390A_ALRM_BYTE_HOURS]); | ||
| 288 | alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]); | ||
| 289 | |||
| 290 | dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n", | ||
| 291 | __func__, alm->time.tm_min, alm->time.tm_hour, | ||
| 292 | alm->time.tm_wday); | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
| 298 | { | ||
| 299 | return s35390a_read_alarm(to_i2c_client(dev), alm); | ||
| 300 | } | ||
| 301 | |||
| 302 | static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
| 303 | { | ||
| 304 | return s35390a_set_alarm(to_i2c_client(dev), alm); | ||
| 305 | } | ||
| 306 | |||
| 187 | static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) | 307 | static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) |
| 188 | { | 308 | { |
| 189 | return s35390a_get_datetime(to_i2c_client(dev), tm); | 309 | return s35390a_get_datetime(to_i2c_client(dev), tm); |
| @@ -197,6 +317,9 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 197 | static const struct rtc_class_ops s35390a_rtc_ops = { | 317 | static const struct rtc_class_ops s35390a_rtc_ops = { |
| 198 | .read_time = s35390a_rtc_read_time, | 318 | .read_time = s35390a_rtc_read_time, |
| 199 | .set_time = s35390a_rtc_set_time, | 319 | .set_time = s35390a_rtc_set_time, |
| 320 | .set_alarm = s35390a_rtc_set_alarm, | ||
| 321 | .read_alarm = s35390a_rtc_read_alarm, | ||
| 322 | |||
| 200 | }; | 323 | }; |
| 201 | 324 | ||
| 202 | static struct i2c_driver s35390a_driver; | 325 | static struct i2c_driver s35390a_driver; |
| @@ -261,6 +384,8 @@ static int s35390a_probe(struct i2c_client *client, | |||
| 261 | if (s35390a_get_datetime(client, &tm) < 0) | 384 | if (s35390a_get_datetime(client, &tm) < 0) |
| 262 | dev_warn(&client->dev, "clock needs to be set\n"); | 385 | dev_warn(&client->dev, "clock needs to be set\n"); |
| 263 | 386 | ||
| 387 | device_set_wakeup_capable(&client->dev, 1); | ||
| 388 | |||
| 264 | s35390a->rtc = rtc_device_register(s35390a_driver.driver.name, | 389 | s35390a->rtc = rtc_device_register(s35390a_driver.driver.name, |
| 265 | &client->dev, &s35390a_rtc_ops, THIS_MODULE); | 390 | &client->dev, &s35390a_rtc_ops, THIS_MODULE); |
| 266 | 391 | ||
