xref: /linux/drivers/rtc/rtc-ssd202d.c (revision 45d8b572fac3aa8b49d53c946b3685eaf78a2824)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Real time clocks driver for MStar/SigmaStar SSD202D SoCs.
4  *
5  * (C) 2021 Daniel Palmer
6  * (C) 2023 Romain Perier
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/module.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/platform_device.h>
14 #include <linux/rtc.h>
15 #include <linux/regmap.h>
16 #include <linux/pm.h>
17 
18 #define REG_CTRL	0x0
19 #define REG_CTRL1	0x4
20 #define REG_ISO_CTRL	0xc
21 #define REG_WRDATA_L	0x10
22 #define REG_WRDATA_H	0x14
23 #define REG_ISOACK	0x20
24 #define REG_RDDATA_L	0x24
25 #define REG_RDDATA_H	0x28
26 #define REG_RDCNT_L	0x30
27 #define REG_RDCNT_H	0x34
28 #define REG_CNT_TRIG	0x38
29 #define REG_PWRCTRL	0x3c
30 #define REG_RTC_TEST	0x54
31 
32 #define CNT_RD_TRIG_BIT BIT(0)
33 #define CNT_RD_BIT BIT(0)
34 #define BASE_WR_BIT BIT(1)
35 #define BASE_RD_BIT BIT(2)
36 #define CNT_RST_BIT BIT(3)
37 #define ISO_CTRL_ACK_MASK BIT(3)
38 #define ISO_CTRL_ACK_SHIFT 3
39 #define SW0_WR_BIT BIT(5)
40 #define SW1_WR_BIT BIT(6)
41 #define SW0_RD_BIT BIT(7)
42 #define SW1_RD_BIT BIT(8)
43 
44 #define ISO_CTRL_MASK GENMASK(2, 0)
45 
46 struct ssd202d_rtc {
47 	struct rtc_device *rtc_dev;
48 	void __iomem *base;
49 };
50 
51 static u8 read_iso_en(void __iomem *base)
52 {
53 	return readb(base + REG_RTC_TEST) & 0x1;
54 }
55 
56 static u8 read_iso_ctrl_ack(void __iomem *base)
57 {
58 	return (readb(base + REG_ISOACK) & ISO_CTRL_ACK_MASK) >> ISO_CTRL_ACK_SHIFT;
59 }
60 
61 static int ssd202d_rtc_isoctrl(struct ssd202d_rtc *priv)
62 {
63 	static const unsigned int sequence[] = { 0x0, 0x1, 0x3, 0x7, 0x5, 0x1, 0x0 };
64 	unsigned int val;
65 	struct device *dev = &priv->rtc_dev->dev;
66 	int i, ret;
67 
68 	/*
69 	 * This gates iso_en by writing a special sequence of bytes to iso_ctrl
70 	 * and ensuring that it has been correctly applied by reading iso_ctrl_ack
71 	 */
72 	for (i = 0; i < ARRAY_SIZE(sequence); i++) {
73 		writeb(sequence[i] & ISO_CTRL_MASK, priv->base +  REG_ISO_CTRL);
74 
75 		ret = read_poll_timeout(read_iso_ctrl_ack, val, val == (i % 2), 100,
76 					20 * 100, true, priv->base);
77 		if (ret) {
78 			dev_dbg(dev, "Timeout waiting for ack byte %i (%x) of sequence\n", i,
79 				sequence[i]);
80 			return ret;
81 		}
82 	}
83 
84 	/*
85 	 * At this point iso_en should be raised for 1ms
86 	 */
87 	ret = read_poll_timeout(read_iso_en, val, val, 100, 22 * 100, true, priv->base);
88 	if (ret)
89 		dev_dbg(dev, "Timeout waiting for iso_en\n");
90 	mdelay(2);
91 	return 0;
92 }
93 
94 static void ssd202d_rtc_read_reg(struct ssd202d_rtc *priv, unsigned int reg,
95 				 unsigned int field, unsigned int *base)
96 {
97 	unsigned int l, h;
98 	u16 val;
99 
100 	/* Ask for the content of an RTC value into RDDATA by gating iso_en,
101 	 * then iso_en is gated and the content of RDDATA can be read
102 	 */
103 	val = readw(priv->base + reg);
104 	writew(val | field, priv->base + reg);
105 	ssd202d_rtc_isoctrl(priv);
106 	writew(val & ~field, priv->base + reg);
107 
108 	l = readw(priv->base + REG_RDDATA_L);
109 	h = readw(priv->base + REG_RDDATA_H);
110 
111 	*base = (h << 16) | l;
112 }
113 
114 static void ssd202d_rtc_write_reg(struct ssd202d_rtc *priv, unsigned int reg,
115 				  unsigned int field, u32 base)
116 {
117 	u16 val;
118 
119 	/* Set the content of an RTC value from WRDATA by gating iso_en */
120 	val = readw(priv->base + reg);
121 	writew(val | field, priv->base + reg);
122 	writew(base, priv->base + REG_WRDATA_L);
123 	writew(base >> 16, priv->base + REG_WRDATA_H);
124 	ssd202d_rtc_isoctrl(priv);
125 	writew(val & ~field, priv->base + reg);
126 }
127 
128 static int ssd202d_rtc_read_counter(struct ssd202d_rtc *priv, unsigned int *counter)
129 {
130 	unsigned int l, h;
131 	u16 val;
132 
133 	val = readw(priv->base + REG_CTRL1);
134 	writew(val | CNT_RD_BIT, priv->base + REG_CTRL1);
135 	ssd202d_rtc_isoctrl(priv);
136 	writew(val & ~CNT_RD_BIT, priv->base + REG_CTRL1);
137 
138 	val = readw(priv->base + REG_CTRL1);
139 	writew(val | CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
140 	writew(val & ~CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
141 
142 	l = readw(priv->base + REG_RDCNT_L);
143 	h = readw(priv->base + REG_RDCNT_H);
144 
145 	*counter = (h << 16) | l;
146 
147 	return 0;
148 }
149 
150 static int ssd202d_rtc_read_time(struct device *dev, struct rtc_time *tm)
151 {
152 	struct ssd202d_rtc *priv = dev_get_drvdata(dev);
153 	unsigned int sw0, base, counter;
154 	u32 seconds;
155 	int ret;
156 
157 	/* Check that RTC is enabled by SW */
158 	ssd202d_rtc_read_reg(priv, REG_CTRL, SW0_RD_BIT, &sw0);
159 	if (sw0 != 1)
160 		return -EINVAL;
161 
162 	/* Get RTC base value from RDDATA */
163 	ssd202d_rtc_read_reg(priv, REG_CTRL, BASE_RD_BIT, &base);
164 	/* Get RTC counter value from RDDATA */
165 	ret = ssd202d_rtc_read_counter(priv, &counter);
166 	if (ret)
167 		return ret;
168 
169 	seconds = base + counter;
170 
171 	rtc_time64_to_tm(seconds, tm);
172 
173 	return 0;
174 }
175 
176 static int ssd202d_rtc_reset_counter(struct ssd202d_rtc *priv)
177 {
178 	u16 val;
179 
180 	val = readw(priv->base + REG_CTRL);
181 	writew(val | CNT_RST_BIT, priv->base + REG_CTRL);
182 	ssd202d_rtc_isoctrl(priv);
183 	writew(val & ~CNT_RST_BIT, priv->base + REG_CTRL);
184 	ssd202d_rtc_isoctrl(priv);
185 
186 	return 0;
187 }
188 
189 static int ssd202d_rtc_set_time(struct device *dev, struct rtc_time *tm)
190 {
191 	struct ssd202d_rtc *priv = dev_get_drvdata(dev);
192 	unsigned long seconds = rtc_tm_to_time64(tm);
193 
194 	ssd202d_rtc_write_reg(priv, REG_CTRL, BASE_WR_BIT, seconds);
195 	ssd202d_rtc_reset_counter(priv);
196 	ssd202d_rtc_write_reg(priv, REG_CTRL, SW0_WR_BIT, 1);
197 
198 	return 0;
199 }
200 
201 static const struct rtc_class_ops ssd202d_rtc_ops = {
202 	.read_time = ssd202d_rtc_read_time,
203 	.set_time = ssd202d_rtc_set_time,
204 };
205 
206 static int ssd202d_rtc_probe(struct platform_device *pdev)
207 {
208 	struct device *dev = &pdev->dev;
209 	struct ssd202d_rtc *priv;
210 
211 	priv = devm_kzalloc(&pdev->dev, sizeof(struct ssd202d_rtc), GFP_KERNEL);
212 	if (!priv)
213 		return -ENOMEM;
214 
215 	priv->base = devm_platform_ioremap_resource(pdev, 0);
216 	if (IS_ERR(priv->base))
217 		return PTR_ERR(priv->base);
218 
219 	priv->rtc_dev = devm_rtc_allocate_device(dev);
220 	if (IS_ERR(priv->rtc_dev))
221 		return PTR_ERR(priv->rtc_dev);
222 
223 	priv->rtc_dev->ops = &ssd202d_rtc_ops;
224 	priv->rtc_dev->range_max = U32_MAX;
225 
226 	platform_set_drvdata(pdev, priv);
227 
228 	return devm_rtc_register_device(priv->rtc_dev);
229 }
230 
231 static const struct of_device_id ssd202d_rtc_of_match_table[] = {
232 	{ .compatible = "mstar,ssd202d-rtc" },
233 	{ }
234 };
235 MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table);
236 
237 static struct platform_driver ssd202d_rtc_driver = {
238 	.probe = ssd202d_rtc_probe,
239 	.driver = {
240 		.name = "ssd202d-rtc",
241 		.of_match_table = ssd202d_rtc_of_match_table,
242 	},
243 };
244 module_platform_driver(ssd202d_rtc_driver);
245 
246 MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
247 MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
248 MODULE_DESCRIPTION("MStar SSD202D RTC Driver");
249 MODULE_LICENSE("GPL");
250