Blame view
drivers/rtc/rtc-s35390a.c
12.5 KB
c46288b09 rtc: add support ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Seiko Instruments S-35390A RTC Driver * * Copyright (c) 2007 Byron Bradley * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> #include <linux/rtc.h> #include <linux/i2c.h> #include <linux/bitrev.h> #include <linux/bcd.h> #include <linux/slab.h> |
8e6583f1b rtc: s35390a: imp... |
18 |
#include <linux/delay.h> |
c46288b09 rtc: add support ... |
19 20 21 22 |
#define S35390A_CMD_STATUS1 0 #define S35390A_CMD_STATUS2 1 #define S35390A_CMD_TIME1 2 |
542dd33a4 drivers/rtc/rtc-s... |
23 24 |
#define S35390A_CMD_TIME2 3 #define S35390A_CMD_INT2_REG1 5 |
c46288b09 rtc: add support ... |
25 26 27 28 29 30 31 32 |
#define S35390A_BYTE_YEAR 0 #define S35390A_BYTE_MONTH 1 #define S35390A_BYTE_DAY 2 #define S35390A_BYTE_WDAY 3 #define S35390A_BYTE_HOURS 4 #define S35390A_BYTE_MINS 5 #define S35390A_BYTE_SECS 6 |
542dd33a4 drivers/rtc/rtc-s... |
33 34 35 |
#define S35390A_ALRM_BYTE_WDAY 0 #define S35390A_ALRM_BYTE_HOURS 1 #define S35390A_ALRM_BYTE_MINS 2 |
3bd32722c rtc: s35390a: imp... |
36 |
/* flags for STATUS1 */ |
c46288b09 rtc: add support ... |
37 38 |
#define S35390A_FLAG_POC 0x01 #define S35390A_FLAG_BLD 0x02 |
3bd32722c rtc: s35390a: imp... |
39 |
#define S35390A_FLAG_INT2 0x04 |
c46288b09 rtc: add support ... |
40 41 |
#define S35390A_FLAG_24H 0x40 #define S35390A_FLAG_RESET 0x80 |
3bd32722c rtc: s35390a: imp... |
42 43 |
/* flag for STATUS2 */ |
c46288b09 rtc: add support ... |
44 |
#define S35390A_FLAG_TEST 0x01 |
542dd33a4 drivers/rtc/rtc-s... |
45 46 47 48 49 50 |
#define S35390A_INT2_MODE_MASK 0xF0 #define S35390A_INT2_MODE_NOINTR 0x00 #define S35390A_INT2_MODE_FREQ 0x10 #define S35390A_INT2_MODE_ALARM 0x40 #define S35390A_INT2_MODE_PMIN_EDG 0x20 |
3760f7367 i2c: Convert most... |
51 52 53 54 55 |
static const struct i2c_device_id s35390a_id[] = { { "s35390a", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, s35390a_id); |
c46288b09 rtc: add support ... |
56 57 58 59 60 61 62 63 64 65 |
struct s35390a { struct i2c_client *client[8]; struct rtc_device *rtc; int twentyfourhour; }; static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { |
65659f639 drivers/rtc/rtc-s... |
66 67 68 69 70 |
{ .addr = client->addr, .len = len, .buf = buf }, |
c46288b09 rtc: add support ... |
71 72 73 74 75 76 77 78 79 80 81 82 |
}; if ((i2c_transfer(client->adapter, msg, 1)) != 1) return -EIO; return 0; } static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { |
65659f639 drivers/rtc/rtc-s... |
83 84 85 86 87 88 |
{ .addr = client->addr, .flags = I2C_M_RD, .len = len, .buf = buf }, |
c46288b09 rtc: add support ... |
89 90 91 92 93 94 95 |
}; if ((i2c_transfer(client->adapter, msg, 1)) != 1) return -EIO; return 0; } |
8e6583f1b rtc: s35390a: imp... |
96 97 98 99 100 101 |
/* * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset. * To keep the information if an irq is pending, pass the value read from * STATUS1 to the caller. */ static int s35390a_reset(struct s35390a *s35390a, char *status1) |
c46288b09 rtc: add support ... |
102 |
{ |
8e6583f1b rtc: s35390a: imp... |
103 104 105 |
char buf; int ret; unsigned initcount = 0; |
c46288b09 rtc: add support ... |
106 |
|
8e6583f1b rtc: s35390a: imp... |
107 108 109 |
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1); if (ret < 0) return ret; |
c46288b09 rtc: add support ... |
110 |
|
8e6583f1b rtc: s35390a: imp... |
111 112 113 114 115 116 117 118 119 120 |
if (*status1 & S35390A_FLAG_POC) /* * Do not communicate for 0.5 seconds since the power-on * detection circuit is in operation. */ msleep(500); else if (!(*status1 & S35390A_FLAG_BLD)) /* * If both POC and BLD are unset everything is fine. */ |
c46288b09 rtc: add support ... |
121 |
return 0; |
8e6583f1b rtc: s35390a: imp... |
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
/* * At least one of POC and BLD are set, so reinitialise chip. Keeping * this information in the hardware to know later that the time isn't * valid is unfortunately not possible because POC and BLD are cleared * on read. So the reset is best done now. * * The 24H bit is kept over reset, so set it already here. */ initialize: *status1 = S35390A_FLAG_24H; buf = S35390A_FLAG_RESET | S35390A_FLAG_24H; ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1); if (ret < 0) return ret; ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1); if (ret < 0) return ret; if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) { /* Try up to five times to reset the chip */ if (initcount < 5) { ++initcount; goto initialize; } else return -EIO; } return 1; |
c46288b09 rtc: add support ... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
} static int s35390a_disable_test_mode(struct s35390a *s35390a) { char buf[1]; if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0) return -EIO; if (!(buf[0] & S35390A_FLAG_TEST)) return 0; buf[0] &= ~S35390A_FLAG_TEST; return s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)); } static char s35390a_hr2reg(struct s35390a *s35390a, int hour) { if (s35390a->twentyfourhour) |
fe20ba70a drivers/rtc/: use... |
171 |
return bin2bcd(hour); |
c46288b09 rtc: add support ... |
172 173 |
if (hour < 12) |
fe20ba70a drivers/rtc/: use... |
174 |
return bin2bcd(hour); |
c46288b09 rtc: add support ... |
175 |
|
fe20ba70a drivers/rtc/: use... |
176 |
return 0x40 | bin2bcd(hour - 12); |
c46288b09 rtc: add support ... |
177 178 179 180 181 182 183 |
} static int s35390a_reg2hr(struct s35390a *s35390a, char reg) { unsigned hour; if (s35390a->twentyfourhour) |
fe20ba70a drivers/rtc/: use... |
184 |
return bcd2bin(reg & 0x3f); |
c46288b09 rtc: add support ... |
185 |
|
fe20ba70a drivers/rtc/: use... |
186 |
hour = bcd2bin(reg & 0x3f); |
c46288b09 rtc: add support ... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
if (reg & 0x40) hour += 12; return hour; } static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm) { struct s35390a *s35390a = i2c_get_clientdata(client); int i, err; char buf[7]; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, " "mon=%d, year=%d, wday=%d ", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); |
fe20ba70a drivers/rtc/: use... |
204 205 206 207 |
buf[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 100); buf[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon + 1); buf[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday); buf[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday); |
c46288b09 rtc: add support ... |
208 |
buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(s35390a, tm->tm_hour); |
fe20ba70a drivers/rtc/: use... |
209 210 |
buf[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min); buf[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec); |
c46288b09 rtc: add support ... |
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
/* This chip expects the bits of each byte to be in reverse order */ for (i = 0; i < 7; ++i) buf[i] = bitrev8(buf[i]); err = s35390a_set_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); return err; } static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm) { struct s35390a *s35390a = i2c_get_clientdata(client); char buf[7]; int i, err; err = s35390a_get_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); if (err < 0) return err; /* This chip returns the bits of each byte in reverse order */ for (i = 0; i < 7; ++i) buf[i] = bitrev8(buf[i]); |
fe20ba70a drivers/rtc/: use... |
234 235 |
tm->tm_sec = bcd2bin(buf[S35390A_BYTE_SECS]); tm->tm_min = bcd2bin(buf[S35390A_BYTE_MINS]); |
c46288b09 rtc: add support ... |
236 |
tm->tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_BYTE_HOURS]); |
fe20ba70a drivers/rtc/: use... |
237 238 239 240 |
tm->tm_wday = bcd2bin(buf[S35390A_BYTE_WDAY]); tm->tm_mday = bcd2bin(buf[S35390A_BYTE_DAY]); tm->tm_mon = bcd2bin(buf[S35390A_BYTE_MONTH]) - 1; tm->tm_year = bcd2bin(buf[S35390A_BYTE_YEAR]) + 100; |
c46288b09 rtc: add support ... |
241 242 243 244 245 246 247 248 249 |
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, " "mon=%d, year=%d, wday=%d ", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); return rtc_valid_tm(tm); } |
542dd33a4 drivers/rtc/rtc-s... |
250 251 252 253 254 255 256 257 258 259 260 |
static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) { struct s35390a *s35390a = i2c_get_clientdata(client); char buf[3], sts = 0; int err, i; dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\ "mon=%d, year=%d, wday=%d ", __func__, alm->time.tm_sec, alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday, alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday); |
5227e8a2a rtc: s35390a: imp... |
261 |
/* disable interrupt (which deasserts the irq line) */ |
542dd33a4 drivers/rtc/rtc-s... |
262 263 264 |
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) return err; |
5227e8a2a rtc: s35390a: imp... |
265 |
/* clear pending interrupt (in STATUS1 only), if any */ |
542dd33a4 drivers/rtc/rtc-s... |
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts)); if (err < 0) return err; if (alm->enabled) sts = S35390A_INT2_MODE_ALARM; else sts = S35390A_INT2_MODE_NOINTR; /* This chip expects the bits of each byte to be in reverse order */ sts = bitrev8(sts); /* set interupt mode*/ err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) return err; if (alm->time.tm_wday != -1) buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80; |
f87e904dd rtc: s35390a: fix... |
285 286 |
else buf[S35390A_ALRM_BYTE_WDAY] = 0; |
542dd33a4 drivers/rtc/rtc-s... |
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a, alm->time.tm_hour) | 0x80; buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80; if (alm->time.tm_hour >= 12) buf[S35390A_ALRM_BYTE_HOURS] |= 0x40; for (i = 0; i < 3; ++i) buf[i] = bitrev8(buf[i]); err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf)); return err; } static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) { struct s35390a *s35390a = i2c_get_clientdata(client); char buf[3], sts; int i, err; err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) return err; |
f87e904dd rtc: s35390a: fix... |
313 314 315 316 317 318 319 320 321 322 |
if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) { /* * When the alarm isn't enabled, the register to configure * the alarm time isn't accessible. */ alm->enabled = 0; return 0; } else { alm->enabled = 1; } |
542dd33a4 drivers/rtc/rtc-s... |
323 324 325 326 327 328 |
err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf)); if (err < 0) return err; /* This chip returns the bits of each byte in reverse order */ |
f87e904dd rtc: s35390a: fix... |
329 |
for (i = 0; i < 3; ++i) |
542dd33a4 drivers/rtc/rtc-s... |
330 |
buf[i] = bitrev8(buf[i]); |
542dd33a4 drivers/rtc/rtc-s... |
331 |
|
f87e904dd rtc: s35390a: fix... |
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
/* * B0 of the three matching registers is an enable flag. Iff it is set * the configured value is used for matching. */ if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80) alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80); if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80) alm->time.tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_ALRM_BYTE_HOURS] & ~0x80); if (buf[S35390A_ALRM_BYTE_MINS] & 0x80) alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80); /* alarm triggers always at s=0 */ alm->time.tm_sec = 0; |
542dd33a4 drivers/rtc/rtc-s... |
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d ", __func__, alm->time.tm_min, alm->time.tm_hour, alm->time.tm_wday); return 0; } static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { return s35390a_read_alarm(to_i2c_client(dev), alm); } static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { return s35390a_set_alarm(to_i2c_client(dev), alm); } |
c46288b09 rtc: add support ... |
368 369 370 371 372 373 374 375 376 377 378 379 380 |
static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) { return s35390a_get_datetime(to_i2c_client(dev), tm); } static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) { return s35390a_set_datetime(to_i2c_client(dev), tm); } static const struct rtc_class_ops s35390a_rtc_ops = { .read_time = s35390a_rtc_read_time, .set_time = s35390a_rtc_set_time, |
542dd33a4 drivers/rtc/rtc-s... |
381 382 |
.set_alarm = s35390a_rtc_set_alarm, .read_alarm = s35390a_rtc_read_alarm, |
c46288b09 rtc: add support ... |
383 384 385 |
}; static struct i2c_driver s35390a_driver; |
d2653e927 i2c: Add support ... |
386 387 |
static int s35390a_probe(struct i2c_client *client, const struct i2c_device_id *id) |
c46288b09 rtc: add support ... |
388 |
{ |
3bd32722c rtc: s35390a: imp... |
389 |
int err, err_reset; |
c46288b09 rtc: add support ... |
390 391 392 |
unsigned int i; struct s35390a *s35390a; struct rtc_time tm; |
3bd32722c rtc: s35390a: imp... |
393 |
char buf, status1; |
c46288b09 rtc: add support ... |
394 395 396 397 398 |
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { err = -ENODEV; goto exit; } |
b4cd3d6a7 rtc: rtc-s35390a:... |
399 400 |
s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a), GFP_KERNEL); |
c46288b09 rtc: add support ... |
401 402 403 404 405 406 407 408 409 410 411 |
if (!s35390a) { err = -ENOMEM; goto exit; } s35390a->client[0] = client; i2c_set_clientdata(client, s35390a); /* This chip uses multiple addresses, use dummy devices for them */ for (i = 1; i < 8; ++i) { s35390a->client[i] = i2c_new_dummy(client->adapter, |
60b129d7b i2c: Match dummy ... |
412 |
client->addr + i); |
c46288b09 rtc: add support ... |
413 414 415 416 417 418 419 420 |
if (!s35390a->client[i]) { dev_err(&client->dev, "Address %02x unavailable ", client->addr + i); err = -EBUSY; goto exit_dummy; } } |
3bd32722c rtc: s35390a: imp... |
421 422 423 |
err_reset = s35390a_reset(s35390a, &status1); if (err_reset < 0) { err = err_reset; |
c46288b09 rtc: add support ... |
424 425 426 427 |
dev_err(&client->dev, "error resetting chip "); goto exit_dummy; } |
3bd32722c rtc: s35390a: imp... |
428 |
if (status1 & S35390A_FLAG_24H) |
c46288b09 rtc: add support ... |
429 430 431 |
s35390a->twentyfourhour = 1; else s35390a->twentyfourhour = 0; |
3bd32722c rtc: s35390a: imp... |
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
if (status1 & S35390A_FLAG_INT2) { /* disable alarm (and maybe test mode) */ buf = 0; err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1); if (err < 0) { dev_err(&client->dev, "error disabling alarm"); goto exit_dummy; } } else { err = s35390a_disable_test_mode(s35390a); if (err < 0) { dev_err(&client->dev, "error disabling test mode "); goto exit_dummy; } } if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0) |
c46288b09 rtc: add support ... |
450 451 |
dev_warn(&client->dev, "clock needs to be set "); |
542dd33a4 drivers/rtc/rtc-s... |
452 |
device_set_wakeup_capable(&client->dev, 1); |
b4cd3d6a7 rtc: rtc-s35390a:... |
453 454 455 |
s35390a->rtc = devm_rtc_device_register(&client->dev, s35390a_driver.driver.name, &s35390a_rtc_ops, THIS_MODULE); |
c46288b09 rtc: add support ... |
456 457 458 459 460 |
if (IS_ERR(s35390a->rtc)) { err = PTR_ERR(s35390a->rtc); goto exit_dummy; } |
3bd32722c rtc: s35390a: imp... |
461 462 463 |
if (status1 & S35390A_FLAG_INT2) rtc_update_irq(s35390a->rtc, 1, RTC_AF); |
c46288b09 rtc: add support ... |
464 465 466 467 468 469 |
return 0; exit_dummy: for (i = 1; i < 8; ++i) if (s35390a->client[i]) i2c_unregister_device(s35390a->client[i]); |
c46288b09 rtc: add support ... |
470 471 472 473 474 475 476 477 |
exit: return err; } static int s35390a_remove(struct i2c_client *client) { unsigned int i; |
c46288b09 rtc: add support ... |
478 |
struct s35390a *s35390a = i2c_get_clientdata(client); |
b4cd3d6a7 rtc: rtc-s35390a:... |
479 |
|
c46288b09 rtc: add support ... |
480 481 482 |
for (i = 1; i < 8; ++i) if (s35390a->client[i]) i2c_unregister_device(s35390a->client[i]); |
c46288b09 rtc: add support ... |
483 484 485 486 487 488 489 490 491 |
return 0; } static struct i2c_driver s35390a_driver = { .driver = { .name = "rtc-s35390a", }, .probe = s35390a_probe, .remove = s35390a_remove, |
3760f7367 i2c: Convert most... |
492 |
.id_table = s35390a_id, |
c46288b09 rtc: add support ... |
493 |
}; |
0abc92011 rtc: convert rtc ... |
494 |
module_i2c_driver(s35390a_driver); |
c46288b09 rtc: add support ... |
495 496 497 498 |
MODULE_AUTHOR("Byron Bradley <byron.bbradley@gmail.com>"); MODULE_DESCRIPTION("S35390A RTC driver"); MODULE_LICENSE("GPL"); |