156573ca7SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0 2a9687aa2SEric Nelson /* 3a9687aa2SEric Nelson * drivers/rtc/rtc-pcf85363.c 4a9687aa2SEric Nelson * 5a9687aa2SEric Nelson * Driver for NXP PCF85363 real-time clock. 6a9687aa2SEric Nelson * 7a9687aa2SEric Nelson * Copyright (C) 2017 Eric Nelson 8a9687aa2SEric Nelson */ 9a9687aa2SEric Nelson #include <linux/module.h> 10a9687aa2SEric Nelson #include <linux/i2c.h> 11a9687aa2SEric Nelson #include <linux/slab.h> 12a9687aa2SEric Nelson #include <linux/rtc.h> 13a9687aa2SEric Nelson #include <linux/init.h> 14a9687aa2SEric Nelson #include <linux/err.h> 15a9687aa2SEric Nelson #include <linux/errno.h> 16a9687aa2SEric Nelson #include <linux/bcd.h> 17a9687aa2SEric Nelson #include <linux/of.h> 18a9687aa2SEric Nelson #include <linux/of_device.h> 19a9687aa2SEric Nelson #include <linux/regmap.h> 20a9687aa2SEric Nelson 21a9687aa2SEric Nelson /* 22a9687aa2SEric Nelson * Date/Time registers 23a9687aa2SEric Nelson */ 24a9687aa2SEric Nelson #define DT_100THS 0x00 25a9687aa2SEric Nelson #define DT_SECS 0x01 26a9687aa2SEric Nelson #define DT_MINUTES 0x02 27a9687aa2SEric Nelson #define DT_HOURS 0x03 28a9687aa2SEric Nelson #define DT_DAYS 0x04 29a9687aa2SEric Nelson #define DT_WEEKDAYS 0x05 30a9687aa2SEric Nelson #define DT_MONTHS 0x06 31a9687aa2SEric Nelson #define DT_YEARS 0x07 32a9687aa2SEric Nelson 33a9687aa2SEric Nelson /* 34a9687aa2SEric Nelson * Alarm registers 35a9687aa2SEric Nelson */ 36a9687aa2SEric Nelson #define DT_SECOND_ALM1 0x08 37a9687aa2SEric Nelson #define DT_MINUTE_ALM1 0x09 38a9687aa2SEric Nelson #define DT_HOUR_ALM1 0x0a 39a9687aa2SEric Nelson #define DT_DAY_ALM1 0x0b 40a9687aa2SEric Nelson #define DT_MONTH_ALM1 0x0c 41a9687aa2SEric Nelson #define DT_MINUTE_ALM2 0x0d 42a9687aa2SEric Nelson #define DT_HOUR_ALM2 0x0e 43a9687aa2SEric Nelson #define DT_WEEKDAY_ALM2 0x0f 44a9687aa2SEric Nelson #define DT_ALARM_EN 0x10 45a9687aa2SEric Nelson 46a9687aa2SEric Nelson /* 47a9687aa2SEric Nelson * Time stamp registers 48a9687aa2SEric Nelson */ 49a9687aa2SEric Nelson #define DT_TIMESTAMP1 0x11 50a9687aa2SEric Nelson #define DT_TIMESTAMP2 0x17 51a9687aa2SEric Nelson #define DT_TIMESTAMP3 0x1d 52a9687aa2SEric Nelson #define DT_TS_MODE 0x23 53a9687aa2SEric Nelson 54a9687aa2SEric Nelson /* 55a9687aa2SEric Nelson * control registers 56a9687aa2SEric Nelson */ 57a9687aa2SEric Nelson #define CTRL_OFFSET 0x24 58a9687aa2SEric Nelson #define CTRL_OSCILLATOR 0x25 59a9687aa2SEric Nelson #define CTRL_BATTERY 0x26 60a9687aa2SEric Nelson #define CTRL_PIN_IO 0x27 61a9687aa2SEric Nelson #define CTRL_FUNCTION 0x28 62a9687aa2SEric Nelson #define CTRL_INTA_EN 0x29 63a9687aa2SEric Nelson #define CTRL_INTB_EN 0x2a 64a9687aa2SEric Nelson #define CTRL_FLAGS 0x2b 65a9687aa2SEric Nelson #define CTRL_RAMBYTE 0x2c 66a9687aa2SEric Nelson #define CTRL_WDOG 0x2d 67a9687aa2SEric Nelson #define CTRL_STOP_EN 0x2e 68a9687aa2SEric Nelson #define CTRL_RESETS 0x2f 69a9687aa2SEric Nelson #define CTRL_RAM 0x40 70a9687aa2SEric Nelson 71e5aac267SAlexandre Belloni #define ALRM_SEC_A1E BIT(0) 72e5aac267SAlexandre Belloni #define ALRM_MIN_A1E BIT(1) 73e5aac267SAlexandre Belloni #define ALRM_HR_A1E BIT(2) 74e5aac267SAlexandre Belloni #define ALRM_DAY_A1E BIT(3) 75e5aac267SAlexandre Belloni #define ALRM_MON_A1E BIT(4) 76e5aac267SAlexandre Belloni #define ALRM_MIN_A2E BIT(5) 77e5aac267SAlexandre Belloni #define ALRM_HR_A2E BIT(6) 78e5aac267SAlexandre Belloni #define ALRM_DAY_A2E BIT(7) 79e5aac267SAlexandre Belloni 80e5aac267SAlexandre Belloni #define INT_WDIE BIT(0) 81e5aac267SAlexandre Belloni #define INT_BSIE BIT(1) 82e5aac267SAlexandre Belloni #define INT_TSRIE BIT(2) 83e5aac267SAlexandre Belloni #define INT_A2IE BIT(3) 84e5aac267SAlexandre Belloni #define INT_A1IE BIT(4) 85e5aac267SAlexandre Belloni #define INT_OIE BIT(5) 86e5aac267SAlexandre Belloni #define INT_PIE BIT(6) 87e5aac267SAlexandre Belloni #define INT_ILP BIT(7) 88e5aac267SAlexandre Belloni 89e5aac267SAlexandre Belloni #define FLAGS_TSR1F BIT(0) 90e5aac267SAlexandre Belloni #define FLAGS_TSR2F BIT(1) 91e5aac267SAlexandre Belloni #define FLAGS_TSR3F BIT(2) 92e5aac267SAlexandre Belloni #define FLAGS_BSF BIT(3) 93e5aac267SAlexandre Belloni #define FLAGS_WDF BIT(4) 94e5aac267SAlexandre Belloni #define FLAGS_A1F BIT(5) 95e5aac267SAlexandre Belloni #define FLAGS_A2F BIT(6) 96e5aac267SAlexandre Belloni #define FLAGS_PIF BIT(7) 97e5aac267SAlexandre Belloni 98e5aac267SAlexandre Belloni #define PIN_IO_INTAPM GENMASK(1, 0) 99e5aac267SAlexandre Belloni #define PIN_IO_INTA_CLK 0 100e5aac267SAlexandre Belloni #define PIN_IO_INTA_BAT 1 101e5aac267SAlexandre Belloni #define PIN_IO_INTA_OUT 2 102e5aac267SAlexandre Belloni #define PIN_IO_INTA_HIZ 3 103e5aac267SAlexandre Belloni 104*fd9a6a13SJavier Carrasco #define OSC_CAP_SEL GENMASK(1, 0) 105*fd9a6a13SJavier Carrasco #define OSC_CAP_6000 0x01 106*fd9a6a13SJavier Carrasco #define OSC_CAP_12500 0x02 107*fd9a6a13SJavier Carrasco 108188306acSAlexandre Belloni #define STOP_EN_STOP BIT(0) 109188306acSAlexandre Belloni 110188306acSAlexandre Belloni #define RESET_CPR 0xa4 111188306acSAlexandre Belloni 112a9687aa2SEric Nelson #define NVRAM_SIZE 0x40 113a9687aa2SEric Nelson 114a9687aa2SEric Nelson struct pcf85363 { 115a9687aa2SEric Nelson struct rtc_device *rtc; 116a9687aa2SEric Nelson struct regmap *regmap; 117a9687aa2SEric Nelson }; 118a9687aa2SEric Nelson 119fc979933SBiju Das struct pcf85x63_config { 120fc979933SBiju Das struct regmap_config regmap; 121fc979933SBiju Das unsigned int num_nvram; 122fc979933SBiju Das }; 123fc979933SBiju Das 124*fd9a6a13SJavier Carrasco static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node) 125*fd9a6a13SJavier Carrasco { 126*fd9a6a13SJavier Carrasco u32 load = 7000; 127*fd9a6a13SJavier Carrasco u8 value = 0; 128*fd9a6a13SJavier Carrasco 129*fd9a6a13SJavier Carrasco of_property_read_u32(node, "quartz-load-femtofarads", &load); 130*fd9a6a13SJavier Carrasco 131*fd9a6a13SJavier Carrasco switch (load) { 132*fd9a6a13SJavier Carrasco default: 133*fd9a6a13SJavier Carrasco dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000", 134*fd9a6a13SJavier Carrasco load); 135*fd9a6a13SJavier Carrasco fallthrough; 136*fd9a6a13SJavier Carrasco case 7000: 137*fd9a6a13SJavier Carrasco break; 138*fd9a6a13SJavier Carrasco case 6000: 139*fd9a6a13SJavier Carrasco value = OSC_CAP_6000; 140*fd9a6a13SJavier Carrasco break; 141*fd9a6a13SJavier Carrasco case 12500: 142*fd9a6a13SJavier Carrasco value = OSC_CAP_12500; 143*fd9a6a13SJavier Carrasco break; 144*fd9a6a13SJavier Carrasco } 145*fd9a6a13SJavier Carrasco 146*fd9a6a13SJavier Carrasco return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR, 147*fd9a6a13SJavier Carrasco OSC_CAP_SEL, value); 148*fd9a6a13SJavier Carrasco } 149*fd9a6a13SJavier Carrasco 150a9687aa2SEric Nelson static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) 151a9687aa2SEric Nelson { 152a9687aa2SEric Nelson struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 153a9687aa2SEric Nelson unsigned char buf[DT_YEARS + 1]; 154a9687aa2SEric Nelson int ret, len = sizeof(buf); 155a9687aa2SEric Nelson 156a9687aa2SEric Nelson /* read the RTC date and time registers all at once */ 157a9687aa2SEric Nelson ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len); 158a9687aa2SEric Nelson if (ret) { 159a9687aa2SEric Nelson dev_err(dev, "%s: error %d\n", __func__, ret); 160a9687aa2SEric Nelson return ret; 161a9687aa2SEric Nelson } 162a9687aa2SEric Nelson 163a9687aa2SEric Nelson tm->tm_year = bcd2bin(buf[DT_YEARS]); 164a9687aa2SEric Nelson /* adjust for 1900 base of rtc_time */ 165a9687aa2SEric Nelson tm->tm_year += 100; 166a9687aa2SEric Nelson 167a9687aa2SEric Nelson tm->tm_wday = buf[DT_WEEKDAYS] & 7; 168a9687aa2SEric Nelson buf[DT_SECS] &= 0x7F; 169a9687aa2SEric Nelson tm->tm_sec = bcd2bin(buf[DT_SECS]); 170a9687aa2SEric Nelson buf[DT_MINUTES] &= 0x7F; 171a9687aa2SEric Nelson tm->tm_min = bcd2bin(buf[DT_MINUTES]); 172a9687aa2SEric Nelson tm->tm_hour = bcd2bin(buf[DT_HOURS]); 173a9687aa2SEric Nelson tm->tm_mday = bcd2bin(buf[DT_DAYS]); 174a9687aa2SEric Nelson tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1; 175a9687aa2SEric Nelson 176a9687aa2SEric Nelson return 0; 177a9687aa2SEric Nelson } 178a9687aa2SEric Nelson 179a9687aa2SEric Nelson static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm) 180a9687aa2SEric Nelson { 181a9687aa2SEric Nelson struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 182188306acSAlexandre Belloni unsigned char tmp[11]; 183188306acSAlexandre Belloni unsigned char *buf = &tmp[2]; 184188306acSAlexandre Belloni int ret; 185188306acSAlexandre Belloni 186188306acSAlexandre Belloni tmp[0] = STOP_EN_STOP; 187188306acSAlexandre Belloni tmp[1] = RESET_CPR; 188a9687aa2SEric Nelson 189a9687aa2SEric Nelson buf[DT_100THS] = 0; 190a9687aa2SEric Nelson buf[DT_SECS] = bin2bcd(tm->tm_sec); 191a9687aa2SEric Nelson buf[DT_MINUTES] = bin2bcd(tm->tm_min); 192a9687aa2SEric Nelson buf[DT_HOURS] = bin2bcd(tm->tm_hour); 193a9687aa2SEric Nelson buf[DT_DAYS] = bin2bcd(tm->tm_mday); 194a9687aa2SEric Nelson buf[DT_WEEKDAYS] = tm->tm_wday; 195a9687aa2SEric Nelson buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1); 196a9687aa2SEric Nelson buf[DT_YEARS] = bin2bcd(tm->tm_year % 100); 197a9687aa2SEric Nelson 198188306acSAlexandre Belloni ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN, 1997ef66122SBiwen Li tmp, 2); 2007ef66122SBiwen Li if (ret) 2017ef66122SBiwen Li return ret; 2027ef66122SBiwen Li 2037ef66122SBiwen Li ret = regmap_bulk_write(pcf85363->regmap, DT_100THS, 2047ef66122SBiwen Li buf, sizeof(tmp) - 2); 205188306acSAlexandre Belloni if (ret) 206188306acSAlexandre Belloni return ret; 207188306acSAlexandre Belloni 208188306acSAlexandre Belloni return regmap_write(pcf85363->regmap, CTRL_STOP_EN, 0); 209a9687aa2SEric Nelson } 210a9687aa2SEric Nelson 211e5aac267SAlexandre Belloni static int pcf85363_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 212e5aac267SAlexandre Belloni { 213e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 214e5aac267SAlexandre Belloni unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; 215e5aac267SAlexandre Belloni unsigned int val; 216e5aac267SAlexandre Belloni int ret; 217e5aac267SAlexandre Belloni 218e5aac267SAlexandre Belloni ret = regmap_bulk_read(pcf85363->regmap, DT_SECOND_ALM1, buf, 219e5aac267SAlexandre Belloni sizeof(buf)); 220e5aac267SAlexandre Belloni if (ret) 221e5aac267SAlexandre Belloni return ret; 222e5aac267SAlexandre Belloni 223e5aac267SAlexandre Belloni alrm->time.tm_sec = bcd2bin(buf[0]); 224e5aac267SAlexandre Belloni alrm->time.tm_min = bcd2bin(buf[1]); 225e5aac267SAlexandre Belloni alrm->time.tm_hour = bcd2bin(buf[2]); 226e5aac267SAlexandre Belloni alrm->time.tm_mday = bcd2bin(buf[3]); 227e5aac267SAlexandre Belloni alrm->time.tm_mon = bcd2bin(buf[4]) - 1; 228e5aac267SAlexandre Belloni 229e5aac267SAlexandre Belloni ret = regmap_read(pcf85363->regmap, CTRL_INTA_EN, &val); 230e5aac267SAlexandre Belloni if (ret) 231e5aac267SAlexandre Belloni return ret; 232e5aac267SAlexandre Belloni 233e5aac267SAlexandre Belloni alrm->enabled = !!(val & INT_A1IE); 234e5aac267SAlexandre Belloni 235e5aac267SAlexandre Belloni return 0; 236e5aac267SAlexandre Belloni } 237e5aac267SAlexandre Belloni 238e5aac267SAlexandre Belloni static int _pcf85363_rtc_alarm_irq_enable(struct pcf85363 *pcf85363, unsigned 239e5aac267SAlexandre Belloni int enabled) 240e5aac267SAlexandre Belloni { 241e5aac267SAlexandre Belloni unsigned int alarm_flags = ALRM_SEC_A1E | ALRM_MIN_A1E | ALRM_HR_A1E | 242e5aac267SAlexandre Belloni ALRM_DAY_A1E | ALRM_MON_A1E; 243e5aac267SAlexandre Belloni int ret; 244e5aac267SAlexandre Belloni 245e5aac267SAlexandre Belloni ret = regmap_update_bits(pcf85363->regmap, DT_ALARM_EN, alarm_flags, 246e5aac267SAlexandre Belloni enabled ? alarm_flags : 0); 247e5aac267SAlexandre Belloni if (ret) 248e5aac267SAlexandre Belloni return ret; 249e5aac267SAlexandre Belloni 250e5aac267SAlexandre Belloni ret = regmap_update_bits(pcf85363->regmap, CTRL_INTA_EN, 251e5aac267SAlexandre Belloni INT_A1IE, enabled ? INT_A1IE : 0); 252e5aac267SAlexandre Belloni 253e5aac267SAlexandre Belloni if (ret || enabled) 254e5aac267SAlexandre Belloni return ret; 255e5aac267SAlexandre Belloni 256e5aac267SAlexandre Belloni /* clear current flags */ 257e5aac267SAlexandre Belloni return regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0); 258e5aac267SAlexandre Belloni } 259e5aac267SAlexandre Belloni 260e5aac267SAlexandre Belloni static int pcf85363_rtc_alarm_irq_enable(struct device *dev, 261e5aac267SAlexandre Belloni unsigned int enabled) 262e5aac267SAlexandre Belloni { 263e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 264e5aac267SAlexandre Belloni 265e5aac267SAlexandre Belloni return _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled); 266e5aac267SAlexandre Belloni } 267e5aac267SAlexandre Belloni 268e5aac267SAlexandre Belloni static int pcf85363_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 269e5aac267SAlexandre Belloni { 270e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = dev_get_drvdata(dev); 271e5aac267SAlexandre Belloni unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; 272e5aac267SAlexandre Belloni int ret; 273e5aac267SAlexandre Belloni 274e5aac267SAlexandre Belloni buf[0] = bin2bcd(alrm->time.tm_sec); 275e5aac267SAlexandre Belloni buf[1] = bin2bcd(alrm->time.tm_min); 276e5aac267SAlexandre Belloni buf[2] = bin2bcd(alrm->time.tm_hour); 277e5aac267SAlexandre Belloni buf[3] = bin2bcd(alrm->time.tm_mday); 278e5aac267SAlexandre Belloni buf[4] = bin2bcd(alrm->time.tm_mon + 1); 279e5aac267SAlexandre Belloni 280e5aac267SAlexandre Belloni /* 281e5aac267SAlexandre Belloni * Disable the alarm interrupt before changing the value to avoid 282e5aac267SAlexandre Belloni * spurious interrupts 283e5aac267SAlexandre Belloni */ 284e5aac267SAlexandre Belloni ret = _pcf85363_rtc_alarm_irq_enable(pcf85363, 0); 285e5aac267SAlexandre Belloni if (ret) 286e5aac267SAlexandre Belloni return ret; 287e5aac267SAlexandre Belloni 288e5aac267SAlexandre Belloni ret = regmap_bulk_write(pcf85363->regmap, DT_SECOND_ALM1, buf, 289e5aac267SAlexandre Belloni sizeof(buf)); 290e5aac267SAlexandre Belloni if (ret) 291e5aac267SAlexandre Belloni return ret; 292e5aac267SAlexandre Belloni 293e5aac267SAlexandre Belloni return _pcf85363_rtc_alarm_irq_enable(pcf85363, alrm->enabled); 294e5aac267SAlexandre Belloni } 295e5aac267SAlexandre Belloni 296e5aac267SAlexandre Belloni static irqreturn_t pcf85363_rtc_handle_irq(int irq, void *dev_id) 297e5aac267SAlexandre Belloni { 298e5aac267SAlexandre Belloni struct pcf85363 *pcf85363 = i2c_get_clientdata(dev_id); 299e5aac267SAlexandre Belloni unsigned int flags; 300e5aac267SAlexandre Belloni int err; 301e5aac267SAlexandre Belloni 302e5aac267SAlexandre Belloni err = regmap_read(pcf85363->regmap, CTRL_FLAGS, &flags); 303e5aac267SAlexandre Belloni if (err) 304e5aac267SAlexandre Belloni return IRQ_NONE; 305e5aac267SAlexandre Belloni 306e5aac267SAlexandre Belloni if (flags & FLAGS_A1F) { 307e5aac267SAlexandre Belloni rtc_update_irq(pcf85363->rtc, 1, RTC_IRQF | RTC_AF); 308e5aac267SAlexandre Belloni regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0); 309e5aac267SAlexandre Belloni return IRQ_HANDLED; 310e5aac267SAlexandre Belloni } 311e5aac267SAlexandre Belloni 312e5aac267SAlexandre Belloni return IRQ_NONE; 313e5aac267SAlexandre Belloni } 314e5aac267SAlexandre Belloni 315a9687aa2SEric Nelson static const struct rtc_class_ops rtc_ops = { 316a9687aa2SEric Nelson .read_time = pcf85363_rtc_read_time, 317a9687aa2SEric Nelson .set_time = pcf85363_rtc_set_time, 318e5aac267SAlexandre Belloni .read_alarm = pcf85363_rtc_read_alarm, 319e5aac267SAlexandre Belloni .set_alarm = pcf85363_rtc_set_alarm, 320e5aac267SAlexandre Belloni .alarm_irq_enable = pcf85363_rtc_alarm_irq_enable, 321e5aac267SAlexandre Belloni }; 322e5aac267SAlexandre Belloni 323a9687aa2SEric Nelson static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val, 324a9687aa2SEric Nelson size_t bytes) 325a9687aa2SEric Nelson { 326a9687aa2SEric Nelson struct pcf85363 *pcf85363 = priv; 327a9687aa2SEric Nelson 328a9687aa2SEric Nelson return regmap_bulk_read(pcf85363->regmap, CTRL_RAM + offset, 329a9687aa2SEric Nelson val, bytes); 330a9687aa2SEric Nelson } 331a9687aa2SEric Nelson 332a9687aa2SEric Nelson static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val, 333a9687aa2SEric Nelson size_t bytes) 334a9687aa2SEric Nelson { 335a9687aa2SEric Nelson struct pcf85363 *pcf85363 = priv; 336a9687aa2SEric Nelson 337a9687aa2SEric Nelson return regmap_bulk_write(pcf85363->regmap, CTRL_RAM + offset, 338a9687aa2SEric Nelson val, bytes); 339a9687aa2SEric Nelson } 340a9687aa2SEric Nelson 341fc979933SBiju Das static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val, 342fc979933SBiju Das size_t bytes) 343fc979933SBiju Das { 344fc979933SBiju Das struct pcf85363 *pcf85363 = priv; 345fc979933SBiju Das unsigned int tmp_val; 346fc979933SBiju Das int ret; 347fc979933SBiju Das 348fc979933SBiju Das ret = regmap_read(pcf85363->regmap, CTRL_RAMBYTE, &tmp_val); 349fc979933SBiju Das (*(unsigned char *) val) = (unsigned char) tmp_val; 350fc979933SBiju Das 351fc979933SBiju Das return ret; 352fc979933SBiju Das } 353fc979933SBiju Das 354fc979933SBiju Das static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val, 355fc979933SBiju Das size_t bytes) 356fc979933SBiju Das { 357fc979933SBiju Das struct pcf85363 *pcf85363 = priv; 358fc979933SBiju Das unsigned char tmp_val; 359fc979933SBiju Das 360fc979933SBiju Das tmp_val = *((unsigned char *)val); 361fc979933SBiju Das return regmap_write(pcf85363->regmap, CTRL_RAMBYTE, 362fc979933SBiju Das (unsigned int)tmp_val); 363fc979933SBiju Das } 364fc979933SBiju Das 365fc979933SBiju Das static const struct pcf85x63_config pcf_85263_config = { 366fc979933SBiju Das .regmap = { 367fc979933SBiju Das .reg_bits = 8, 368fc979933SBiju Das .val_bits = 8, 369fc979933SBiju Das .max_register = 0x2f, 370fc979933SBiju Das }, 371fc979933SBiju Das .num_nvram = 1 372fc979933SBiju Das }; 373fc979933SBiju Das 374fc979933SBiju Das static const struct pcf85x63_config pcf_85363_config = { 375fc979933SBiju Das .regmap = { 376a9687aa2SEric Nelson .reg_bits = 8, 377a9687aa2SEric Nelson .val_bits = 8, 378c57849ddSAlexandre Belloni .max_register = 0x7f, 379fc979933SBiju Das }, 380fc979933SBiju Das .num_nvram = 2 381a9687aa2SEric Nelson }; 382a9687aa2SEric Nelson 3833f4a3322SStephen Kitt static int pcf85363_probe(struct i2c_client *client) 384a9687aa2SEric Nelson { 385a9687aa2SEric Nelson struct pcf85363 *pcf85363; 386fc979933SBiju Das const struct pcf85x63_config *config = &pcf_85363_config; 387fc979933SBiju Das const void *data = of_device_get_match_data(&client->dev); 388fc979933SBiju Das static struct nvmem_config nvmem_cfg[] = { 389fc979933SBiju Das { 390fc979933SBiju Das .name = "pcf85x63-", 391fc979933SBiju Das .word_size = 1, 392fc979933SBiju Das .stride = 1, 393fc979933SBiju Das .size = 1, 394fc979933SBiju Das .reg_read = pcf85x63_nvram_read, 395fc979933SBiju Das .reg_write = pcf85x63_nvram_write, 396fc979933SBiju Das }, { 3970e7a412fSAlexandre Belloni .name = "pcf85363-", 3980e7a412fSAlexandre Belloni .word_size = 1, 3990e7a412fSAlexandre Belloni .stride = 1, 4000e7a412fSAlexandre Belloni .size = NVRAM_SIZE, 4010e7a412fSAlexandre Belloni .reg_read = pcf85363_nvram_read, 4020e7a412fSAlexandre Belloni .reg_write = pcf85363_nvram_write, 403fc979933SBiju Das }, 4040e7a412fSAlexandre Belloni }; 405*fd9a6a13SJavier Carrasco int ret, i, err; 406fc979933SBiju Das 407fc979933SBiju Das if (data) 408fc979933SBiju Das config = data; 409a9687aa2SEric Nelson 410a9687aa2SEric Nelson pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363), 411a9687aa2SEric Nelson GFP_KERNEL); 412a9687aa2SEric Nelson if (!pcf85363) 413a9687aa2SEric Nelson return -ENOMEM; 414a9687aa2SEric Nelson 415fc979933SBiju Das pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap); 416a9687aa2SEric Nelson if (IS_ERR(pcf85363->regmap)) { 417a9687aa2SEric Nelson dev_err(&client->dev, "regmap allocation failed\n"); 418a9687aa2SEric Nelson return PTR_ERR(pcf85363->regmap); 419a9687aa2SEric Nelson } 420a9687aa2SEric Nelson 421a9687aa2SEric Nelson i2c_set_clientdata(client, pcf85363); 422a9687aa2SEric Nelson 4238f7b1d71SAlexandre Belloni pcf85363->rtc = devm_rtc_allocate_device(&client->dev); 424a9687aa2SEric Nelson if (IS_ERR(pcf85363->rtc)) 425a9687aa2SEric Nelson return PTR_ERR(pcf85363->rtc); 426a9687aa2SEric Nelson 427*fd9a6a13SJavier Carrasco err = pcf85363_load_capacitance(pcf85363, client->dev.of_node); 428*fd9a6a13SJavier Carrasco if (err < 0) 429*fd9a6a13SJavier Carrasco dev_warn(&client->dev, "failed to set xtal load capacitance: %d", 430*fd9a6a13SJavier Carrasco err); 431*fd9a6a13SJavier Carrasco 432a9687aa2SEric Nelson pcf85363->rtc->ops = &rtc_ops; 433c0ec8319SAlexandre Belloni pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 434c0ec8319SAlexandre Belloni pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; 435732b7341SAlexandre Belloni clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); 436a9687aa2SEric Nelson 437e5aac267SAlexandre Belloni if (client->irq > 0) { 438dd7166c8SAlexandre Belloni unsigned long irqflags = IRQF_TRIGGER_LOW; 439dd7166c8SAlexandre Belloni 440dd7166c8SAlexandre Belloni if (dev_fwnode(&client->dev)) 441dd7166c8SAlexandre Belloni irqflags = 0; 442dd7166c8SAlexandre Belloni 443e5aac267SAlexandre Belloni regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); 444e5aac267SAlexandre Belloni regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, 445e5aac267SAlexandre Belloni PIN_IO_INTA_OUT, PIN_IO_INTAPM); 4468f7b1d71SAlexandre Belloni ret = devm_request_threaded_irq(&client->dev, client->irq, 447e5aac267SAlexandre Belloni NULL, pcf85363_rtc_handle_irq, 448dd7166c8SAlexandre Belloni irqflags | IRQF_ONESHOT, 449e5aac267SAlexandre Belloni "pcf85363", client); 450e5aac267SAlexandre Belloni if (ret) 451e5aac267SAlexandre Belloni dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); 452e5aac267SAlexandre Belloni else 453732b7341SAlexandre Belloni set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); 454e5aac267SAlexandre Belloni } 455e5aac267SAlexandre Belloni 456fdcfd854SBartosz Golaszewski ret = devm_rtc_register_device(pcf85363->rtc); 45724849d17SAlexandre Belloni 458fc979933SBiju Das for (i = 0; i < config->num_nvram; i++) { 459fc979933SBiju Das nvmem_cfg[i].priv = pcf85363; 4603a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg[i]); 461fc979933SBiju Das } 46224849d17SAlexandre Belloni 46324849d17SAlexandre Belloni return ret; 464a9687aa2SEric Nelson } 465a9687aa2SEric Nelson 466c506bc10SAlexandre Belloni static const __maybe_unused struct of_device_id dev_ids[] = { 467fc979933SBiju Das { .compatible = "nxp,pcf85263", .data = &pcf_85263_config }, 468fc979933SBiju Das { .compatible = "nxp,pcf85363", .data = &pcf_85363_config }, 469fc979933SBiju Das { /* sentinel */ } 470a9687aa2SEric Nelson }; 471a9687aa2SEric Nelson MODULE_DEVICE_TABLE(of, dev_ids); 472a9687aa2SEric Nelson 473a9687aa2SEric Nelson static struct i2c_driver pcf85363_driver = { 474a9687aa2SEric Nelson .driver = { 475a9687aa2SEric Nelson .name = "pcf85363", 476a9687aa2SEric Nelson .of_match_table = of_match_ptr(dev_ids), 477a9687aa2SEric Nelson }, 4783f4a3322SStephen Kitt .probe_new = pcf85363_probe, 479a9687aa2SEric Nelson }; 480a9687aa2SEric Nelson 481a9687aa2SEric Nelson module_i2c_driver(pcf85363_driver); 482a9687aa2SEric Nelson 483a9687aa2SEric Nelson MODULE_AUTHOR("Eric Nelson"); 484fc979933SBiju Das MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver"); 485a9687aa2SEric Nelson MODULE_LICENSE("GPL"); 486