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