1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Loongson RTC driver 4 * 5 * Maintained out-of-tree by Huacai Chen <chenhuacai@kernel.org>. 6 * Rewritten for mainline by WANG Xuerui <git@xen0n.name>. 7 * Binbin Zhou <zhoubinbin@loongson.cn> 8 */ 9 10 #include <linux/bitfield.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 #include <linux/rtc.h> 16 #include <linux/acpi.h> 17 18 /* Time Of Year(TOY) counters registers */ 19 #define TOY_TRIM_REG 0x20 /* Must be initialized to 0 */ 20 #define TOY_WRITE0_REG 0x24 /* TOY low 32-bits value (write-only) */ 21 #define TOY_WRITE1_REG 0x28 /* TOY high 32-bits value (write-only) */ 22 #define TOY_READ0_REG 0x2c /* TOY low 32-bits value (read-only) */ 23 #define TOY_READ1_REG 0x30 /* TOY high 32-bits value (read-only) */ 24 #define TOY_MATCH0_REG 0x34 /* TOY timing interrupt 0 */ 25 #define TOY_MATCH1_REG 0x38 /* TOY timing interrupt 1 */ 26 #define TOY_MATCH2_REG 0x3c /* TOY timing interrupt 2 */ 27 28 /* RTC counters registers */ 29 #define RTC_CTRL_REG 0x40 /* TOY and RTC control register */ 30 #define RTC_TRIM_REG 0x60 /* Must be initialized to 0 */ 31 #define RTC_WRITE0_REG 0x64 /* RTC counters value (write-only) */ 32 #define RTC_READ0_REG 0x68 /* RTC counters value (read-only) */ 33 #define RTC_MATCH0_REG 0x6c /* RTC timing interrupt 0 */ 34 #define RTC_MATCH1_REG 0x70 /* RTC timing interrupt 1 */ 35 #define RTC_MATCH2_REG 0x74 /* RTC timing interrupt 2 */ 36 37 /* bitmask of TOY_WRITE0_REG */ 38 #define TOY_MON GENMASK(31, 26) 39 #define TOY_DAY GENMASK(25, 21) 40 #define TOY_HOUR GENMASK(20, 16) 41 #define TOY_MIN GENMASK(15, 10) 42 #define TOY_SEC GENMASK(9, 4) 43 #define TOY_MSEC GENMASK(3, 0) 44 45 /* bitmask of TOY_MATCH0/1/2_REG */ 46 #define TOY_MATCH_YEAR GENMASK(31, 26) 47 #define TOY_MATCH_MON GENMASK(25, 22) 48 #define TOY_MATCH_DAY GENMASK(21, 17) 49 #define TOY_MATCH_HOUR GENMASK(16, 12) 50 #define TOY_MATCH_MIN GENMASK(11, 6) 51 #define TOY_MATCH_SEC GENMASK(5, 0) 52 53 /* bitmask of RTC_CTRL_REG */ 54 #define RTC_ENABLE BIT(13) /* 1: RTC counters enable */ 55 #define TOY_ENABLE BIT(11) /* 1: TOY counters enable */ 56 #define OSC_ENABLE BIT(8) /* 1: 32.768k crystal enable */ 57 #define TOY_ENABLE_MASK (TOY_ENABLE | OSC_ENABLE) 58 59 /* PM domain registers */ 60 #define PM1_STS_REG 0x0c /* Power management 1 status register */ 61 #define RTC_STS BIT(10) /* RTC status */ 62 #define PM1_EN_REG 0x10 /* Power management 1 enable register */ 63 #define RTC_EN BIT(10) /* RTC event enable */ 64 65 /* 66 * According to the LS1C manual, RTC_CTRL and alarm-related registers are not defined. 67 * Accessing the relevant registers will cause the system to hang. 68 */ 69 #define LOONGSON_RTC_CTRL_WORKAROUND BIT(0) 70 #define LOONGSON_RTC_ALARM_WORKAROUND BIT(1) 71 72 struct loongson_rtc_config { 73 u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */ 74 u32 flags; /* Workaround bits */ 75 }; 76 77 struct loongson_rtc_priv { 78 spinlock_t lock; /* protects PM registers access */ 79 u32 fix_year; /* RTC alarm year compensation value */ 80 struct rtc_device *rtcdev; 81 struct regmap *regmap; 82 void __iomem *pm_base; /* PM domain base, for RTC alarm wakeup */ 83 const struct loongson_rtc_config *config; 84 }; 85 86 static const struct loongson_rtc_config ls1b_rtc_config = { 87 .pm_offset = 0, 88 .flags = 0, 89 }; 90 91 static const struct loongson_rtc_config ls1c_rtc_config = { 92 .pm_offset = 0, 93 .flags = LOONGSON_RTC_CTRL_WORKAROUND | LOONGSON_RTC_ALARM_WORKAROUND, 94 }; 95 96 static const struct loongson_rtc_config generic_rtc_config = { 97 .pm_offset = 0x100, 98 .flags = 0, 99 }; 100 101 static const struct loongson_rtc_config ls2k0300_rtc_config = { 102 .pm_offset = 0x0, 103 .flags = LOONGSON_RTC_ALARM_WORKAROUND, 104 }; 105 106 static const struct loongson_rtc_config ls2k1000_rtc_config = { 107 .pm_offset = 0x800, 108 .flags = 0, 109 }; 110 111 static const struct regmap_config loongson_rtc_regmap_config = { 112 .reg_bits = 32, 113 .val_bits = 32, 114 .reg_stride = 4, 115 }; 116 117 /* RTC alarm irq handler */ 118 static irqreturn_t loongson_rtc_isr(int irq, void *id) 119 { 120 struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id; 121 122 rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF); 123 124 /* 125 * The TOY_MATCH0_REG should be cleared 0 here, 126 * otherwise the interrupt cannot be cleared. 127 */ 128 regmap_write(priv->regmap, TOY_MATCH0_REG, 0); 129 130 return IRQ_HANDLED; 131 } 132 133 /* For ACPI fixed event handler */ 134 static u32 loongson_rtc_handler(void *id) 135 { 136 struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id; 137 138 rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF); 139 140 /* 141 * The TOY_MATCH0_REG should be cleared 0 here, 142 * otherwise the interrupt cannot be cleared. 143 */ 144 regmap_write(priv->regmap, TOY_MATCH0_REG, 0); 145 146 spin_lock(&priv->lock); 147 /* Disable RTC alarm wakeup and interrupt */ 148 writel(readl(priv->pm_base + PM1_EN_REG) & ~RTC_EN, 149 priv->pm_base + PM1_EN_REG); 150 151 /* Clear RTC interrupt status */ 152 writel(RTC_STS, priv->pm_base + PM1_STS_REG); 153 spin_unlock(&priv->lock); 154 155 return ACPI_INTERRUPT_HANDLED; 156 } 157 158 static int loongson_rtc_set_enabled(struct device *dev) 159 { 160 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 161 162 if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND) 163 return 0; 164 165 /* Enable RTC TOY counters and crystal */ 166 return regmap_update_bits(priv->regmap, RTC_CTRL_REG, TOY_ENABLE_MASK, 167 TOY_ENABLE_MASK); 168 } 169 170 static bool loongson_rtc_get_enabled(struct device *dev) 171 { 172 int ret; 173 u32 ctrl_data; 174 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 175 176 if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND) 177 return true; 178 179 ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data); 180 if (ret < 0) 181 return false; 182 183 return ctrl_data & TOY_ENABLE_MASK; 184 } 185 186 static int loongson_rtc_read_time(struct device *dev, struct rtc_time *tm) 187 { 188 int ret; 189 u32 rtc_data[2]; 190 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 191 192 if (!loongson_rtc_get_enabled(dev)) 193 return -EINVAL; 194 195 ret = regmap_bulk_read(priv->regmap, TOY_READ0_REG, rtc_data, 196 ARRAY_SIZE(rtc_data)); 197 if (ret < 0) 198 return ret; 199 200 tm->tm_sec = FIELD_GET(TOY_SEC, rtc_data[0]); 201 tm->tm_min = FIELD_GET(TOY_MIN, rtc_data[0]); 202 tm->tm_hour = FIELD_GET(TOY_HOUR, rtc_data[0]); 203 tm->tm_mday = FIELD_GET(TOY_DAY, rtc_data[0]); 204 tm->tm_mon = FIELD_GET(TOY_MON, rtc_data[0]) - 1; 205 tm->tm_year = rtc_data[1]; 206 207 /* Prepare for RTC alarm year compensation value. */ 208 priv->fix_year = tm->tm_year / 64 * 64; 209 return 0; 210 } 211 212 static int loongson_rtc_set_time(struct device *dev, struct rtc_time *tm) 213 { 214 int ret; 215 u32 rtc_data[2]; 216 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 217 218 rtc_data[0] = FIELD_PREP(TOY_SEC, tm->tm_sec) 219 | FIELD_PREP(TOY_MIN, tm->tm_min) 220 | FIELD_PREP(TOY_HOUR, tm->tm_hour) 221 | FIELD_PREP(TOY_DAY, tm->tm_mday) 222 | FIELD_PREP(TOY_MON, tm->tm_mon + 1); 223 rtc_data[1] = tm->tm_year; 224 225 ret = regmap_bulk_write(priv->regmap, TOY_WRITE0_REG, rtc_data, 226 ARRAY_SIZE(rtc_data)); 227 if (ret < 0) 228 return ret; 229 230 return loongson_rtc_set_enabled(dev); 231 } 232 233 static int loongson_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 234 { 235 int ret; 236 u32 alarm_data; 237 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 238 239 ret = regmap_read(priv->regmap, TOY_MATCH0_REG, &alarm_data); 240 if (ret < 0) 241 return ret; 242 243 alrm->time.tm_sec = FIELD_GET(TOY_MATCH_SEC, alarm_data); 244 alrm->time.tm_min = FIELD_GET(TOY_MATCH_MIN, alarm_data); 245 alrm->time.tm_hour = FIELD_GET(TOY_MATCH_HOUR, alarm_data); 246 alrm->time.tm_mday = FIELD_GET(TOY_MATCH_DAY, alarm_data); 247 alrm->time.tm_mon = FIELD_GET(TOY_MATCH_MON, alarm_data) - 1; 248 /* 249 * This is a hardware bug: the year field of SYS_TOYMATCH is only 6 bits, 250 * making it impossible to save year values larger than 64. 251 * 252 * SYS_TOYMATCH is used to match the alarm time value and determine if 253 * an alarm is triggered, so we must keep the lower 6 bits of the year 254 * value constant during the value conversion. 255 * 256 * In summary, we need to manually add 64(or a multiple of 64) to the 257 * year value to avoid the invalid alarm prompt at startup. 258 */ 259 alrm->time.tm_year = FIELD_GET(TOY_MATCH_YEAR, alarm_data) + priv->fix_year; 260 261 alrm->enabled = !!(readl(priv->pm_base + PM1_EN_REG) & RTC_EN); 262 return 0; 263 } 264 265 static int loongson_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 266 { 267 u32 val; 268 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 269 270 spin_lock(&priv->lock); 271 val = readl(priv->pm_base + PM1_EN_REG); 272 /* Enable RTC alarm wakeup */ 273 writel(enabled ? val | RTC_EN : val & ~RTC_EN, 274 priv->pm_base + PM1_EN_REG); 275 spin_unlock(&priv->lock); 276 277 return 0; 278 } 279 280 static int loongson_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 281 { 282 int ret; 283 u32 alarm_data; 284 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 285 286 alarm_data = FIELD_PREP(TOY_MATCH_SEC, alrm->time.tm_sec) 287 | FIELD_PREP(TOY_MATCH_MIN, alrm->time.tm_min) 288 | FIELD_PREP(TOY_MATCH_HOUR, alrm->time.tm_hour) 289 | FIELD_PREP(TOY_MATCH_DAY, alrm->time.tm_mday) 290 | FIELD_PREP(TOY_MATCH_MON, alrm->time.tm_mon + 1) 291 | FIELD_PREP(TOY_MATCH_YEAR, alrm->time.tm_year - priv->fix_year); 292 293 ret = regmap_write(priv->regmap, TOY_MATCH0_REG, alarm_data); 294 if (ret < 0) 295 return ret; 296 297 return loongson_rtc_alarm_irq_enable(dev, alrm->enabled); 298 } 299 300 static const struct rtc_class_ops loongson_rtc_ops = { 301 .read_time = loongson_rtc_read_time, 302 .set_time = loongson_rtc_set_time, 303 .read_alarm = loongson_rtc_read_alarm, 304 .set_alarm = loongson_rtc_set_alarm, 305 .alarm_irq_enable = loongson_rtc_alarm_irq_enable, 306 }; 307 308 static int loongson_rtc_alarm_setting(struct platform_device *pdev, void __iomem *regs) 309 { 310 int ret = 0, alarm_irq; 311 struct device *dev = &pdev->dev; 312 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 313 314 if (priv->config->flags & LOONGSON_RTC_ALARM_WORKAROUND) { 315 /* Loongson-1C/Loongson-2K0300 RTC does not support alarm */ 316 clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features); 317 return 0; 318 } 319 320 /* Get RTC alarm irq */ 321 alarm_irq = platform_get_irq(pdev, 0); 322 if (alarm_irq < 0) 323 return alarm_irq; 324 325 ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr, 0, "loongson-alarm", 326 priv); 327 if (ret < 0) 328 return ret; 329 330 priv->pm_base = regs - priv->config->pm_offset; 331 device_init_wakeup(dev, true); 332 333 if (has_acpi_companion(dev)) 334 acpi_install_fixed_event_handler(ACPI_EVENT_RTC, 335 loongson_rtc_handler, priv); 336 337 return ret; 338 } 339 340 static int loongson_rtc_probe(struct platform_device *pdev) 341 { 342 int ret; 343 void __iomem *regs; 344 struct loongson_rtc_priv *priv; 345 struct device *dev = &pdev->dev; 346 347 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 348 if (!priv) 349 return -ENOMEM; 350 351 regs = devm_platform_ioremap_resource(pdev, 0); 352 if (IS_ERR(regs)) 353 return dev_err_probe(dev, PTR_ERR(regs), 354 "devm_platform_ioremap_resource failed\n"); 355 356 priv->regmap = devm_regmap_init_mmio(dev, regs, 357 &loongson_rtc_regmap_config); 358 if (IS_ERR(priv->regmap)) 359 return dev_err_probe(dev, PTR_ERR(priv->regmap), 360 "devm_regmap_init_mmio failed\n"); 361 362 priv->config = device_get_match_data(dev); 363 spin_lock_init(&priv->lock); 364 platform_set_drvdata(pdev, priv); 365 366 priv->rtcdev = devm_rtc_allocate_device(dev); 367 if (IS_ERR(priv->rtcdev)) 368 return dev_err_probe(dev, PTR_ERR(priv->rtcdev), 369 "devm_rtc_allocate_device failed\n"); 370 371 ret = loongson_rtc_alarm_setting(pdev, regs); 372 if (ret) 373 return ret; 374 375 /* Loongson RTC does not support UIE */ 376 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features); 377 priv->rtcdev->ops = &loongson_rtc_ops; 378 priv->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; 379 priv->rtcdev->range_max = RTC_TIMESTAMP_END_2099; 380 381 return devm_rtc_register_device(priv->rtcdev); 382 } 383 384 static void loongson_rtc_remove(struct platform_device *pdev) 385 { 386 struct device *dev = &pdev->dev; 387 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 388 389 if (!test_bit(RTC_FEATURE_ALARM, priv->rtcdev->features)) 390 return; 391 392 if (has_acpi_companion(dev)) 393 acpi_remove_fixed_event_handler(ACPI_EVENT_RTC, 394 loongson_rtc_handler); 395 396 device_init_wakeup(dev, false); 397 loongson_rtc_alarm_irq_enable(dev, 0); 398 } 399 400 static const struct of_device_id loongson_rtc_of_match[] = { 401 { .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config }, 402 { .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config }, 403 { .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config }, 404 { .compatible = "loongson,ls2k0300-rtc", .data = &ls2k0300_rtc_config }, 405 { .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config }, 406 { /* sentinel */ } 407 }; 408 MODULE_DEVICE_TABLE(of, loongson_rtc_of_match); 409 410 static const struct acpi_device_id loongson_rtc_acpi_match[] = { 411 { "LOON0001", .driver_data = (kernel_ulong_t)&generic_rtc_config }, 412 { } 413 }; 414 MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match); 415 416 static struct platform_driver loongson_rtc_driver = { 417 .probe = loongson_rtc_probe, 418 .remove = loongson_rtc_remove, 419 .driver = { 420 .name = "loongson-rtc", 421 .of_match_table = loongson_rtc_of_match, 422 .acpi_match_table = loongson_rtc_acpi_match, 423 }, 424 }; 425 module_platform_driver(loongson_rtc_driver); 426 427 MODULE_DESCRIPTION("Loongson RTC driver"); 428 MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>"); 429 MODULE_AUTHOR("WANG Xuerui <git@xen0n.name>"); 430 MODULE_AUTHOR("Huacai Chen <chenhuacai@kernel.org>"); 431 MODULE_LICENSE("GPL"); 432