xref: /openbmc/linux/drivers/rtc/rtc-mxc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
175d01b75SFabio Estevam // SPDX-License-Identifier: GPL-2.0+
275d01b75SFabio Estevam //
375d01b75SFabio Estevam // Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
4d00ed3cfSDaniel Mack 
5d00ed3cfSDaniel Mack #include <linux/io.h>
6d00ed3cfSDaniel Mack #include <linux/rtc.h>
7d00ed3cfSDaniel Mack #include <linux/module.h>
85a0e3ad6STejun Heo #include <linux/slab.h>
9d00ed3cfSDaniel Mack #include <linux/interrupt.h>
10d00ed3cfSDaniel Mack #include <linux/platform_device.h>
11bc0e731fSAnson Huang #include <linux/pm_wakeirq.h>
12d00ed3cfSDaniel Mack #include <linux/clk.h>
13cec13c26SPhilippe Reynes #include <linux/of.h>
14d00ed3cfSDaniel Mack 
15d00ed3cfSDaniel Mack #define RTC_INPUT_CLK_32768HZ	(0x00 << 5)
16d00ed3cfSDaniel Mack #define RTC_INPUT_CLK_32000HZ	(0x01 << 5)
17d00ed3cfSDaniel Mack #define RTC_INPUT_CLK_38400HZ	(0x02 << 5)
18d00ed3cfSDaniel Mack 
19d00ed3cfSDaniel Mack #define RTC_SW_BIT      (1 << 0)
20d00ed3cfSDaniel Mack #define RTC_ALM_BIT     (1 << 2)
21d00ed3cfSDaniel Mack #define RTC_1HZ_BIT     (1 << 4)
22d00ed3cfSDaniel Mack #define RTC_2HZ_BIT     (1 << 7)
23d00ed3cfSDaniel Mack #define RTC_SAM0_BIT    (1 << 8)
24d00ed3cfSDaniel Mack #define RTC_SAM1_BIT    (1 << 9)
25d00ed3cfSDaniel Mack #define RTC_SAM2_BIT    (1 << 10)
26d00ed3cfSDaniel Mack #define RTC_SAM3_BIT    (1 << 11)
27d00ed3cfSDaniel Mack #define RTC_SAM4_BIT    (1 << 12)
28d00ed3cfSDaniel Mack #define RTC_SAM5_BIT    (1 << 13)
29d00ed3cfSDaniel Mack #define RTC_SAM6_BIT    (1 << 14)
30d00ed3cfSDaniel Mack #define RTC_SAM7_BIT    (1 << 15)
31d00ed3cfSDaniel Mack #define PIT_ALL_ON      (RTC_2HZ_BIT | RTC_SAM0_BIT | RTC_SAM1_BIT | \
32d00ed3cfSDaniel Mack 			 RTC_SAM2_BIT | RTC_SAM3_BIT | RTC_SAM4_BIT | \
33d00ed3cfSDaniel Mack 			 RTC_SAM5_BIT | RTC_SAM6_BIT | RTC_SAM7_BIT)
34d00ed3cfSDaniel Mack 
35d00ed3cfSDaniel Mack #define RTC_ENABLE_BIT  (1 << 7)
36d00ed3cfSDaniel Mack 
37d00ed3cfSDaniel Mack #define MAX_PIE_NUM     9
38d00ed3cfSDaniel Mack #define MAX_PIE_FREQ    512
39d00ed3cfSDaniel Mack 
40d00ed3cfSDaniel Mack #define MXC_RTC_TIME	0
41d00ed3cfSDaniel Mack #define MXC_RTC_ALARM	1
42d00ed3cfSDaniel Mack 
43d00ed3cfSDaniel Mack #define RTC_HOURMIN	0x00	/*  32bit rtc hour/min counter reg */
44d00ed3cfSDaniel Mack #define RTC_SECOND	0x04	/*  32bit rtc seconds counter reg */
45d00ed3cfSDaniel Mack #define RTC_ALRM_HM	0x08	/*  32bit rtc alarm hour/min reg */
46d00ed3cfSDaniel Mack #define RTC_ALRM_SEC	0x0C	/*  32bit rtc alarm seconds reg */
47d00ed3cfSDaniel Mack #define RTC_RTCCTL	0x10	/*  32bit rtc control reg */
48d00ed3cfSDaniel Mack #define RTC_RTCISR	0x14	/*  32bit rtc interrupt status reg */
49d00ed3cfSDaniel Mack #define RTC_RTCIENR	0x18	/*  32bit rtc interrupt enable reg */
50d00ed3cfSDaniel Mack #define RTC_STPWCH	0x1C	/*  32bit rtc stopwatch min reg */
51d00ed3cfSDaniel Mack #define RTC_DAYR	0x20	/*  32bit rtc days counter reg */
52d00ed3cfSDaniel Mack #define RTC_DAYALARM	0x24	/*  32bit rtc day alarm reg */
53d00ed3cfSDaniel Mack #define RTC_TEST1	0x28	/*  32bit rtc test reg 1 */
54d00ed3cfSDaniel Mack #define RTC_TEST2	0x2C	/*  32bit rtc test reg 2 */
55d00ed3cfSDaniel Mack #define RTC_TEST3	0x30	/*  32bit rtc test reg 3 */
56d00ed3cfSDaniel Mack 
57bb1d34a2SShawn Guo enum imx_rtc_type {
58bb1d34a2SShawn Guo 	IMX1_RTC,
59bb1d34a2SShawn Guo 	IMX21_RTC,
60bb1d34a2SShawn Guo };
61bb1d34a2SShawn Guo 
62d00ed3cfSDaniel Mack struct rtc_plat_data {
63d00ed3cfSDaniel Mack 	struct rtc_device *rtc;
64d00ed3cfSDaniel Mack 	void __iomem *ioaddr;
65d00ed3cfSDaniel Mack 	int irq;
668f5fe778SPhilippe Reynes 	struct clk *clk_ref;
678f5fe778SPhilippe Reynes 	struct clk *clk_ipg;
68d00ed3cfSDaniel Mack 	struct rtc_time g_rtc_alarm;
69bb1d34a2SShawn Guo 	enum imx_rtc_type devtype;
70d00ed3cfSDaniel Mack };
71d00ed3cfSDaniel Mack 
72cec13c26SPhilippe Reynes static const struct of_device_id imx_rtc_dt_ids[] = {
73cec13c26SPhilippe Reynes 	{ .compatible = "fsl,imx1-rtc", .data = (const void *)IMX1_RTC },
74cec13c26SPhilippe Reynes 	{ .compatible = "fsl,imx21-rtc", .data = (const void *)IMX21_RTC },
75cec13c26SPhilippe Reynes 	{}
76cec13c26SPhilippe Reynes };
77cec13c26SPhilippe Reynes MODULE_DEVICE_TABLE(of, imx_rtc_dt_ids);
78cec13c26SPhilippe Reynes 
is_imx1_rtc(struct rtc_plat_data * data)79bb1d34a2SShawn Guo static inline int is_imx1_rtc(struct rtc_plat_data *data)
80bb1d34a2SShawn Guo {
81bb1d34a2SShawn Guo 	return data->devtype == IMX1_RTC;
82bb1d34a2SShawn Guo }
83bb1d34a2SShawn Guo 
84d00ed3cfSDaniel Mack /*
85d00ed3cfSDaniel Mack  * This function is used to obtain the RTC time or the alarm value in
86d00ed3cfSDaniel Mack  * second.
87d00ed3cfSDaniel Mack  */
get_alarm_or_time(struct device * dev,int time_alarm)88a015b8aaSXunlei Pang static time64_t get_alarm_or_time(struct device *dev, int time_alarm)
89d00ed3cfSDaniel Mack {
9085368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
91d00ed3cfSDaniel Mack 	void __iomem *ioaddr = pdata->ioaddr;
92d00ed3cfSDaniel Mack 	u32 day = 0, hr = 0, min = 0, sec = 0, hr_min = 0;
93d00ed3cfSDaniel Mack 
94d00ed3cfSDaniel Mack 	switch (time_alarm) {
95d00ed3cfSDaniel Mack 	case MXC_RTC_TIME:
96d00ed3cfSDaniel Mack 		day = readw(ioaddr + RTC_DAYR);
97d00ed3cfSDaniel Mack 		hr_min = readw(ioaddr + RTC_HOURMIN);
98d00ed3cfSDaniel Mack 		sec = readw(ioaddr + RTC_SECOND);
99d00ed3cfSDaniel Mack 		break;
100d00ed3cfSDaniel Mack 	case MXC_RTC_ALARM:
101d00ed3cfSDaniel Mack 		day = readw(ioaddr + RTC_DAYALARM);
102d00ed3cfSDaniel Mack 		hr_min = readw(ioaddr + RTC_ALRM_HM) & 0xffff;
103d00ed3cfSDaniel Mack 		sec = readw(ioaddr + RTC_ALRM_SEC);
104d00ed3cfSDaniel Mack 		break;
105d00ed3cfSDaniel Mack 	}
106d00ed3cfSDaniel Mack 
107d00ed3cfSDaniel Mack 	hr = hr_min >> 8;
108d00ed3cfSDaniel Mack 	min = hr_min & 0xff;
109d00ed3cfSDaniel Mack 
110a015b8aaSXunlei Pang 	return ((((time64_t)day * 24 + hr) * 60) + min) * 60 + sec;
111d00ed3cfSDaniel Mack }
112d00ed3cfSDaniel Mack 
113d00ed3cfSDaniel Mack /*
114d00ed3cfSDaniel Mack  * This function sets the RTC alarm value or the time value.
115d00ed3cfSDaniel Mack  */
set_alarm_or_time(struct device * dev,int time_alarm,time64_t time)116a015b8aaSXunlei Pang static void set_alarm_or_time(struct device *dev, int time_alarm, time64_t time)
117d00ed3cfSDaniel Mack {
118a015b8aaSXunlei Pang 	u32 tod, day, hr, min, sec, temp;
11985368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
120d00ed3cfSDaniel Mack 	void __iomem *ioaddr = pdata->ioaddr;
121d00ed3cfSDaniel Mack 
122a015b8aaSXunlei Pang 	day = div_s64_rem(time, 86400, &tod);
123d00ed3cfSDaniel Mack 
124d00ed3cfSDaniel Mack 	/* time is within a day now */
125a015b8aaSXunlei Pang 	hr = tod / 3600;
126a015b8aaSXunlei Pang 	tod -= hr * 3600;
127d00ed3cfSDaniel Mack 
128d00ed3cfSDaniel Mack 	/* time is within an hour now */
129a015b8aaSXunlei Pang 	min = tod / 60;
130a015b8aaSXunlei Pang 	sec = tod - min * 60;
131d00ed3cfSDaniel Mack 
132d00ed3cfSDaniel Mack 	temp = (hr << 8) + min;
133d00ed3cfSDaniel Mack 
134d00ed3cfSDaniel Mack 	switch (time_alarm) {
135d00ed3cfSDaniel Mack 	case MXC_RTC_TIME:
136d00ed3cfSDaniel Mack 		writew(day, ioaddr + RTC_DAYR);
137d00ed3cfSDaniel Mack 		writew(sec, ioaddr + RTC_SECOND);
138d00ed3cfSDaniel Mack 		writew(temp, ioaddr + RTC_HOURMIN);
139d00ed3cfSDaniel Mack 		break;
140d00ed3cfSDaniel Mack 	case MXC_RTC_ALARM:
141d00ed3cfSDaniel Mack 		writew(day, ioaddr + RTC_DAYALARM);
142d00ed3cfSDaniel Mack 		writew(sec, ioaddr + RTC_ALRM_SEC);
143d00ed3cfSDaniel Mack 		writew(temp, ioaddr + RTC_ALRM_HM);
144d00ed3cfSDaniel Mack 		break;
145d00ed3cfSDaniel Mack 	}
146d00ed3cfSDaniel Mack }
147d00ed3cfSDaniel Mack 
148d00ed3cfSDaniel Mack /*
149d00ed3cfSDaniel Mack  * This function updates the RTC alarm registers and then clears all the
150d00ed3cfSDaniel Mack  * interrupt status bits.
151d00ed3cfSDaniel Mack  */
rtc_update_alarm(struct device * dev,struct rtc_time * alrm)152482494a8SXunlei Pang static void rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
153d00ed3cfSDaniel Mack {
154a015b8aaSXunlei Pang 	time64_t time;
15585368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
156d00ed3cfSDaniel Mack 	void __iomem *ioaddr = pdata->ioaddr;
157d00ed3cfSDaniel Mack 
158a015b8aaSXunlei Pang 	time = rtc_tm_to_time64(alrm);
159d00ed3cfSDaniel Mack 
160d00ed3cfSDaniel Mack 	/* clear all the interrupt status bits */
161d00ed3cfSDaniel Mack 	writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR);
162d00ed3cfSDaniel Mack 	set_alarm_or_time(dev, MXC_RTC_ALARM, time);
163c92182eeSYauhen Kharuzhy }
164c92182eeSYauhen Kharuzhy 
mxc_rtc_irq_enable(struct device * dev,unsigned int bit,unsigned int enabled)165c92182eeSYauhen Kharuzhy static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
166c92182eeSYauhen Kharuzhy 				unsigned int enabled)
167c92182eeSYauhen Kharuzhy {
16885368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
169c92182eeSYauhen Kharuzhy 	void __iomem *ioaddr = pdata->ioaddr;
170c92182eeSYauhen Kharuzhy 	u32 reg;
171b0a3fa44SFuqian Huang 	unsigned long flags;
172c92182eeSYauhen Kharuzhy 
173b0a3fa44SFuqian Huang 	spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
174c92182eeSYauhen Kharuzhy 	reg = readw(ioaddr + RTC_RTCIENR);
175c92182eeSYauhen Kharuzhy 
176c92182eeSYauhen Kharuzhy 	if (enabled)
177c92182eeSYauhen Kharuzhy 		reg |= bit;
178c92182eeSYauhen Kharuzhy 	else
179c92182eeSYauhen Kharuzhy 		reg &= ~bit;
180c92182eeSYauhen Kharuzhy 
181c92182eeSYauhen Kharuzhy 	writew(reg, ioaddr + RTC_RTCIENR);
182b0a3fa44SFuqian Huang 	spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
183d00ed3cfSDaniel Mack }
184d00ed3cfSDaniel Mack 
185d00ed3cfSDaniel Mack /* This function is the RTC interrupt service routine. */
mxc_rtc_interrupt(int irq,void * dev_id)186d00ed3cfSDaniel Mack static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
187d00ed3cfSDaniel Mack {
188d00ed3cfSDaniel Mack 	struct platform_device *pdev = dev_id;
189d00ed3cfSDaniel Mack 	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
190d00ed3cfSDaniel Mack 	void __iomem *ioaddr = pdata->ioaddr;
191d00ed3cfSDaniel Mack 	u32 status;
192d00ed3cfSDaniel Mack 	u32 events = 0;
193d00ed3cfSDaniel Mack 
1943f2d3018SXiaofei Tan 	spin_lock(&pdata->rtc->irq_lock);
195d00ed3cfSDaniel Mack 	status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
196d00ed3cfSDaniel Mack 	/* clear interrupt sources */
197d00ed3cfSDaniel Mack 	writew(status, ioaddr + RTC_RTCISR);
198d00ed3cfSDaniel Mack 
199d00ed3cfSDaniel Mack 	/* update irq data & counter */
200c92182eeSYauhen Kharuzhy 	if (status & RTC_ALM_BIT) {
201d00ed3cfSDaniel Mack 		events |= (RTC_AF | RTC_IRQF);
202c92182eeSYauhen Kharuzhy 		/* RTC alarm should be one-shot */
203c92182eeSYauhen Kharuzhy 		mxc_rtc_irq_enable(&pdev->dev, RTC_ALM_BIT, 0);
204c92182eeSYauhen Kharuzhy 	}
205d00ed3cfSDaniel Mack 
206d00ed3cfSDaniel Mack 	if (status & PIT_ALL_ON)
207d00ed3cfSDaniel Mack 		events |= (RTC_PF | RTC_IRQF);
208d00ed3cfSDaniel Mack 
209d00ed3cfSDaniel Mack 	rtc_update_irq(pdata->rtc, 1, events);
2103f2d3018SXiaofei Tan 	spin_unlock(&pdata->rtc->irq_lock);
211d00ed3cfSDaniel Mack 
212d00ed3cfSDaniel Mack 	return IRQ_HANDLED;
213d00ed3cfSDaniel Mack }
214d00ed3cfSDaniel Mack 
mxc_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)215d00ed3cfSDaniel Mack static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
216d00ed3cfSDaniel Mack {
217d00ed3cfSDaniel Mack 	mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled);
218d00ed3cfSDaniel Mack 	return 0;
219d00ed3cfSDaniel Mack }
220d00ed3cfSDaniel Mack 
221d00ed3cfSDaniel Mack /*
222d00ed3cfSDaniel Mack  * This function reads the current RTC time into tm in Gregorian date.
223d00ed3cfSDaniel Mack  */
mxc_rtc_read_time(struct device * dev,struct rtc_time * tm)224d00ed3cfSDaniel Mack static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
225d00ed3cfSDaniel Mack {
226a015b8aaSXunlei Pang 	time64_t val;
227d00ed3cfSDaniel Mack 
228d00ed3cfSDaniel Mack 	/* Avoid roll-over from reading the different registers */
229d00ed3cfSDaniel Mack 	do {
230d00ed3cfSDaniel Mack 		val = get_alarm_or_time(dev, MXC_RTC_TIME);
231d00ed3cfSDaniel Mack 	} while (val != get_alarm_or_time(dev, MXC_RTC_TIME));
232d00ed3cfSDaniel Mack 
233a015b8aaSXunlei Pang 	rtc_time64_to_tm(val, tm);
234d00ed3cfSDaniel Mack 
235d00ed3cfSDaniel Mack 	return 0;
236d00ed3cfSDaniel Mack }
237d00ed3cfSDaniel Mack 
238d00ed3cfSDaniel Mack /*
239d00ed3cfSDaniel Mack  * This function sets the internal RTC time based on tm in Gregorian date.
240d00ed3cfSDaniel Mack  */
mxc_rtc_set_time(struct device * dev,struct rtc_time * tm)24102bc7235SAlexandre Belloni static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
242d00ed3cfSDaniel Mack {
24302bc7235SAlexandre Belloni 	time64_t time = rtc_tm_to_time64(tm);
24402bc7235SAlexandre Belloni 
245d00ed3cfSDaniel Mack 	/* Avoid roll-over from reading the different registers */
246d00ed3cfSDaniel Mack 	do {
247d00ed3cfSDaniel Mack 		set_alarm_or_time(dev, MXC_RTC_TIME, time);
248d00ed3cfSDaniel Mack 	} while (time != get_alarm_or_time(dev, MXC_RTC_TIME));
249d00ed3cfSDaniel Mack 
250d00ed3cfSDaniel Mack 	return 0;
251d00ed3cfSDaniel Mack }
252d00ed3cfSDaniel Mack 
253d00ed3cfSDaniel Mack /*
254d00ed3cfSDaniel Mack  * This function reads the current alarm value into the passed in 'alrm'
255d00ed3cfSDaniel Mack  * argument. It updates the alrm's pending field value based on the whether
256d00ed3cfSDaniel Mack  * an alarm interrupt occurs or not.
257d00ed3cfSDaniel Mack  */
mxc_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)258d00ed3cfSDaniel Mack static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
259d00ed3cfSDaniel Mack {
26085368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
261d00ed3cfSDaniel Mack 	void __iomem *ioaddr = pdata->ioaddr;
262d00ed3cfSDaniel Mack 
263a015b8aaSXunlei Pang 	rtc_time64_to_tm(get_alarm_or_time(dev, MXC_RTC_ALARM), &alrm->time);
264d00ed3cfSDaniel Mack 	alrm->pending = ((readw(ioaddr + RTC_RTCISR) & RTC_ALM_BIT)) ? 1 : 0;
265d00ed3cfSDaniel Mack 
266d00ed3cfSDaniel Mack 	return 0;
267d00ed3cfSDaniel Mack }
268d00ed3cfSDaniel Mack 
269d00ed3cfSDaniel Mack /*
270d00ed3cfSDaniel Mack  * This function sets the RTC alarm based on passed in alrm.
271d00ed3cfSDaniel Mack  */
mxc_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)272d00ed3cfSDaniel Mack static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
273d00ed3cfSDaniel Mack {
27485368bb9SWolfram Sang 	struct rtc_plat_data *pdata = dev_get_drvdata(dev);
275d00ed3cfSDaniel Mack 
276482494a8SXunlei Pang 	rtc_update_alarm(dev, &alrm->time);
277d00ed3cfSDaniel Mack 
278d00ed3cfSDaniel Mack 	memcpy(&pdata->g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
279d00ed3cfSDaniel Mack 	mxc_rtc_irq_enable(dev, RTC_ALM_BIT, alrm->enabled);
280d00ed3cfSDaniel Mack 
281d00ed3cfSDaniel Mack 	return 0;
282d00ed3cfSDaniel Mack }
283d00ed3cfSDaniel Mack 
284d00ed3cfSDaniel Mack /* RTC layer */
2858bc57e7fSBhumika Goyal static const struct rtc_class_ops mxc_rtc_ops = {
286d00ed3cfSDaniel Mack 	.read_time		= mxc_rtc_read_time,
28702bc7235SAlexandre Belloni 	.set_time		= mxc_rtc_set_time,
288d00ed3cfSDaniel Mack 	.read_alarm		= mxc_rtc_read_alarm,
289d00ed3cfSDaniel Mack 	.set_alarm		= mxc_rtc_set_alarm,
290d00ed3cfSDaniel Mack 	.alarm_irq_enable	= mxc_rtc_alarm_irq_enable,
291d00ed3cfSDaniel Mack };
292d00ed3cfSDaniel Mack 
mxc_rtc_probe(struct platform_device * pdev)2935a167f45SGreg Kroah-Hartman static int mxc_rtc_probe(struct platform_device *pdev)
294d00ed3cfSDaniel Mack {
295d00ed3cfSDaniel Mack 	struct rtc_device *rtc;
296d00ed3cfSDaniel Mack 	struct rtc_plat_data *pdata = NULL;
297d00ed3cfSDaniel Mack 	u32 reg;
298c783a29eSVladimir Zapolskiy 	unsigned long rate;
299c783a29eSVladimir Zapolskiy 	int ret;
300d00ed3cfSDaniel Mack 
301c783a29eSVladimir Zapolskiy 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
302d00ed3cfSDaniel Mack 	if (!pdata)
303d00ed3cfSDaniel Mack 		return -ENOMEM;
304d00ed3cfSDaniel Mack 
305f78e3d40SFabio Estevam 	pdata->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev);
306bb1d34a2SShawn Guo 
307cf37fa79SAnson Huang 	pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0);
3087c1d69eeSJulia Lawall 	if (IS_ERR(pdata->ioaddr))
3097c1d69eeSJulia Lawall 		return PTR_ERR(pdata->ioaddr);
310d00ed3cfSDaniel Mack 
311ebc2ec4eSAlexandre Belloni 	rtc = devm_rtc_allocate_device(&pdev->dev);
312ebc2ec4eSAlexandre Belloni 	if (IS_ERR(rtc))
313ebc2ec4eSAlexandre Belloni 		return PTR_ERR(rtc);
314ebc2ec4eSAlexandre Belloni 
315ebc2ec4eSAlexandre Belloni 	pdata->rtc = rtc;
316ebc2ec4eSAlexandre Belloni 	rtc->ops = &mxc_rtc_ops;
31783888df4SAlexandre Belloni 	if (is_imx1_rtc(pdata)) {
31883888df4SAlexandre Belloni 		struct rtc_time tm;
31983888df4SAlexandre Belloni 
32083888df4SAlexandre Belloni 		/* 9bit days + hours minutes seconds */
32183888df4SAlexandre Belloni 		rtc->range_max = (1 << 9) * 86400 - 1;
32283888df4SAlexandre Belloni 
32383888df4SAlexandre Belloni 		/*
32483888df4SAlexandre Belloni 		 * Set the start date as beginning of the current year. This can
32583888df4SAlexandre Belloni 		 * be overridden using device tree.
32683888df4SAlexandre Belloni 		 */
32783888df4SAlexandre Belloni 		rtc_time64_to_tm(ktime_get_real_seconds(), &tm);
32883888df4SAlexandre Belloni 		rtc->start_secs =  mktime64(tm.tm_year, 1, 1, 0, 0, 0);
32983888df4SAlexandre Belloni 		rtc->set_start_time = true;
33083888df4SAlexandre Belloni 	} else {
33183888df4SAlexandre Belloni 		/* 16bit days + hours minutes seconds */
33283888df4SAlexandre Belloni 		rtc->range_max = (1 << 16) * 86400ULL - 1;
33383888df4SAlexandre Belloni 	}
334ebc2ec4eSAlexandre Belloni 
335*25bcfaadSChristophe JAILLET 	pdata->clk_ipg = devm_clk_get_enabled(&pdev->dev, "ipg");
3368f5fe778SPhilippe Reynes 	if (IS_ERR(pdata->clk_ipg)) {
3378f5fe778SPhilippe Reynes 		dev_err(&pdev->dev, "unable to get ipg clock!\n");
3388f5fe778SPhilippe Reynes 		return PTR_ERR(pdata->clk_ipg);
33949908e73SAlexander Beregalov 	}
340d00ed3cfSDaniel Mack 
341*25bcfaadSChristophe JAILLET 	pdata->clk_ref = devm_clk_get_enabled(&pdev->dev, "ref");
3428f5fe778SPhilippe Reynes 	if (IS_ERR(pdata->clk_ref)) {
3438f5fe778SPhilippe Reynes 		dev_err(&pdev->dev, "unable to get ref clock!\n");
344fdc9f0eaSAnson Huang 		return PTR_ERR(pdata->clk_ref);
3458f5fe778SPhilippe Reynes 	}
3468f5fe778SPhilippe Reynes 
3478f5fe778SPhilippe Reynes 	rate = clk_get_rate(pdata->clk_ref);
348d00ed3cfSDaniel Mack 
349d00ed3cfSDaniel Mack 	if (rate == 32768)
350d00ed3cfSDaniel Mack 		reg = RTC_INPUT_CLK_32768HZ;
351d00ed3cfSDaniel Mack 	else if (rate == 32000)
352d00ed3cfSDaniel Mack 		reg = RTC_INPUT_CLK_32000HZ;
353d00ed3cfSDaniel Mack 	else if (rate == 38400)
354d00ed3cfSDaniel Mack 		reg = RTC_INPUT_CLK_38400HZ;
355d00ed3cfSDaniel Mack 	else {
356c783a29eSVladimir Zapolskiy 		dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
357fdc9f0eaSAnson Huang 		return -EINVAL;
358d00ed3cfSDaniel Mack 	}
359d00ed3cfSDaniel Mack 
360d00ed3cfSDaniel Mack 	reg |= RTC_ENABLE_BIT;
361d00ed3cfSDaniel Mack 	writew(reg, (pdata->ioaddr + RTC_RTCCTL));
362d00ed3cfSDaniel Mack 	if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
363d00ed3cfSDaniel Mack 		dev_err(&pdev->dev, "hardware module can't be enabled!\n");
364fdc9f0eaSAnson Huang 		return -EIO;
365d00ed3cfSDaniel Mack 	}
366d00ed3cfSDaniel Mack 
367d00ed3cfSDaniel Mack 	platform_set_drvdata(pdev, pdata);
368d00ed3cfSDaniel Mack 
369d00ed3cfSDaniel Mack 	/* Configure and enable the RTC */
370d00ed3cfSDaniel Mack 	pdata->irq = platform_get_irq(pdev, 0);
371d00ed3cfSDaniel Mack 
372d00ed3cfSDaniel Mack 	if (pdata->irq >= 0 &&
373c783a29eSVladimir Zapolskiy 	    devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
374c783a29eSVladimir Zapolskiy 			     IRQF_SHARED, pdev->name, pdev) < 0) {
375d00ed3cfSDaniel Mack 		dev_warn(&pdev->dev, "interrupt not available.\n");
376d00ed3cfSDaniel Mack 		pdata->irq = -1;
377d00ed3cfSDaniel Mack 	}
378d00ed3cfSDaniel Mack 
379bc0e731fSAnson Huang 	if (pdata->irq >= 0) {
380c92182eeSYauhen Kharuzhy 		device_init_wakeup(&pdev->dev, 1);
381bc0e731fSAnson Huang 		ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
382bc0e731fSAnson Huang 		if (ret)
383bc0e731fSAnson Huang 			dev_err(&pdev->dev, "failed to enable irq wake\n");
384bc0e731fSAnson Huang 	}
385c92182eeSYauhen Kharuzhy 
386fdcfd854SBartosz Golaszewski 	ret = devm_rtc_register_device(rtc);
387d00ed3cfSDaniel Mack 
388d00ed3cfSDaniel Mack 	return ret;
389d00ed3cfSDaniel Mack }
390d00ed3cfSDaniel Mack 
391d00ed3cfSDaniel Mack static struct platform_driver mxc_rtc_driver = {
392d00ed3cfSDaniel Mack 	.driver = {
393d00ed3cfSDaniel Mack 		   .name	= "mxc_rtc",
3949346ff0bSFabio Estevam 		   .of_match_table = imx_rtc_dt_ids,
395d00ed3cfSDaniel Mack 	},
396be8b6d51SFabio Estevam 	.probe = mxc_rtc_probe,
397d00ed3cfSDaniel Mack };
398d00ed3cfSDaniel Mack 
399be8b6d51SFabio Estevam module_platform_driver(mxc_rtc_driver)
400d00ed3cfSDaniel Mack 
401d00ed3cfSDaniel Mack MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
402d00ed3cfSDaniel Mack MODULE_DESCRIPTION("RTC driver for Freescale MXC");
403d00ed3cfSDaniel Mack MODULE_LICENSE("GPL");
404d00ed3cfSDaniel Mack 
405