18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * rtc-palmas.c -- Palmas Real Time Clock driver.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci * RTC driver for TI Palma series devices like TPS65913,
58c2ecf20Sopenharmony_ci * TPS65914 power management IC.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2012, NVIDIA Corporation.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Author: Laxman Dewangan <ldewangan@nvidia.com>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
128c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as
138c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
168c2ecf20Sopenharmony_ci * whether express or implied; without even the implied warranty of
178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
188c2ecf20Sopenharmony_ci * General Public License for more details.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
218c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software
228c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
238c2ecf20Sopenharmony_ci * 02111-1307, USA
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/bcd.h>
278c2ecf20Sopenharmony_ci#include <linux/errno.h>
288c2ecf20Sopenharmony_ci#include <linux/init.h>
298c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
308c2ecf20Sopenharmony_ci#include <linux/kernel.h>
318c2ecf20Sopenharmony_ci#include <linux/mfd/palmas.h>
328c2ecf20Sopenharmony_ci#include <linux/module.h>
338c2ecf20Sopenharmony_ci#include <linux/of.h>
348c2ecf20Sopenharmony_ci#include <linux/rtc.h>
358c2ecf20Sopenharmony_ci#include <linux/types.h>
368c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
378c2ecf20Sopenharmony_ci#include <linux/pm.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct palmas_rtc {
408c2ecf20Sopenharmony_ci	struct rtc_device	*rtc;
418c2ecf20Sopenharmony_ci	struct device		*dev;
428c2ecf20Sopenharmony_ci	unsigned int		irq;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Total number of RTC registers needed to set time*/
468c2ecf20Sopenharmony_ci#define PALMAS_NUM_TIME_REGS	(PALMAS_YEARS_REG - PALMAS_SECONDS_REG + 1)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
518c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
528c2ecf20Sopenharmony_ci	int ret;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Copy RTC counting registers to static registers or latches */
558c2ecf20Sopenharmony_ci	ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
568c2ecf20Sopenharmony_ci		PALMAS_RTC_CTRL_REG_GET_TIME, PALMAS_RTC_CTRL_REG_GET_TIME);
578c2ecf20Sopenharmony_ci	if (ret < 0) {
588c2ecf20Sopenharmony_ci		dev_err(dev, "RTC CTRL reg update failed, err: %d\n", ret);
598c2ecf20Sopenharmony_ci		return ret;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
638c2ecf20Sopenharmony_ci			rtc_data, PALMAS_NUM_TIME_REGS);
648c2ecf20Sopenharmony_ci	if (ret < 0) {
658c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_SECONDS reg read failed, err = %d\n", ret);
668c2ecf20Sopenharmony_ci		return ret;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	tm->tm_sec = bcd2bin(rtc_data[0]);
708c2ecf20Sopenharmony_ci	tm->tm_min = bcd2bin(rtc_data[1]);
718c2ecf20Sopenharmony_ci	tm->tm_hour = bcd2bin(rtc_data[2]);
728c2ecf20Sopenharmony_ci	tm->tm_mday = bcd2bin(rtc_data[3]);
738c2ecf20Sopenharmony_ci	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
748c2ecf20Sopenharmony_ci	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return ret;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	unsigned char rtc_data[PALMAS_NUM_TIME_REGS];
828c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
838c2ecf20Sopenharmony_ci	int ret;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	rtc_data[0] = bin2bcd(tm->tm_sec);
868c2ecf20Sopenharmony_ci	rtc_data[1] = bin2bcd(tm->tm_min);
878c2ecf20Sopenharmony_ci	rtc_data[2] = bin2bcd(tm->tm_hour);
888c2ecf20Sopenharmony_ci	rtc_data[3] = bin2bcd(tm->tm_mday);
898c2ecf20Sopenharmony_ci	rtc_data[4] = bin2bcd(tm->tm_mon + 1);
908c2ecf20Sopenharmony_ci	rtc_data[5] = bin2bcd(tm->tm_year - 100);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Stop RTC while updating the RTC time registers */
938c2ecf20Sopenharmony_ci	ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
948c2ecf20Sopenharmony_ci		PALMAS_RTC_CTRL_REG_STOP_RTC, 0);
958c2ecf20Sopenharmony_ci	if (ret < 0) {
968c2ecf20Sopenharmony_ci		dev_err(dev, "RTC stop failed, err = %d\n", ret);
978c2ecf20Sopenharmony_ci		return ret;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG,
1018c2ecf20Sopenharmony_ci		rtc_data, PALMAS_NUM_TIME_REGS);
1028c2ecf20Sopenharmony_ci	if (ret < 0) {
1038c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_SECONDS reg write failed, err = %d\n", ret);
1048c2ecf20Sopenharmony_ci		return ret;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Start back RTC */
1088c2ecf20Sopenharmony_ci	ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
1098c2ecf20Sopenharmony_ci		PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC);
1108c2ecf20Sopenharmony_ci	if (ret < 0)
1118c2ecf20Sopenharmony_ci		dev_err(dev, "RTC start failed, err = %d\n", ret);
1128c2ecf20Sopenharmony_ci	return ret;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
1188c2ecf20Sopenharmony_ci	u8 val;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	val = enabled ? PALMAS_RTC_INTERRUPTS_REG_IT_ALARM : 0;
1218c2ecf20Sopenharmony_ci	return palmas_write(palmas, PALMAS_RTC_BASE,
1228c2ecf20Sopenharmony_ci		PALMAS_RTC_INTERRUPTS_REG, val);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
1288c2ecf20Sopenharmony_ci	u32 int_val;
1298c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
1308c2ecf20Sopenharmony_ci	int ret;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE,
1338c2ecf20Sopenharmony_ci			PALMAS_ALARM_SECONDS_REG,
1348c2ecf20Sopenharmony_ci			alarm_data, PALMAS_NUM_TIME_REGS);
1358c2ecf20Sopenharmony_ci	if (ret < 0) {
1368c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret);
1378c2ecf20Sopenharmony_ci		return ret;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	alm->time.tm_sec = bcd2bin(alarm_data[0]);
1418c2ecf20Sopenharmony_ci	alm->time.tm_min = bcd2bin(alarm_data[1]);
1428c2ecf20Sopenharmony_ci	alm->time.tm_hour = bcd2bin(alarm_data[2]);
1438c2ecf20Sopenharmony_ci	alm->time.tm_mday = bcd2bin(alarm_data[3]);
1448c2ecf20Sopenharmony_ci	alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
1458c2ecf20Sopenharmony_ci	alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG,
1488c2ecf20Sopenharmony_ci			&int_val);
1498c2ecf20Sopenharmony_ci	if (ret < 0) {
1508c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret);
1518c2ecf20Sopenharmony_ci		return ret;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM)
1558c2ecf20Sopenharmony_ci		alm->enabled = 1;
1568c2ecf20Sopenharmony_ci	return ret;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	unsigned char alarm_data[PALMAS_NUM_TIME_REGS];
1628c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
1638c2ecf20Sopenharmony_ci	int ret;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	ret = palmas_rtc_alarm_irq_enable(dev, 0);
1668c2ecf20Sopenharmony_ci	if (ret < 0) {
1678c2ecf20Sopenharmony_ci		dev_err(dev, "Disable RTC alarm failed\n");
1688c2ecf20Sopenharmony_ci		return ret;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	alarm_data[0] = bin2bcd(alm->time.tm_sec);
1728c2ecf20Sopenharmony_ci	alarm_data[1] = bin2bcd(alm->time.tm_min);
1738c2ecf20Sopenharmony_ci	alarm_data[2] = bin2bcd(alm->time.tm_hour);
1748c2ecf20Sopenharmony_ci	alarm_data[3] = bin2bcd(alm->time.tm_mday);
1758c2ecf20Sopenharmony_ci	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
1768c2ecf20Sopenharmony_ci	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE,
1798c2ecf20Sopenharmony_ci		PALMAS_ALARM_SECONDS_REG, alarm_data, PALMAS_NUM_TIME_REGS);
1808c2ecf20Sopenharmony_ci	if (ret < 0) {
1818c2ecf20Sopenharmony_ci		dev_err(dev, "ALARM_SECONDS_REG write failed, err = %d\n", ret);
1828c2ecf20Sopenharmony_ci		return ret;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (alm->enabled)
1868c2ecf20Sopenharmony_ci		ret = palmas_rtc_alarm_irq_enable(dev, 1);
1878c2ecf20Sopenharmony_ci	return ret;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int palmas_clear_interrupts(struct device *dev)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(dev->parent);
1938c2ecf20Sopenharmony_ci	unsigned int rtc_reg;
1948c2ecf20Sopenharmony_ci	int ret;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
1978c2ecf20Sopenharmony_ci				&rtc_reg);
1988c2ecf20Sopenharmony_ci	if (ret < 0) {
1998c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret);
2008c2ecf20Sopenharmony_ci		return ret;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG,
2048c2ecf20Sopenharmony_ci			rtc_reg);
2058c2ecf20Sopenharmony_ci	if (ret < 0) {
2068c2ecf20Sopenharmony_ci		dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret);
2078c2ecf20Sopenharmony_ci		return ret;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic irqreturn_t palmas_rtc_interrupt(int irq, void *context)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct palmas_rtc *palmas_rtc = context;
2158c2ecf20Sopenharmony_ci	struct device *dev = palmas_rtc->dev;
2168c2ecf20Sopenharmony_ci	int ret;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	ret = palmas_clear_interrupts(dev);
2198c2ecf20Sopenharmony_ci	if (ret < 0) {
2208c2ecf20Sopenharmony_ci		dev_err(dev, "RTC interrupt clear failed, err = %d\n", ret);
2218c2ecf20Sopenharmony_ci		return IRQ_NONE;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	rtc_update_irq(palmas_rtc->rtc, 1, RTC_IRQF | RTC_AF);
2258c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic const struct rtc_class_ops palmas_rtc_ops = {
2298c2ecf20Sopenharmony_ci	.read_time	= palmas_rtc_read_time,
2308c2ecf20Sopenharmony_ci	.set_time	= palmas_rtc_set_time,
2318c2ecf20Sopenharmony_ci	.read_alarm	= palmas_rtc_read_alarm,
2328c2ecf20Sopenharmony_ci	.set_alarm	= palmas_rtc_set_alarm,
2338c2ecf20Sopenharmony_ci	.alarm_irq_enable = palmas_rtc_alarm_irq_enable,
2348c2ecf20Sopenharmony_ci};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int palmas_rtc_probe(struct platform_device *pdev)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
2398c2ecf20Sopenharmony_ci	struct palmas_rtc *palmas_rtc = NULL;
2408c2ecf20Sopenharmony_ci	int ret;
2418c2ecf20Sopenharmony_ci	bool enable_bb_charging = false;
2428c2ecf20Sopenharmony_ci	bool high_bb_charging = false;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (pdev->dev.of_node) {
2458c2ecf20Sopenharmony_ci		enable_bb_charging = of_property_read_bool(pdev->dev.of_node,
2468c2ecf20Sopenharmony_ci					"ti,backup-battery-chargeable");
2478c2ecf20Sopenharmony_ci		high_bb_charging = of_property_read_bool(pdev->dev.of_node,
2488c2ecf20Sopenharmony_ci					"ti,backup-battery-charge-high-current");
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc),
2528c2ecf20Sopenharmony_ci			GFP_KERNEL);
2538c2ecf20Sopenharmony_ci	if (!palmas_rtc)
2548c2ecf20Sopenharmony_ci		return -ENOMEM;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* Clear pending interrupts */
2578c2ecf20Sopenharmony_ci	ret = palmas_clear_interrupts(&pdev->dev);
2588c2ecf20Sopenharmony_ci	if (ret < 0) {
2598c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret);
2608c2ecf20Sopenharmony_ci		return ret;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	palmas_rtc->dev = &pdev->dev;
2648c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, palmas_rtc);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (enable_bb_charging) {
2678c2ecf20Sopenharmony_ci		unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		if (high_bb_charging)
2708c2ecf20Sopenharmony_ci			reg = 0;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
2738c2ecf20Sopenharmony_ci			PALMAS_BACKUP_BATTERY_CTRL,
2748c2ecf20Sopenharmony_ci			PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg);
2758c2ecf20Sopenharmony_ci		if (ret < 0) {
2768c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
2778c2ecf20Sopenharmony_ci				"BACKUP_BATTERY_CTRL update failed, %d\n", ret);
2788c2ecf20Sopenharmony_ci			return ret;
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
2828c2ecf20Sopenharmony_ci			PALMAS_BACKUP_BATTERY_CTRL,
2838c2ecf20Sopenharmony_ci			PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN,
2848c2ecf20Sopenharmony_ci			PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN);
2858c2ecf20Sopenharmony_ci		if (ret < 0) {
2868c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
2878c2ecf20Sopenharmony_ci				"BACKUP_BATTERY_CTRL update failed, %d\n", ret);
2888c2ecf20Sopenharmony_ci			return ret;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Start RTC */
2938c2ecf20Sopenharmony_ci	ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
2948c2ecf20Sopenharmony_ci			PALMAS_RTC_CTRL_REG_STOP_RTC,
2958c2ecf20Sopenharmony_ci			PALMAS_RTC_CTRL_REG_STOP_RTC);
2968c2ecf20Sopenharmony_ci	if (ret < 0) {
2978c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret);
2988c2ecf20Sopenharmony_ci		return ret;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	palmas_rtc->irq = platform_get_irq(pdev, 0);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	device_init_wakeup(&pdev->dev, 1);
3048c2ecf20Sopenharmony_ci	palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
3058c2ecf20Sopenharmony_ci				&palmas_rtc_ops, THIS_MODULE);
3068c2ecf20Sopenharmony_ci	if (IS_ERR(palmas_rtc->rtc)) {
3078c2ecf20Sopenharmony_ci		ret = PTR_ERR(palmas_rtc->rtc);
3088c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret);
3098c2ecf20Sopenharmony_ci		return ret;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,
3138c2ecf20Sopenharmony_ci			palmas_rtc_interrupt,
3148c2ecf20Sopenharmony_ci			IRQF_TRIGGER_LOW | IRQF_ONESHOT,
3158c2ecf20Sopenharmony_ci			dev_name(&pdev->dev), palmas_rtc);
3168c2ecf20Sopenharmony_ci	if (ret < 0) {
3178c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
3188c2ecf20Sopenharmony_ci		return ret;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int palmas_rtc_remove(struct platform_device *pdev)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	palmas_rtc_alarm_irq_enable(&pdev->dev, 0);
3278c2ecf20Sopenharmony_ci	return 0;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
3318c2ecf20Sopenharmony_cistatic int palmas_rtc_suspend(struct device *dev)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (device_may_wakeup(dev))
3368c2ecf20Sopenharmony_ci		enable_irq_wake(palmas_rtc->irq);
3378c2ecf20Sopenharmony_ci	return 0;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int palmas_rtc_resume(struct device *dev)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (device_may_wakeup(dev))
3458c2ecf20Sopenharmony_ci		disable_irq_wake(palmas_rtc->irq);
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci#endif
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,
3518c2ecf20Sopenharmony_ci			 palmas_rtc_resume);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
3548c2ecf20Sopenharmony_cistatic const struct of_device_id of_palmas_rtc_match[] = {
3558c2ecf20Sopenharmony_ci	{ .compatible = "ti,palmas-rtc"},
3568c2ecf20Sopenharmony_ci	{ },
3578c2ecf20Sopenharmony_ci};
3588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_palmas_rtc_match);
3598c2ecf20Sopenharmony_ci#endif
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic struct platform_driver palmas_rtc_driver = {
3628c2ecf20Sopenharmony_ci	.probe		= palmas_rtc_probe,
3638c2ecf20Sopenharmony_ci	.remove		= palmas_rtc_remove,
3648c2ecf20Sopenharmony_ci	.driver		= {
3658c2ecf20Sopenharmony_ci		.name	= "palmas-rtc",
3668c2ecf20Sopenharmony_ci		.pm	= &palmas_rtc_pm_ops,
3678c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(of_palmas_rtc_match),
3688c2ecf20Sopenharmony_ci	},
3698c2ecf20Sopenharmony_ci};
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cimodule_platform_driver(palmas_rtc_driver);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:palmas_rtc");
3748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI PALMAS series RTC driver");
3758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
3768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
377