Linux Audio

Check our new training course

Loading...
v6.13.7
  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
 46struct ssd202d_rtc {
 47	struct rtc_device *rtc_dev;
 48	void __iomem *base;
 49};
 50
 51static u8 read_iso_en(void __iomem *base)
 52{
 53	return readb(base + REG_RTC_TEST) & 0x1;
 54}
 55
 56static 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
 61static 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
 94static 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
114static 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
128static 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
150static 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
176static 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
189static 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
201static const struct rtc_class_ops ssd202d_rtc_ops = {
202	.read_time = ssd202d_rtc_read_time,
203	.set_time = ssd202d_rtc_set_time,
204};
205
206static 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
231static const struct of_device_id ssd202d_rtc_of_match_table[] = {
232	{ .compatible = "mstar,ssd202d-rtc" },
233	{ }
234};
235MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table);
236
237static 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};
244module_platform_driver(ssd202d_rtc_driver);
245
246MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
247MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
248MODULE_DESCRIPTION("MStar SSD202D RTC Driver");
249MODULE_LICENSE("GPL");
v6.8
  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
 46struct ssd202d_rtc {
 47	struct rtc_device *rtc_dev;
 48	void __iomem *base;
 49};
 50
 51static u8 read_iso_en(void __iomem *base)
 52{
 53	return readb(base + REG_RTC_TEST) & 0x1;
 54}
 55
 56static 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
 61static 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
 94static 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
114static 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
128static 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
150static 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
176static 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
189static 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
201static const struct rtc_class_ops ssd202d_rtc_ops = {
202	.read_time = ssd202d_rtc_read_time,
203	.set_time = ssd202d_rtc_set_time,
204};
205
206static 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
231static const struct of_device_id ssd202d_rtc_of_match_table[] = {
232	{ .compatible = "mstar,ssd202d-rtc" },
233	{ }
234};
235MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table);
236
237static 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};
244module_platform_driver(ssd202d_rtc_driver);
245
246MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
247MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
248MODULE_DESCRIPTION("MStar SSD202D RTC Driver");
249MODULE_LICENSE("GPL");