brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · ed64932 Raw
250 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Real time clocks driver for MStar/SigmaStar SSD202D SoCs.4 *5 * (C) 2021 Daniel Palmer6 * (C) 2023 Romain Perier7 */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	0x019#define REG_CTRL1	0x420#define REG_ISO_CTRL	0xc21#define REG_WRDATA_L	0x1022#define REG_WRDATA_H	0x1423#define REG_ISOACK	0x2024#define REG_RDDATA_L	0x2425#define REG_RDDATA_H	0x2826#define REG_RDCNT_L	0x3027#define REG_RDCNT_H	0x3428#define REG_CNT_TRIG	0x3829#define REG_PWRCTRL	0x3c30#define REG_RTC_TEST	0x5431 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 339#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_ctrl70	 * and ensuring that it has been correctly applied by reading iso_ctrl_ack71	 */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 1ms86	 */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 read102	 */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");250