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 LS1C_RTC_CTRL_WORKAROUND BIT(0) 70 71 struct loongson_rtc_config { 72 u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */ 73 u32 flags; /* Workaround bits */ 74 }; 75 76 struct loongson_rtc_priv { 77 spinlock_t lock; /* protects PM registers access */ 78 u32 fix_year; /* RTC alarm year compensation value */ 79 struct rtc_device *rtcdev; 80 struct regmap *regmap; 81 void __iomem *pm_base; /* PM domain base, for RTC alarm wakeup */ 82 const struct loongson_rtc_config *config; 83 }; 84 85 static const struct loongson_rtc_config ls1b_rtc_config = { 86 .pm_offset = 0, 87 .flags = 0, 88 }; 89 90 static const struct loongson_rtc_config ls1c_rtc_config = { 91 .pm_offset = 0, 92 .flags = LS1C_RTC_CTRL_WORKAROUND, 93 }; 94 95 static const struct loongson_rtc_config generic_rtc_config = { 96 .pm_offset = 0x100, 97 .flags = 0, 98 }; 99 100 static const struct loongson_rtc_config ls2k1000_rtc_config = { 101 .pm_offset = 0x800, 102 .flags = 0, 103 }; 104 105 static const struct regmap_config loongson_rtc_regmap_config = { 106 .reg_bits = 32, 107 .val_bits = 32, 108 .reg_stride = 4, 109 }; 110 111 /* RTC alarm irq handler */ 112 static irqreturn_t loongson_rtc_isr(int irq, void *id) 113 { 114 struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id; 115 116 rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF); 117 118 /* 119 * The TOY_MATCH0_REG should be cleared 0 here, 120 * otherwise the interrupt cannot be cleared. 121 */ 122 regmap_write(priv->regmap, TOY_MATCH0_REG, 0); 123 124 return IRQ_HANDLED; 125 } 126 127 /* For ACPI fixed event handler */ 128 static u32 loongson_rtc_handler(void *id) 129 { 130 struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id; 131 132 rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF); 133 134 /* 135 * The TOY_MATCH0_REG should be cleared 0 here, 136 * otherwise the interrupt cannot be cleared. 137 */ 138 regmap_write(priv->regmap, TOY_MATCH0_REG, 0); 139 140 spin_lock(&priv->lock); 141 /* Disable RTC alarm wakeup and interrupt */ 142 writel(readl(priv->pm_base + PM1_EN_REG) & ~RTC_EN, 143 priv->pm_base + PM1_EN_REG); 144 145 /* Clear RTC interrupt status */ 146 writel(RTC_STS, priv->pm_base + PM1_STS_REG); 147 spin_unlock(&priv->lock); 148 149 return ACPI_INTERRUPT_HANDLED; 150 } 151 152 static int loongson_rtc_set_enabled(struct device *dev) 153 { 154 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 155 156 if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND) 157 return 0; 158 159 /* Enable RTC TOY counters and crystal */ 160 return regmap_update_bits(priv->regmap, RTC_CTRL_REG, TOY_ENABLE_MASK, 161 TOY_ENABLE_MASK); 162 } 163 164 static bool loongson_rtc_get_enabled(struct device *dev) 165 { 166 int ret; 167 u32 ctrl_data; 168 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 169 170 if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND) 171 return true; 172 173 ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data); 174 if (ret < 0) 175 return false; 176 177 return ctrl_data & TOY_ENABLE_MASK; 178 } 179 180 static int loongson_rtc_read_time(struct device *dev, struct rtc_time *tm) 181 { 182 int ret; 183 u32 rtc_data[2]; 184 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 185 186 if (!loongson_rtc_get_enabled(dev)) 187 return -EINVAL; 188 189 ret = regmap_bulk_read(priv->regmap, TOY_READ0_REG, rtc_data, 190 ARRAY_SIZE(rtc_data)); 191 if (ret < 0) 192 return ret; 193 194 tm->tm_sec = FIELD_GET(TOY_SEC, rtc_data[0]); 195 tm->tm_min = FIELD_GET(TOY_MIN, rtc_data[0]); 196 tm->tm_hour = FIELD_GET(TOY_HOUR, rtc_data[0]); 197 tm->tm_mday = FIELD_GET(TOY_DAY, rtc_data[0]); 198 tm->tm_mon = FIELD_GET(TOY_MON, rtc_data[0]) - 1; 199 tm->tm_year = rtc_data[1]; 200 201 /* Prepare for RTC alarm year compensation value. */ 202 priv->fix_year = tm->tm_year / 64 * 64; 203 return 0; 204 } 205 206 static int loongson_rtc_set_time(struct device *dev, struct rtc_time *tm) 207 { 208 int ret; 209 u32 rtc_data[2]; 210 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 211 212 rtc_data[0] = FIELD_PREP(TOY_SEC, tm->tm_sec) 213 | FIELD_PREP(TOY_MIN, tm->tm_min) 214 | FIELD_PREP(TOY_HOUR, tm->tm_hour) 215 | FIELD_PREP(TOY_DAY, tm->tm_mday) 216 | FIELD_PREP(TOY_MON, tm->tm_mon + 1); 217 rtc_data[1] = tm->tm_year; 218 219 ret = regmap_bulk_write(priv->regmap, TOY_WRITE0_REG, rtc_data, 220 ARRAY_SIZE(rtc_data)); 221 if (ret < 0) 222 return ret; 223 224 return loongson_rtc_set_enabled(dev); 225 } 226 227 static int loongson_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 228 { 229 int ret; 230 u32 alarm_data; 231 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 232 233 ret = regmap_read(priv->regmap, TOY_MATCH0_REG, &alarm_data); 234 if (ret < 0) 235 return ret; 236 237 alrm->time.tm_sec = FIELD_GET(TOY_MATCH_SEC, alarm_data); 238 alrm->time.tm_min = FIELD_GET(TOY_MATCH_MIN, alarm_data); 239 alrm->time.tm_hour = FIELD_GET(TOY_MATCH_HOUR, alarm_data); 240 alrm->time.tm_mday = FIELD_GET(TOY_MATCH_DAY, alarm_data); 241 alrm->time.tm_mon = FIELD_GET(TOY_MATCH_MON, alarm_data) - 1; 242 /* 243 * This is a hardware bug: the year field of SYS_TOYMATCH is only 6 bits, 244 * making it impossible to save year values larger than 64. 245 * 246 * SYS_TOYMATCH is used to match the alarm time value and determine if 247 * an alarm is triggered, so we must keep the lower 6 bits of the year 248 * value constant during the value conversion. 249 * 250 * In summary, we need to manually add 64(or a multiple of 64) to the 251 * year value to avoid the invalid alarm prompt at startup. 252 */ 253 alrm->time.tm_year = FIELD_GET(TOY_MATCH_YEAR, alarm_data) + priv->fix_year; 254 255 alrm->enabled = !!(readl(priv->pm_base + PM1_EN_REG) & RTC_EN); 256 return 0; 257 } 258 259 static int loongson_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 260 { 261 u32 val; 262 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 263 264 spin_lock(&priv->lock); 265 val = readl(priv->pm_base + PM1_EN_REG); 266 /* Enable RTC alarm wakeup */ 267 writel(enabled ? val | RTC_EN : val & ~RTC_EN, 268 priv->pm_base + PM1_EN_REG); 269 spin_unlock(&priv->lock); 270 271 return 0; 272 } 273 274 static int loongson_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 275 { 276 int ret; 277 u32 alarm_data; 278 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 279 280 alarm_data = FIELD_PREP(TOY_MATCH_SEC, alrm->time.tm_sec) 281 | FIELD_PREP(TOY_MATCH_MIN, alrm->time.tm_min) 282 | FIELD_PREP(TOY_MATCH_HOUR, alrm->time.tm_hour) 283 | FIELD_PREP(TOY_MATCH_DAY, alrm->time.tm_mday) 284 | FIELD_PREP(TOY_MATCH_MON, alrm->time.tm_mon + 1) 285 | FIELD_PREP(TOY_MATCH_YEAR, alrm->time.tm_year - priv->fix_year); 286 287 ret = regmap_write(priv->regmap, TOY_MATCH0_REG, alarm_data); 288 if (ret < 0) 289 return ret; 290 291 return loongson_rtc_alarm_irq_enable(dev, alrm->enabled); 292 } 293 294 static const struct rtc_class_ops loongson_rtc_ops = { 295 .read_time = loongson_rtc_read_time, 296 .set_time = loongson_rtc_set_time, 297 .read_alarm = loongson_rtc_read_alarm, 298 .set_alarm = loongson_rtc_set_alarm, 299 .alarm_irq_enable = loongson_rtc_alarm_irq_enable, 300 }; 301 302 static int loongson_rtc_probe(struct platform_device *pdev) 303 { 304 int ret, alarm_irq; 305 void __iomem *regs; 306 struct loongson_rtc_priv *priv; 307 struct device *dev = &pdev->dev; 308 309 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 310 if (!priv) 311 return -ENOMEM; 312 313 regs = devm_platform_ioremap_resource(pdev, 0); 314 if (IS_ERR(regs)) 315 return dev_err_probe(dev, PTR_ERR(regs), 316 "devm_platform_ioremap_resource failed\n"); 317 318 priv->regmap = devm_regmap_init_mmio(dev, regs, 319 &loongson_rtc_regmap_config); 320 if (IS_ERR(priv->regmap)) 321 return dev_err_probe(dev, PTR_ERR(priv->regmap), 322 "devm_regmap_init_mmio failed\n"); 323 324 priv->config = device_get_match_data(dev); 325 spin_lock_init(&priv->lock); 326 platform_set_drvdata(pdev, priv); 327 328 priv->rtcdev = devm_rtc_allocate_device(dev); 329 if (IS_ERR(priv->rtcdev)) 330 return dev_err_probe(dev, PTR_ERR(priv->rtcdev), 331 "devm_rtc_allocate_device failed\n"); 332 333 /* Get RTC alarm irq */ 334 alarm_irq = platform_get_irq(pdev, 0); 335 if (alarm_irq > 0) { 336 ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr, 337 0, "loongson-alarm", priv); 338 if (ret < 0) 339 return dev_err_probe(dev, ret, "Unable to request irq %d\n", 340 alarm_irq); 341 342 priv->pm_base = regs - priv->config->pm_offset; 343 device_init_wakeup(dev, true); 344 345 if (has_acpi_companion(dev)) 346 acpi_install_fixed_event_handler(ACPI_EVENT_RTC, 347 loongson_rtc_handler, priv); 348 } else { 349 /* Loongson-1C RTC does not support alarm */ 350 clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features); 351 } 352 353 /* Loongson RTC does not support UIE */ 354 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features); 355 priv->rtcdev->ops = &loongson_rtc_ops; 356 priv->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; 357 priv->rtcdev->range_max = RTC_TIMESTAMP_END_2099; 358 359 return devm_rtc_register_device(priv->rtcdev); 360 } 361 362 static void loongson_rtc_remove(struct platform_device *pdev) 363 { 364 struct device *dev = &pdev->dev; 365 struct loongson_rtc_priv *priv = dev_get_drvdata(dev); 366 367 if (!test_bit(RTC_FEATURE_ALARM, priv->rtcdev->features)) 368 return; 369 370 if (has_acpi_companion(dev)) 371 acpi_remove_fixed_event_handler(ACPI_EVENT_RTC, 372 loongson_rtc_handler); 373 374 device_init_wakeup(dev, false); 375 loongson_rtc_alarm_irq_enable(dev, 0); 376 } 377 378 static const struct of_device_id loongson_rtc_of_match[] = { 379 { .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config }, 380 { .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config }, 381 { .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config }, 382 { .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config }, 383 { /* sentinel */ } 384 }; 385 MODULE_DEVICE_TABLE(of, loongson_rtc_of_match); 386 387 static const struct acpi_device_id loongson_rtc_acpi_match[] = { 388 { "LOON0001", .driver_data = (kernel_ulong_t)&generic_rtc_config }, 389 { } 390 }; 391 MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match); 392 393 static struct platform_driver loongson_rtc_driver = { 394 .probe = loongson_rtc_probe, 395 .remove = loongson_rtc_remove, 396 .driver = { 397 .name = "loongson-rtc", 398 .of_match_table = loongson_rtc_of_match, 399 .acpi_match_table = loongson_rtc_acpi_match, 400 }, 401 }; 402 module_platform_driver(loongson_rtc_driver); 403 404 MODULE_DESCRIPTION("Loongson RTC driver"); 405 MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>"); 406 MODULE_AUTHOR("WANG Xuerui <git@xen0n.name>"); 407 MODULE_AUTHOR("Huacai Chen <chenhuacai@kernel.org>"); 408 MODULE_LICENSE("GPL"); 409