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