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