Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rtc: support for the Amlogic on-chip RTC

This is the third amlogic driver. The RTC hardware of A4 SoC is different
from the previous one. This RTC hardware includes a timing function and
an alarm function. But the existing has only timing function, alarm
function is using the system clock to implement a virtual alarm. Add
the RTC driver to support it.

Signed-off-by: Yiting Deng <yiting.deng@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
Link: https://lore.kernel.org/r/20241112-rtc-v6-2-a71b60d2f354@amlogic.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Yiting Deng and committed by
Alexandre Belloni
c89ac918 ce57cf73

+487
+12
drivers/rtc/Kconfig
··· 2091 2091 This driver can also be built as a module, if so, the module 2092 2092 will be called "rtc-ssd20xd". 2093 2093 2094 + config RTC_DRV_AMLOGIC_A4 2095 + tristate "Amlogic RTC" 2096 + depends on ARCH_MESON || COMPILE_TEST 2097 + select REGMAP_MMIO 2098 + default y 2099 + help 2100 + If you say yes here you get support for the RTC block on the 2101 + Amlogic A113L2(A4) and A113X2(A5) SoCs. 2102 + 2103 + This driver can also be built as a module. If so, the module 2104 + will be called "rtc-amlogic-a4". 2105 + 2094 2106 endif # RTC_CLASS
+1
drivers/rtc/Makefile
··· 27 27 obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o 28 28 obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o 29 29 obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o 30 + obj-$(CONFIG_RTC_DRV_AMLOGIC_A4) += rtc-amlogic-a4.o 30 31 obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o 31 32 obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o 32 33 obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
+474
drivers/rtc/rtc-amlogic-a4.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 + /* 3 + * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 + * Author: Yiting Deng <yiting.deng@amlogic.com> 5 + */ 6 + 7 + #include <linux/bitfield.h> 8 + #include <linux/clk.h> 9 + #include <linux/clk-provider.h> 10 + #include <linux/delay.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 14 + #include <linux/rtc.h> 15 + #include <linux/time64.h> 16 + 17 + /* rtc oscillator rate */ 18 + #define OSC_32K 32768 19 + #define OSC_24M 24000000 20 + 21 + #define RTC_CTRL (0x0 << 2) /* Control RTC */ 22 + #define RTC_ALRM0_EN BIT(0) 23 + #define RTC_OSC_SEL BIT(8) 24 + #define RTC_ENABLE BIT(12) 25 + 26 + #define RTC_COUNTER_REG (0x1 << 2) /* Program RTC counter initial value */ 27 + 28 + #define RTC_ALARM0_REG (0x2 << 2) /* Program RTC alarm0 value */ 29 + 30 + #define RTC_SEC_ADJUST_REG (0x6 << 2) /* Control second-based timing adjustment */ 31 + #define RTC_MATCH_COUNTER GENMASK(18, 0) 32 + #define RTC_SEC_ADJUST_CTRL GENMASK(20, 19) 33 + #define RTC_ADJ_VALID BIT(23) 34 + 35 + #define RTC_INT_MASK (0x8 << 2) /* RTC interrupt mask */ 36 + #define RTC_ALRM0_IRQ_MSK BIT(0) 37 + 38 + #define RTC_INT_CLR (0x9 << 2) /* Clear RTC interrupt */ 39 + #define RTC_ALRM0_IRQ_CLR BIT(0) 40 + 41 + #define RTC_OSCIN_CTRL0 (0xa << 2) /* Control RTC clk from 24M */ 42 + #define RTC_OSCIN_CTRL1 (0xb << 2) /* Control RTC clk from 24M */ 43 + #define RTC_OSCIN_IN_EN BIT(31) 44 + #define RTC_OSCIN_OUT_CFG GENMASK(29, 28) 45 + #define RTC_OSCIN_OUT_N0M0 GENMASK(11, 0) 46 + #define RTC_OSCIN_OUT_N1M1 GENMASK(23, 12) 47 + 48 + #define RTC_INT_STATUS (0xc << 2) /* RTC interrupt status */ 49 + #define RTC_ALRM0_IRQ_STATUS BIT(0) 50 + 51 + #define RTC_REAL_TIME (0xd << 2) /* RTC time value */ 52 + 53 + #define RTC_OSCIN_OUT_32K_N0 0x2dc 54 + #define RTC_OSCIN_OUT_32K_N1 0x2db 55 + #define RTC_OSCIN_OUT_32K_M0 0x1 56 + #define RTC_OSCIN_OUT_32K_M1 0x2 57 + 58 + #define RTC_SWALLOW_SECOND 0x2 59 + #define RTC_INSERT_SECOND 0x3 60 + 61 + struct aml_rtc_config { 62 + bool gray_stored; 63 + }; 64 + 65 + struct aml_rtc_data { 66 + struct regmap *map; 67 + struct rtc_device *rtc_dev; 68 + int irq; 69 + struct clk *rtc_clk; 70 + struct clk *sys_clk; 71 + int rtc_enabled; 72 + const struct aml_rtc_config *config; 73 + }; 74 + 75 + static const struct regmap_config aml_rtc_regmap_config = { 76 + .reg_bits = 32, 77 + .val_bits = 32, 78 + .reg_stride = 4, 79 + .max_register = RTC_REAL_TIME, 80 + }; 81 + 82 + static inline u32 gray_to_binary(u32 gray) 83 + { 84 + u32 bcd = gray; 85 + int size = sizeof(bcd) * 8; 86 + int i; 87 + 88 + for (i = 0; (1 << i) < size; i++) 89 + bcd ^= bcd >> (1 << i); 90 + 91 + return bcd; 92 + } 93 + 94 + static inline u32 binary_to_gray(u32 bcd) 95 + { 96 + return bcd ^ (bcd >> 1); 97 + } 98 + 99 + static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm) 100 + { 101 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 102 + u32 time_sec; 103 + 104 + /* if RTC disabled, read time failed */ 105 + if (!rtc->rtc_enabled) { 106 + dev_err(dev, "RTC disabled, read time failed\n"); 107 + return -EINVAL; 108 + } 109 + 110 + regmap_read(rtc->map, RTC_REAL_TIME, &time_sec); 111 + if (rtc->config->gray_stored) 112 + time_sec = gray_to_binary(time_sec); 113 + rtc_time64_to_tm(time_sec, tm); 114 + dev_dbg(dev, "%s: read time = %us\n", __func__, time_sec); 115 + 116 + return 0; 117 + } 118 + 119 + static int aml_rtc_set_time(struct device *dev, struct rtc_time *tm) 120 + { 121 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 122 + u32 time_sec; 123 + 124 + /* if RTC disabled, first enable it */ 125 + if (!rtc->rtc_enabled) { 126 + regmap_write_bits(rtc->map, RTC_CTRL, RTC_ENABLE, RTC_ENABLE); 127 + usleep_range(100, 200); 128 + rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE); 129 + if (!rtc->rtc_enabled) 130 + return -EINVAL; 131 + } 132 + 133 + time_sec = rtc_tm_to_time64(tm); 134 + if (rtc->config->gray_stored) 135 + time_sec = binary_to_gray(time_sec); 136 + regmap_write(rtc->map, RTC_COUNTER_REG, time_sec); 137 + dev_dbg(dev, "%s: set time = %us\n", __func__, time_sec); 138 + 139 + return 0; 140 + } 141 + 142 + static int aml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 143 + { 144 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 145 + time64_t alarm_sec; 146 + 147 + /* if RTC disabled, set alarm failed */ 148 + if (!rtc->rtc_enabled) { 149 + dev_err(dev, "RTC disabled, set alarm failed\n"); 150 + return -EINVAL; 151 + } 152 + 153 + regmap_update_bits(rtc->map, RTC_CTRL, 154 + RTC_ALRM0_EN, RTC_ALRM0_EN); 155 + regmap_update_bits(rtc->map, RTC_INT_MASK, 156 + RTC_ALRM0_IRQ_MSK, 0); 157 + 158 + alarm_sec = rtc_tm_to_time64(&alarm->time); 159 + if (rtc->config->gray_stored) 160 + alarm_sec = binary_to_gray(alarm_sec); 161 + regmap_write(rtc->map, RTC_ALARM0_REG, alarm_sec); 162 + 163 + dev_dbg(dev, "%s: alarm->enabled=%d alarm_set=%llds\n", __func__, 164 + alarm->enabled, alarm_sec); 165 + 166 + return 0; 167 + } 168 + 169 + static int aml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 170 + { 171 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 172 + u32 alarm_sec; 173 + int alarm_enable; 174 + int alarm_mask; 175 + 176 + /* if RTC disabled, read alarm failed */ 177 + if (!rtc->rtc_enabled) { 178 + dev_err(dev, "RTC disabled, read alarm failed\n"); 179 + return -EINVAL; 180 + } 181 + 182 + regmap_read(rtc->map, RTC_ALARM0_REG, &alarm_sec); 183 + if (rtc->config->gray_stored) 184 + alarm_sec = gray_to_binary(alarm_sec); 185 + rtc_time64_to_tm(alarm_sec, &alarm->time); 186 + 187 + alarm_enable = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN); 188 + alarm_mask = regmap_test_bits(rtc->map, RTC_INT_MASK, RTC_ALRM0_IRQ_MSK); 189 + alarm->enabled = (alarm_enable && !alarm_mask) ? 1 : 0; 190 + dev_dbg(dev, "%s: alarm->enabled=%d alarm=%us\n", __func__, 191 + alarm->enabled, alarm_sec); 192 + 193 + return 0; 194 + } 195 + 196 + static int aml_rtc_read_offset(struct device *dev, long *offset) 197 + { 198 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 199 + u32 reg_val; 200 + long val; 201 + int sign, match_counter, enable; 202 + 203 + /* if RTC disabled, read offset failed */ 204 + if (!rtc->rtc_enabled) { 205 + dev_err(dev, "RTC disabled, read offset failed\n"); 206 + return -EINVAL; 207 + } 208 + 209 + regmap_read(rtc->map, RTC_SEC_ADJUST_REG, &reg_val); 210 + enable = FIELD_GET(RTC_ADJ_VALID, reg_val); 211 + if (!enable) { 212 + val = 0; 213 + } else { 214 + sign = FIELD_GET(RTC_SEC_ADJUST_CTRL, reg_val); 215 + match_counter = FIELD_GET(RTC_MATCH_COUNTER, reg_val); 216 + val = 1000000000 / (match_counter + 1); 217 + if (sign == RTC_SWALLOW_SECOND) 218 + val = -val; 219 + } 220 + *offset = val; 221 + 222 + return 0; 223 + } 224 + 225 + static int aml_rtc_set_offset(struct device *dev, long offset) 226 + { 227 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 228 + int sign = 0; 229 + int match_counter = 0; 230 + int enable = 0; 231 + u32 reg_val; 232 + 233 + /* if RTC disabled, set offset failed */ 234 + if (!rtc->rtc_enabled) { 235 + dev_err(dev, "RTC disabled, set offset failed\n"); 236 + return -EINVAL; 237 + } 238 + 239 + if (offset) { 240 + enable = 1; 241 + sign = offset < 0 ? RTC_SWALLOW_SECOND : RTC_INSERT_SECOND; 242 + match_counter = 1000000000 / abs(offset) - 1; 243 + if (match_counter < 0 || match_counter > RTC_MATCH_COUNTER) 244 + return -EINVAL; 245 + } 246 + 247 + reg_val = FIELD_PREP(RTC_ADJ_VALID, enable) | 248 + FIELD_PREP(RTC_SEC_ADJUST_CTRL, sign) | 249 + FIELD_PREP(RTC_MATCH_COUNTER, match_counter); 250 + regmap_write(rtc->map, RTC_SEC_ADJUST_REG, reg_val); 251 + 252 + return 0; 253 + } 254 + 255 + static int aml_rtc_alarm_enable(struct device *dev, unsigned int enabled) 256 + { 257 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 258 + 259 + if (enabled) { 260 + regmap_update_bits(rtc->map, RTC_CTRL, 261 + RTC_ALRM0_EN, RTC_ALRM0_EN); 262 + regmap_update_bits(rtc->map, RTC_INT_MASK, 263 + RTC_ALRM0_IRQ_MSK, 0); 264 + } else { 265 + regmap_update_bits(rtc->map, RTC_INT_MASK, 266 + RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK); 267 + regmap_update_bits(rtc->map, RTC_CTRL, 268 + RTC_ALRM0_EN, 0); 269 + } 270 + 271 + return 0; 272 + } 273 + 274 + static const struct rtc_class_ops aml_rtc_ops = { 275 + .read_time = aml_rtc_read_time, 276 + .set_time = aml_rtc_set_time, 277 + .read_alarm = aml_rtc_read_alarm, 278 + .set_alarm = aml_rtc_set_alarm, 279 + .alarm_irq_enable = aml_rtc_alarm_enable, 280 + .read_offset = aml_rtc_read_offset, 281 + .set_offset = aml_rtc_set_offset, 282 + }; 283 + 284 + static irqreturn_t aml_rtc_handler(int irq, void *data) 285 + { 286 + struct aml_rtc_data *rtc = (struct aml_rtc_data *)data; 287 + 288 + regmap_write(rtc->map, RTC_ALARM0_REG, 0); 289 + regmap_write(rtc->map, RTC_INT_CLR, RTC_ALRM0_IRQ_STATUS); 290 + 291 + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); 292 + 293 + return IRQ_HANDLED; 294 + } 295 + 296 + static void aml_rtc_init(struct aml_rtc_data *rtc) 297 + { 298 + u32 reg_val = 0; 299 + 300 + rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE); 301 + if (!rtc->rtc_enabled) { 302 + if (clk_get_rate(rtc->rtc_clk) == OSC_24M) { 303 + /* select 24M oscillator */ 304 + regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, RTC_OSC_SEL); 305 + 306 + /* 307 + * Set RTC oscillator to freq_out to freq_in/((N0*M0+N1*M1)/(M0+M1)) 308 + * Enable clock_in gate of oscillator 24MHz 309 + * Set N0 to 733, N1 to 732 310 + */ 311 + reg_val = FIELD_PREP(RTC_OSCIN_IN_EN, 1) 312 + | FIELD_PREP(RTC_OSCIN_OUT_CFG, 1) 313 + | FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_N0) 314 + | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_N1); 315 + regmap_write_bits(rtc->map, RTC_OSCIN_CTRL0, RTC_OSCIN_IN_EN 316 + | RTC_OSCIN_OUT_CFG | RTC_OSCIN_OUT_N0M0 317 + | RTC_OSCIN_OUT_N1M1, reg_val); 318 + 319 + /* Set M0 to 2, M1 to 3, so freq_out = 32768 Hz*/ 320 + reg_val = FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_M0) 321 + | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_M1); 322 + regmap_write_bits(rtc->map, RTC_OSCIN_CTRL1, RTC_OSCIN_OUT_N0M0 323 + | RTC_OSCIN_OUT_N1M1, reg_val); 324 + } else { 325 + /* select 32K oscillator */ 326 + regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, 0); 327 + } 328 + } 329 + regmap_write_bits(rtc->map, RTC_INT_MASK, 330 + RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK); 331 + regmap_write_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN, 0); 332 + } 333 + 334 + static int aml_rtc_probe(struct platform_device *pdev) 335 + { 336 + struct device *dev = &pdev->dev; 337 + struct aml_rtc_data *rtc; 338 + void __iomem *base; 339 + int ret = 0; 340 + 341 + rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); 342 + if (!rtc) 343 + return -ENOMEM; 344 + 345 + rtc->config = of_device_get_match_data(dev); 346 + if (!rtc->config) 347 + return -ENODEV; 348 + 349 + base = devm_platform_ioremap_resource(pdev, 0); 350 + if (IS_ERR(base)) 351 + return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n"); 352 + 353 + rtc->map = devm_regmap_init_mmio(dev, base, &aml_rtc_regmap_config); 354 + if (IS_ERR(rtc->map)) 355 + return dev_err_probe(dev, PTR_ERR(rtc->map), "regmap init failed\n"); 356 + 357 + rtc->irq = platform_get_irq(pdev, 0); 358 + if (rtc->irq < 0) 359 + return rtc->irq; 360 + 361 + rtc->rtc_clk = devm_clk_get(dev, "osc"); 362 + if (IS_ERR(rtc->rtc_clk)) 363 + return dev_err_probe(dev, PTR_ERR(rtc->rtc_clk), 364 + "failed to find rtc clock\n"); 365 + if (clk_get_rate(rtc->rtc_clk) != OSC_32K && clk_get_rate(rtc->rtc_clk) != OSC_24M) 366 + return dev_err_probe(dev, -EINVAL, "Invalid clock configuration\n"); 367 + 368 + rtc->sys_clk = devm_clk_get_enabled(dev, "sys"); 369 + if (IS_ERR(rtc->sys_clk)) 370 + return dev_err_probe(dev, PTR_ERR(rtc->sys_clk), 371 + "failed to get_enable rtc sys clk\n"); 372 + aml_rtc_init(rtc); 373 + 374 + device_init_wakeup(dev, 1); 375 + platform_set_drvdata(pdev, rtc); 376 + 377 + rtc->rtc_dev = devm_rtc_allocate_device(dev); 378 + if (IS_ERR(rtc->rtc_dev)) { 379 + ret = PTR_ERR(rtc->rtc_dev); 380 + goto err_clk; 381 + } 382 + 383 + ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, 384 + IRQF_ONESHOT, "aml-rtc alarm", rtc); 385 + if (ret) { 386 + dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", 387 + rtc->irq, ret); 388 + goto err_clk; 389 + } 390 + 391 + rtc->rtc_dev->ops = &aml_rtc_ops; 392 + rtc->rtc_dev->range_min = 0; 393 + rtc->rtc_dev->range_max = U32_MAX; 394 + 395 + ret = devm_rtc_register_device(rtc->rtc_dev); 396 + if (ret) { 397 + dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret); 398 + goto err_clk; 399 + } 400 + 401 + return 0; 402 + err_clk: 403 + clk_disable_unprepare(rtc->sys_clk); 404 + device_init_wakeup(dev, 0); 405 + 406 + return ret; 407 + } 408 + 409 + #ifdef CONFIG_PM_SLEEP 410 + static int aml_rtc_suspend(struct device *dev) 411 + { 412 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 413 + 414 + if (device_may_wakeup(dev)) 415 + enable_irq_wake(rtc->irq); 416 + 417 + return 0; 418 + } 419 + 420 + static int aml_rtc_resume(struct device *dev) 421 + { 422 + struct aml_rtc_data *rtc = dev_get_drvdata(dev); 423 + 424 + if (device_may_wakeup(dev)) 425 + disable_irq_wake(rtc->irq); 426 + 427 + return 0; 428 + } 429 + #endif 430 + 431 + static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops, 432 + aml_rtc_suspend, aml_rtc_resume); 433 + 434 + static void aml_rtc_remove(struct platform_device *pdev) 435 + { 436 + struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev); 437 + 438 + clk_disable_unprepare(rtc->sys_clk); 439 + device_init_wakeup(&pdev->dev, 0); 440 + } 441 + 442 + static const struct aml_rtc_config a5_rtc_config = { 443 + }; 444 + 445 + static const struct aml_rtc_config a4_rtc_config = { 446 + .gray_stored = true, 447 + }; 448 + 449 + static const struct of_device_id aml_rtc_device_id[] = { 450 + { 451 + .compatible = "amlogic,a4-rtc", 452 + .data = &a4_rtc_config, 453 + }, 454 + { 455 + .compatible = "amlogic,a5-rtc", 456 + .data = &a5_rtc_config, 457 + }, 458 + }; 459 + MODULE_DEVICE_TABLE(of, aml_rtc_device_id); 460 + 461 + static struct platform_driver aml_rtc_driver = { 462 + .probe = aml_rtc_probe, 463 + .remove = aml_rtc_remove, 464 + .driver = { 465 + .name = "aml-rtc", 466 + .pm = &aml_rtc_pm_ops, 467 + .of_match_table = aml_rtc_device_id, 468 + }, 469 + }; 470 + 471 + module_platform_driver(aml_rtc_driver); 472 + MODULE_DESCRIPTION("Amlogic RTC driver"); 473 + MODULE_AUTHOR("Yiting Deng <yiting.deng@amlogic.com>"); 474 + MODULE_LICENSE("GPL");