Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/rtc/rtc-pcf8563.c: add alarm support

This patch adds alarm support for the NXP PCF8563 chip.

Signed-off-by: Vincent Donnefort <vdonnefort@gmail.com>
Cc: Simon Guinot <simon.guinot@sequanux.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vincent Donnefort and committed by
Linus Torvalds
ede3e9d4 2784366c

+153 -4
+153 -4
drivers/rtc/rtc-pcf8563.c
··· 26 26 27 27 #define PCF8563_REG_ST1 0x00 /* status */ 28 28 #define PCF8563_REG_ST2 0x01 29 + #define PCF8563_BIT_AIE (1 << 1) 30 + #define PCF8563_BIT_AF (1 << 3) 29 31 30 32 #define PCF8563_REG_SC 0x02 /* datetime */ 31 33 #define PCF8563_REG_MN 0x03 ··· 38 36 #define PCF8563_REG_YR 0x08 39 37 40 38 #define PCF8563_REG_AMN 0x09 /* alarm */ 41 - #define PCF8563_REG_AHR 0x0A 42 - #define PCF8563_REG_ADM 0x0B 43 - #define PCF8563_REG_ADW 0x0C 44 39 45 40 #define PCF8563_REG_CLKO 0x0D /* clock out */ 46 41 #define PCF8563_REG_TMRC 0x0E /* timer control */ ··· 66 67 */ 67 68 int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ 68 69 int voltage_low; /* incicates if a low_voltage was detected */ 70 + 71 + struct i2c_client *client; 69 72 }; 70 73 71 74 static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, ··· 114 113 } 115 114 116 115 return 0; 116 + } 117 + 118 + static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) 119 + { 120 + unsigned char buf[2]; 121 + int err; 122 + 123 + err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1); 124 + if (err < 0) 125 + return err; 126 + 127 + if (on) 128 + buf[1] |= PCF8563_BIT_AIE; 129 + else 130 + buf[1] &= ~PCF8563_BIT_AIE; 131 + 132 + buf[1] &= ~PCF8563_BIT_AF; 133 + buf[0] = PCF8563_REG_ST2; 134 + 135 + err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1); 136 + if (err < 0) { 137 + dev_err(&client->dev, "%s: write error\n", __func__); 138 + return -EIO; 139 + } 140 + 141 + return 0; 142 + } 143 + 144 + static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, 145 + unsigned char *pen) 146 + { 147 + unsigned char buf; 148 + int err; 149 + 150 + err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); 151 + if (err) 152 + return err; 153 + 154 + if (en) 155 + *en = !!(buf & PCF8563_BIT_AIE); 156 + if (pen) 157 + *pen = !!(buf & PCF8563_BIT_AF); 158 + 159 + return 0; 160 + } 161 + 162 + static irqreturn_t pcf8563_irq(int irq, void *dev_id) 163 + { 164 + struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id); 165 + int err; 166 + char pending; 167 + 168 + err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending); 169 + if (err < 0) 170 + return err; 171 + 172 + if (pending) { 173 + rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF); 174 + pcf8563_set_alarm_mode(pcf8563->client, 1); 175 + return IRQ_HANDLED; 176 + } 177 + 178 + return IRQ_NONE; 117 179 } 118 180 119 181 /* ··· 321 257 return pcf8563_set_datetime(to_i2c_client(dev), tm); 322 258 } 323 259 260 + static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) 261 + { 262 + struct i2c_client *client = to_i2c_client(dev); 263 + unsigned char buf[4]; 264 + int err; 265 + 266 + err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf); 267 + if (err) 268 + return err; 269 + 270 + dev_dbg(&client->dev, 271 + "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n", 272 + __func__, buf[0], buf[1], buf[2], buf[3]); 273 + 274 + tm->time.tm_min = bcd2bin(buf[0] & 0x7F); 275 + tm->time.tm_hour = bcd2bin(buf[1] & 0x7F); 276 + tm->time.tm_mday = bcd2bin(buf[2] & 0x1F); 277 + tm->time.tm_wday = bcd2bin(buf[3] & 0x7); 278 + tm->time.tm_mon = -1; 279 + tm->time.tm_year = -1; 280 + tm->time.tm_yday = -1; 281 + tm->time.tm_isdst = -1; 282 + 283 + err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending); 284 + if (err < 0) 285 + return err; 286 + 287 + dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," 288 + " enabled=%d, pending=%d\n", __func__, tm->time.tm_min, 289 + tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday, 290 + tm->enabled, tm->pending); 291 + 292 + return 0; 293 + } 294 + 295 + static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) 296 + { 297 + struct i2c_client *client = to_i2c_client(dev); 298 + unsigned char buf[4]; 299 + int err; 300 + 301 + dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " 302 + "enabled=%d pending=%d\n", __func__, 303 + tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday, 304 + tm->time.tm_mday, tm->enabled, tm->pending); 305 + 306 + buf[0] = bin2bcd(tm->time.tm_min); 307 + buf[1] = bin2bcd(tm->time.tm_hour); 308 + buf[2] = bin2bcd(tm->time.tm_mday); 309 + buf[3] = tm->time.tm_wday & 0x07; 310 + 311 + err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf); 312 + if (err) 313 + return err; 314 + 315 + return pcf8563_set_alarm_mode(client, 1); 316 + } 317 + 318 + static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) 319 + { 320 + return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); 321 + } 322 + 324 323 static const struct rtc_class_ops pcf8563_rtc_ops = { 325 324 .ioctl = pcf8563_rtc_ioctl, 326 325 .read_time = pcf8563_rtc_read_time, 327 326 .set_time = pcf8563_rtc_set_time, 327 + .read_alarm = pcf8563_rtc_read_alarm, 328 + .set_alarm = pcf8563_rtc_set_alarm, 329 + .alarm_irq_enable = pcf8563_irq_enable, 328 330 }; 329 331 330 332 static int pcf8563_probe(struct i2c_client *client, 331 333 const struct i2c_device_id *id) 332 334 { 333 335 struct pcf8563 *pcf8563; 336 + int err; 334 337 335 338 dev_dbg(&client->dev, "%s\n", __func__); 336 339 ··· 412 281 dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); 413 282 414 283 i2c_set_clientdata(client, pcf8563); 284 + pcf8563->client = client; 285 + device_set_wakeup_capable(&client->dev, 1); 415 286 416 287 pcf8563->rtc = devm_rtc_device_register(&client->dev, 417 288 pcf8563_driver.driver.name, 418 289 &pcf8563_rtc_ops, THIS_MODULE); 419 290 420 - return PTR_ERR_OR_ZERO(pcf8563->rtc); 291 + if (IS_ERR(pcf8563->rtc)) 292 + return PTR_ERR(pcf8563->rtc); 293 + 294 + if (client->irq > 0) { 295 + err = devm_request_threaded_irq(&client->dev, client->irq, 296 + NULL, pcf8563_irq, 297 + IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, 298 + pcf8563->rtc->name, client); 299 + if (err) { 300 + dev_err(&client->dev, "unable to request IRQ %d\n", 301 + client->irq); 302 + return err; 303 + } 304 + 305 + } 306 + 307 + return 0; 421 308 } 422 309 423 310 static const struct i2c_device_id pcf8563_id[] = {