File Index
Files and directories
Sign in
FILE

rtc-cv1800.c

File preview with syntax highlighting.

linux-6.19.14/drivers/rtc/rtc-cv1800.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * rtc-cv1800.c: RTC driver for Sophgo cv1800 RTC
  4 *
  5 * Author: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
  6 */
  7
  8#include <linux/clk.h>
  9#include <linux/irq.h>
 10#include <linux/kernel.h>
 11#include <linux/mfd/syscon.h>
 12#include <linux/module.h>
 13#include <linux/of.h>
 14#include <linux/platform_device.h>
 15#include <linux/regmap.h>
 16#include <linux/rtc.h>
 17
 18#define SEC_PULSE_GEN          0x1004
 19#define ALARM_TIME             0x1008
 20#define ALARM_ENABLE           0x100C
 21#define SET_SEC_CNTR_VAL       0x1010
 22#define SET_SEC_CNTR_TRIG      0x1014
 23#define SEC_CNTR_VAL           0x1018
 24
 25/*
 26 * When in VDDBKUP domain, this MACRO register
 27 * does not power down
 28 */
 29#define MACRO_RO_T             0x14A8
 30#define MACRO_RG_SET_T         0x1498
 31
 32#define ALARM_ENABLE_MASK      BIT(0)
 33#define SEL_SEC_PULSE          BIT(31)
 34
 35struct cv1800_rtc_priv {
 36	struct rtc_device *rtc_dev;
 37	struct regmap *rtc_map;
 38	struct clk *clk;
 39	int irq;
 40};
 41
 42static bool cv1800_rtc_enabled(struct device *dev)
 43{
 44	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
 45	u32 reg;
 46
 47	regmap_read(info->rtc_map, SEC_PULSE_GEN, &reg);
 48
 49	return (reg & SEL_SEC_PULSE) == 0;
 50}
 51
 52static void cv1800_rtc_enable(struct device *dev)
 53{
 54	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
 55
 56	/* Sec pulse generated internally */
 57	regmap_update_bits(info->rtc_map, SEC_PULSE_GEN, SEL_SEC_PULSE, 0);
 58}
 59
 60static int cv1800_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 61{
 62	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
 63
 64	regmap_write(info->rtc_map, ALARM_ENABLE, enabled);
 65
 66	return 0;
 67}
 68
 69static int cv1800_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 70{
 71	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
 72	unsigned long alarm_time;
 73
 74	alarm_time = rtc_tm_to_time64(&alrm->time);
 75
 76	cv1800_rtc_alarm_irq_enable(dev, 0);
 77
 78	regmap_write(info->rtc_map, ALARM_TIME, alarm_time);
 79
 80	cv1800_rtc_alarm_irq_enable(dev, alrm->enabled);
 81
 82	return 0;
 83}
 84
 85static int cv1800_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 86{
 87	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
 88	u32 enabled;
 89	u32 time;
 90
 91	if (!cv1800_rtc_enabled(dev)) {
 92		alarm->enabled = 0;
 93		return 0;
 94	}
 95
 96	regmap_read(info->rtc_map, ALARM_ENABLE, &enabled);
 97
 98	alarm->enabled = enabled & ALARM_ENABLE_MASK;
 99
100	regmap_read(info->rtc_map, ALARM_TIME, &time);
101
102	rtc_time64_to_tm(time, &alarm->time);
103
104	return 0;
105}
106
107static int cv1800_rtc_read_time(struct device *dev, struct rtc_time *tm)
108{
109	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
110	u32 sec;
111
112	if (!cv1800_rtc_enabled(dev))
113		return -EINVAL;
114
115	regmap_read(info->rtc_map, SEC_CNTR_VAL, &sec);
116
117	rtc_time64_to_tm(sec, tm);
118
119	return 0;
120}
121
122static int cv1800_rtc_set_time(struct device *dev, struct rtc_time *tm)
123{
124	struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
125	unsigned long sec;
126
127	sec = rtc_tm_to_time64(tm);
128
129	regmap_write(info->rtc_map, SET_SEC_CNTR_VAL, sec);
130	regmap_write(info->rtc_map, SET_SEC_CNTR_TRIG, 1);
131
132	regmap_write(info->rtc_map, MACRO_RG_SET_T, sec);
133
134	cv1800_rtc_enable(dev);
135
136	return 0;
137}
138
139static irqreturn_t cv1800_rtc_irq_handler(int irq, void *dev_id)
140{
141	struct cv1800_rtc_priv *info = dev_id;
142
143	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
144
145	regmap_write(info->rtc_map, ALARM_ENABLE, 0);
146
147	return IRQ_HANDLED;
148}
149
150static const struct rtc_class_ops cv1800_rtc_ops = {
151	.read_time = cv1800_rtc_read_time,
152	.set_time = cv1800_rtc_set_time,
153	.read_alarm = cv1800_rtc_read_alarm,
154	.set_alarm = cv1800_rtc_set_alarm,
155	.alarm_irq_enable = cv1800_rtc_alarm_irq_enable,
156};
157
158static int cv1800_rtc_probe(struct platform_device *pdev)
159{
160	struct cv1800_rtc_priv *rtc;
161	int ret;
162
163	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
164	if (!rtc)
165		return -ENOMEM;
166
167	rtc->rtc_map = device_node_to_regmap(pdev->dev.parent->of_node);
168	if (IS_ERR(rtc->rtc_map))
169		return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_map),
170				     "cannot get parent regmap\n");
171
172	rtc->irq = platform_get_irq(pdev, 0);
173	if (rtc->irq < 0)
174		return rtc->irq;
175
176	rtc->clk = devm_clk_get_enabled(pdev->dev.parent, "rtc");
177	if (IS_ERR(rtc->clk))
178		return dev_err_probe(&pdev->dev, PTR_ERR(rtc->clk),
179				     "rtc clk not found\n");
180
181	platform_set_drvdata(pdev, rtc);
182
183	device_init_wakeup(&pdev->dev, 1);
184
185	rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
186	if (IS_ERR(rtc->rtc_dev))
187		return PTR_ERR(rtc->rtc_dev);
188
189	rtc->rtc_dev->ops = &cv1800_rtc_ops;
190	rtc->rtc_dev->range_max = U32_MAX;
191
192	ret = devm_request_irq(&pdev->dev, rtc->irq, cv1800_rtc_irq_handler,
193			       IRQF_TRIGGER_HIGH, "rtc alarm", rtc);
194	if (ret)
195		return dev_err_probe(&pdev->dev, ret,
196				     "cannot register interrupt handler\n");
197
198	return devm_rtc_register_device(rtc->rtc_dev);
199}
200
201static const struct platform_device_id cv1800_rtc_id[] = {
202	{ .name = "cv1800b-rtc" },
203	{ /* sentinel */ },
204};
205MODULE_DEVICE_TABLE(platform, cv1800_rtc_id);
206
207static struct platform_driver cv1800_rtc_driver = {
208	.driver = {
209		.name = "sophgo-cv1800-rtc",
210	},
211	.probe = cv1800_rtc_probe,
212	.id_table = cv1800_rtc_id,
213};
214
215module_platform_driver(cv1800_rtc_driver);
216MODULE_AUTHOR("Jingbao Qiu");
217MODULE_DESCRIPTION("Sophgo cv1800 RTC Driver");
218MODULE_LICENSE("GPL");
~/ Read-only file preview.