177c13d99SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0+
2ba172208SBaruch Siach /*
3ba172208SBaruch Siach * Real Time Clock driver for Conexant Digicolor
4ba172208SBaruch Siach *
5ba172208SBaruch Siach * Copyright (C) 2015 Paradox Innovation Ltd.
6ba172208SBaruch Siach *
7ba172208SBaruch Siach * Author: Baruch Siach <baruch@tkos.co.il>
8ba172208SBaruch Siach */
9ba172208SBaruch Siach
10ba172208SBaruch Siach #include <linux/io.h>
11ba172208SBaruch Siach #include <linux/iopoll.h>
12ba172208SBaruch Siach #include <linux/delay.h>
13ba172208SBaruch Siach #include <linux/module.h>
14ba172208SBaruch Siach #include <linux/platform_device.h>
15ba172208SBaruch Siach #include <linux/rtc.h>
16ba172208SBaruch Siach #include <linux/of.h>
17ba172208SBaruch Siach
18ba172208SBaruch Siach #define DC_RTC_CONTROL 0x0
19ba172208SBaruch Siach #define DC_RTC_TIME 0x8
20ba172208SBaruch Siach #define DC_RTC_REFERENCE 0xc
21ba172208SBaruch Siach #define DC_RTC_ALARM 0x10
22ba172208SBaruch Siach #define DC_RTC_INTFLAG_CLEAR 0x14
23ba172208SBaruch Siach #define DC_RTC_INTENABLE 0x16
24ba172208SBaruch Siach
25ba172208SBaruch Siach #define DC_RTC_CMD_MASK 0xf
26ba172208SBaruch Siach #define DC_RTC_GO_BUSY BIT(7)
27ba172208SBaruch Siach
28ba172208SBaruch Siach #define CMD_NOP 0
29ba172208SBaruch Siach #define CMD_RESET 1
30ba172208SBaruch Siach #define CMD_WRITE 3
31ba172208SBaruch Siach #define CMD_READ 4
32ba172208SBaruch Siach
33ba172208SBaruch Siach #define CMD_DELAY_US (10*1000)
34ba172208SBaruch Siach #define CMD_TIMEOUT_US (500*CMD_DELAY_US)
35ba172208SBaruch Siach
36ba172208SBaruch Siach struct dc_rtc {
37ba172208SBaruch Siach struct rtc_device *rtc_dev;
38ba172208SBaruch Siach void __iomem *regs;
39ba172208SBaruch Siach };
40ba172208SBaruch Siach
dc_rtc_cmds(struct dc_rtc * rtc,const u8 * cmds,int len)41ba172208SBaruch Siach static int dc_rtc_cmds(struct dc_rtc *rtc, const u8 *cmds, int len)
42ba172208SBaruch Siach {
43ba172208SBaruch Siach u8 val;
44ba172208SBaruch Siach int i, ret;
45ba172208SBaruch Siach
46ba172208SBaruch Siach for (i = 0; i < len; i++) {
47ba172208SBaruch Siach writeb_relaxed((cmds[i] & DC_RTC_CMD_MASK) | DC_RTC_GO_BUSY,
48ba172208SBaruch Siach rtc->regs + DC_RTC_CONTROL);
49ba172208SBaruch Siach ret = readb_relaxed_poll_timeout(
50ba172208SBaruch Siach rtc->regs + DC_RTC_CONTROL, val,
51ba172208SBaruch Siach !(val & DC_RTC_GO_BUSY), CMD_DELAY_US, CMD_TIMEOUT_US);
52ba172208SBaruch Siach if (ret < 0)
53ba172208SBaruch Siach return ret;
54ba172208SBaruch Siach }
55ba172208SBaruch Siach
56ba172208SBaruch Siach return 0;
57ba172208SBaruch Siach }
58ba172208SBaruch Siach
dc_rtc_read(struct dc_rtc * rtc,unsigned long * val)59ba172208SBaruch Siach static int dc_rtc_read(struct dc_rtc *rtc, unsigned long *val)
60ba172208SBaruch Siach {
61ba172208SBaruch Siach static const u8 read_cmds[] = {CMD_READ, CMD_NOP};
62ba172208SBaruch Siach u32 reference, time1, time2;
63ba172208SBaruch Siach int ret;
64ba172208SBaruch Siach
65ba172208SBaruch Siach ret = dc_rtc_cmds(rtc, read_cmds, ARRAY_SIZE(read_cmds));
66ba172208SBaruch Siach if (ret < 0)
67ba172208SBaruch Siach return ret;
68ba172208SBaruch Siach
69ba172208SBaruch Siach reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
70ba172208SBaruch Siach time1 = readl_relaxed(rtc->regs + DC_RTC_TIME);
71ba172208SBaruch Siach /* Read twice to ensure consistency */
72ba172208SBaruch Siach while (1) {
73ba172208SBaruch Siach time2 = readl_relaxed(rtc->regs + DC_RTC_TIME);
74ba172208SBaruch Siach if (time1 == time2)
75ba172208SBaruch Siach break;
76ba172208SBaruch Siach time1 = time2;
77ba172208SBaruch Siach }
78ba172208SBaruch Siach
79ba172208SBaruch Siach *val = reference + time1;
80ba172208SBaruch Siach return 0;
81ba172208SBaruch Siach }
82ba172208SBaruch Siach
dc_rtc_write(struct dc_rtc * rtc,u32 val)83ba172208SBaruch Siach static int dc_rtc_write(struct dc_rtc *rtc, u32 val)
84ba172208SBaruch Siach {
85ba172208SBaruch Siach static const u8 write_cmds[] = {CMD_WRITE, CMD_NOP, CMD_RESET, CMD_NOP};
86ba172208SBaruch Siach
87ba172208SBaruch Siach writel_relaxed(val, rtc->regs + DC_RTC_REFERENCE);
88ba172208SBaruch Siach return dc_rtc_cmds(rtc, write_cmds, ARRAY_SIZE(write_cmds));
89ba172208SBaruch Siach }
90ba172208SBaruch Siach
dc_rtc_read_time(struct device * dev,struct rtc_time * tm)91ba172208SBaruch Siach static int dc_rtc_read_time(struct device *dev, struct rtc_time *tm)
92ba172208SBaruch Siach {
93ba172208SBaruch Siach struct dc_rtc *rtc = dev_get_drvdata(dev);
94ba172208SBaruch Siach unsigned long now;
95ba172208SBaruch Siach int ret;
96ba172208SBaruch Siach
97ba172208SBaruch Siach ret = dc_rtc_read(rtc, &now);
98ba172208SBaruch Siach if (ret < 0)
99ba172208SBaruch Siach return ret;
100ba172208SBaruch Siach rtc_time64_to_tm(now, tm);
101ba172208SBaruch Siach
102ba172208SBaruch Siach return 0;
103ba172208SBaruch Siach }
104ba172208SBaruch Siach
dc_rtc_set_time(struct device * dev,struct rtc_time * tm)10572ef256eSAlexandre Belloni static int dc_rtc_set_time(struct device *dev, struct rtc_time *tm)
106ba172208SBaruch Siach {
107ba172208SBaruch Siach struct dc_rtc *rtc = dev_get_drvdata(dev);
108ba172208SBaruch Siach
10972ef256eSAlexandre Belloni return dc_rtc_write(rtc, rtc_tm_to_time64(tm));
110ba172208SBaruch Siach }
111ba172208SBaruch Siach
dc_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alarm)112ba172208SBaruch Siach static int dc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
113ba172208SBaruch Siach {
114ba172208SBaruch Siach struct dc_rtc *rtc = dev_get_drvdata(dev);
115ba172208SBaruch Siach u32 alarm_reg, reference;
116ba172208SBaruch Siach unsigned long now;
117ba172208SBaruch Siach int ret;
118ba172208SBaruch Siach
119ba172208SBaruch Siach alarm_reg = readl_relaxed(rtc->regs + DC_RTC_ALARM);
120ba172208SBaruch Siach reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
121ba172208SBaruch Siach rtc_time64_to_tm(reference + alarm_reg, &alarm->time);
122ba172208SBaruch Siach
123ba172208SBaruch Siach ret = dc_rtc_read(rtc, &now);
124ba172208SBaruch Siach if (ret < 0)
125ba172208SBaruch Siach return ret;
126ba172208SBaruch Siach
127ba172208SBaruch Siach alarm->pending = alarm_reg + reference > now;
128ba172208SBaruch Siach alarm->enabled = readl_relaxed(rtc->regs + DC_RTC_INTENABLE);
129ba172208SBaruch Siach
130ba172208SBaruch Siach return 0;
131ba172208SBaruch Siach }
132ba172208SBaruch Siach
dc_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alarm)133ba172208SBaruch Siach static int dc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
134ba172208SBaruch Siach {
135ba172208SBaruch Siach struct dc_rtc *rtc = dev_get_drvdata(dev);
136ba172208SBaruch Siach time64_t alarm_time;
137ba172208SBaruch Siach u32 reference;
138ba172208SBaruch Siach
139ba172208SBaruch Siach alarm_time = rtc_tm_to_time64(&alarm->time);
140ba172208SBaruch Siach
141ba172208SBaruch Siach reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
142ba172208SBaruch Siach writel_relaxed(alarm_time - reference, rtc->regs + DC_RTC_ALARM);
143ba172208SBaruch Siach
144ba172208SBaruch Siach writeb_relaxed(!!alarm->enabled, rtc->regs + DC_RTC_INTENABLE);
145ba172208SBaruch Siach
146ba172208SBaruch Siach return 0;
147ba172208SBaruch Siach }
148ba172208SBaruch Siach
dc_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)149ba172208SBaruch Siach static int dc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
150ba172208SBaruch Siach {
151ba172208SBaruch Siach struct dc_rtc *rtc = dev_get_drvdata(dev);
152ba172208SBaruch Siach
153ba172208SBaruch Siach writeb_relaxed(!!enabled, rtc->regs + DC_RTC_INTENABLE);
154ba172208SBaruch Siach
155ba172208SBaruch Siach return 0;
156ba172208SBaruch Siach }
157ba172208SBaruch Siach
15834c7b3acSJulia Lawall static const struct rtc_class_ops dc_rtc_ops = {
159ba172208SBaruch Siach .read_time = dc_rtc_read_time,
16072ef256eSAlexandre Belloni .set_time = dc_rtc_set_time,
161ba172208SBaruch Siach .read_alarm = dc_rtc_read_alarm,
162ba172208SBaruch Siach .set_alarm = dc_rtc_set_alarm,
163ba172208SBaruch Siach .alarm_irq_enable = dc_rtc_alarm_irq_enable,
164ba172208SBaruch Siach };
165ba172208SBaruch Siach
dc_rtc_irq(int irq,void * dev_id)166ba172208SBaruch Siach static irqreturn_t dc_rtc_irq(int irq, void *dev_id)
167ba172208SBaruch Siach {
168ba172208SBaruch Siach struct dc_rtc *rtc = dev_id;
169ba172208SBaruch Siach
170ba172208SBaruch Siach writeb_relaxed(1, rtc->regs + DC_RTC_INTFLAG_CLEAR);
171ba172208SBaruch Siach rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
172ba172208SBaruch Siach
173ba172208SBaruch Siach return IRQ_HANDLED;
174ba172208SBaruch Siach }
175ba172208SBaruch Siach
dc_rtc_probe(struct platform_device * pdev)176ba172208SBaruch Siach static int __init dc_rtc_probe(struct platform_device *pdev)
177ba172208SBaruch Siach {
178ba172208SBaruch Siach struct dc_rtc *rtc;
179ba172208SBaruch Siach int irq, ret;
180ba172208SBaruch Siach
181ba172208SBaruch Siach rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
182ba172208SBaruch Siach if (!rtc)
183ba172208SBaruch Siach return -ENOMEM;
184ba172208SBaruch Siach
18509ef18bcSYueHaibing rtc->regs = devm_platform_ioremap_resource(pdev, 0);
186ba172208SBaruch Siach if (IS_ERR(rtc->regs))
187ba172208SBaruch Siach return PTR_ERR(rtc->regs);
188ba172208SBaruch Siach
189060711f5SAlexandre Belloni rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
190060711f5SAlexandre Belloni if (IS_ERR(rtc->rtc_dev))
191060711f5SAlexandre Belloni return PTR_ERR(rtc->rtc_dev);
192060711f5SAlexandre Belloni
193ba172208SBaruch Siach irq = platform_get_irq(pdev, 0);
194ba172208SBaruch Siach if (irq < 0)
195ba172208SBaruch Siach return irq;
196ba172208SBaruch Siach ret = devm_request_irq(&pdev->dev, irq, dc_rtc_irq, 0, pdev->name, rtc);
197ba172208SBaruch Siach if (ret < 0)
198ba172208SBaruch Siach return ret;
199ba172208SBaruch Siach
200ba172208SBaruch Siach platform_set_drvdata(pdev, rtc);
201ba172208SBaruch Siach
202060711f5SAlexandre Belloni rtc->rtc_dev->ops = &dc_rtc_ops;
203e5fe3c3eSAlexandre Belloni rtc->rtc_dev->range_max = U32_MAX;
204060711f5SAlexandre Belloni
205fdcfd854SBartosz Golaszewski return devm_rtc_register_device(rtc->rtc_dev);
206ba172208SBaruch Siach }
207ba172208SBaruch Siach
208*97de1f58SAlexandre Belloni static const __maybe_unused struct of_device_id dc_dt_ids[] = {
209ba172208SBaruch Siach { .compatible = "cnxt,cx92755-rtc" },
210ba172208SBaruch Siach { /* sentinel */ }
211ba172208SBaruch Siach };
212ba172208SBaruch Siach MODULE_DEVICE_TABLE(of, dc_dt_ids);
213ba172208SBaruch Siach
214ba172208SBaruch Siach static struct platform_driver dc_rtc_driver = {
215ba172208SBaruch Siach .driver = {
216ba172208SBaruch Siach .name = "digicolor_rtc",
217ba172208SBaruch Siach .of_match_table = of_match_ptr(dc_dt_ids),
218ba172208SBaruch Siach },
219ba172208SBaruch Siach };
220ba172208SBaruch Siach module_platform_driver_probe(dc_rtc_driver, dc_rtc_probe);
221ba172208SBaruch Siach
222ba172208SBaruch Siach MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
223ba172208SBaruch Siach MODULE_DESCRIPTION("Conexant Digicolor Realtime Clock Driver (RTC)");
224ba172208SBaruch Siach MODULE_LICENSE("GPL");
225