Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at master 218 lines 5.2 kB view raw
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");