xref: /OK3568_Linux_fs/kernel/drivers/rtc/rtc-tps65910.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * rtc-tps65910.c -- TPS65910 Real Time Clock interface
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
6*4882a593Smuzhiyun  * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Based on original TI driver rtc-twl.c
9*4882a593Smuzhiyun  *   Copyright (C) 2007 MontaVista Software, Inc
10*4882a593Smuzhiyun  *   Author: Alexandre Rusev <source@mvista.com>
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/rtc.h>
19*4882a593Smuzhiyun #include <linux/bcd.h>
20*4882a593Smuzhiyun #include <linux/math64.h>
21*4882a593Smuzhiyun #include <linux/platform_device.h>
22*4882a593Smuzhiyun #include <linux/interrupt.h>
23*4882a593Smuzhiyun #include <linux/mfd/tps65910.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun struct tps65910_rtc {
26*4882a593Smuzhiyun 	struct rtc_device	*rtc;
27*4882a593Smuzhiyun 	int irq;
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* Total number of RTC registers needed to set time*/
31*4882a593Smuzhiyun #define NUM_TIME_REGS	(TPS65910_YEARS - TPS65910_SECONDS + 1)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* Total number of RTC registers needed to set compensation registers */
34*4882a593Smuzhiyun #define NUM_COMP_REGS	(TPS65910_RTC_COMP_MSB - TPS65910_RTC_COMP_LSB + 1)
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* Min and max values supported with 'offset' interface (swapped sign) */
37*4882a593Smuzhiyun #define MIN_OFFSET	(-277761)
38*4882a593Smuzhiyun #define MAX_OFFSET	(277778)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* Number of ticks per hour */
41*4882a593Smuzhiyun #define TICKS_PER_HOUR	(32768 * 3600)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* Multiplier for ppb conversions */
44*4882a593Smuzhiyun #define PPB_MULT	(1000000000LL)
45*4882a593Smuzhiyun 
tps65910_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)46*4882a593Smuzhiyun static int tps65910_rtc_alarm_irq_enable(struct device *dev,
47*4882a593Smuzhiyun 					 unsigned int enabled)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
50*4882a593Smuzhiyun 	u8 val = 0;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	if (enabled)
53*4882a593Smuzhiyun 		val = TPS65910_RTC_INTERRUPTS_IT_ALARM;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, val);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * Gets current tps65910 RTC time and date parameters.
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * The RTC's time/alarm representation is not what gmtime(3) requires
62*4882a593Smuzhiyun  * Linux to use:
63*4882a593Smuzhiyun  *
64*4882a593Smuzhiyun  *  - Months are 1..12 vs Linux 0-11
65*4882a593Smuzhiyun  *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
66*4882a593Smuzhiyun  */
tps65910_rtc_read_time(struct device * dev,struct rtc_time * tm)67*4882a593Smuzhiyun static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	unsigned char rtc_data[NUM_TIME_REGS];
70*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
71*4882a593Smuzhiyun 	int ret;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	/* Copy RTC counting registers to static registers or latches */
74*4882a593Smuzhiyun 	ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
75*4882a593Smuzhiyun 		TPS65910_RTC_CTRL_GET_TIME, TPS65910_RTC_CTRL_GET_TIME);
76*4882a593Smuzhiyun 	if (ret < 0) {
77*4882a593Smuzhiyun 		dev_err(dev, "RTC CTRL reg update failed with err:%d\n", ret);
78*4882a593Smuzhiyun 		return ret;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, rtc_data,
82*4882a593Smuzhiyun 		NUM_TIME_REGS);
83*4882a593Smuzhiyun 	if (ret < 0) {
84*4882a593Smuzhiyun 		dev_err(dev, "reading from RTC failed with err:%d\n", ret);
85*4882a593Smuzhiyun 		return ret;
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	tm->tm_sec = bcd2bin(rtc_data[0]);
89*4882a593Smuzhiyun 	tm->tm_min = bcd2bin(rtc_data[1]);
90*4882a593Smuzhiyun 	tm->tm_hour = bcd2bin(rtc_data[2]);
91*4882a593Smuzhiyun 	tm->tm_mday = bcd2bin(rtc_data[3]);
92*4882a593Smuzhiyun 	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
93*4882a593Smuzhiyun 	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	return ret;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
tps65910_rtc_set_time(struct device * dev,struct rtc_time * tm)98*4882a593Smuzhiyun static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	unsigned char rtc_data[NUM_TIME_REGS];
101*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
102*4882a593Smuzhiyun 	int ret;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	rtc_data[0] = bin2bcd(tm->tm_sec);
105*4882a593Smuzhiyun 	rtc_data[1] = bin2bcd(tm->tm_min);
106*4882a593Smuzhiyun 	rtc_data[2] = bin2bcd(tm->tm_hour);
107*4882a593Smuzhiyun 	rtc_data[3] = bin2bcd(tm->tm_mday);
108*4882a593Smuzhiyun 	rtc_data[4] = bin2bcd(tm->tm_mon + 1);
109*4882a593Smuzhiyun 	rtc_data[5] = bin2bcd(tm->tm_year - 100);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	/* Stop RTC while updating the RTC time registers */
112*4882a593Smuzhiyun 	ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
113*4882a593Smuzhiyun 		TPS65910_RTC_CTRL_STOP_RTC, 0);
114*4882a593Smuzhiyun 	if (ret < 0) {
115*4882a593Smuzhiyun 		dev_err(dev, "RTC stop failed with err:%d\n", ret);
116*4882a593Smuzhiyun 		return ret;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* update all the time registers in one shot */
120*4882a593Smuzhiyun 	ret = regmap_bulk_write(tps->regmap, TPS65910_SECONDS, rtc_data,
121*4882a593Smuzhiyun 		NUM_TIME_REGS);
122*4882a593Smuzhiyun 	if (ret < 0) {
123*4882a593Smuzhiyun 		dev_err(dev, "rtc_set_time error %d\n", ret);
124*4882a593Smuzhiyun 		return ret;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* Start back RTC */
128*4882a593Smuzhiyun 	ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
129*4882a593Smuzhiyun 		TPS65910_RTC_CTRL_STOP_RTC, 1);
130*4882a593Smuzhiyun 	if (ret < 0)
131*4882a593Smuzhiyun 		dev_err(dev, "RTC start failed with err:%d\n", ret);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return ret;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun  * Gets current tps65910 RTC alarm time.
138*4882a593Smuzhiyun  */
tps65910_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alm)139*4882a593Smuzhiyun static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	unsigned char alarm_data[NUM_TIME_REGS];
142*4882a593Smuzhiyun 	u32 int_val;
143*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
144*4882a593Smuzhiyun 	int ret;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data,
147*4882a593Smuzhiyun 		NUM_TIME_REGS);
148*4882a593Smuzhiyun 	if (ret < 0) {
149*4882a593Smuzhiyun 		dev_err(dev, "rtc_read_alarm error %d\n", ret);
150*4882a593Smuzhiyun 		return ret;
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	alm->time.tm_sec = bcd2bin(alarm_data[0]);
154*4882a593Smuzhiyun 	alm->time.tm_min = bcd2bin(alarm_data[1]);
155*4882a593Smuzhiyun 	alm->time.tm_hour = bcd2bin(alarm_data[2]);
156*4882a593Smuzhiyun 	alm->time.tm_mday = bcd2bin(alarm_data[3]);
157*4882a593Smuzhiyun 	alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
158*4882a593Smuzhiyun 	alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &int_val);
161*4882a593Smuzhiyun 	if (ret < 0)
162*4882a593Smuzhiyun 		return ret;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (int_val & TPS65910_RTC_INTERRUPTS_IT_ALARM)
165*4882a593Smuzhiyun 		alm->enabled = 1;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return ret;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
tps65910_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alm)170*4882a593Smuzhiyun static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	unsigned char alarm_data[NUM_TIME_REGS];
173*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
174*4882a593Smuzhiyun 	int ret;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	ret = tps65910_rtc_alarm_irq_enable(dev, 0);
177*4882a593Smuzhiyun 	if (ret)
178*4882a593Smuzhiyun 		return ret;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	alarm_data[0] = bin2bcd(alm->time.tm_sec);
181*4882a593Smuzhiyun 	alarm_data[1] = bin2bcd(alm->time.tm_min);
182*4882a593Smuzhiyun 	alarm_data[2] = bin2bcd(alm->time.tm_hour);
183*4882a593Smuzhiyun 	alarm_data[3] = bin2bcd(alm->time.tm_mday);
184*4882a593Smuzhiyun 	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
185*4882a593Smuzhiyun 	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* update all the alarm registers in one shot */
188*4882a593Smuzhiyun 	ret = regmap_bulk_write(tps->regmap, TPS65910_ALARM_SECONDS,
189*4882a593Smuzhiyun 		alarm_data, NUM_TIME_REGS);
190*4882a593Smuzhiyun 	if (ret) {
191*4882a593Smuzhiyun 		dev_err(dev, "rtc_set_alarm error %d\n", ret);
192*4882a593Smuzhiyun 		return ret;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (alm->enabled)
196*4882a593Smuzhiyun 		ret = tps65910_rtc_alarm_irq_enable(dev, 1);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return ret;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
tps65910_rtc_set_calibration(struct device * dev,int calibration)201*4882a593Smuzhiyun static int tps65910_rtc_set_calibration(struct device *dev, int calibration)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	unsigned char comp_data[NUM_COMP_REGS];
204*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
205*4882a593Smuzhiyun 	s16 value;
206*4882a593Smuzhiyun 	int ret;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/*
209*4882a593Smuzhiyun 	 * TPS65910 uses two's complement 16 bit value for compensation for RTC
210*4882a593Smuzhiyun 	 * crystal inaccuracies. One time every hour when seconds counter
211*4882a593Smuzhiyun 	 * increments from 0 to 1 compensation value will be added to internal
212*4882a593Smuzhiyun 	 * RTC counter value.
213*4882a593Smuzhiyun 	 *
214*4882a593Smuzhiyun 	 * Compensation value 0x7FFF is prohibited value.
215*4882a593Smuzhiyun 	 *
216*4882a593Smuzhiyun 	 * Valid range for compensation value: [-32768 .. 32766]
217*4882a593Smuzhiyun 	 */
218*4882a593Smuzhiyun 	if ((calibration < -32768) || (calibration > 32766)) {
219*4882a593Smuzhiyun 		dev_err(dev, "RTC calibration value out of range: %d\n",
220*4882a593Smuzhiyun 			calibration);
221*4882a593Smuzhiyun 		return -EINVAL;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	value = (s16)calibration;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	comp_data[0] = (u16)value & 0xFF;
227*4882a593Smuzhiyun 	comp_data[1] = ((u16)value >> 8) & 0xFF;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	/* Update all the compensation registers in one shot */
230*4882a593Smuzhiyun 	ret = regmap_bulk_write(tps->regmap, TPS65910_RTC_COMP_LSB,
231*4882a593Smuzhiyun 		comp_data, NUM_COMP_REGS);
232*4882a593Smuzhiyun 	if (ret < 0) {
233*4882a593Smuzhiyun 		dev_err(dev, "rtc_set_calibration error: %d\n", ret);
234*4882a593Smuzhiyun 		return ret;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* Enable automatic compensation */
238*4882a593Smuzhiyun 	ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
239*4882a593Smuzhiyun 		TPS65910_RTC_CTRL_AUTO_COMP, TPS65910_RTC_CTRL_AUTO_COMP);
240*4882a593Smuzhiyun 	if (ret < 0)
241*4882a593Smuzhiyun 		dev_err(dev, "auto_comp enable failed with error: %d\n", ret);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return ret;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
tps65910_rtc_get_calibration(struct device * dev,int * calibration)246*4882a593Smuzhiyun static int tps65910_rtc_get_calibration(struct device *dev, int *calibration)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	unsigned char comp_data[NUM_COMP_REGS];
249*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
250*4882a593Smuzhiyun 	unsigned int ctrl;
251*4882a593Smuzhiyun 	u16 value;
252*4882a593Smuzhiyun 	int ret;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	ret = regmap_read(tps->regmap, TPS65910_RTC_CTRL, &ctrl);
255*4882a593Smuzhiyun 	if (ret < 0)
256*4882a593Smuzhiyun 		return ret;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	/* If automatic compensation is not enabled report back zero */
259*4882a593Smuzhiyun 	if (!(ctrl & TPS65910_RTC_CTRL_AUTO_COMP)) {
260*4882a593Smuzhiyun 		*calibration = 0;
261*4882a593Smuzhiyun 		return 0;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	ret = regmap_bulk_read(tps->regmap, TPS65910_RTC_COMP_LSB, comp_data,
265*4882a593Smuzhiyun 		NUM_COMP_REGS);
266*4882a593Smuzhiyun 	if (ret < 0) {
267*4882a593Smuzhiyun 		dev_err(dev, "rtc_get_calibration error: %d\n", ret);
268*4882a593Smuzhiyun 		return ret;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	value = (u16)comp_data[0] | ((u16)comp_data[1] << 8);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	*calibration = (s16)value;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
tps65910_read_offset(struct device * dev,long * offset)278*4882a593Smuzhiyun static int tps65910_read_offset(struct device *dev, long *offset)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	int calibration;
281*4882a593Smuzhiyun 	s64 tmp;
282*4882a593Smuzhiyun 	int ret;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	ret = tps65910_rtc_get_calibration(dev, &calibration);
285*4882a593Smuzhiyun 	if (ret < 0)
286*4882a593Smuzhiyun 		return ret;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* Convert from RTC calibration register format to ppb format */
289*4882a593Smuzhiyun 	tmp = calibration * (s64)PPB_MULT;
290*4882a593Smuzhiyun 	if (tmp < 0)
291*4882a593Smuzhiyun 		tmp -= TICKS_PER_HOUR / 2LL;
292*4882a593Smuzhiyun 	else
293*4882a593Smuzhiyun 		tmp += TICKS_PER_HOUR / 2LL;
294*4882a593Smuzhiyun 	tmp = div_s64(tmp, TICKS_PER_HOUR);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	/* Offset value operates in negative way, so swap sign */
297*4882a593Smuzhiyun 	*offset = (long)-tmp;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
tps65910_set_offset(struct device * dev,long offset)302*4882a593Smuzhiyun static int tps65910_set_offset(struct device *dev, long offset)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	int calibration;
305*4882a593Smuzhiyun 	s64 tmp;
306*4882a593Smuzhiyun 	int ret;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Make sure offset value is within supported range */
309*4882a593Smuzhiyun 	if (offset < MIN_OFFSET || offset > MAX_OFFSET)
310*4882a593Smuzhiyun 		return -ERANGE;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* Convert from ppb format to RTC calibration register format */
313*4882a593Smuzhiyun 	tmp = offset * (s64)TICKS_PER_HOUR;
314*4882a593Smuzhiyun 	if (tmp < 0)
315*4882a593Smuzhiyun 		tmp -= PPB_MULT / 2LL;
316*4882a593Smuzhiyun 	else
317*4882a593Smuzhiyun 		tmp += PPB_MULT / 2LL;
318*4882a593Smuzhiyun 	tmp = div_s64(tmp, PPB_MULT);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	/* Offset value operates in negative way, so swap sign */
321*4882a593Smuzhiyun 	calibration = (int)-tmp;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	ret = tps65910_rtc_set_calibration(dev, calibration);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	return ret;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
tps65910_rtc_interrupt(int irq,void * rtc)328*4882a593Smuzhiyun static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	struct device *dev = rtc;
331*4882a593Smuzhiyun 	unsigned long events = 0;
332*4882a593Smuzhiyun 	struct tps65910 *tps = dev_get_drvdata(dev->parent);
333*4882a593Smuzhiyun 	struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
334*4882a593Smuzhiyun 	int ret;
335*4882a593Smuzhiyun 	u32 rtc_reg;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	ret = regmap_read(tps->regmap, TPS65910_RTC_STATUS, &rtc_reg);
338*4882a593Smuzhiyun 	if (ret)
339*4882a593Smuzhiyun 		return IRQ_NONE;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (rtc_reg & TPS65910_RTC_STATUS_ALARM)
342*4882a593Smuzhiyun 		events = RTC_IRQF | RTC_AF;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	ret = regmap_write(tps->regmap, TPS65910_RTC_STATUS, rtc_reg);
345*4882a593Smuzhiyun 	if (ret)
346*4882a593Smuzhiyun 		return IRQ_NONE;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Notify RTC core on event */
349*4882a593Smuzhiyun 	rtc_update_irq(tps_rtc->rtc, 1, events);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	return IRQ_HANDLED;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun static const struct rtc_class_ops tps65910_rtc_ops = {
355*4882a593Smuzhiyun 	.read_time	= tps65910_rtc_read_time,
356*4882a593Smuzhiyun 	.set_time	= tps65910_rtc_set_time,
357*4882a593Smuzhiyun 	.read_alarm	= tps65910_rtc_read_alarm,
358*4882a593Smuzhiyun 	.set_alarm	= tps65910_rtc_set_alarm,
359*4882a593Smuzhiyun 	.alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
360*4882a593Smuzhiyun 	.read_offset	= tps65910_read_offset,
361*4882a593Smuzhiyun 	.set_offset	= tps65910_set_offset,
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun static const struct rtc_class_ops tps65910_rtc_ops_noirq = {
365*4882a593Smuzhiyun 	.read_time	= tps65910_rtc_read_time,
366*4882a593Smuzhiyun 	.set_time	= tps65910_rtc_set_time,
367*4882a593Smuzhiyun 	.read_offset	= tps65910_read_offset,
368*4882a593Smuzhiyun 	.set_offset	= tps65910_set_offset,
369*4882a593Smuzhiyun };
370*4882a593Smuzhiyun 
tps65910_rtc_probe(struct platform_device * pdev)371*4882a593Smuzhiyun static int tps65910_rtc_probe(struct platform_device *pdev)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct tps65910 *tps65910 = NULL;
374*4882a593Smuzhiyun 	struct tps65910_rtc *tps_rtc = NULL;
375*4882a593Smuzhiyun 	int ret;
376*4882a593Smuzhiyun 	int irq;
377*4882a593Smuzhiyun 	u32 rtc_reg;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	tps65910 = dev_get_drvdata(pdev->dev.parent);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	tps_rtc = devm_kzalloc(&pdev->dev, sizeof(struct tps65910_rtc),
382*4882a593Smuzhiyun 			GFP_KERNEL);
383*4882a593Smuzhiyun 	if (!tps_rtc)
384*4882a593Smuzhiyun 		return -ENOMEM;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	tps_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
387*4882a593Smuzhiyun 	if (IS_ERR(tps_rtc->rtc))
388*4882a593Smuzhiyun 		return PTR_ERR(tps_rtc->rtc);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	/* Clear pending interrupts */
391*4882a593Smuzhiyun 	ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg);
392*4882a593Smuzhiyun 	if (ret < 0)
393*4882a593Smuzhiyun 		return ret;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	ret = regmap_write(tps65910->regmap, TPS65910_RTC_STATUS, rtc_reg);
396*4882a593Smuzhiyun 	if (ret < 0)
397*4882a593Smuzhiyun 		return ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n");
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	/* Enable RTC digital power domain */
402*4882a593Smuzhiyun 	ret = regmap_update_bits(tps65910->regmap, TPS65910_DEVCTRL,
403*4882a593Smuzhiyun 		DEVCTRL_RTC_PWDN_MASK, 0 << DEVCTRL_RTC_PWDN_SHIFT);
404*4882a593Smuzhiyun 	if (ret < 0)
405*4882a593Smuzhiyun 		return ret;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	rtc_reg = TPS65910_RTC_CTRL_STOP_RTC;
408*4882a593Smuzhiyun 	ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg);
409*4882a593Smuzhiyun 	if (ret < 0)
410*4882a593Smuzhiyun 		return ret;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	platform_set_drvdata(pdev, tps_rtc);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	irq  = platform_get_irq(pdev, 0);
415*4882a593Smuzhiyun 	if (irq <= 0) {
416*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
417*4882a593Smuzhiyun 			irq);
418*4882a593Smuzhiyun 		return -ENXIO;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
422*4882a593Smuzhiyun 		tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
423*4882a593Smuzhiyun 		dev_name(&pdev->dev), &pdev->dev);
424*4882a593Smuzhiyun 	if (ret < 0)
425*4882a593Smuzhiyun 		irq = -1;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	tps_rtc->irq = irq;
428*4882a593Smuzhiyun 	if (irq != -1) {
429*4882a593Smuzhiyun 		device_set_wakeup_capable(&pdev->dev, 1);
430*4882a593Smuzhiyun 		tps_rtc->rtc->ops = &tps65910_rtc_ops;
431*4882a593Smuzhiyun 	} else
432*4882a593Smuzhiyun 		tps_rtc->rtc->ops = &tps65910_rtc_ops_noirq;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
435*4882a593Smuzhiyun 	tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	return rtc_register_device(tps_rtc->rtc);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
tps65910_rtc_suspend(struct device * dev)441*4882a593Smuzhiyun static int tps65910_rtc_suspend(struct device *dev)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (device_may_wakeup(dev))
446*4882a593Smuzhiyun 		enable_irq_wake(tps_rtc->irq);
447*4882a593Smuzhiyun 	return 0;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
tps65910_rtc_resume(struct device * dev)450*4882a593Smuzhiyun static int tps65910_rtc_resume(struct device *dev)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (device_may_wakeup(dev))
455*4882a593Smuzhiyun 		disable_irq_wake(tps_rtc->irq);
456*4882a593Smuzhiyun 	return 0;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun #endif
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(tps65910_rtc_pm_ops, tps65910_rtc_suspend,
461*4882a593Smuzhiyun 			tps65910_rtc_resume);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun static struct platform_driver tps65910_rtc_driver = {
464*4882a593Smuzhiyun 	.probe		= tps65910_rtc_probe,
465*4882a593Smuzhiyun 	.driver		= {
466*4882a593Smuzhiyun 		.name	= "tps65910-rtc",
467*4882a593Smuzhiyun 		.pm	= &tps65910_rtc_pm_ops,
468*4882a593Smuzhiyun 	},
469*4882a593Smuzhiyun };
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun module_platform_driver(tps65910_rtc_driver);
472*4882a593Smuzhiyun MODULE_ALIAS("platform:tps65910-rtc");
473*4882a593Smuzhiyun MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
474*4882a593Smuzhiyun MODULE_LICENSE("GPL");
475