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