18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * RTC clock driver for the RTC part of the AB8500 Power management chip. 88c2ecf20Sopenharmony_ci * Based on RTC clock driver for the AB3100 Analog Baseband Chip by 98c2ecf20Sopenharmony_ci * Linus Walleij <linus.walleij@stericsson.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/rtc.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/abx500.h> 188c2ecf20Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define AB8500_RTC_SOFF_STAT_REG 0x00 248c2ecf20Sopenharmony_ci#define AB8500_RTC_CC_CONF_REG 0x01 258c2ecf20Sopenharmony_ci#define AB8500_RTC_READ_REQ_REG 0x02 268c2ecf20Sopenharmony_ci#define AB8500_RTC_WATCH_TSECMID_REG 0x03 278c2ecf20Sopenharmony_ci#define AB8500_RTC_WATCH_TSECHI_REG 0x04 288c2ecf20Sopenharmony_ci#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x05 298c2ecf20Sopenharmony_ci#define AB8500_RTC_WATCH_TMIN_MID_REG 0x06 308c2ecf20Sopenharmony_ci#define AB8500_RTC_WATCH_TMIN_HI_REG 0x07 318c2ecf20Sopenharmony_ci#define AB8500_RTC_ALRM_MIN_LOW_REG 0x08 328c2ecf20Sopenharmony_ci#define AB8500_RTC_ALRM_MIN_MID_REG 0x09 338c2ecf20Sopenharmony_ci#define AB8500_RTC_ALRM_MIN_HI_REG 0x0A 348c2ecf20Sopenharmony_ci#define AB8500_RTC_STAT_REG 0x0B 358c2ecf20Sopenharmony_ci#define AB8500_RTC_BKUP_CHG_REG 0x0C 368c2ecf20Sopenharmony_ci#define AB8500_RTC_FORCE_BKUP_REG 0x0D 378c2ecf20Sopenharmony_ci#define AB8500_RTC_CALIB_REG 0x0E 388c2ecf20Sopenharmony_ci#define AB8500_RTC_SWITCH_STAT_REG 0x0F 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* RtcReadRequest bits */ 418c2ecf20Sopenharmony_ci#define RTC_READ_REQUEST 0x01 428c2ecf20Sopenharmony_ci#define RTC_WRITE_REQUEST 0x02 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* RtcCtrl bits */ 458c2ecf20Sopenharmony_ci#define RTC_ALARM_ENA 0x04 468c2ecf20Sopenharmony_ci#define RTC_STATUS_DATA 0x01 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define COUNTS_PER_SEC (0xF000 / 60) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const u8 ab8500_rtc_time_regs[] = { 518c2ecf20Sopenharmony_ci AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG, 528c2ecf20Sopenharmony_ci AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG, 538c2ecf20Sopenharmony_ci AB8500_RTC_WATCH_TSECMID_REG 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const u8 ab8500_rtc_alarm_regs[] = { 578c2ecf20Sopenharmony_ci AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG, 588c2ecf20Sopenharmony_ci AB8500_RTC_ALRM_MIN_LOW_REG 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + HZ; 648c2ecf20Sopenharmony_ci int retval, i; 658c2ecf20Sopenharmony_ci unsigned long mins, secs; 668c2ecf20Sopenharmony_ci unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; 678c2ecf20Sopenharmony_ci u8 value; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Request a data read */ 708c2ecf20Sopenharmony_ci retval = abx500_set_register_interruptible(dev, 718c2ecf20Sopenharmony_ci AB8500_RTC, AB8500_RTC_READ_REQ_REG, RTC_READ_REQUEST); 728c2ecf20Sopenharmony_ci if (retval < 0) 738c2ecf20Sopenharmony_ci return retval; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Wait for some cycles after enabling the rtc read in ab8500 */ 768c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 778c2ecf20Sopenharmony_ci retval = abx500_get_register_interruptible(dev, 788c2ecf20Sopenharmony_ci AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value); 798c2ecf20Sopenharmony_ci if (retval < 0) 808c2ecf20Sopenharmony_ci return retval; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!(value & RTC_READ_REQUEST)) 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci usleep_range(1000, 5000); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Read the Watchtime registers */ 898c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { 908c2ecf20Sopenharmony_ci retval = abx500_get_register_interruptible(dev, 918c2ecf20Sopenharmony_ci AB8500_RTC, ab8500_rtc_time_regs[i], &value); 928c2ecf20Sopenharmony_ci if (retval < 0) 938c2ecf20Sopenharmony_ci return retval; 948c2ecf20Sopenharmony_ci buf[i] = value; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mins = (buf[0] << 16) | (buf[1] << 8) | buf[2]; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci secs = (buf[3] << 8) | buf[4]; 1008c2ecf20Sopenharmony_ci secs = secs / COUNTS_PER_SEC; 1018c2ecf20Sopenharmony_ci secs = secs + (mins * 60); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci rtc_time64_to_tm(secs, tm); 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int retval, i; 1108c2ecf20Sopenharmony_ci unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; 1118c2ecf20Sopenharmony_ci unsigned long no_secs, no_mins, secs = 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci secs = rtc_tm_to_time64(tm); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci no_mins = secs / 60; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci no_secs = secs % 60; 1188c2ecf20Sopenharmony_ci /* Make the seconds count as per the RTC resolution */ 1198c2ecf20Sopenharmony_ci no_secs = no_secs * COUNTS_PER_SEC; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci buf[4] = no_secs & 0xFF; 1228c2ecf20Sopenharmony_ci buf[3] = (no_secs >> 8) & 0xFF; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci buf[2] = no_mins & 0xFF; 1258c2ecf20Sopenharmony_ci buf[1] = (no_mins >> 8) & 0xFF; 1268c2ecf20Sopenharmony_ci buf[0] = (no_mins >> 16) & 0xFF; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { 1298c2ecf20Sopenharmony_ci retval = abx500_set_register_interruptible(dev, AB8500_RTC, 1308c2ecf20Sopenharmony_ci ab8500_rtc_time_regs[i], buf[i]); 1318c2ecf20Sopenharmony_ci if (retval < 0) 1328c2ecf20Sopenharmony_ci return retval; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Request a data write */ 1368c2ecf20Sopenharmony_ci return abx500_set_register_interruptible(dev, AB8500_RTC, 1378c2ecf20Sopenharmony_ci AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int retval, i; 1438c2ecf20Sopenharmony_ci u8 rtc_ctrl, value; 1448c2ecf20Sopenharmony_ci unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; 1458c2ecf20Sopenharmony_ci unsigned long secs, mins; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Check if the alarm is enabled or not */ 1488c2ecf20Sopenharmony_ci retval = abx500_get_register_interruptible(dev, AB8500_RTC, 1498c2ecf20Sopenharmony_ci AB8500_RTC_STAT_REG, &rtc_ctrl); 1508c2ecf20Sopenharmony_ci if (retval < 0) 1518c2ecf20Sopenharmony_ci return retval; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (rtc_ctrl & RTC_ALARM_ENA) 1548c2ecf20Sopenharmony_ci alarm->enabled = 1; 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci alarm->enabled = 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci alarm->pending = 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { 1618c2ecf20Sopenharmony_ci retval = abx500_get_register_interruptible(dev, AB8500_RTC, 1628c2ecf20Sopenharmony_ci ab8500_rtc_alarm_regs[i], &value); 1638c2ecf20Sopenharmony_ci if (retval < 0) 1648c2ecf20Sopenharmony_ci return retval; 1658c2ecf20Sopenharmony_ci buf[i] = value; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); 1698c2ecf20Sopenharmony_ci secs = mins * 60; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci rtc_time64_to_tm(secs, &alarm->time); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return abx500_mask_and_set_register_interruptible(dev, AB8500_RTC, 1798c2ecf20Sopenharmony_ci AB8500_RTC_STAT_REG, RTC_ALARM_ENA, 1808c2ecf20Sopenharmony_ci enabled ? RTC_ALARM_ENA : 0); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int retval, i; 1868c2ecf20Sopenharmony_ci unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; 1878c2ecf20Sopenharmony_ci unsigned long mins, secs = 0, cursec = 0; 1888c2ecf20Sopenharmony_ci struct rtc_time curtm; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Get the number of seconds since 1970 */ 1918c2ecf20Sopenharmony_ci secs = rtc_tm_to_time64(&alarm->time); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Check whether alarm is set less than 1min. 1958c2ecf20Sopenharmony_ci * Since our RTC doesn't support alarm resolution less than 1min, 1968c2ecf20Sopenharmony_ci * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci ab8500_rtc_read_time(dev, &curtm); /* Read current time */ 1998c2ecf20Sopenharmony_ci cursec = rtc_tm_to_time64(&curtm); 2008c2ecf20Sopenharmony_ci if ((secs - cursec) < 59) { 2018c2ecf20Sopenharmony_ci dev_dbg(dev, "Alarm less than 1 minute not supported\r\n"); 2028c2ecf20Sopenharmony_ci return -EINVAL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci mins = secs / 60; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci buf[2] = mins & 0xFF; 2088c2ecf20Sopenharmony_ci buf[1] = (mins >> 8) & 0xFF; 2098c2ecf20Sopenharmony_ci buf[0] = (mins >> 16) & 0xFF; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Set the alarm time */ 2128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { 2138c2ecf20Sopenharmony_ci retval = abx500_set_register_interruptible(dev, AB8500_RTC, 2148c2ecf20Sopenharmony_ci ab8500_rtc_alarm_regs[i], buf[i]); 2158c2ecf20Sopenharmony_ci if (retval < 0) 2168c2ecf20Sopenharmony_ci return retval; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return ab8500_rtc_irq_enable(dev, alarm->enabled); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int ab8500_rtc_set_calibration(struct device *dev, int calibration) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int retval; 2258c2ecf20Sopenharmony_ci u8 rtccal = 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Check that the calibration value (which is in units of 0.5 2298c2ecf20Sopenharmony_ci * parts-per-million) is in the AB8500's range for RtcCalibration 2308c2ecf20Sopenharmony_ci * register. -128 (0x80) is not permitted because the AB8500 uses 2318c2ecf20Sopenharmony_ci * a sign-bit rather than two's complement, so 0x80 is just another 2328c2ecf20Sopenharmony_ci * representation of zero. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if ((calibration < -127) || (calibration > 127)) { 2358c2ecf20Sopenharmony_ci dev_err(dev, "RtcCalibration value outside permitted range\n"); 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * The AB8500 uses sign (in bit7) and magnitude (in bits0-7) 2418c2ecf20Sopenharmony_ci * so need to convert to this sort of representation before writing 2428c2ecf20Sopenharmony_ci * into RtcCalibration register... 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci if (calibration >= 0) 2458c2ecf20Sopenharmony_ci rtccal = 0x7F & calibration; 2468c2ecf20Sopenharmony_ci else 2478c2ecf20Sopenharmony_ci rtccal = ~(calibration - 1) | 0x80; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci retval = abx500_set_register_interruptible(dev, AB8500_RTC, 2508c2ecf20Sopenharmony_ci AB8500_RTC_CALIB_REG, rtccal); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return retval; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int ab8500_rtc_get_calibration(struct device *dev, int *calibration) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int retval; 2588c2ecf20Sopenharmony_ci u8 rtccal = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci retval = abx500_get_register_interruptible(dev, AB8500_RTC, 2618c2ecf20Sopenharmony_ci AB8500_RTC_CALIB_REG, &rtccal); 2628c2ecf20Sopenharmony_ci if (retval >= 0) { 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * The AB8500 uses sign (in bit7) and magnitude (in bits0-7) 2658c2ecf20Sopenharmony_ci * so need to convert value from RtcCalibration register into 2668c2ecf20Sopenharmony_ci * a two's complement signed value... 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if (rtccal & 0x80) 2698c2ecf20Sopenharmony_ci *calibration = 0 - (rtccal & 0x7F); 2708c2ecf20Sopenharmony_ci else 2718c2ecf20Sopenharmony_ci *calibration = 0x7F & rtccal; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return retval; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic ssize_t ab8500_sysfs_store_rtc_calibration(struct device *dev, 2788c2ecf20Sopenharmony_ci struct device_attribute *attr, 2798c2ecf20Sopenharmony_ci const char *buf, size_t count) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci int retval; 2828c2ecf20Sopenharmony_ci int calibration = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (sscanf(buf, " %i ", &calibration) != 1) { 2858c2ecf20Sopenharmony_ci dev_err(dev, "Failed to store RTC calibration attribute\n"); 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci retval = ab8500_rtc_set_calibration(dev, calibration); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return retval ? retval : count; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic ssize_t ab8500_sysfs_show_rtc_calibration(struct device *dev, 2958c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int retval = 0; 2988c2ecf20Sopenharmony_ci int calibration = 0; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci retval = ab8500_rtc_get_calibration(dev, &calibration); 3018c2ecf20Sopenharmony_ci if (retval < 0) { 3028c2ecf20Sopenharmony_ci dev_err(dev, "Failed to read RTC calibration attribute\n"); 3038c2ecf20Sopenharmony_ci sprintf(buf, "0\n"); 3048c2ecf20Sopenharmony_ci return retval; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", calibration); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR, 3118c2ecf20Sopenharmony_ci ab8500_sysfs_show_rtc_calibration, 3128c2ecf20Sopenharmony_ci ab8500_sysfs_store_rtc_calibration); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct attribute *ab8500_rtc_attrs[] = { 3158c2ecf20Sopenharmony_ci &dev_attr_rtc_calibration.attr, 3168c2ecf20Sopenharmony_ci NULL 3178c2ecf20Sopenharmony_ci}; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic const struct attribute_group ab8500_rtc_sysfs_files = { 3208c2ecf20Sopenharmony_ci .attrs = ab8500_rtc_attrs, 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic irqreturn_t rtc_alarm_handler(int irq, void *data) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct rtc_device *rtc = data; 3268c2ecf20Sopenharmony_ci unsigned long events = RTC_IRQF | RTC_AF; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci dev_dbg(&rtc->dev, "%s\n", __func__); 3298c2ecf20Sopenharmony_ci rtc_update_irq(rtc, 1, events); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic const struct rtc_class_ops ab8500_rtc_ops = { 3358c2ecf20Sopenharmony_ci .read_time = ab8500_rtc_read_time, 3368c2ecf20Sopenharmony_ci .set_time = ab8500_rtc_set_time, 3378c2ecf20Sopenharmony_ci .read_alarm = ab8500_rtc_read_alarm, 3388c2ecf20Sopenharmony_ci .set_alarm = ab8500_rtc_set_alarm, 3398c2ecf20Sopenharmony_ci .alarm_irq_enable = ab8500_rtc_irq_enable, 3408c2ecf20Sopenharmony_ci}; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic const struct platform_device_id ab85xx_rtc_ids[] = { 3438c2ecf20Sopenharmony_ci { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, 3448c2ecf20Sopenharmony_ci { /* sentinel */ } 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int ab8500_rtc_probe(struct platform_device *pdev) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci const struct platform_device_id *platid = platform_get_device_id(pdev); 3518c2ecf20Sopenharmony_ci int err; 3528c2ecf20Sopenharmony_ci struct rtc_device *rtc; 3538c2ecf20Sopenharmony_ci u8 rtc_ctrl; 3548c2ecf20Sopenharmony_ci int irq; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "ALARM"); 3578c2ecf20Sopenharmony_ci if (irq < 0) 3588c2ecf20Sopenharmony_ci return irq; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* For RTC supply test */ 3618c2ecf20Sopenharmony_ci err = abx500_mask_and_set_register_interruptible(&pdev->dev, AB8500_RTC, 3628c2ecf20Sopenharmony_ci AB8500_RTC_STAT_REG, RTC_STATUS_DATA, RTC_STATUS_DATA); 3638c2ecf20Sopenharmony_ci if (err < 0) 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Wait for reset by the PorRtc */ 3678c2ecf20Sopenharmony_ci usleep_range(1000, 5000); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC, 3708c2ecf20Sopenharmony_ci AB8500_RTC_STAT_REG, &rtc_ctrl); 3718c2ecf20Sopenharmony_ci if (err < 0) 3728c2ecf20Sopenharmony_ci return err; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Check if the RTC Supply fails */ 3758c2ecf20Sopenharmony_ci if (!(rtc_ctrl & RTC_STATUS_DATA)) { 3768c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "RTC supply failure\n"); 3778c2ecf20Sopenharmony_ci return -ENODEV; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, true); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci rtc = devm_rtc_allocate_device(&pdev->dev); 3838c2ecf20Sopenharmony_ci if (IS_ERR(rtc)) 3848c2ecf20Sopenharmony_ci return PTR_ERR(rtc); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci rtc->ops = (struct rtc_class_ops *)platid->driver_data; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci err = devm_request_threaded_irq(&pdev->dev, irq, NULL, 3898c2ecf20Sopenharmony_ci rtc_alarm_handler, IRQF_ONESHOT, 3908c2ecf20Sopenharmony_ci "ab8500-rtc", rtc); 3918c2ecf20Sopenharmony_ci if (err < 0) 3928c2ecf20Sopenharmony_ci return err; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci dev_pm_set_wake_irq(&pdev->dev, irq); 3958c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rtc); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rtc->uie_unsupported = 1; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci rtc->range_max = (1ULL << 24) * 60 - 1; // 24-bit minutes + 59 secs 4008c2ecf20Sopenharmony_ci rtc->start_secs = RTC_TIMESTAMP_BEGIN_2000; 4018c2ecf20Sopenharmony_ci rtc->set_start_time = true; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci err = rtc_add_group(rtc, &ab8500_rtc_sysfs_files); 4048c2ecf20Sopenharmony_ci if (err) 4058c2ecf20Sopenharmony_ci return err; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return rtc_register_device(rtc); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int ab8500_rtc_remove(struct platform_device *pdev) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci dev_pm_clear_wake_irq(&pdev->dev); 4138c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, false); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic struct platform_driver ab8500_rtc_driver = { 4198c2ecf20Sopenharmony_ci .driver = { 4208c2ecf20Sopenharmony_ci .name = "ab8500-rtc", 4218c2ecf20Sopenharmony_ci }, 4228c2ecf20Sopenharmony_ci .probe = ab8500_rtc_probe, 4238c2ecf20Sopenharmony_ci .remove = ab8500_rtc_remove, 4248c2ecf20Sopenharmony_ci .id_table = ab85xx_rtc_ids, 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cimodule_platform_driver(ab8500_rtc_driver); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>"); 4308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AB8500 RTC Driver"); 4318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 432