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