Skip to content

Commit ede3e9d

Browse files
vdonneforttorvalds
authored andcommitted
drivers/rtc/rtc-pcf8563.c: add alarm support
This patch adds alarm support for the NXP PCF8563 chip. Signed-off-by: Vincent Donnefort <[email protected]> Cc: Simon Guinot <[email protected]> Cc: Jason Cooper <[email protected]> Cc: Andrew Lunn <[email protected]> Cc: Alessandro Zummo <[email protected]> Cc: Dan Carpenter <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2784366 commit ede3e9d

1 file changed

Lines changed: 153 additions & 4 deletions

File tree

drivers/rtc/rtc-pcf8563.c

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#define PCF8563_REG_ST1 0x00 /* status */
2828
#define PCF8563_REG_ST2 0x01
29+
#define PCF8563_BIT_AIE (1 << 1)
30+
#define PCF8563_BIT_AF (1 << 3)
2931

3032
#define PCF8563_REG_SC 0x02 /* datetime */
3133
#define PCF8563_REG_MN 0x03
@@ -36,9 +38,6 @@
3638
#define PCF8563_REG_YR 0x08
3739

3840
#define PCF8563_REG_AMN 0x09 /* alarm */
39-
#define PCF8563_REG_AHR 0x0A
40-
#define PCF8563_REG_ADM 0x0B
41-
#define PCF8563_REG_ADW 0x0C
4241

4342
#define PCF8563_REG_CLKO 0x0D /* clock out */
4443
#define PCF8563_REG_TMRC 0x0E /* timer control */
@@ -67,6 +66,8 @@ struct pcf8563 {
6766
*/
6867
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
6968
int voltage_low; /* incicates if a low_voltage was detected */
69+
70+
struct i2c_client *client;
7071
};
7172

7273
static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
@@ -115,6 +116,69 @@ static int pcf8563_write_block_data(struct i2c_client *client,
115116
return 0;
116117
}
117118

119+
static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
120+
{
121+
unsigned char buf[2];
122+
int err;
123+
124+
err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
125+
if (err < 0)
126+
return err;
127+
128+
if (on)
129+
buf[1] |= PCF8563_BIT_AIE;
130+
else
131+
buf[1] &= ~PCF8563_BIT_AIE;
132+
133+
buf[1] &= ~PCF8563_BIT_AF;
134+
buf[0] = PCF8563_REG_ST2;
135+
136+
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
137+
if (err < 0) {
138+
dev_err(&client->dev, "%s: write error\n", __func__);
139+
return -EIO;
140+
}
141+
142+
return 0;
143+
}
144+
145+
static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
146+
unsigned char *pen)
147+
{
148+
unsigned char buf;
149+
int err;
150+
151+
err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
152+
if (err)
153+
return err;
154+
155+
if (en)
156+
*en = !!(buf & PCF8563_BIT_AIE);
157+
if (pen)
158+
*pen = !!(buf & PCF8563_BIT_AF);
159+
160+
return 0;
161+
}
162+
163+
static irqreturn_t pcf8563_irq(int irq, void *dev_id)
164+
{
165+
struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id);
166+
int err;
167+
char pending;
168+
169+
err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
170+
if (err < 0)
171+
return err;
172+
173+
if (pending) {
174+
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
175+
pcf8563_set_alarm_mode(pcf8563->client, 1);
176+
return IRQ_HANDLED;
177+
}
178+
179+
return IRQ_NONE;
180+
}
181+
118182
/*
119183
* In the routines that deal directly with the pcf8563 hardware, we use
120184
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
@@ -257,16 +321,83 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
257321
return pcf8563_set_datetime(to_i2c_client(dev), tm);
258322
}
259323

324+
static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
325+
{
326+
struct i2c_client *client = to_i2c_client(dev);
327+
unsigned char buf[4];
328+
int err;
329+
330+
err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf);
331+
if (err)
332+
return err;
333+
334+
dev_dbg(&client->dev,
335+
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
336+
__func__, buf[0], buf[1], buf[2], buf[3]);
337+
338+
tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
339+
tm->time.tm_hour = bcd2bin(buf[1] & 0x7F);
340+
tm->time.tm_mday = bcd2bin(buf[2] & 0x1F);
341+
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
342+
tm->time.tm_mon = -1;
343+
tm->time.tm_year = -1;
344+
tm->time.tm_yday = -1;
345+
tm->time.tm_isdst = -1;
346+
347+
err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
348+
if (err < 0)
349+
return err;
350+
351+
dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
352+
" enabled=%d, pending=%d\n", __func__, tm->time.tm_min,
353+
tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
354+
tm->enabled, tm->pending);
355+
356+
return 0;
357+
}
358+
359+
static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
360+
{
361+
struct i2c_client *client = to_i2c_client(dev);
362+
unsigned char buf[4];
363+
int err;
364+
365+
dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
366+
"enabled=%d pending=%d\n", __func__,
367+
tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday,
368+
tm->time.tm_mday, tm->enabled, tm->pending);
369+
370+
buf[0] = bin2bcd(tm->time.tm_min);
371+
buf[1] = bin2bcd(tm->time.tm_hour);
372+
buf[2] = bin2bcd(tm->time.tm_mday);
373+
buf[3] = tm->time.tm_wday & 0x07;
374+
375+
err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf);
376+
if (err)
377+
return err;
378+
379+
return pcf8563_set_alarm_mode(client, 1);
380+
}
381+
382+
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
383+
{
384+
return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
385+
}
386+
260387
static const struct rtc_class_ops pcf8563_rtc_ops = {
261388
.ioctl = pcf8563_rtc_ioctl,
262389
.read_time = pcf8563_rtc_read_time,
263390
.set_time = pcf8563_rtc_set_time,
391+
.read_alarm = pcf8563_rtc_read_alarm,
392+
.set_alarm = pcf8563_rtc_set_alarm,
393+
.alarm_irq_enable = pcf8563_irq_enable,
264394
};
265395

266396
static int pcf8563_probe(struct i2c_client *client,
267397
const struct i2c_device_id *id)
268398
{
269399
struct pcf8563 *pcf8563;
400+
int err;
270401

271402
dev_dbg(&client->dev, "%s\n", __func__);
272403

@@ -281,12 +412,30 @@ static int pcf8563_probe(struct i2c_client *client,
281412
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
282413

283414
i2c_set_clientdata(client, pcf8563);
415+
pcf8563->client = client;
416+
device_set_wakeup_capable(&client->dev, 1);
284417

285418
pcf8563->rtc = devm_rtc_device_register(&client->dev,
286419
pcf8563_driver.driver.name,
287420
&pcf8563_rtc_ops, THIS_MODULE);
288421

289-
return PTR_ERR_OR_ZERO(pcf8563->rtc);
422+
if (IS_ERR(pcf8563->rtc))
423+
return PTR_ERR(pcf8563->rtc);
424+
425+
if (client->irq > 0) {
426+
err = devm_request_threaded_irq(&client->dev, client->irq,
427+
NULL, pcf8563_irq,
428+
IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
429+
pcf8563->rtc->name, client);
430+
if (err) {
431+
dev_err(&client->dev, "unable to request IRQ %d\n",
432+
client->irq);
433+
return err;
434+
}
435+
436+
}
437+
438+
return 0;
290439
}
291440

292441
static const struct i2c_device_id pcf8563_id[] = {

0 commit comments

Comments
 (0)