1540d1e15SAndreas Kemnade // SPDX-License-Identifier: GPL-2.0+ 2540d1e15SAndreas Kemnade /* 3540d1e15SAndreas Kemnade * drivers/rtc/rtc-rc5t619.c 4540d1e15SAndreas Kemnade * 5540d1e15SAndreas Kemnade * Real time clock driver for RICOH RC5T619 power management chip. 6540d1e15SAndreas Kemnade * 7540d1e15SAndreas Kemnade * Copyright (C) 2019 Andreas Kemnade 8540d1e15SAndreas Kemnade */ 9540d1e15SAndreas Kemnade 10540d1e15SAndreas Kemnade #include <linux/kernel.h> 11540d1e15SAndreas Kemnade #include <linux/device.h> 12540d1e15SAndreas Kemnade #include <linux/errno.h> 13540d1e15SAndreas Kemnade #include <linux/init.h> 14540d1e15SAndreas Kemnade #include <linux/module.h> 15540d1e15SAndreas Kemnade #include <linux/mfd/rn5t618.h> 16540d1e15SAndreas Kemnade #include <linux/platform_device.h> 17540d1e15SAndreas Kemnade #include <linux/regmap.h> 18540d1e15SAndreas Kemnade #include <linux/bcd.h> 19540d1e15SAndreas Kemnade #include <linux/rtc.h> 20540d1e15SAndreas Kemnade #include <linux/slab.h> 21540d1e15SAndreas Kemnade #include <linux/irqdomain.h> 22540d1e15SAndreas Kemnade 23540d1e15SAndreas Kemnade struct rc5t619_rtc { 24540d1e15SAndreas Kemnade int irq; 25540d1e15SAndreas Kemnade struct rtc_device *rtc; 26540d1e15SAndreas Kemnade struct rn5t618 *rn5t618; 27540d1e15SAndreas Kemnade }; 28540d1e15SAndreas Kemnade 29540d1e15SAndreas Kemnade #define CTRL1_ALARM_ENABLED 0x40 30540d1e15SAndreas Kemnade #define CTRL1_24HR 0x20 31540d1e15SAndreas Kemnade #define CTRL1_PERIODIC_MASK 0xf 32540d1e15SAndreas Kemnade 33540d1e15SAndreas Kemnade #define CTRL2_PON 0x10 34540d1e15SAndreas Kemnade #define CTRL2_ALARM_STATUS 0x80 35540d1e15SAndreas Kemnade #define CTRL2_CTFG 0x4 36540d1e15SAndreas Kemnade #define CTRL2_CTC 0x1 37540d1e15SAndreas Kemnade 38540d1e15SAndreas Kemnade #define MONTH_CENTFLAG 0x80 39540d1e15SAndreas Kemnade #define HOUR_PMFLAG 0x20 40540d1e15SAndreas Kemnade #define MDAY_DAL_EXT 0x80 41540d1e15SAndreas Kemnade 42540d1e15SAndreas Kemnade static uint8_t rtc5t619_12hour_bcd2bin(uint8_t hour) 43540d1e15SAndreas Kemnade { 44540d1e15SAndreas Kemnade if (hour & HOUR_PMFLAG) { 45540d1e15SAndreas Kemnade hour = bcd2bin(hour & ~HOUR_PMFLAG); 46540d1e15SAndreas Kemnade return hour == 12 ? 12 : 12 + hour; 47540d1e15SAndreas Kemnade } 48540d1e15SAndreas Kemnade 49540d1e15SAndreas Kemnade hour = bcd2bin(hour); 50540d1e15SAndreas Kemnade return hour == 12 ? 0 : hour; 51540d1e15SAndreas Kemnade } 52540d1e15SAndreas Kemnade 53540d1e15SAndreas Kemnade static uint8_t rtc5t619_12hour_bin2bcd(uint8_t hour) 54540d1e15SAndreas Kemnade { 55540d1e15SAndreas Kemnade if (!hour) 56540d1e15SAndreas Kemnade return 0x12; 57540d1e15SAndreas Kemnade 58540d1e15SAndreas Kemnade if (hour < 12) 59540d1e15SAndreas Kemnade return bin2bcd(hour); 60540d1e15SAndreas Kemnade 61540d1e15SAndreas Kemnade if (hour == 12) 62540d1e15SAndreas Kemnade return 0x12 | HOUR_PMFLAG; 63540d1e15SAndreas Kemnade 64540d1e15SAndreas Kemnade return bin2bcd(hour - 12) | HOUR_PMFLAG; 65540d1e15SAndreas Kemnade } 66540d1e15SAndreas Kemnade 67540d1e15SAndreas Kemnade static int rc5t619_rtc_periodic_disable(struct device *dev) 68540d1e15SAndreas Kemnade { 69540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 70540d1e15SAndreas Kemnade int err; 71540d1e15SAndreas Kemnade 72540d1e15SAndreas Kemnade /* disable function */ 73540d1e15SAndreas Kemnade err = regmap_update_bits(rtc->rn5t618->regmap, 74540d1e15SAndreas Kemnade RN5T618_RTC_CTRL1, CTRL1_PERIODIC_MASK, 0); 75540d1e15SAndreas Kemnade if (err < 0) 76540d1e15SAndreas Kemnade return err; 77540d1e15SAndreas Kemnade 78540d1e15SAndreas Kemnade /* clear alarm flag and CTFG */ 79540d1e15SAndreas Kemnade err = regmap_update_bits(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, 80540d1e15SAndreas Kemnade CTRL2_ALARM_STATUS | CTRL2_CTFG | CTRL2_CTC, 81540d1e15SAndreas Kemnade 0); 82540d1e15SAndreas Kemnade if (err < 0) 83540d1e15SAndreas Kemnade return err; 84540d1e15SAndreas Kemnade 85540d1e15SAndreas Kemnade return 0; 86540d1e15SAndreas Kemnade } 87540d1e15SAndreas Kemnade 88540d1e15SAndreas Kemnade /* things to be done once after power on */ 89540d1e15SAndreas Kemnade static int rc5t619_rtc_pon_setup(struct device *dev) 90540d1e15SAndreas Kemnade { 91540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 92540d1e15SAndreas Kemnade int err; 93540d1e15SAndreas Kemnade unsigned int reg_data; 94540d1e15SAndreas Kemnade 95540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, ®_data); 96540d1e15SAndreas Kemnade if (err < 0) 97540d1e15SAndreas Kemnade return err; 98540d1e15SAndreas Kemnade 99540d1e15SAndreas Kemnade /* clear VDET PON */ 100540d1e15SAndreas Kemnade reg_data &= ~(CTRL2_PON | CTRL2_CTC | 0x4a); /* 0101-1011 */ 101540d1e15SAndreas Kemnade reg_data |= 0x20; /* 0010-0000 */ 102540d1e15SAndreas Kemnade err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, reg_data); 103540d1e15SAndreas Kemnade if (err < 0) 104540d1e15SAndreas Kemnade return err; 105540d1e15SAndreas Kemnade 106540d1e15SAndreas Kemnade /* clearing RTC Adjust register */ 107540d1e15SAndreas Kemnade err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_ADJUST, 0); 108540d1e15SAndreas Kemnade if (err) 109540d1e15SAndreas Kemnade return err; 110540d1e15SAndreas Kemnade 111540d1e15SAndreas Kemnade return regmap_update_bits(rtc->rn5t618->regmap, 112540d1e15SAndreas Kemnade RN5T618_RTC_CTRL1, 113540d1e15SAndreas Kemnade CTRL1_24HR, CTRL1_24HR); 114540d1e15SAndreas Kemnade } 115540d1e15SAndreas Kemnade 116540d1e15SAndreas Kemnade static int rc5t619_rtc_read_time(struct device *dev, struct rtc_time *tm) 117540d1e15SAndreas Kemnade { 118540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 119540d1e15SAndreas Kemnade u8 buff[7]; 120540d1e15SAndreas Kemnade int err; 121540d1e15SAndreas Kemnade int cent_flag; 122540d1e15SAndreas Kemnade unsigned int ctrl1; 123540d1e15SAndreas Kemnade unsigned int ctrl2; 124540d1e15SAndreas Kemnade 125540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2); 126540d1e15SAndreas Kemnade if (err < 0) 127540d1e15SAndreas Kemnade return err; 128540d1e15SAndreas Kemnade 129540d1e15SAndreas Kemnade if (ctrl2 & CTRL2_PON) 130540d1e15SAndreas Kemnade return -EINVAL; 131540d1e15SAndreas Kemnade 132540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1); 133540d1e15SAndreas Kemnade if (err < 0) 134540d1e15SAndreas Kemnade return err; 135540d1e15SAndreas Kemnade 136540d1e15SAndreas Kemnade err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS, 137540d1e15SAndreas Kemnade buff, sizeof(buff)); 138540d1e15SAndreas Kemnade if (err < 0) 139540d1e15SAndreas Kemnade return err; 140540d1e15SAndreas Kemnade 141540d1e15SAndreas Kemnade if (buff[5] & MONTH_CENTFLAG) 142540d1e15SAndreas Kemnade cent_flag = 1; 143540d1e15SAndreas Kemnade else 144540d1e15SAndreas Kemnade cent_flag = 0; 145540d1e15SAndreas Kemnade 146540d1e15SAndreas Kemnade tm->tm_sec = bcd2bin(buff[0]); 147540d1e15SAndreas Kemnade tm->tm_min = bcd2bin(buff[1]); 148540d1e15SAndreas Kemnade 149540d1e15SAndreas Kemnade if (ctrl1 & CTRL1_24HR) 150540d1e15SAndreas Kemnade tm->tm_hour = bcd2bin(buff[2]); 151540d1e15SAndreas Kemnade else 152540d1e15SAndreas Kemnade tm->tm_hour = rtc5t619_12hour_bcd2bin(buff[2]); 153540d1e15SAndreas Kemnade 154540d1e15SAndreas Kemnade tm->tm_wday = bcd2bin(buff[3]); 155540d1e15SAndreas Kemnade tm->tm_mday = bcd2bin(buff[4]); 156540d1e15SAndreas Kemnade tm->tm_mon = bcd2bin(buff[5] & 0x1f) - 1; /* back to system 0-11 */ 157540d1e15SAndreas Kemnade tm->tm_year = bcd2bin(buff[6]) + 100 * cent_flag; 158540d1e15SAndreas Kemnade 159540d1e15SAndreas Kemnade return 0; 160540d1e15SAndreas Kemnade } 161540d1e15SAndreas Kemnade 162540d1e15SAndreas Kemnade static int rc5t619_rtc_set_time(struct device *dev, struct rtc_time *tm) 163540d1e15SAndreas Kemnade { 164540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 165540d1e15SAndreas Kemnade u8 buff[7]; 166540d1e15SAndreas Kemnade int err; 167540d1e15SAndreas Kemnade int cent_flag; 168540d1e15SAndreas Kemnade unsigned int ctrl1; 169540d1e15SAndreas Kemnade unsigned int ctrl2; 170540d1e15SAndreas Kemnade 171540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2); 172540d1e15SAndreas Kemnade if (err < 0) 173540d1e15SAndreas Kemnade return err; 174540d1e15SAndreas Kemnade 175540d1e15SAndreas Kemnade if (ctrl2 & CTRL2_PON) 176540d1e15SAndreas Kemnade rc5t619_rtc_pon_setup(dev); 177540d1e15SAndreas Kemnade 178540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1); 179540d1e15SAndreas Kemnade if (err < 0) 180540d1e15SAndreas Kemnade return err; 181540d1e15SAndreas Kemnade 182540d1e15SAndreas Kemnade if (tm->tm_year >= 100) 183540d1e15SAndreas Kemnade cent_flag = 1; 184540d1e15SAndreas Kemnade else 185540d1e15SAndreas Kemnade cent_flag = 0; 186540d1e15SAndreas Kemnade 187540d1e15SAndreas Kemnade buff[0] = bin2bcd(tm->tm_sec); 188540d1e15SAndreas Kemnade buff[1] = bin2bcd(tm->tm_min); 189540d1e15SAndreas Kemnade 190540d1e15SAndreas Kemnade if (ctrl1 & CTRL1_24HR) 191540d1e15SAndreas Kemnade buff[2] = bin2bcd(tm->tm_hour); 192540d1e15SAndreas Kemnade else 193540d1e15SAndreas Kemnade buff[2] = rtc5t619_12hour_bin2bcd(tm->tm_hour); 194540d1e15SAndreas Kemnade 195540d1e15SAndreas Kemnade buff[3] = bin2bcd(tm->tm_wday); 196540d1e15SAndreas Kemnade buff[4] = bin2bcd(tm->tm_mday); 197540d1e15SAndreas Kemnade buff[5] = bin2bcd(tm->tm_mon + 1); /* system set 0-11 */ 198540d1e15SAndreas Kemnade buff[6] = bin2bcd(tm->tm_year - cent_flag * 100); 199540d1e15SAndreas Kemnade 200540d1e15SAndreas Kemnade if (cent_flag) 201540d1e15SAndreas Kemnade buff[5] |= MONTH_CENTFLAG; 202540d1e15SAndreas Kemnade 203540d1e15SAndreas Kemnade err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS, 204540d1e15SAndreas Kemnade buff, sizeof(buff)); 205540d1e15SAndreas Kemnade if (err < 0) { 206540d1e15SAndreas Kemnade dev_err(dev, "failed to program new time: %d\n", err); 207540d1e15SAndreas Kemnade return err; 208540d1e15SAndreas Kemnade } 209540d1e15SAndreas Kemnade 210540d1e15SAndreas Kemnade return 0; 211540d1e15SAndreas Kemnade } 212540d1e15SAndreas Kemnade 213540d1e15SAndreas Kemnade /* 0-disable, 1-enable */ 214540d1e15SAndreas Kemnade static int rc5t619_rtc_alarm_enable(struct device *dev, unsigned int enabled) 215540d1e15SAndreas Kemnade { 216540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 217540d1e15SAndreas Kemnade 218540d1e15SAndreas Kemnade return regmap_update_bits(rtc->rn5t618->regmap, 219540d1e15SAndreas Kemnade RN5T618_RTC_CTRL1, 220540d1e15SAndreas Kemnade CTRL1_ALARM_ENABLED, 221540d1e15SAndreas Kemnade enabled ? CTRL1_ALARM_ENABLED : 0); 222540d1e15SAndreas Kemnade } 223540d1e15SAndreas Kemnade 224540d1e15SAndreas Kemnade static int rc5t619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 225540d1e15SAndreas Kemnade { 226540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 227540d1e15SAndreas Kemnade u8 buff[6]; 228540d1e15SAndreas Kemnade unsigned int buff_cent; 229540d1e15SAndreas Kemnade int err; 230540d1e15SAndreas Kemnade int cent_flag; 231540d1e15SAndreas Kemnade unsigned int ctrl1; 232540d1e15SAndreas Kemnade 233540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1); 234540d1e15SAndreas Kemnade if (err) 235540d1e15SAndreas Kemnade return err; 236540d1e15SAndreas Kemnade 237540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_MONTH, &buff_cent); 238540d1e15SAndreas Kemnade if (err < 0) { 239540d1e15SAndreas Kemnade dev_err(dev, "failed to read time: %d\n", err); 240540d1e15SAndreas Kemnade return err; 241540d1e15SAndreas Kemnade } 242540d1e15SAndreas Kemnade 243540d1e15SAndreas Kemnade if (buff_cent & MONTH_CENTFLAG) 244540d1e15SAndreas Kemnade cent_flag = 1; 245540d1e15SAndreas Kemnade else 246540d1e15SAndreas Kemnade cent_flag = 0; 247540d1e15SAndreas Kemnade 248540d1e15SAndreas Kemnade err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC, 249540d1e15SAndreas Kemnade buff, sizeof(buff)); 250540d1e15SAndreas Kemnade if (err) 251540d1e15SAndreas Kemnade return err; 252540d1e15SAndreas Kemnade 253540d1e15SAndreas Kemnade buff[3] = buff[3] & 0x3f; 254540d1e15SAndreas Kemnade 255540d1e15SAndreas Kemnade alrm->time.tm_sec = bcd2bin(buff[0]); 256540d1e15SAndreas Kemnade alrm->time.tm_min = bcd2bin(buff[1]); 257540d1e15SAndreas Kemnade 258540d1e15SAndreas Kemnade if (ctrl1 & CTRL1_24HR) 259540d1e15SAndreas Kemnade alrm->time.tm_hour = bcd2bin(buff[2]); 260540d1e15SAndreas Kemnade else 261540d1e15SAndreas Kemnade alrm->time.tm_hour = rtc5t619_12hour_bcd2bin(buff[2]); 262540d1e15SAndreas Kemnade 263540d1e15SAndreas Kemnade alrm->time.tm_mday = bcd2bin(buff[3]); 264540d1e15SAndreas Kemnade alrm->time.tm_mon = bcd2bin(buff[4]) - 1; 265540d1e15SAndreas Kemnade alrm->time.tm_year = bcd2bin(buff[5]) + 100 * cent_flag; 266540d1e15SAndreas Kemnade alrm->enabled = !!(ctrl1 & CTRL1_ALARM_ENABLED); 267540d1e15SAndreas Kemnade dev_dbg(dev, "read alarm: %ptR\n", &alrm->time); 268540d1e15SAndreas Kemnade 269540d1e15SAndreas Kemnade return 0; 270540d1e15SAndreas Kemnade } 271540d1e15SAndreas Kemnade 272540d1e15SAndreas Kemnade static int rc5t619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 273540d1e15SAndreas Kemnade { 274540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 275540d1e15SAndreas Kemnade u8 buff[6]; 276540d1e15SAndreas Kemnade int err; 277540d1e15SAndreas Kemnade int cent_flag; 278540d1e15SAndreas Kemnade unsigned int ctrl1; 279540d1e15SAndreas Kemnade 280540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1); 281540d1e15SAndreas Kemnade if (err) 282540d1e15SAndreas Kemnade return err; 283540d1e15SAndreas Kemnade 284540d1e15SAndreas Kemnade err = rc5t619_rtc_alarm_enable(dev, 0); 285540d1e15SAndreas Kemnade if (err < 0) 286540d1e15SAndreas Kemnade return err; 287540d1e15SAndreas Kemnade 288540d1e15SAndreas Kemnade if (rtc->irq == -1) 289540d1e15SAndreas Kemnade return -EINVAL; 290540d1e15SAndreas Kemnade 291540d1e15SAndreas Kemnade if (alrm->enabled == 0) 292540d1e15SAndreas Kemnade return 0; 293540d1e15SAndreas Kemnade 294540d1e15SAndreas Kemnade if (alrm->time.tm_year >= 100) 295540d1e15SAndreas Kemnade cent_flag = 1; 296540d1e15SAndreas Kemnade else 297540d1e15SAndreas Kemnade cent_flag = 0; 298540d1e15SAndreas Kemnade 299540d1e15SAndreas Kemnade alrm->time.tm_mon += 1; 300540d1e15SAndreas Kemnade buff[0] = bin2bcd(alrm->time.tm_sec); 301540d1e15SAndreas Kemnade buff[1] = bin2bcd(alrm->time.tm_min); 302540d1e15SAndreas Kemnade 303540d1e15SAndreas Kemnade if (ctrl1 & CTRL1_24HR) 304540d1e15SAndreas Kemnade buff[2] = bin2bcd(alrm->time.tm_hour); 305540d1e15SAndreas Kemnade else 306540d1e15SAndreas Kemnade buff[2] = rtc5t619_12hour_bin2bcd(alrm->time.tm_hour); 307540d1e15SAndreas Kemnade 308540d1e15SAndreas Kemnade buff[3] = bin2bcd(alrm->time.tm_mday); 309540d1e15SAndreas Kemnade buff[4] = bin2bcd(alrm->time.tm_mon); 310540d1e15SAndreas Kemnade buff[5] = bin2bcd(alrm->time.tm_year - 100 * cent_flag); 311540d1e15SAndreas Kemnade buff[3] |= MDAY_DAL_EXT; 312540d1e15SAndreas Kemnade 313540d1e15SAndreas Kemnade err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC, 314540d1e15SAndreas Kemnade buff, sizeof(buff)); 315540d1e15SAndreas Kemnade if (err < 0) 316540d1e15SAndreas Kemnade return err; 317540d1e15SAndreas Kemnade 318540d1e15SAndreas Kemnade return rc5t619_rtc_alarm_enable(dev, alrm->enabled); 319540d1e15SAndreas Kemnade } 320540d1e15SAndreas Kemnade 321540d1e15SAndreas Kemnade static const struct rtc_class_ops rc5t619_rtc_ops = { 322540d1e15SAndreas Kemnade .read_time = rc5t619_rtc_read_time, 323540d1e15SAndreas Kemnade .set_time = rc5t619_rtc_set_time, 324540d1e15SAndreas Kemnade .set_alarm = rc5t619_rtc_set_alarm, 325540d1e15SAndreas Kemnade .read_alarm = rc5t619_rtc_read_alarm, 326540d1e15SAndreas Kemnade .alarm_irq_enable = rc5t619_rtc_alarm_enable, 327540d1e15SAndreas Kemnade }; 328540d1e15SAndreas Kemnade 329540d1e15SAndreas Kemnade static int rc5t619_rtc_alarm_flag_clr(struct device *dev) 330540d1e15SAndreas Kemnade { 331540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 332540d1e15SAndreas Kemnade 333540d1e15SAndreas Kemnade /* clear alarm-D status bits.*/ 334540d1e15SAndreas Kemnade return regmap_update_bits(rtc->rn5t618->regmap, 335540d1e15SAndreas Kemnade RN5T618_RTC_CTRL2, 336540d1e15SAndreas Kemnade CTRL2_ALARM_STATUS | CTRL2_CTC, 0); 337540d1e15SAndreas Kemnade } 338540d1e15SAndreas Kemnade 339540d1e15SAndreas Kemnade static irqreturn_t rc5t619_rtc_irq(int irq, void *data) 340540d1e15SAndreas Kemnade { 341540d1e15SAndreas Kemnade struct device *dev = data; 342540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc = dev_get_drvdata(dev); 343540d1e15SAndreas Kemnade 344540d1e15SAndreas Kemnade rc5t619_rtc_alarm_flag_clr(dev); 345540d1e15SAndreas Kemnade 346540d1e15SAndreas Kemnade rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); 347540d1e15SAndreas Kemnade return IRQ_HANDLED; 348540d1e15SAndreas Kemnade } 349540d1e15SAndreas Kemnade 350540d1e15SAndreas Kemnade static int rc5t619_rtc_probe(struct platform_device *pdev) 351540d1e15SAndreas Kemnade { 352540d1e15SAndreas Kemnade struct device *dev = &pdev->dev; 353540d1e15SAndreas Kemnade struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); 354540d1e15SAndreas Kemnade struct rc5t619_rtc *rtc; 355540d1e15SAndreas Kemnade unsigned int ctrl2; 356540d1e15SAndreas Kemnade int err; 357540d1e15SAndreas Kemnade 358540d1e15SAndreas Kemnade rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); 35911ddbdfbSDan Carpenter if (!rtc) 360540d1e15SAndreas Kemnade return -ENOMEM; 361540d1e15SAndreas Kemnade 362540d1e15SAndreas Kemnade rtc->rn5t618 = rn5t618; 363540d1e15SAndreas Kemnade 364540d1e15SAndreas Kemnade dev_set_drvdata(dev, rtc); 365540d1e15SAndreas Kemnade rtc->irq = -1; 366540d1e15SAndreas Kemnade 367540d1e15SAndreas Kemnade if (rn5t618->irq_data) 368540d1e15SAndreas Kemnade rtc->irq = regmap_irq_get_virq(rn5t618->irq_data, 369540d1e15SAndreas Kemnade RN5T618_IRQ_RTC); 370540d1e15SAndreas Kemnade 371540d1e15SAndreas Kemnade if (rtc->irq < 0) 372540d1e15SAndreas Kemnade rtc->irq = -1; 373540d1e15SAndreas Kemnade 374540d1e15SAndreas Kemnade err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2); 375540d1e15SAndreas Kemnade if (err < 0) 376540d1e15SAndreas Kemnade return err; 377540d1e15SAndreas Kemnade 378540d1e15SAndreas Kemnade /* disable rtc periodic function */ 379540d1e15SAndreas Kemnade err = rc5t619_rtc_periodic_disable(&pdev->dev); 380540d1e15SAndreas Kemnade if (err) 381540d1e15SAndreas Kemnade return err; 382540d1e15SAndreas Kemnade 383540d1e15SAndreas Kemnade if (ctrl2 & CTRL2_PON) { 384540d1e15SAndreas Kemnade err = rc5t619_rtc_alarm_flag_clr(&pdev->dev); 385540d1e15SAndreas Kemnade if (err) 386540d1e15SAndreas Kemnade return err; 387540d1e15SAndreas Kemnade } 388540d1e15SAndreas Kemnade 389540d1e15SAndreas Kemnade rtc->rtc = devm_rtc_allocate_device(&pdev->dev); 390540d1e15SAndreas Kemnade if (IS_ERR(rtc->rtc)) { 391540d1e15SAndreas Kemnade err = PTR_ERR(rtc->rtc); 392540d1e15SAndreas Kemnade dev_err(dev, "RTC device register: err %d\n", err); 393540d1e15SAndreas Kemnade return err; 394540d1e15SAndreas Kemnade } 395540d1e15SAndreas Kemnade 396540d1e15SAndreas Kemnade rtc->rtc->ops = &rc5t619_rtc_ops; 397540d1e15SAndreas Kemnade rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900; 398540d1e15SAndreas Kemnade rtc->rtc->range_max = RTC_TIMESTAMP_END_2099; 399540d1e15SAndreas Kemnade 400540d1e15SAndreas Kemnade /* set interrupt and enable it */ 401540d1e15SAndreas Kemnade if (rtc->irq != -1) { 402540d1e15SAndreas Kemnade err = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, 403540d1e15SAndreas Kemnade rc5t619_rtc_irq, 404540d1e15SAndreas Kemnade IRQF_ONESHOT, 405540d1e15SAndreas Kemnade "rtc-rc5t619", 406540d1e15SAndreas Kemnade &pdev->dev); 407540d1e15SAndreas Kemnade if (err < 0) { 408540d1e15SAndreas Kemnade dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq); 409540d1e15SAndreas Kemnade rtc->irq = -1; 410540d1e15SAndreas Kemnade 411540d1e15SAndreas Kemnade err = rc5t619_rtc_alarm_enable(&pdev->dev, 0); 412540d1e15SAndreas Kemnade if (err) 413540d1e15SAndreas Kemnade return err; 414540d1e15SAndreas Kemnade 415540d1e15SAndreas Kemnade } else { 416540d1e15SAndreas Kemnade /* enable wake */ 417540d1e15SAndreas Kemnade device_init_wakeup(&pdev->dev, 1); 418540d1e15SAndreas Kemnade enable_irq_wake(rtc->irq); 419540d1e15SAndreas Kemnade } 420540d1e15SAndreas Kemnade } else { 421540d1e15SAndreas Kemnade /* system don't want to using alarm interrupt, so close it */ 422540d1e15SAndreas Kemnade err = rc5t619_rtc_alarm_enable(&pdev->dev, 0); 423540d1e15SAndreas Kemnade if (err) 424540d1e15SAndreas Kemnade return err; 425540d1e15SAndreas Kemnade 426540d1e15SAndreas Kemnade dev_warn(&pdev->dev, "rc5t619 interrupt is disabled\n"); 427540d1e15SAndreas Kemnade } 428540d1e15SAndreas Kemnade 429540d1e15SAndreas Kemnade return rtc_register_device(rtc->rtc); 430540d1e15SAndreas Kemnade } 431540d1e15SAndreas Kemnade 432540d1e15SAndreas Kemnade static struct platform_driver rc5t619_rtc_driver = { 433540d1e15SAndreas Kemnade .driver = { 434540d1e15SAndreas Kemnade .name = "rc5t619-rtc", 435540d1e15SAndreas Kemnade }, 436540d1e15SAndreas Kemnade .probe = rc5t619_rtc_probe, 437540d1e15SAndreas Kemnade }; 438540d1e15SAndreas Kemnade 439540d1e15SAndreas Kemnade module_platform_driver(rc5t619_rtc_driver); 440540d1e15SAndreas Kemnade MODULE_ALIAS("platform:rc5t619-rtc"); 441540d1e15SAndreas Kemnade MODULE_DESCRIPTION("RICOH RC5T619 RTC driver"); 442540d1e15SAndreas Kemnade MODULE_LICENSE("GPL"); 443