Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: New RTC driver for SuperH On-Chip RTC.

This replaces the old SH RTC driver, and allows us to
clean quite a lot of things up on the board-specific
side.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>

+478
+10
drivers/rtc/Kconfig
··· 238 238 To compile this driver as a module, choose M here: the 239 239 module will be called rtc-sa1100. 240 240 241 + config RTC_DRV_SH 242 + tristate "SuperH On-Chip RTC" 243 + depends on RTC_CLASS && SUPERH 244 + help 245 + Say Y here to enable support for the on-chip RTC found in 246 + most SuperH processors. 247 + 248 + To compile this driver as a module, choose M here: the 249 + module will be called rtc-sh. 250 + 241 251 config RTC_DRV_VR41XX 242 252 tristate "NEC VR41XX" 243 253 depends on RTC_CLASS && CPU_VR41XX
+1
drivers/rtc/Makefile
··· 31 31 obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o 32 32 obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o 33 33 obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o 34 + obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+467
drivers/rtc/rtc-sh.c
··· 1 + /* 2 + * SuperH On-Chip RTC Support 3 + * 4 + * Copyright (C) 2006 Paul Mundt 5 + * 6 + * Based on the old arch/sh/kernel/cpu/rtc.c by: 7 + * 8 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 9 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 10 + * 11 + * This file is subject to the terms and conditions of the GNU General Public 12 + * License. See the file "COPYING" in the main directory of this archive 13 + * for more details. 14 + */ 15 + #include <linux/module.h> 16 + #include <linux/kernel.h> 17 + #include <linux/bcd.h> 18 + #include <linux/rtc.h> 19 + #include <linux/init.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/seq_file.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/spinlock.h> 24 + #include <asm/io.h> 25 + 26 + #ifdef CONFIG_CPU_SH3 27 + #define rtc_reg_size sizeof(u16) 28 + #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ 29 + #elif defined(CONFIG_CPU_SH4) 30 + #define rtc_reg_size sizeof(u32) 31 + #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ 32 + #endif 33 + 34 + #define RTC_REG(r) ((r) * rtc_reg_size) 35 + 36 + #define R64CNT RTC_REG(0) 37 + #define RSECCNT RTC_REG(1) 38 + #define RMINCNT RTC_REG(2) 39 + #define RHRCNT RTC_REG(3) 40 + #define RWKCNT RTC_REG(4) 41 + #define RDAYCNT RTC_REG(5) 42 + #define RMONCNT RTC_REG(6) 43 + #define RYRCNT RTC_REG(7) 44 + #define RSECAR RTC_REG(8) 45 + #define RMINAR RTC_REG(9) 46 + #define RHRAR RTC_REG(10) 47 + #define RWKAR RTC_REG(11) 48 + #define RDAYAR RTC_REG(12) 49 + #define RMONAR RTC_REG(13) 50 + #define RCR1 RTC_REG(14) 51 + #define RCR2 RTC_REG(15) 52 + 53 + /* RCR1 Bits */ 54 + #define RCR1_CF 0x80 /* Carry Flag */ 55 + #define RCR1_CIE 0x10 /* Carry Interrupt Enable */ 56 + #define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ 57 + #define RCR1_AF 0x01 /* Alarm Flag */ 58 + 59 + /* RCR2 Bits */ 60 + #define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ 61 + #define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ 62 + #define RCR2_RTCEN 0x08 /* ENable RTC */ 63 + #define RCR2_ADJ 0x04 /* ADJustment (30-second) */ 64 + #define RCR2_RESET 0x02 /* Reset bit */ 65 + #define RCR2_START 0x01 /* Start bit */ 66 + 67 + struct sh_rtc { 68 + void __iomem *regbase; 69 + unsigned long regsize; 70 + struct resource *res; 71 + unsigned int alarm_irq, periodic_irq, carry_irq; 72 + struct rtc_device *rtc_dev; 73 + spinlock_t lock; 74 + }; 75 + 76 + static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) 77 + { 78 + struct platform_device *pdev = id; 79 + struct sh_rtc *rtc = platform_get_drvdata(pdev); 80 + unsigned int tmp, events = 0; 81 + 82 + spin_lock(&rtc->lock); 83 + 84 + tmp = readb(rtc->regbase + RCR1); 85 + 86 + if (tmp & RCR1_AF) 87 + events |= RTC_AF | RTC_IRQF; 88 + 89 + tmp &= ~(RCR1_CF | RCR1_AF); 90 + 91 + writeb(tmp, rtc->regbase + RCR1); 92 + 93 + rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); 94 + 95 + spin_unlock(&rtc->lock); 96 + 97 + return IRQ_HANDLED; 98 + } 99 + 100 + static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs) 101 + { 102 + struct sh_rtc *rtc = dev_get_drvdata(id); 103 + 104 + spin_lock(&rtc->lock); 105 + 106 + rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF); 107 + 108 + spin_unlock(&rtc->lock); 109 + 110 + return IRQ_HANDLED; 111 + } 112 + 113 + static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) 114 + { 115 + struct sh_rtc *rtc = dev_get_drvdata(dev); 116 + unsigned int tmp; 117 + 118 + spin_lock_irq(&rtc->lock); 119 + 120 + tmp = readb(rtc->regbase + RCR2); 121 + 122 + if (enable) { 123 + tmp &= ~RCR2_PESMASK; 124 + tmp |= RCR2_PEF | (2 << 4); 125 + } else 126 + tmp &= ~(RCR2_PESMASK | RCR2_PEF); 127 + 128 + writeb(tmp, rtc->regbase + RCR2); 129 + 130 + spin_unlock_irq(&rtc->lock); 131 + } 132 + 133 + static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) 134 + { 135 + struct sh_rtc *rtc = dev_get_drvdata(dev); 136 + unsigned int tmp; 137 + 138 + spin_lock_irq(&rtc->lock); 139 + 140 + tmp = readb(rtc->regbase + RCR1); 141 + 142 + if (enable) 143 + tmp |= RCR1_AIE; 144 + else 145 + tmp &= ~RCR1_AIE; 146 + 147 + writeb(tmp, rtc->regbase + RCR1); 148 + 149 + spin_unlock_irq(&rtc->lock); 150 + } 151 + 152 + static int sh_rtc_open(struct device *dev) 153 + { 154 + struct sh_rtc *rtc = dev_get_drvdata(dev); 155 + unsigned int tmp; 156 + int ret; 157 + 158 + tmp = readb(rtc->regbase + RCR1); 159 + tmp &= ~RCR1_CF; 160 + tmp |= RCR1_CIE; 161 + writeb(tmp, rtc->regbase + RCR1); 162 + 163 + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT, 164 + "sh-rtc period", dev); 165 + if (unlikely(ret)) { 166 + dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", 167 + ret, rtc->periodic_irq); 168 + return ret; 169 + } 170 + 171 + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT, 172 + "sh-rtc carry", dev); 173 + if (unlikely(ret)) { 174 + dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", 175 + ret, rtc->carry_irq); 176 + free_irq(rtc->periodic_irq, dev); 177 + goto err_bad_carry; 178 + } 179 + 180 + ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, 181 + "sh-rtc alarm", dev); 182 + if (unlikely(ret)) { 183 + dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", 184 + ret, rtc->alarm_irq); 185 + goto err_bad_alarm; 186 + } 187 + 188 + return 0; 189 + 190 + err_bad_alarm: 191 + free_irq(rtc->carry_irq, dev); 192 + err_bad_carry: 193 + free_irq(rtc->periodic_irq, dev); 194 + 195 + return ret; 196 + } 197 + 198 + static void sh_rtc_release(struct device *dev) 199 + { 200 + struct sh_rtc *rtc = dev_get_drvdata(dev); 201 + 202 + sh_rtc_setpie(dev, 0); 203 + 204 + free_irq(rtc->periodic_irq, dev); 205 + free_irq(rtc->carry_irq, dev); 206 + free_irq(rtc->alarm_irq, dev); 207 + } 208 + 209 + static int sh_rtc_proc(struct device *dev, struct seq_file *seq) 210 + { 211 + struct sh_rtc *rtc = dev_get_drvdata(dev); 212 + unsigned int tmp; 213 + 214 + tmp = readb(rtc->regbase + RCR1); 215 + seq_printf(seq, "alarm_IRQ\t: %s\n", 216 + (tmp & RCR1_AIE) ? "yes" : "no"); 217 + seq_printf(seq, "carry_IRQ\t: %s\n", 218 + (tmp & RCR1_CIE) ? "yes" : "no"); 219 + 220 + tmp = readb(rtc->regbase + RCR2); 221 + seq_printf(seq, "periodic_IRQ\t: %s\n", 222 + (tmp & RCR2_PEF) ? "yes" : "no"); 223 + 224 + return 0; 225 + } 226 + 227 + static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 228 + { 229 + unsigned int ret = -ENOIOCTLCMD; 230 + 231 + switch (cmd) { 232 + case RTC_PIE_OFF: 233 + case RTC_PIE_ON: 234 + sh_rtc_setpie(dev, cmd == RTC_PIE_ON); 235 + ret = 0; 236 + break; 237 + case RTC_AIE_OFF: 238 + case RTC_AIE_ON: 239 + sh_rtc_setaie(dev, cmd == RTC_AIE_ON); 240 + ret = 0; 241 + break; 242 + } 243 + 244 + return ret; 245 + } 246 + 247 + static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) 248 + { 249 + struct platform_device *pdev = to_platform_device(dev); 250 + struct sh_rtc *rtc = platform_get_drvdata(pdev); 251 + unsigned int sec128, sec2, yr, yr100, cf_bit; 252 + 253 + do { 254 + unsigned int tmp; 255 + 256 + spin_lock_irq(&rtc->lock); 257 + 258 + tmp = readb(rtc->regbase + RCR1); 259 + tmp &= ~RCR1_CF; /* Clear CF-bit */ 260 + tmp |= RCR1_CIE; 261 + writeb(tmp, rtc->regbase + RCR1); 262 + 263 + sec128 = readb(rtc->regbase + R64CNT); 264 + 265 + tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT)); 266 + tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT)); 267 + tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT)); 268 + tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT)); 269 + tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); 270 + tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)); 271 + 272 + #if defined(CONFIG_CPU_SH4) 273 + yr = readw(rtc->regbase + RYRCNT); 274 + yr100 = BCD2BIN(yr >> 8); 275 + yr &= 0xff; 276 + #else 277 + yr = readb(rtc->regbase + RYRCNT); 278 + yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); 279 + #endif 280 + 281 + tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; 282 + 283 + sec2 = readb(rtc->regbase + R64CNT); 284 + cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF; 285 + 286 + spin_unlock_irq(&rtc->lock); 287 + } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0); 288 + 289 + #if RTC_BIT_INVERTED != 0 290 + if ((sec128 & RTC_BIT_INVERTED)) 291 + tm->tm_sec--; 292 + #endif 293 + 294 + dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, " 295 + "mday=%d, mon=%d, year=%d, wday=%d\n", 296 + __FUNCTION__, 297 + tm->tm_sec, tm->tm_min, tm->tm_hour, 298 + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 299 + 300 + if (rtc_valid_tm(tm) < 0) 301 + dev_err(dev, "invalid date\n"); 302 + 303 + return 0; 304 + } 305 + 306 + static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) 307 + { 308 + struct platform_device *pdev = to_platform_device(dev); 309 + struct sh_rtc *rtc = platform_get_drvdata(pdev); 310 + unsigned int tmp; 311 + int year; 312 + 313 + spin_lock_irq(&rtc->lock); 314 + 315 + /* Reset pre-scaler & stop RTC */ 316 + tmp = readb(rtc->regbase + RCR2); 317 + tmp |= RCR2_RESET; 318 + writeb(tmp, rtc->regbase + RCR2); 319 + 320 + writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT); 321 + writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT); 322 + writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT); 323 + writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT); 324 + writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); 325 + writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT); 326 + 327 + #ifdef CONFIG_CPU_SH3 328 + year = tm->tm_year % 100; 329 + writeb(BIN2BCD(year), rtc->regbase + RYRCNT); 330 + #else 331 + year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | 332 + BIN2BCD(tm->tm_year % 100); 333 + writew(year, rtc->regbase + RYRCNT); 334 + #endif 335 + 336 + /* Start RTC */ 337 + tmp = readb(rtc->regbase + RCR2); 338 + tmp &= ~RCR2_RESET; 339 + tmp |= RCR2_RTCEN | RCR2_START; 340 + writeb(tmp, rtc->regbase + RCR2); 341 + 342 + spin_unlock_irq(&rtc->lock); 343 + 344 + return 0; 345 + } 346 + 347 + static struct rtc_class_ops sh_rtc_ops = { 348 + .open = sh_rtc_open, 349 + .release = sh_rtc_release, 350 + .ioctl = sh_rtc_ioctl, 351 + .read_time = sh_rtc_read_time, 352 + .set_time = sh_rtc_set_time, 353 + .proc = sh_rtc_proc, 354 + }; 355 + 356 + static int __devinit sh_rtc_probe(struct platform_device *pdev) 357 + { 358 + struct sh_rtc *rtc; 359 + struct resource *res; 360 + int ret = -ENOENT; 361 + 362 + rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); 363 + if (unlikely(!rtc)) 364 + return -ENOMEM; 365 + 366 + spin_lock_init(&rtc->lock); 367 + 368 + rtc->periodic_irq = platform_get_irq(pdev, 0); 369 + if (unlikely(rtc->periodic_irq < 0)) { 370 + dev_err(&pdev->dev, "No IRQ for period\n"); 371 + goto err_badres; 372 + } 373 + 374 + rtc->carry_irq = platform_get_irq(pdev, 1); 375 + if (unlikely(rtc->carry_irq < 0)) { 376 + dev_err(&pdev->dev, "No IRQ for carry\n"); 377 + goto err_badres; 378 + } 379 + 380 + rtc->alarm_irq = platform_get_irq(pdev, 2); 381 + if (unlikely(rtc->alarm_irq < 0)) { 382 + dev_err(&pdev->dev, "No IRQ for alarm\n"); 383 + goto err_badres; 384 + } 385 + 386 + res = platform_get_resource(pdev, IORESOURCE_IO, 0); 387 + if (unlikely(res == NULL)) { 388 + dev_err(&pdev->dev, "No IO resource\n"); 389 + goto err_badres; 390 + } 391 + 392 + rtc->regsize = res->end - res->start + 1; 393 + 394 + rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); 395 + if (unlikely(!rtc->res)) { 396 + ret = -EBUSY; 397 + goto err_badres; 398 + } 399 + 400 + rtc->regbase = (void __iomem *)rtc->res->start; 401 + if (unlikely(!rtc->regbase)) { 402 + ret = -EINVAL; 403 + goto err_badmap; 404 + } 405 + 406 + rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, 407 + &sh_rtc_ops, THIS_MODULE); 408 + if (IS_ERR(rtc)) { 409 + ret = PTR_ERR(rtc->rtc_dev); 410 + goto err_badmap; 411 + } 412 + 413 + platform_set_drvdata(pdev, rtc); 414 + 415 + return 0; 416 + 417 + err_badmap: 418 + release_resource(rtc->res); 419 + err_badres: 420 + kfree(rtc); 421 + 422 + return ret; 423 + } 424 + 425 + static int __devexit sh_rtc_remove(struct platform_device *pdev) 426 + { 427 + struct sh_rtc *rtc = platform_get_drvdata(pdev); 428 + 429 + if (likely(rtc->rtc_dev)) 430 + rtc_device_unregister(rtc->rtc_dev); 431 + 432 + sh_rtc_setpie(&pdev->dev, 0); 433 + sh_rtc_setaie(&pdev->dev, 0); 434 + 435 + release_resource(rtc->res); 436 + 437 + platform_set_drvdata(pdev, NULL); 438 + 439 + kfree(rtc); 440 + 441 + return 0; 442 + } 443 + static struct platform_driver sh_rtc_platform_driver = { 444 + .driver = { 445 + .name = "sh-rtc", 446 + .owner = THIS_MODULE, 447 + }, 448 + .probe = sh_rtc_probe, 449 + .remove = __devexit_p(sh_rtc_remove), 450 + }; 451 + 452 + static int __init sh_rtc_init(void) 453 + { 454 + return platform_driver_register(&sh_rtc_platform_driver); 455 + } 456 + 457 + static void __exit sh_rtc_exit(void) 458 + { 459 + platform_driver_unregister(&sh_rtc_platform_driver); 460 + } 461 + 462 + module_init(sh_rtc_init); 463 + module_exit(sh_rtc_exit); 464 + 465 + MODULE_DESCRIPTION("SuperH on-chip RTC driver"); 466 + MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); 467 + MODULE_LICENSE("GPL");