diff options
Diffstat (limited to 'drivers/rtc/rtc-pcf8563.c')
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 55 |
1 files changed, 46 insertions, 9 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index c2ef0a22ee94..96fb32e7d6f8 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #define PCF8563_REG_ST2 0x01 | 28 | #define PCF8563_REG_ST2 0x01 |
29 | #define PCF8563_BIT_AIE (1 << 1) | 29 | #define PCF8563_BIT_AIE (1 << 1) |
30 | #define PCF8563_BIT_AF (1 << 3) | 30 | #define PCF8563_BIT_AF (1 << 3) |
31 | #define PCF8563_BITS_ST2_N (7 << 5) | ||
31 | 32 | ||
32 | #define PCF8563_REG_SC 0x02 /* datetime */ | 33 | #define PCF8563_REG_SC 0x02 /* datetime */ |
33 | #define PCF8563_REG_MN 0x03 | 34 | #define PCF8563_REG_MN 0x03 |
@@ -41,6 +42,13 @@ | |||
41 | 42 | ||
42 | #define PCF8563_REG_CLKO 0x0D /* clock out */ | 43 | #define PCF8563_REG_CLKO 0x0D /* clock out */ |
43 | #define PCF8563_REG_TMRC 0x0E /* timer control */ | 44 | #define PCF8563_REG_TMRC 0x0E /* timer control */ |
45 | #define PCF8563_TMRC_ENABLE BIT(7) | ||
46 | #define PCF8563_TMRC_4096 0 | ||
47 | #define PCF8563_TMRC_64 1 | ||
48 | #define PCF8563_TMRC_1 2 | ||
49 | #define PCF8563_TMRC_1_60 3 | ||
50 | #define PCF8563_TMRC_MASK 3 | ||
51 | |||
44 | #define PCF8563_REG_TMR 0x0F /* timer */ | 52 | #define PCF8563_REG_TMR 0x0F /* timer */ |
45 | 53 | ||
46 | #define PCF8563_SC_LV 0x80 /* low voltage */ | 54 | #define PCF8563_SC_LV 0x80 /* low voltage */ |
@@ -118,22 +126,21 @@ static int pcf8563_write_block_data(struct i2c_client *client, | |||
118 | 126 | ||
119 | static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) | 127 | static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) |
120 | { | 128 | { |
121 | unsigned char buf[2]; | 129 | unsigned char buf; |
122 | int err; | 130 | int err; |
123 | 131 | ||
124 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | 132 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); |
125 | if (err < 0) | 133 | if (err < 0) |
126 | return err; | 134 | return err; |
127 | 135 | ||
128 | if (on) | 136 | if (on) |
129 | buf[1] |= PCF8563_BIT_AIE; | 137 | buf |= PCF8563_BIT_AIE; |
130 | else | 138 | else |
131 | buf[1] &= ~PCF8563_BIT_AIE; | 139 | buf &= ~PCF8563_BIT_AIE; |
132 | 140 | ||
133 | buf[1] &= ~PCF8563_BIT_AF; | 141 | buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N); |
134 | buf[0] = PCF8563_REG_ST2; | ||
135 | 142 | ||
136 | err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | 143 | err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); |
137 | if (err < 0) { | 144 | if (err < 0) { |
138 | dev_err(&client->dev, "%s: write error\n", __func__); | 145 | dev_err(&client->dev, "%s: write error\n", __func__); |
139 | return -EIO; | 146 | return -EIO; |
@@ -336,8 +343,8 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) | |||
336 | __func__, buf[0], buf[1], buf[2], buf[3]); | 343 | __func__, buf[0], buf[1], buf[2], buf[3]); |
337 | 344 | ||
338 | tm->time.tm_min = bcd2bin(buf[0] & 0x7F); | 345 | tm->time.tm_min = bcd2bin(buf[0] & 0x7F); |
339 | tm->time.tm_hour = bcd2bin(buf[1] & 0x7F); | 346 | tm->time.tm_hour = bcd2bin(buf[1] & 0x3F); |
340 | tm->time.tm_mday = bcd2bin(buf[2] & 0x1F); | 347 | tm->time.tm_mday = bcd2bin(buf[2] & 0x3F); |
341 | tm->time.tm_wday = bcd2bin(buf[3] & 0x7); | 348 | tm->time.tm_wday = bcd2bin(buf[3] & 0x7); |
342 | tm->time.tm_mon = -1; | 349 | tm->time.tm_mon = -1; |
343 | tm->time.tm_year = -1; | 350 | tm->time.tm_year = -1; |
@@ -361,6 +368,14 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) | |||
361 | struct i2c_client *client = to_i2c_client(dev); | 368 | struct i2c_client *client = to_i2c_client(dev); |
362 | unsigned char buf[4]; | 369 | unsigned char buf[4]; |
363 | int err; | 370 | int err; |
371 | unsigned long alarm_time; | ||
372 | |||
373 | /* The alarm has no seconds, round up to nearest minute */ | ||
374 | if (tm->time.tm_sec) { | ||
375 | rtc_tm_to_time(&tm->time, &alarm_time); | ||
376 | alarm_time += 60-tm->time.tm_sec; | ||
377 | rtc_time_to_tm(alarm_time, &tm->time); | ||
378 | } | ||
364 | 379 | ||
365 | dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " | 380 | dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " |
366 | "enabled=%d pending=%d\n", __func__, | 381 | "enabled=%d pending=%d\n", __func__, |
@@ -381,6 +396,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) | |||
381 | 396 | ||
382 | static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) | 397 | static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) |
383 | { | 398 | { |
399 | dev_dbg(dev, "%s: en=%d\n", __func__, enabled); | ||
384 | return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); | 400 | return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); |
385 | } | 401 | } |
386 | 402 | ||
@@ -398,6 +414,8 @@ static int pcf8563_probe(struct i2c_client *client, | |||
398 | { | 414 | { |
399 | struct pcf8563 *pcf8563; | 415 | struct pcf8563 *pcf8563; |
400 | int err; | 416 | int err; |
417 | unsigned char buf; | ||
418 | unsigned char alm_pending; | ||
401 | 419 | ||
402 | dev_dbg(&client->dev, "%s\n", __func__); | 420 | dev_dbg(&client->dev, "%s\n", __func__); |
403 | 421 | ||
@@ -415,6 +433,22 @@ static int pcf8563_probe(struct i2c_client *client, | |||
415 | pcf8563->client = client; | 433 | pcf8563->client = client; |
416 | device_set_wakeup_capable(&client->dev, 1); | 434 | device_set_wakeup_capable(&client->dev, 1); |
417 | 435 | ||
436 | /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */ | ||
437 | buf = PCF8563_TMRC_1_60; | ||
438 | err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf); | ||
439 | if (err < 0) { | ||
440 | dev_err(&client->dev, "%s: write error\n", __func__); | ||
441 | return err; | ||
442 | } | ||
443 | |||
444 | err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); | ||
445 | if (err < 0) { | ||
446 | dev_err(&client->dev, "%s: read error\n", __func__); | ||
447 | return err; | ||
448 | } | ||
449 | if (alm_pending) | ||
450 | pcf8563_set_alarm_mode(client, 0); | ||
451 | |||
418 | pcf8563->rtc = devm_rtc_device_register(&client->dev, | 452 | pcf8563->rtc = devm_rtc_device_register(&client->dev, |
419 | pcf8563_driver.driver.name, | 453 | pcf8563_driver.driver.name, |
420 | &pcf8563_rtc_ops, THIS_MODULE); | 454 | &pcf8563_rtc_ops, THIS_MODULE); |
@@ -435,6 +469,9 @@ static int pcf8563_probe(struct i2c_client *client, | |||
435 | 469 | ||
436 | } | 470 | } |
437 | 471 | ||
472 | /* the pcf8563 alarm only supports a minute accuracy */ | ||
473 | pcf8563->rtc->uie_unsupported = 1; | ||
474 | |||
438 | return 0; | 475 | return 0; |
439 | } | 476 | } |
440 | 477 | ||