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