1a9687aa2SEric Nelson /* 2a9687aa2SEric Nelson * drivers/rtc/rtc-pcf85363.c 3a9687aa2SEric Nelson * 4a9687aa2SEric Nelson * Driver for NXP PCF85363 real-time clock. 5a9687aa2SEric Nelson * 6a9687aa2SEric Nelson * Copyright (C) 2017 Eric Nelson 7a9687aa2SEric Nelson * 8a9687aa2SEric Nelson * This program is free software; you can redistribute it and/or modify 9a9687aa2SEric Nelson * it under the terms of the GNU General Public License version 2 as 10a9687aa2SEric Nelson * published by the Free Software Foundation. 11a9687aa2SEric Nelson * 12a9687aa2SEric Nelson * Based loosely on rtc-8583 by Russell King, Wolfram Sang and Juergen Beisert 13a9687aa2SEric Nelson */ 14a9687aa2SEric Nelson #include <linux/module.h> 15a9687aa2SEric Nelson #include <linux/i2c.h> 16a9687aa2SEric Nelson #include <linux/slab.h> 17a9687aa2SEric Nelson #include <linux/rtc.h> 18a9687aa2SEric Nelson #include <linux/init.h> 19a9687aa2SEric Nelson #include <linux/err.h> 20a9687aa2SEric Nelson #include <linux/errno.h> 21a9687aa2SEric Nelson #include <linux/bcd.h> 22a9687aa2SEric Nelson #include <linux/of.h> 23a9687aa2SEric Nelson #include <linux/of_device.h> 24a9687aa2SEric Nelson #include <linux/regmap.h> 25a9687aa2SEric Nelson 26a9687aa2SEric Nelson /* 27a9687aa2SEric Nelson * Date/Time registers 28a9687aa2SEric Nelson */ 29a9687aa2SEric Nelson #define DT_100THS 0x00 30a9687aa2SEric Nelson #define DT_SECS 0x01 31a9687aa2SEric Nelson #define DT_MINUTES 0x02 32a9687aa2SEric Nelson #define DT_HOURS 0x03 33a9687aa2SEric Nelson #define DT_DAYS 0x04 34a9687aa2SEric Nelson #define DT_WEEKDAYS 0x05 35a9687aa2SEric Nelson #define DT_MONTHS 0x06 36a9687aa2SEric Nelson #define DT_YEARS 0x07 37a9687aa2SEric Nelson 38a9687aa2SEric Nelson /* 39a9687aa2SEric Nelson * Alarm registers 40a9687aa2SEric Nelson */ 41a9687aa2SEric Nelson #define DT_SECOND_ALM1 0x08 42a9687aa2SEric Nelson #define DT_MINUTE_ALM1 0x09 43a9687aa2SEric Nelson #define DT_HOUR_ALM1 0x0a 44a9687aa2SEric Nelson #define DT_DAY_ALM1 0x0b 45a9687aa2SEric Nelson #define DT_MONTH_ALM1 0x0c 46a9687aa2SEric Nelson #define DT_MINUTE_ALM2 0x0d 47a9687aa2SEric Nelson #define DT_HOUR_ALM2 0x0e 48a9687aa2SEric Nelson #define DT_WEEKDAY_ALM2 0x0f 49a9687aa2SEric Nelson #define DT_ALARM_EN 0x10 50a9687aa2SEric Nelson 51a9687aa2SEric Nelson /* 52a9687aa2SEric Nelson * Time stamp registers 53a9687aa2SEric Nelson */ 54a9687aa2SEric Nelson #define DT_TIMESTAMP1 0x11 55a9687aa2SEric Nelson #define DT_TIMESTAMP2 0x17 56a9687aa2SEric Nelson #define DT_TIMESTAMP3 0x1d 57a9687aa2SEric Nelson #define DT_TS_MODE 0x23 58a9687aa2SEric Nelson 59a9687aa2SEric Nelson /* 60a9687aa2SEric Nelson * control registers 61a9687aa2SEric Nelson */ 62a9687aa2SEric Nelson #define CTRL_OFFSET 0x24 63a9687aa2SEric Nelson #define CTRL_OSCILLATOR 0x25 64a9687aa2SEric Nelson #define CTRL_BATTERY 0x26 65a9687aa2SEric Nelson #define CTRL_PIN_IO 0x27 66a9687aa2SEric Nelson #define CTRL_FUNCTION 0x28 67a9687aa2SEric Nelson #define CTRL_INTA_EN 0x29 68a9687aa2SEric Nelson #define CTRL_INTB_EN 0x2a 69a9687aa2SEric Nelson #define CTRL_FLAGS 0x2b 70a9687aa2SEric Nelson #define CTRL_RAMBYTE 0x2c 71a9687aa2SEric Nelson #define CTRL_WDOG 0x2d 72a9687aa2SEric Nelson #define CTRL_STOP_EN 0x2e 73a9687aa2SEric Nelson #define CTRL_RESETS 0x2f 74a9687aa2SEric Nelson #define CTRL_RAM 0x40 75a9687aa2SEric Nelson 76e5aac267SAlexandre Belloni #define ALRM_SEC_A1E BIT(0) 77e5aac267SAlexandre Belloni #define ALRM_MIN_A1E BIT(1) 78e5aac267SAlexandre Belloni #define ALRM_HR_A1E BIT(2) 79e5aac267SAlexandre Belloni #define ALRM_DAY_A1E BIT(3) 80e5aac267SAlexandre Belloni #define ALRM_MON_A1E BIT(4) 81e5aac267SAlexandre Belloni #define ALRM_MIN_A2E BIT(5) 82e5aac267SAlexandre Belloni #define ALRM_HR_A2E BIT(6) 83e5aac267SAlexandre Belloni #define ALRM_DAY_A2E BIT(7) 84e5aac267SAlexandre Belloni 85e5aac267SAlexandre Belloni #define INT_WDIE BIT(0) 86e5aac267SAlexandre Belloni #define INT_BSIE BIT(1) 87e5aac267SAlexandre Belloni #define INT_TSRIE BIT(2) 88e5aac267SAlexandre Belloni #define INT_A2IE BIT(3) 89e5aac267SAlexandre Belloni #define INT_A1IE BIT(4) 90e5aac267SAlexandre Belloni #define INT_OIE BIT(5) 91e5aac267SAlexandre Belloni #define INT_PIE BIT(6) 92e5aac267SAlexandre Belloni #define INT_ILP BIT(7) 93e5aac267SAlexandre Belloni 94e5aac267SAlexandre Belloni #define FLAGS_TSR1F BIT(0) 95e5aac267SAlexandre Belloni #define FLAGS_TSR2F BIT(1) 96e5aac267SAlexandre Belloni #define FLAGS_TSR3F BIT(2) 97e5aac267SAlexandre Belloni #define FLAGS_BSF BIT(3) 98e5aac267SAlexandre Belloni #define FLAGS_WDF BIT(4) 99e5aac267SAlexandre Belloni #define FLAGS_A1F BIT(5) 100e5aac267SAlexandre Belloni #define FLAGS_A2F BIT(6) 101e5aac267SAlexandre Belloni #define FLAGS_PIF BIT(7) 102e5aac267SAlexandre Belloni 103e5aac267SAlexandre Belloni #define PIN_IO_INTAPM GENMASK(1, 0) 104e5aac267SAlexandre Belloni #define PIN_IO_INTA_CLK 0 105e5aac267SAlexandre Belloni #define PIN_IO_INTA_BAT 1 106e5aac267SAlexandre Belloni #define PIN_IO_INTA_OUT 2 107e5aac267SAlexandre Belloni #define PIN_IO_INTA_HIZ 3 108e5aac267SAlexandre Belloni 109*188306acSAlexandre Belloni #define STOP_EN_STOP BIT(0) 110*188306acSAlexandre Belloni 111*188306acSAlexandre Belloni #define RESET_CPR 0xa4 112*188306acSAlexandre Belloni 113a9687aa2SEric Nelson #define NVRAM_SIZE 0x40 114a9687aa2SEric Nelson 115a9687aa2SEric Nelson static struct i2c_driver pcf85363_driver; 116a9687aa2SEric Nelson 117a9687aa2SEric Nelson struct pcf85363 { 118a9687aa2SEric Nelson struct device *dev; 119a9687aa2SEric Nelson struct rtc_device *rtc; 120a9687aa2SEric Nelson struct regmap *regmap; 121a9687aa2SEric Nelson }; 122a9687aa2SEric Nelson 123a9687aa2SEric Nelson static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) 124a9687aa2SEric Nelson { 125a9687aa2SEric Nelson struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 126a9687aa2SEric Nelson unsigned char buf[DT_YEARS + 1]; 127a9687aa2SEric Nelson int ret, len = sizeof(buf); 128a9687aa2SEric Nelson 129a9687aa2SEric Nelson /* read the RTC date and time registers all at once */ 130a9687aa2SEric Nelson ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len); 131a9687aa2SEric Nelson if (ret) { 132a9687aa2SEric Nelson dev_err(dev, "%s: error %d\n", __func__, ret); 133a9687aa2SEric Nelson return ret; 134a9687aa2SEric Nelson } 135a9687aa2SEric Nelson 136a9687aa2SEric Nelson tm->tm_year = bcd2bin(buf[DT_YEARS]); 137a9687aa2SEric Nelson /* adjust for 1900 base of rtc_time */ 138a9687aa2SEric Nelson tm->tm_year += 100; 139a9687aa2SEric Nelson 140a9687aa2SEric Nelson tm->tm_wday = buf[DT_WEEKDAYS] & 7; 141a9687aa2SEric Nelson buf[DT_SECS] &= 0x7F; 142a9687aa2SEric Nelson tm->tm_sec = bcd2bin(buf[DT_SECS]); 143a9687aa2SEric Nelson buf[DT_MINUTES] &= 0x7F; 144a9687aa2SEric Nelson tm->tm_min = bcd2bin(buf[DT_MINUTES]); 145a9687aa2SEric Nelson tm->tm_hour = bcd2bin(buf[DT_HOURS]); 146a9687aa2SEric Nelson tm->tm_mday = bcd2bin(buf[DT_DAYS]); 147a9687aa2SEric Nelson tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1; 148a9687aa2SEric Nelson 149a9687aa2SEric Nelson return 0; 150a9687aa2SEric Nelson } 151a9687aa2SEric Nelson 152a9687aa2SEric Nelson static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm) 153a9687aa2SEric Nelson { 154a9687aa2SEric Nelson struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 155*188306acSAlexandre Belloni unsigned char tmp[11]; 156*188306acSAlexandre Belloni unsigned char *buf = &tmp[2]; 157*188306acSAlexandre Belloni int ret; 158*188306acSAlexandre Belloni 159*188306acSAlexandre Belloni tmp[0] = STOP_EN_STOP; 160*188306acSAlexandre Belloni tmp[1] = RESET_CPR; 161a9687aa2SEric Nelson 162a9687aa2SEric Nelson buf[DT_100THS] = 0; 163a9687aa2SEric Nelson buf[DT_SECS] = bin2bcd(tm->tm_sec); 164a9687aa2SEric Nelson buf[DT_MINUTES] = bin2bcd(tm->tm_min); 165a9687aa2SEric Nelson buf[DT_HOURS] = bin2bcd(tm->tm_hour); 166a9687aa2SEric Nelson buf[DT_DAYS] = bin2bcd(tm->tm_mday); 167a9687aa2SEric Nelson buf[DT_WEEKDAYS] = tm->tm_wday; 168a9687aa2SEric Nelson buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1); 169a9687aa2SEric Nelson buf[DT_YEARS] = bin2bcd(tm->tm_year % 100); 170a9687aa2SEric Nelson 171*188306acSAlexandre Belloni ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN, 172*188306acSAlexandre Belloni tmp, sizeof(tmp)); 173*188306acSAlexandre Belloni if (ret) 174*188306acSAlexandre Belloni return ret; 175*188306acSAlexandre Belloni 176*188306acSAlexandre Belloni return regmap_write(pcf85363->regmap, CTRL_STOP_EN, 0); 177a9687aa2SEric Nelson } 178a9687aa2SEric Nelson 179e5aac267SAlexandre Belloni static int pcf85363_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 180e5aac267SAlexandre Belloni { 181e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 182e5aac267SAlexandre Belloni unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; 183e5aac267SAlexandre Belloni unsigned int val; 184e5aac267SAlexandre Belloni int ret; 185e5aac267SAlexandre Belloni 186e5aac267SAlexandre Belloni ret = regmap_bulk_read(pcf85363->regmap, DT_SECOND_ALM1, buf, 187e5aac267SAlexandre Belloni sizeof(buf)); 188e5aac267SAlexandre Belloni if (ret) 189e5aac267SAlexandre Belloni return ret; 190e5aac267SAlexandre Belloni 191e5aac267SAlexandre Belloni alrm->time.tm_sec = bcd2bin(buf[0]); 192e5aac267SAlexandre Belloni alrm->time.tm_min = bcd2bin(buf[1]); 193e5aac267SAlexandre Belloni alrm->time.tm_hour = bcd2bin(buf[2]); 194e5aac267SAlexandre Belloni alrm->time.tm_mday = bcd2bin(buf[3]); 195e5aac267SAlexandre Belloni alrm->time.tm_mon = bcd2bin(buf[4]) - 1; 196e5aac267SAlexandre Belloni 197e5aac267SAlexandre Belloni ret = regmap_read(pcf85363->regmap, CTRL_INTA_EN, &val); 198e5aac267SAlexandre Belloni if (ret) 199e5aac267SAlexandre Belloni return ret; 200e5aac267SAlexandre Belloni 201e5aac267SAlexandre Belloni alrm->enabled = !!(val & INT_A1IE); 202e5aac267SAlexandre Belloni 203e5aac267SAlexandre Belloni return 0; 204e5aac267SAlexandre Belloni } 205e5aac267SAlexandre Belloni 206e5aac267SAlexandre Belloni static int _pcf85363_rtc_alarm_irq_enable(struct pcf85363 *pcf85363, unsigned 207e5aac267SAlexandre Belloni int enabled) 208e5aac267SAlexandre Belloni { 209e5aac267SAlexandre Belloni unsigned int alarm_flags = ALRM_SEC_A1E | ALRM_MIN_A1E | ALRM_HR_A1E | 210e5aac267SAlexandre Belloni ALRM_DAY_A1E | ALRM_MON_A1E; 211e5aac267SAlexandre Belloni int ret; 212e5aac267SAlexandre Belloni 213e5aac267SAlexandre Belloni ret = regmap_update_bits(pcf85363->regmap, DT_ALARM_EN, alarm_flags, 214e5aac267SAlexandre Belloni enabled ? alarm_flags : 0); 215e5aac267SAlexandre Belloni if (ret) 216e5aac267SAlexandre Belloni return ret; 217e5aac267SAlexandre Belloni 218e5aac267SAlexandre Belloni ret = regmap_update_bits(pcf85363->regmap, CTRL_INTA_EN, 219e5aac267SAlexandre Belloni INT_A1IE, enabled ? INT_A1IE : 0); 220e5aac267SAlexandre Belloni 221e5aac267SAlexandre Belloni if (ret || enabled) 222e5aac267SAlexandre Belloni return ret; 223e5aac267SAlexandre Belloni 224e5aac267SAlexandre Belloni /* clear current flags */ 225e5aac267SAlexandre Belloni return regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0); 226e5aac267SAlexandre Belloni } 227e5aac267SAlexandre Belloni 228e5aac267SAlexandre Belloni static int pcf85363_rtc_alarm_irq_enable(struct device *dev, 229e5aac267SAlexandre Belloni unsigned int enabled) 230e5aac267SAlexandre Belloni { 231e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 232e5aac267SAlexandre Belloni 233e5aac267SAlexandre Belloni return _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled); 234e5aac267SAlexandre Belloni } 235e5aac267SAlexandre Belloni 236e5aac267SAlexandre Belloni static int pcf85363_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 237e5aac267SAlexandre Belloni { 238e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 239e5aac267SAlexandre Belloni unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; 240e5aac267SAlexandre Belloni int ret; 241e5aac267SAlexandre Belloni 242e5aac267SAlexandre Belloni buf[0] = bin2bcd(alrm->time.tm_sec); 243e5aac267SAlexandre Belloni buf[1] = bin2bcd(alrm->time.tm_min); 244e5aac267SAlexandre Belloni buf[2] = bin2bcd(alrm->time.tm_hour); 245e5aac267SAlexandre Belloni buf[3] = bin2bcd(alrm->time.tm_mday); 246e5aac267SAlexandre Belloni buf[4] = bin2bcd(alrm->time.tm_mon + 1); 247e5aac267SAlexandre Belloni 248e5aac267SAlexandre Belloni /* 249e5aac267SAlexandre Belloni * Disable the alarm interrupt before changing the value to avoid 250e5aac267SAlexandre Belloni * spurious interrupts 251e5aac267SAlexandre Belloni */ 252e5aac267SAlexandre Belloni ret = _pcf85363_rtc_alarm_irq_enable(pcf85363, 0); 253e5aac267SAlexandre Belloni if (ret) 254e5aac267SAlexandre Belloni return ret; 255e5aac267SAlexandre Belloni 256e5aac267SAlexandre Belloni ret = regmap_bulk_write(pcf85363->regmap, DT_SECOND_ALM1, buf, 257e5aac267SAlexandre Belloni sizeof(buf)); 258e5aac267SAlexandre Belloni if (ret) 259e5aac267SAlexandre Belloni return ret; 260e5aac267SAlexandre Belloni 261e5aac267SAlexandre Belloni return _pcf85363_rtc_alarm_irq_enable(pcf85363, alrm->enabled); 262e5aac267SAlexandre Belloni } 263e5aac267SAlexandre Belloni 264e5aac267SAlexandre Belloni static irqreturn_t pcf85363_rtc_handle_irq(int irq, void *dev_id) 265e5aac267SAlexandre Belloni { 266e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = i2c_get_clientdata(dev_id); 267e5aac267SAlexandre Belloni unsigned int flags; 268e5aac267SAlexandre Belloni int err; 269e5aac267SAlexandre Belloni 270e5aac267SAlexandre Belloni err = regmap_read(pcf85363->regmap, CTRL_FLAGS, &flags); 271e5aac267SAlexandre Belloni if (err) 272e5aac267SAlexandre Belloni return IRQ_NONE; 273e5aac267SAlexandre Belloni 274e5aac267SAlexandre Belloni if (flags & FLAGS_A1F) { 275e5aac267SAlexandre Belloni rtc_update_irq(pcf85363->rtc, 1, RTC_IRQF | RTC_AF); 276e5aac267SAlexandre Belloni regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0); 277e5aac267SAlexandre Belloni return IRQ_HANDLED; 278e5aac267SAlexandre Belloni } 279e5aac267SAlexandre Belloni 280e5aac267SAlexandre Belloni return IRQ_NONE; 281e5aac267SAlexandre Belloni } 282e5aac267SAlexandre Belloni 283a9687aa2SEric Nelson static const struct rtc_class_ops rtc_ops = { 284a9687aa2SEric Nelson .read_time = pcf85363_rtc_read_time, 285a9687aa2SEric Nelson .set_time = pcf85363_rtc_set_time, 286a9687aa2SEric Nelson }; 287a9687aa2SEric Nelson 288e5aac267SAlexandre Belloni static const struct rtc_class_ops rtc_ops_alarm = { 289e5aac267SAlexandre Belloni .read_time = pcf85363_rtc_read_time, 290e5aac267SAlexandre Belloni .set_time = pcf85363_rtc_set_time, 291e5aac267SAlexandre Belloni .read_alarm = pcf85363_rtc_read_alarm, 292e5aac267SAlexandre Belloni .set_alarm = pcf85363_rtc_set_alarm, 293e5aac267SAlexandre Belloni .alarm_irq_enable = pcf85363_rtc_alarm_irq_enable, 294e5aac267SAlexandre Belloni }; 295e5aac267SAlexandre Belloni 296a9687aa2SEric Nelson static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val, 297a9687aa2SEric Nelson size_t bytes) 298a9687aa2SEric Nelson { 299a9687aa2SEric Nelson struct pcf85363 *pcf85363 = priv; 300a9687aa2SEric Nelson 301a9687aa2SEric Nelson return regmap_bulk_read(pcf85363->regmap, CTRL_RAM + offset, 302a9687aa2SEric Nelson val, bytes); 303a9687aa2SEric Nelson } 304a9687aa2SEric Nelson 305a9687aa2SEric Nelson static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val, 306a9687aa2SEric Nelson size_t bytes) 307a9687aa2SEric Nelson { 308a9687aa2SEric Nelson struct pcf85363 *pcf85363 = priv; 309a9687aa2SEric Nelson 310a9687aa2SEric Nelson return regmap_bulk_write(pcf85363->regmap, CTRL_RAM + offset, 311a9687aa2SEric Nelson val, bytes); 312a9687aa2SEric Nelson } 313a9687aa2SEric Nelson 314a9687aa2SEric Nelson static const struct regmap_config regmap_config = { 315a9687aa2SEric Nelson .reg_bits = 8, 316a9687aa2SEric Nelson .val_bits = 8, 317c57849ddSAlexandre Belloni .max_register = 0x7f, 318a9687aa2SEric Nelson }; 319a9687aa2SEric Nelson 320a9687aa2SEric Nelson static int pcf85363_probe(struct i2c_client *client, 321a9687aa2SEric Nelson const struct i2c_device_id *id) 322a9687aa2SEric Nelson { 323a9687aa2SEric Nelson struct pcf85363 *pcf85363; 3240e7a412fSAlexandre Belloni struct nvmem_config nvmem_cfg = { 3250e7a412fSAlexandre Belloni .name = "pcf85363-", 3260e7a412fSAlexandre Belloni .word_size = 1, 3270e7a412fSAlexandre Belloni .stride = 1, 3280e7a412fSAlexandre Belloni .size = NVRAM_SIZE, 3290e7a412fSAlexandre Belloni .reg_read = pcf85363_nvram_read, 3300e7a412fSAlexandre Belloni .reg_write = pcf85363_nvram_write, 3310e7a412fSAlexandre Belloni }; 33224849d17SAlexandre Belloni int ret; 333a9687aa2SEric Nelson 334a9687aa2SEric Nelson if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 335a9687aa2SEric Nelson return -ENODEV; 336a9687aa2SEric Nelson 337a9687aa2SEric Nelson pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363), 338a9687aa2SEric Nelson GFP_KERNEL); 339a9687aa2SEric Nelson if (!pcf85363) 340a9687aa2SEric Nelson return -ENOMEM; 341a9687aa2SEric Nelson 342a9687aa2SEric Nelson pcf85363->regmap = devm_regmap_init_i2c(client, ®map_config); 343a9687aa2SEric Nelson if (IS_ERR(pcf85363->regmap)) { 344a9687aa2SEric Nelson dev_err(&client->dev, "regmap allocation failed\n"); 345a9687aa2SEric Nelson return PTR_ERR(pcf85363->regmap); 346a9687aa2SEric Nelson } 347a9687aa2SEric Nelson 348a9687aa2SEric Nelson pcf85363->dev = &client->dev; 349a9687aa2SEric Nelson i2c_set_clientdata(client, pcf85363); 350a9687aa2SEric Nelson 351a9687aa2SEric Nelson pcf85363->rtc = devm_rtc_allocate_device(pcf85363->dev); 352a9687aa2SEric Nelson if (IS_ERR(pcf85363->rtc)) 353a9687aa2SEric Nelson return PTR_ERR(pcf85363->rtc); 354a9687aa2SEric Nelson 355a9687aa2SEric Nelson pcf85363->rtc->ops = &rtc_ops; 356a9687aa2SEric Nelson 357e5aac267SAlexandre Belloni if (client->irq > 0) { 358e5aac267SAlexandre Belloni regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); 359e5aac267SAlexandre Belloni regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, 360e5aac267SAlexandre Belloni PIN_IO_INTA_OUT, PIN_IO_INTAPM); 361e5aac267SAlexandre Belloni ret = devm_request_threaded_irq(pcf85363->dev, client->irq, 362e5aac267SAlexandre Belloni NULL, pcf85363_rtc_handle_irq, 363e5aac267SAlexandre Belloni IRQF_TRIGGER_LOW | IRQF_ONESHOT, 364e5aac267SAlexandre Belloni "pcf85363", client); 365e5aac267SAlexandre Belloni if (ret) 366e5aac267SAlexandre Belloni dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); 367e5aac267SAlexandre Belloni else 368e5aac267SAlexandre Belloni pcf85363->rtc->ops = &rtc_ops_alarm; 369e5aac267SAlexandre Belloni } 370e5aac267SAlexandre Belloni 37124849d17SAlexandre Belloni ret = rtc_register_device(pcf85363->rtc); 37224849d17SAlexandre Belloni 3730e7a412fSAlexandre Belloni nvmem_cfg.priv = pcf85363; 3740e7a412fSAlexandre Belloni rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg); 37524849d17SAlexandre Belloni 37624849d17SAlexandre Belloni return ret; 377a9687aa2SEric Nelson } 378a9687aa2SEric Nelson 379a9687aa2SEric Nelson static const struct of_device_id dev_ids[] = { 380a9687aa2SEric Nelson { .compatible = "nxp,pcf85363" }, 381a9687aa2SEric Nelson {} 382a9687aa2SEric Nelson }; 383a9687aa2SEric Nelson MODULE_DEVICE_TABLE(of, dev_ids); 384a9687aa2SEric Nelson 385a9687aa2SEric Nelson static struct i2c_driver pcf85363_driver = { 386a9687aa2SEric Nelson .driver = { 387a9687aa2SEric Nelson .name = "pcf85363", 388a9687aa2SEric Nelson .of_match_table = of_match_ptr(dev_ids), 389a9687aa2SEric Nelson }, 390a9687aa2SEric Nelson .probe = pcf85363_probe, 391a9687aa2SEric Nelson }; 392a9687aa2SEric Nelson 393a9687aa2SEric Nelson module_i2c_driver(pcf85363_driver); 394a9687aa2SEric Nelson 395a9687aa2SEric Nelson MODULE_AUTHOR("Eric Nelson"); 396a9687aa2SEric Nelson MODULE_DESCRIPTION("pcf85363 I2C RTC driver"); 397a9687aa2SEric Nelson MODULE_LICENSE("GPL"); 398