12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20e783980SVenu Byravarasu /*
30e783980SVenu Byravarasu * rtc-tps65910.c -- TPS65910 Real Time Clock interface
40e783980SVenu Byravarasu *
50e783980SVenu Byravarasu * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
60e783980SVenu Byravarasu * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
70e783980SVenu Byravarasu *
80e783980SVenu Byravarasu * Based on original TI driver rtc-twl.c
90e783980SVenu Byravarasu * Copyright (C) 2007 MontaVista Software, Inc
100e783980SVenu Byravarasu * Author: Alexandre Rusev <source@mvista.com>
110e783980SVenu Byravarasu */
120e783980SVenu Byravarasu
130e783980SVenu Byravarasu #include <linux/kernel.h>
140e783980SVenu Byravarasu #include <linux/errno.h>
150e783980SVenu Byravarasu #include <linux/init.h>
160e783980SVenu Byravarasu #include <linux/module.h>
170e783980SVenu Byravarasu #include <linux/types.h>
180e783980SVenu Byravarasu #include <linux/rtc.h>
190e783980SVenu Byravarasu #include <linux/bcd.h>
20aecb57daSVesa Jääskeläinen #include <linux/math64.h>
21936d3685SArnd Bergmann #include <linux/property.h>
220e783980SVenu Byravarasu #include <linux/platform_device.h>
230e783980SVenu Byravarasu #include <linux/interrupt.h>
240e783980SVenu Byravarasu #include <linux/mfd/tps65910.h>
250e783980SVenu Byravarasu
260e783980SVenu Byravarasu struct tps65910_rtc {
270e783980SVenu Byravarasu struct rtc_device *rtc;
28eb5eba4eSLaxman Dewangan int irq;
290e783980SVenu Byravarasu };
300e783980SVenu Byravarasu
310e783980SVenu Byravarasu /* Total number of RTC registers needed to set time*/
320e783980SVenu Byravarasu #define NUM_TIME_REGS (TPS65910_YEARS - TPS65910_SECONDS + 1)
330e783980SVenu Byravarasu
34aecb57daSVesa Jääskeläinen /* Total number of RTC registers needed to set compensation registers */
35aecb57daSVesa Jääskeläinen #define NUM_COMP_REGS (TPS65910_RTC_COMP_MSB - TPS65910_RTC_COMP_LSB + 1)
36aecb57daSVesa Jääskeläinen
37aecb57daSVesa Jääskeläinen /* Min and max values supported with 'offset' interface (swapped sign) */
38aecb57daSVesa Jääskeläinen #define MIN_OFFSET (-277761)
39aecb57daSVesa Jääskeläinen #define MAX_OFFSET (277778)
40aecb57daSVesa Jääskeläinen
41aecb57daSVesa Jääskeläinen /* Number of ticks per hour */
42aecb57daSVesa Jääskeläinen #define TICKS_PER_HOUR (32768 * 3600)
43aecb57daSVesa Jääskeläinen
44aecb57daSVesa Jääskeläinen /* Multiplier for ppb conversions */
45aecb57daSVesa Jääskeläinen #define PPB_MULT (1000000000LL)
46aecb57daSVesa Jääskeläinen
tps65910_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)47e3dcb749SVesa Jääskeläinen static int tps65910_rtc_alarm_irq_enable(struct device *dev,
48e3dcb749SVesa Jääskeläinen unsigned int enabled)
490e783980SVenu Byravarasu {
500e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
510e783980SVenu Byravarasu u8 val = 0;
520e783980SVenu Byravarasu
530e783980SVenu Byravarasu if (enabled)
540e783980SVenu Byravarasu val = TPS65910_RTC_INTERRUPTS_IT_ALARM;
550e783980SVenu Byravarasu
560e783980SVenu Byravarasu return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, val);
570e783980SVenu Byravarasu }
580e783980SVenu Byravarasu
590e783980SVenu Byravarasu /*
600e783980SVenu Byravarasu * Gets current tps65910 RTC time and date parameters.
610e783980SVenu Byravarasu *
620e783980SVenu Byravarasu * The RTC's time/alarm representation is not what gmtime(3) requires
630e783980SVenu Byravarasu * Linux to use:
640e783980SVenu Byravarasu *
650e783980SVenu Byravarasu * - Months are 1..12 vs Linux 0-11
660e783980SVenu Byravarasu * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
670e783980SVenu Byravarasu */
tps65910_rtc_read_time(struct device * dev,struct rtc_time * tm)680e783980SVenu Byravarasu static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm)
690e783980SVenu Byravarasu {
700e783980SVenu Byravarasu unsigned char rtc_data[NUM_TIME_REGS];
710e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
720e783980SVenu Byravarasu int ret;
730e783980SVenu Byravarasu
740e783980SVenu Byravarasu /* Copy RTC counting registers to static registers or latches */
750e783980SVenu Byravarasu ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
760e783980SVenu Byravarasu TPS65910_RTC_CTRL_GET_TIME, TPS65910_RTC_CTRL_GET_TIME);
770e783980SVenu Byravarasu if (ret < 0) {
780e783980SVenu Byravarasu dev_err(dev, "RTC CTRL reg update failed with err:%d\n", ret);
790e783980SVenu Byravarasu return ret;
800e783980SVenu Byravarasu }
810e783980SVenu Byravarasu
820e783980SVenu Byravarasu ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, rtc_data,
830e783980SVenu Byravarasu NUM_TIME_REGS);
840e783980SVenu Byravarasu if (ret < 0) {
850e783980SVenu Byravarasu dev_err(dev, "reading from RTC failed with err:%d\n", ret);
860e783980SVenu Byravarasu return ret;
870e783980SVenu Byravarasu }
880e783980SVenu Byravarasu
890e783980SVenu Byravarasu tm->tm_sec = bcd2bin(rtc_data[0]);
900e783980SVenu Byravarasu tm->tm_min = bcd2bin(rtc_data[1]);
910e783980SVenu Byravarasu tm->tm_hour = bcd2bin(rtc_data[2]);
920e783980SVenu Byravarasu tm->tm_mday = bcd2bin(rtc_data[3]);
930e783980SVenu Byravarasu tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
940e783980SVenu Byravarasu tm->tm_year = bcd2bin(rtc_data[5]) + 100;
950e783980SVenu Byravarasu
960e783980SVenu Byravarasu return ret;
970e783980SVenu Byravarasu }
980e783980SVenu Byravarasu
tps65910_rtc_set_time(struct device * dev,struct rtc_time * tm)990e783980SVenu Byravarasu static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
1000e783980SVenu Byravarasu {
1010e783980SVenu Byravarasu unsigned char rtc_data[NUM_TIME_REGS];
1020e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
1030e783980SVenu Byravarasu int ret;
1040e783980SVenu Byravarasu
1050e783980SVenu Byravarasu rtc_data[0] = bin2bcd(tm->tm_sec);
1060e783980SVenu Byravarasu rtc_data[1] = bin2bcd(tm->tm_min);
1070e783980SVenu Byravarasu rtc_data[2] = bin2bcd(tm->tm_hour);
1080e783980SVenu Byravarasu rtc_data[3] = bin2bcd(tm->tm_mday);
1090e783980SVenu Byravarasu rtc_data[4] = bin2bcd(tm->tm_mon + 1);
1100e783980SVenu Byravarasu rtc_data[5] = bin2bcd(tm->tm_year - 100);
1110e783980SVenu Byravarasu
1120e783980SVenu Byravarasu /* Stop RTC while updating the RTC time registers */
1130e783980SVenu Byravarasu ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
1140e783980SVenu Byravarasu TPS65910_RTC_CTRL_STOP_RTC, 0);
1150e783980SVenu Byravarasu if (ret < 0) {
1160e783980SVenu Byravarasu dev_err(dev, "RTC stop failed with err:%d\n", ret);
1170e783980SVenu Byravarasu return ret;
1180e783980SVenu Byravarasu }
1190e783980SVenu Byravarasu
1200e783980SVenu Byravarasu /* update all the time registers in one shot */
1210e783980SVenu Byravarasu ret = regmap_bulk_write(tps->regmap, TPS65910_SECONDS, rtc_data,
1220e783980SVenu Byravarasu NUM_TIME_REGS);
1230e783980SVenu Byravarasu if (ret < 0) {
1240e783980SVenu Byravarasu dev_err(dev, "rtc_set_time error %d\n", ret);
1250e783980SVenu Byravarasu return ret;
1260e783980SVenu Byravarasu }
1270e783980SVenu Byravarasu
1280e783980SVenu Byravarasu /* Start back RTC */
1290e783980SVenu Byravarasu ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
1300e783980SVenu Byravarasu TPS65910_RTC_CTRL_STOP_RTC, 1);
1310e783980SVenu Byravarasu if (ret < 0)
1320e783980SVenu Byravarasu dev_err(dev, "RTC start failed with err:%d\n", ret);
1330e783980SVenu Byravarasu
1340e783980SVenu Byravarasu return ret;
1350e783980SVenu Byravarasu }
1360e783980SVenu Byravarasu
1370e783980SVenu Byravarasu /*
1380e783980SVenu Byravarasu * Gets current tps65910 RTC alarm time.
1390e783980SVenu Byravarasu */
tps65910_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alm)1400e783980SVenu Byravarasu static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
1410e783980SVenu Byravarasu {
1420e783980SVenu Byravarasu unsigned char alarm_data[NUM_TIME_REGS];
1430e783980SVenu Byravarasu u32 int_val;
1440e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
1450e783980SVenu Byravarasu int ret;
1460e783980SVenu Byravarasu
14742ca37caSMichał Mirosław ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data,
1480e783980SVenu Byravarasu NUM_TIME_REGS);
1490e783980SVenu Byravarasu if (ret < 0) {
1500e783980SVenu Byravarasu dev_err(dev, "rtc_read_alarm error %d\n", ret);
1510e783980SVenu Byravarasu return ret;
1520e783980SVenu Byravarasu }
1530e783980SVenu Byravarasu
1540e783980SVenu Byravarasu alm->time.tm_sec = bcd2bin(alarm_data[0]);
1550e783980SVenu Byravarasu alm->time.tm_min = bcd2bin(alarm_data[1]);
1560e783980SVenu Byravarasu alm->time.tm_hour = bcd2bin(alarm_data[2]);
1570e783980SVenu Byravarasu alm->time.tm_mday = bcd2bin(alarm_data[3]);
1580e783980SVenu Byravarasu alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
1590e783980SVenu Byravarasu alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
1600e783980SVenu Byravarasu
1610e783980SVenu Byravarasu ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &int_val);
1620e783980SVenu Byravarasu if (ret < 0)
1630e783980SVenu Byravarasu return ret;
1640e783980SVenu Byravarasu
1650e783980SVenu Byravarasu if (int_val & TPS65910_RTC_INTERRUPTS_IT_ALARM)
1660e783980SVenu Byravarasu alm->enabled = 1;
1670e783980SVenu Byravarasu
1680e783980SVenu Byravarasu return ret;
1690e783980SVenu Byravarasu }
1700e783980SVenu Byravarasu
tps65910_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alm)1710e783980SVenu Byravarasu static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
1720e783980SVenu Byravarasu {
1730e783980SVenu Byravarasu unsigned char alarm_data[NUM_TIME_REGS];
1740e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
1750e783980SVenu Byravarasu int ret;
1760e783980SVenu Byravarasu
1770e783980SVenu Byravarasu ret = tps65910_rtc_alarm_irq_enable(dev, 0);
1780e783980SVenu Byravarasu if (ret)
1790e783980SVenu Byravarasu return ret;
1800e783980SVenu Byravarasu
1810e783980SVenu Byravarasu alarm_data[0] = bin2bcd(alm->time.tm_sec);
1820e783980SVenu Byravarasu alarm_data[1] = bin2bcd(alm->time.tm_min);
1830e783980SVenu Byravarasu alarm_data[2] = bin2bcd(alm->time.tm_hour);
1840e783980SVenu Byravarasu alarm_data[3] = bin2bcd(alm->time.tm_mday);
1850e783980SVenu Byravarasu alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
1860e783980SVenu Byravarasu alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
1870e783980SVenu Byravarasu
1880e783980SVenu Byravarasu /* update all the alarm registers in one shot */
1890e783980SVenu Byravarasu ret = regmap_bulk_write(tps->regmap, TPS65910_ALARM_SECONDS,
1900e783980SVenu Byravarasu alarm_data, NUM_TIME_REGS);
1910e783980SVenu Byravarasu if (ret) {
1920e783980SVenu Byravarasu dev_err(dev, "rtc_set_alarm error %d\n", ret);
1930e783980SVenu Byravarasu return ret;
1940e783980SVenu Byravarasu }
1950e783980SVenu Byravarasu
1960e783980SVenu Byravarasu if (alm->enabled)
1970e783980SVenu Byravarasu ret = tps65910_rtc_alarm_irq_enable(dev, 1);
1980e783980SVenu Byravarasu
1990e783980SVenu Byravarasu return ret;
2000e783980SVenu Byravarasu }
2010e783980SVenu Byravarasu
tps65910_rtc_set_calibration(struct device * dev,int calibration)202aecb57daSVesa Jääskeläinen static int tps65910_rtc_set_calibration(struct device *dev, int calibration)
203aecb57daSVesa Jääskeläinen {
204aecb57daSVesa Jääskeläinen unsigned char comp_data[NUM_COMP_REGS];
205aecb57daSVesa Jääskeläinen struct tps65910 *tps = dev_get_drvdata(dev->parent);
206aecb57daSVesa Jääskeläinen s16 value;
207aecb57daSVesa Jääskeläinen int ret;
208aecb57daSVesa Jääskeläinen
209aecb57daSVesa Jääskeläinen /*
210aecb57daSVesa Jääskeläinen * TPS65910 uses two's complement 16 bit value for compensation for RTC
211aecb57daSVesa Jääskeläinen * crystal inaccuracies. One time every hour when seconds counter
212aecb57daSVesa Jääskeläinen * increments from 0 to 1 compensation value will be added to internal
213aecb57daSVesa Jääskeläinen * RTC counter value.
214aecb57daSVesa Jääskeläinen *
215aecb57daSVesa Jääskeläinen * Compensation value 0x7FFF is prohibited value.
216aecb57daSVesa Jääskeläinen *
217aecb57daSVesa Jääskeläinen * Valid range for compensation value: [-32768 .. 32766]
218aecb57daSVesa Jääskeläinen */
219aecb57daSVesa Jääskeläinen if ((calibration < -32768) || (calibration > 32766)) {
220aecb57daSVesa Jääskeläinen dev_err(dev, "RTC calibration value out of range: %d\n",
221aecb57daSVesa Jääskeläinen calibration);
222aecb57daSVesa Jääskeläinen return -EINVAL;
223aecb57daSVesa Jääskeläinen }
224aecb57daSVesa Jääskeläinen
225aecb57daSVesa Jääskeläinen value = (s16)calibration;
226aecb57daSVesa Jääskeläinen
227aecb57daSVesa Jääskeläinen comp_data[0] = (u16)value & 0xFF;
228aecb57daSVesa Jääskeläinen comp_data[1] = ((u16)value >> 8) & 0xFF;
229aecb57daSVesa Jääskeläinen
230aecb57daSVesa Jääskeläinen /* Update all the compensation registers in one shot */
231aecb57daSVesa Jääskeläinen ret = regmap_bulk_write(tps->regmap, TPS65910_RTC_COMP_LSB,
232aecb57daSVesa Jääskeläinen comp_data, NUM_COMP_REGS);
233aecb57daSVesa Jääskeläinen if (ret < 0) {
234aecb57daSVesa Jääskeläinen dev_err(dev, "rtc_set_calibration error: %d\n", ret);
235aecb57daSVesa Jääskeläinen return ret;
236aecb57daSVesa Jääskeläinen }
237aecb57daSVesa Jääskeläinen
238aecb57daSVesa Jääskeläinen /* Enable automatic compensation */
239aecb57daSVesa Jääskeläinen ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
240aecb57daSVesa Jääskeläinen TPS65910_RTC_CTRL_AUTO_COMP, TPS65910_RTC_CTRL_AUTO_COMP);
241aecb57daSVesa Jääskeläinen if (ret < 0)
242aecb57daSVesa Jääskeläinen dev_err(dev, "auto_comp enable failed with error: %d\n", ret);
243aecb57daSVesa Jääskeläinen
244aecb57daSVesa Jääskeläinen return ret;
245aecb57daSVesa Jääskeläinen }
246aecb57daSVesa Jääskeläinen
tps65910_rtc_get_calibration(struct device * dev,int * calibration)247aecb57daSVesa Jääskeläinen static int tps65910_rtc_get_calibration(struct device *dev, int *calibration)
248aecb57daSVesa Jääskeläinen {
249aecb57daSVesa Jääskeläinen unsigned char comp_data[NUM_COMP_REGS];
250aecb57daSVesa Jääskeläinen struct tps65910 *tps = dev_get_drvdata(dev->parent);
251aecb57daSVesa Jääskeläinen unsigned int ctrl;
252aecb57daSVesa Jääskeläinen u16 value;
253aecb57daSVesa Jääskeläinen int ret;
254aecb57daSVesa Jääskeläinen
255aecb57daSVesa Jääskeläinen ret = regmap_read(tps->regmap, TPS65910_RTC_CTRL, &ctrl);
256aecb57daSVesa Jääskeläinen if (ret < 0)
257aecb57daSVesa Jääskeläinen return ret;
258aecb57daSVesa Jääskeläinen
259aecb57daSVesa Jääskeläinen /* If automatic compensation is not enabled report back zero */
260aecb57daSVesa Jääskeläinen if (!(ctrl & TPS65910_RTC_CTRL_AUTO_COMP)) {
261aecb57daSVesa Jääskeläinen *calibration = 0;
262aecb57daSVesa Jääskeläinen return 0;
263aecb57daSVesa Jääskeläinen }
264aecb57daSVesa Jääskeläinen
265aecb57daSVesa Jääskeläinen ret = regmap_bulk_read(tps->regmap, TPS65910_RTC_COMP_LSB, comp_data,
266aecb57daSVesa Jääskeläinen NUM_COMP_REGS);
267aecb57daSVesa Jääskeläinen if (ret < 0) {
268aecb57daSVesa Jääskeläinen dev_err(dev, "rtc_get_calibration error: %d\n", ret);
269aecb57daSVesa Jääskeläinen return ret;
270aecb57daSVesa Jääskeläinen }
271aecb57daSVesa Jääskeläinen
272aecb57daSVesa Jääskeläinen value = (u16)comp_data[0] | ((u16)comp_data[1] << 8);
273aecb57daSVesa Jääskeläinen
274aecb57daSVesa Jääskeläinen *calibration = (s16)value;
275aecb57daSVesa Jääskeläinen
276aecb57daSVesa Jääskeläinen return 0;
277aecb57daSVesa Jääskeläinen }
278aecb57daSVesa Jääskeläinen
tps65910_read_offset(struct device * dev,long * offset)279aecb57daSVesa Jääskeläinen static int tps65910_read_offset(struct device *dev, long *offset)
280aecb57daSVesa Jääskeläinen {
281aecb57daSVesa Jääskeläinen int calibration;
282aecb57daSVesa Jääskeläinen s64 tmp;
283aecb57daSVesa Jääskeläinen int ret;
284aecb57daSVesa Jääskeläinen
285aecb57daSVesa Jääskeläinen ret = tps65910_rtc_get_calibration(dev, &calibration);
286aecb57daSVesa Jääskeläinen if (ret < 0)
287aecb57daSVesa Jääskeläinen return ret;
288aecb57daSVesa Jääskeläinen
289aecb57daSVesa Jääskeläinen /* Convert from RTC calibration register format to ppb format */
290aecb57daSVesa Jääskeläinen tmp = calibration * (s64)PPB_MULT;
291aecb57daSVesa Jääskeläinen if (tmp < 0)
292aecb57daSVesa Jääskeläinen tmp -= TICKS_PER_HOUR / 2LL;
293aecb57daSVesa Jääskeläinen else
294aecb57daSVesa Jääskeläinen tmp += TICKS_PER_HOUR / 2LL;
295aecb57daSVesa Jääskeläinen tmp = div_s64(tmp, TICKS_PER_HOUR);
296aecb57daSVesa Jääskeläinen
297aecb57daSVesa Jääskeläinen /* Offset value operates in negative way, so swap sign */
298aecb57daSVesa Jääskeläinen *offset = (long)-tmp;
299aecb57daSVesa Jääskeläinen
300aecb57daSVesa Jääskeläinen return 0;
301aecb57daSVesa Jääskeläinen }
302aecb57daSVesa Jääskeläinen
tps65910_set_offset(struct device * dev,long offset)303aecb57daSVesa Jääskeläinen static int tps65910_set_offset(struct device *dev, long offset)
304aecb57daSVesa Jääskeläinen {
305aecb57daSVesa Jääskeläinen int calibration;
306aecb57daSVesa Jääskeläinen s64 tmp;
307aecb57daSVesa Jääskeläinen int ret;
308aecb57daSVesa Jääskeläinen
309aecb57daSVesa Jääskeläinen /* Make sure offset value is within supported range */
310aecb57daSVesa Jääskeläinen if (offset < MIN_OFFSET || offset > MAX_OFFSET)
311aecb57daSVesa Jääskeläinen return -ERANGE;
312aecb57daSVesa Jääskeläinen
313aecb57daSVesa Jääskeläinen /* Convert from ppb format to RTC calibration register format */
314aecb57daSVesa Jääskeläinen tmp = offset * (s64)TICKS_PER_HOUR;
315aecb57daSVesa Jääskeläinen if (tmp < 0)
316aecb57daSVesa Jääskeläinen tmp -= PPB_MULT / 2LL;
317aecb57daSVesa Jääskeläinen else
318aecb57daSVesa Jääskeläinen tmp += PPB_MULT / 2LL;
319aecb57daSVesa Jääskeläinen tmp = div_s64(tmp, PPB_MULT);
320aecb57daSVesa Jääskeläinen
321aecb57daSVesa Jääskeläinen /* Offset value operates in negative way, so swap sign */
322aecb57daSVesa Jääskeläinen calibration = (int)-tmp;
323aecb57daSVesa Jääskeläinen
324aecb57daSVesa Jääskeläinen ret = tps65910_rtc_set_calibration(dev, calibration);
325aecb57daSVesa Jääskeläinen
326aecb57daSVesa Jääskeläinen return ret;
327aecb57daSVesa Jääskeläinen }
328aecb57daSVesa Jääskeläinen
tps65910_rtc_interrupt(int irq,void * rtc)3290e783980SVenu Byravarasu static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc)
3300e783980SVenu Byravarasu {
3310e783980SVenu Byravarasu struct device *dev = rtc;
3320e783980SVenu Byravarasu unsigned long events = 0;
3330e783980SVenu Byravarasu struct tps65910 *tps = dev_get_drvdata(dev->parent);
3340e783980SVenu Byravarasu struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
3350e783980SVenu Byravarasu int ret;
3360e783980SVenu Byravarasu u32 rtc_reg;
3370e783980SVenu Byravarasu
3380e783980SVenu Byravarasu ret = regmap_read(tps->regmap, TPS65910_RTC_STATUS, &rtc_reg);
3390e783980SVenu Byravarasu if (ret)
3400e783980SVenu Byravarasu return IRQ_NONE;
3410e783980SVenu Byravarasu
3420e783980SVenu Byravarasu if (rtc_reg & TPS65910_RTC_STATUS_ALARM)
3430e783980SVenu Byravarasu events = RTC_IRQF | RTC_AF;
3440e783980SVenu Byravarasu
3450e783980SVenu Byravarasu ret = regmap_write(tps->regmap, TPS65910_RTC_STATUS, rtc_reg);
3460e783980SVenu Byravarasu if (ret)
3470e783980SVenu Byravarasu return IRQ_NONE;
3480e783980SVenu Byravarasu
3490e783980SVenu Byravarasu /* Notify RTC core on event */
3500e783980SVenu Byravarasu rtc_update_irq(tps_rtc->rtc, 1, events);
3510e783980SVenu Byravarasu
3520e783980SVenu Byravarasu return IRQ_HANDLED;
3530e783980SVenu Byravarasu }
3540e783980SVenu Byravarasu
3550e783980SVenu Byravarasu static const struct rtc_class_ops tps65910_rtc_ops = {
3560e783980SVenu Byravarasu .read_time = tps65910_rtc_read_time,
3570e783980SVenu Byravarasu .set_time = tps65910_rtc_set_time,
3580e783980SVenu Byravarasu .read_alarm = tps65910_rtc_read_alarm,
3590e783980SVenu Byravarasu .set_alarm = tps65910_rtc_set_alarm,
3600e783980SVenu Byravarasu .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
361aecb57daSVesa Jääskeläinen .read_offset = tps65910_read_offset,
362aecb57daSVesa Jääskeläinen .set_offset = tps65910_set_offset,
3630e783980SVenu Byravarasu };
3640e783980SVenu Byravarasu
tps65910_rtc_probe(struct platform_device * pdev)3655a167f45SGreg Kroah-Hartman static int tps65910_rtc_probe(struct platform_device *pdev)
3660e783980SVenu Byravarasu {
3670e783980SVenu Byravarasu struct tps65910 *tps65910 = NULL;
3680e783980SVenu Byravarasu struct tps65910_rtc *tps_rtc = NULL;
3690e783980SVenu Byravarasu int ret;
3700e783980SVenu Byravarasu int irq;
3710e783980SVenu Byravarasu u32 rtc_reg;
3720e783980SVenu Byravarasu
3730e783980SVenu Byravarasu tps65910 = dev_get_drvdata(pdev->dev.parent);
3740e783980SVenu Byravarasu
3750e783980SVenu Byravarasu tps_rtc = devm_kzalloc(&pdev->dev, sizeof(struct tps65910_rtc),
3760e783980SVenu Byravarasu GFP_KERNEL);
3770e783980SVenu Byravarasu if (!tps_rtc)
3780e783980SVenu Byravarasu return -ENOMEM;
3790e783980SVenu Byravarasu
380e6000a43SAlexandre Belloni tps_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
381e6000a43SAlexandre Belloni if (IS_ERR(tps_rtc->rtc))
382e6000a43SAlexandre Belloni return PTR_ERR(tps_rtc->rtc);
383e6000a43SAlexandre Belloni
3840e783980SVenu Byravarasu /* Clear pending interrupts */
3850e783980SVenu Byravarasu ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg);
3860e783980SVenu Byravarasu if (ret < 0)
3870e783980SVenu Byravarasu return ret;
3880e783980SVenu Byravarasu
3890e783980SVenu Byravarasu ret = regmap_write(tps65910->regmap, TPS65910_RTC_STATUS, rtc_reg);
3900e783980SVenu Byravarasu if (ret < 0)
3910e783980SVenu Byravarasu return ret;
3920e783980SVenu Byravarasu
3930e783980SVenu Byravarasu dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n");
39418c701a9SKim, Milo
39518c701a9SKim, Milo /* Enable RTC digital power domain */
39618c701a9SKim, Milo ret = regmap_update_bits(tps65910->regmap, TPS65910_DEVCTRL,
39718c701a9SKim, Milo DEVCTRL_RTC_PWDN_MASK, 0 << DEVCTRL_RTC_PWDN_SHIFT);
39818c701a9SKim, Milo if (ret < 0)
39918c701a9SKim, Milo return ret;
40018c701a9SKim, Milo
4010e783980SVenu Byravarasu rtc_reg = TPS65910_RTC_CTRL_STOP_RTC;
4020e783980SVenu Byravarasu ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg);
4030e783980SVenu Byravarasu if (ret < 0)
4040e783980SVenu Byravarasu return ret;
4050e783980SVenu Byravarasu
4069f7d7a1dSThierry Reding platform_set_drvdata(pdev, tps_rtc);
4079f7d7a1dSThierry Reding
40806f77d18SVenu Byravarasu irq = platform_get_irq(pdev, 0);
409*dac78378SRuan Jinjie if (irq < 0)
410*dac78378SRuan Jinjie return irq;
4110e783980SVenu Byravarasu
4120e783980SVenu Byravarasu ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
413be563c9aSGrygorii Strashko tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
41432c4746cSSivaram Nair dev_name(&pdev->dev), &pdev->dev);
415db96d571SAndrey Skvortsov if (ret < 0)
416db96d571SAndrey Skvortsov irq = -1;
4170e783980SVenu Byravarasu
418db96d571SAndrey Skvortsov tps_rtc->irq = irq;
419454ba154SDmitry Osipenko if (irq != -1) {
420454ba154SDmitry Osipenko if (device_property_present(tps65910->dev, "wakeup-source"))
421454ba154SDmitry Osipenko device_init_wakeup(&pdev->dev, 1);
42212b1ef32SAlexandre Belloni else
423454ba154SDmitry Osipenko device_set_wakeup_capable(&pdev->dev, 1);
424454ba154SDmitry Osipenko } else {
42512b1ef32SAlexandre Belloni clear_bit(RTC_FEATURE_ALARM, tps_rtc->rtc->features);
426454ba154SDmitry Osipenko }
427db96d571SAndrey Skvortsov
42812b1ef32SAlexandre Belloni tps_rtc->rtc->ops = &tps65910_rtc_ops;
42957ad9e69SAlexandre Belloni tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
43057ad9e69SAlexandre Belloni tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
431e6000a43SAlexandre Belloni
432fdcfd854SBartosz Golaszewski return devm_rtc_register_device(tps_rtc->rtc);
4330e783980SVenu Byravarasu }
4340e783980SVenu Byravarasu
4350e783980SVenu Byravarasu #ifdef CONFIG_PM_SLEEP
tps65910_rtc_suspend(struct device * dev)4360e783980SVenu Byravarasu static int tps65910_rtc_suspend(struct device *dev)
4370e783980SVenu Byravarasu {
438eb5eba4eSLaxman Dewangan struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
4390e783980SVenu Byravarasu
440eb5eba4eSLaxman Dewangan if (device_may_wakeup(dev))
441eb5eba4eSLaxman Dewangan enable_irq_wake(tps_rtc->irq);
442dfaf09acSLaxman Dewangan return 0;
4430e783980SVenu Byravarasu }
4440e783980SVenu Byravarasu
tps65910_rtc_resume(struct device * dev)4450e783980SVenu Byravarasu static int tps65910_rtc_resume(struct device *dev)
4460e783980SVenu Byravarasu {
447eb5eba4eSLaxman Dewangan struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
448eb5eba4eSLaxman Dewangan
449eb5eba4eSLaxman Dewangan if (device_may_wakeup(dev))
450eb5eba4eSLaxman Dewangan disable_irq_wake(tps_rtc->irq);
451dfaf09acSLaxman Dewangan return 0;
4520e783980SVenu Byravarasu }
453176a9f20SLaxman Dewangan #endif
4540e783980SVenu Byravarasu
455e4ae909bSJingoo Han static SIMPLE_DEV_PM_OPS(tps65910_rtc_pm_ops, tps65910_rtc_suspend,
456e4ae909bSJingoo Han tps65910_rtc_resume);
4570e783980SVenu Byravarasu
4580e783980SVenu Byravarasu static struct platform_driver tps65910_rtc_driver = {
4590e783980SVenu Byravarasu .probe = tps65910_rtc_probe,
4600e783980SVenu Byravarasu .driver = {
4610e783980SVenu Byravarasu .name = "tps65910-rtc",
462176a9f20SLaxman Dewangan .pm = &tps65910_rtc_pm_ops,
4630e783980SVenu Byravarasu },
4640e783980SVenu Byravarasu };
4650e783980SVenu Byravarasu
4660e783980SVenu Byravarasu module_platform_driver(tps65910_rtc_driver);
4678d448fa0SDmitry Osipenko MODULE_ALIAS("platform:tps65910-rtc");
4680e783980SVenu Byravarasu MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
4690e783980SVenu Byravarasu MODULE_LICENSE("GPL");
470