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