xref: /openbmc/linux/drivers/rtc/rtc-digicolor.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
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