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

drivers/rtc/rtc-cmos.c: drivers/char/rtc.c features for DECstation support

This brings in drivers/char/rtc.c functionality required for DECstation
and, should the maintainers decide to switch, Alpha systems to use
rtc-cmos.

Specifically these features are made available:

* RTC iomem rather than x86/PCI port I/O mapping, controlled with the
RTC_IOMAPPED macro as with the original driver. The DS1287A chip in all
DECstation systems is mapped in the host bus address space as a
contiguous block of 64 32-bit words of which the least significant byte
accesses the RTC chip for both reads and writes. All the address and
data window register accesses are made transparently by the chipset glue
logic so that the device appears directly mapped on the host bus.

* A way to set the size of the address space explicitly with the
newly-added `address_space' member of the platform part of the RTC
device structure. This avoids the unreliable heuristics that does not
work in a setup where the RTC is not explicitly accessed with the usual
address and data window register pair.

* The ability to use the RTC periodic interrupt as a system clock
device, which is implemented by arch/mips/kernel/cevt-ds1287.c for
DECstation systems and takes the RTC interrupt away from the RTC driver.
Eventually hooking back to the clock device's interrupt handler should
be possible for the purpose of the alarm clock and possibly also
update-in-progress interrupt, but this is not done by this change.

o To avoid interfering with the clock interrupt all the places where
the RTC interrupt mask is fiddled with are only executed if and IRQ
has been assigned to the RTC driver.

o To avoid changing the clock setup Register A is not fiddled with
if CMOS_RTC_FLAGS_NOFREQ is set in the newly-added `flags' member of
the platform part of the RTC device structure. Originally, in
drivers/char/rtc.c, this was keyed with the absence of the RTC
interrupt, just like the interrupt mask, but there only the periodic
interrupt frequency is set, whereas rtc-cmos also sets the divider
bits. Therefore a new flag is introduced so that systems where the
RTC interrupt is not usable rather than used as a system clock device
can fully initialise the RTC.

* A small clean-up is made to the IRQ assignment code that makes the IRQ
number hardcoded to -1 rather than arbitrary -ENXIO (or whatever error
happens to be returned by platform_get_irq) where no IRQ has been
assigned to the RTC driver (NO_IRQ might be another candidate, but it
looks like this macro has inconsistent or missing definitions and
limited use and might therefore be unsafe).

Verified to work correctly with a DECstation 5000/240 system.

[akpm@linux-foundation.org: fix weird code layout]
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Maciej W. Rozycki and committed by
Linus Torvalds
31632dbd 809d9627

+64 -25
+60 -25
drivers/rtc/rtc-cmos.c
··· 647 647 int retval = 0; 648 648 unsigned char rtc_control; 649 649 unsigned address_space; 650 + u32 flags = 0; 650 651 651 652 /* there can be only one ... */ 652 653 if (cmos_rtc.dev) ··· 661 660 * REVISIT non-x86 systems may instead use memory space resources 662 661 * (needing ioremap etc), not i/o space resources like this ... 663 662 */ 664 - ports = request_region(ports->start, 665 - resource_size(ports), 666 - driver_name); 663 + if (RTC_IOMAPPED) 664 + ports = request_region(ports->start, resource_size(ports), 665 + driver_name); 666 + else 667 + ports = request_mem_region(ports->start, resource_size(ports), 668 + driver_name); 667 669 if (!ports) { 668 670 dev_dbg(dev, "i/o registers already in use\n"); 669 671 return -EBUSY; ··· 703 699 * expect CMOS_READ and friends to handle. 704 700 */ 705 701 if (info) { 702 + if (info->flags) 703 + flags = info->flags; 704 + if (info->address_space) 705 + address_space = info->address_space; 706 + 706 707 if (info->rtc_day_alarm && info->rtc_day_alarm < 128) 707 708 cmos_rtc.day_alrm = info->rtc_day_alarm; 708 709 if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) ··· 735 726 736 727 spin_lock_irq(&rtc_lock); 737 728 738 - /* force periodic irq to CMOS reset default of 1024Hz; 739 - * 740 - * REVISIT it's been reported that at least one x86_64 ALI mobo 741 - * doesn't use 32KHz here ... for portability we might need to 742 - * do something about other clock frequencies. 743 - */ 744 - cmos_rtc.rtc->irq_freq = 1024; 745 - hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); 746 - CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); 729 + if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { 730 + /* force periodic irq to CMOS reset default of 1024Hz; 731 + * 732 + * REVISIT it's been reported that at least one x86_64 ALI 733 + * mobo doesn't use 32KHz here ... for portability we might 734 + * need to do something about other clock frequencies. 735 + */ 736 + cmos_rtc.rtc->irq_freq = 1024; 737 + hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); 738 + CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); 739 + } 747 740 748 741 /* disable irqs */ 749 - cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); 742 + if (is_valid_irq(rtc_irq)) 743 + cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); 750 744 751 745 rtc_control = CMOS_READ(RTC_CONTROL); 752 746 ··· 814 802 cmos_rtc.dev = NULL; 815 803 rtc_device_unregister(cmos_rtc.rtc); 816 804 cleanup0: 817 - release_region(ports->start, resource_size(ports)); 805 + if (RTC_IOMAPPED) 806 + release_region(ports->start, resource_size(ports)); 807 + else 808 + release_mem_region(ports->start, resource_size(ports)); 818 809 return retval; 819 810 } 820 811 821 - static void cmos_do_shutdown(void) 812 + static void cmos_do_shutdown(int rtc_irq) 822 813 { 823 814 spin_lock_irq(&rtc_lock); 824 - cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); 815 + if (is_valid_irq(rtc_irq)) 816 + cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); 825 817 spin_unlock_irq(&rtc_lock); 826 818 } 827 819 ··· 834 818 struct cmos_rtc *cmos = dev_get_drvdata(dev); 835 819 struct resource *ports; 836 820 837 - cmos_do_shutdown(); 821 + cmos_do_shutdown(cmos->irq); 838 822 839 823 sysfs_remove_bin_file(&dev->kobj, &nvram); 840 824 ··· 847 831 cmos->rtc = NULL; 848 832 849 833 ports = cmos->iomem; 850 - release_region(ports->start, resource_size(ports)); 834 + if (RTC_IOMAPPED) 835 + release_region(ports->start, resource_size(ports)); 836 + else 837 + release_mem_region(ports->start, resource_size(ports)); 851 838 cmos->iomem = NULL; 852 839 853 840 cmos->dev = NULL; ··· 1084 1065 1085 1066 static void cmos_pnp_shutdown(struct pnp_dev *pnp) 1086 1067 { 1087 - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev)) 1068 + struct device *dev = &pnp->dev; 1069 + struct cmos_rtc *cmos = dev_get_drvdata(dev); 1070 + 1071 + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) 1088 1072 return; 1089 1073 1090 - cmos_do_shutdown(); 1074 + cmos_do_shutdown(cmos->irq); 1091 1075 } 1092 1076 1093 1077 static const struct pnp_device_id rtc_ids[] = { ··· 1165 1143 1166 1144 static int __init cmos_platform_probe(struct platform_device *pdev) 1167 1145 { 1146 + struct resource *resource; 1147 + int irq; 1148 + 1168 1149 cmos_of_init(pdev); 1169 1150 cmos_wake_setup(&pdev->dev); 1170 - return cmos_do_probe(&pdev->dev, 1171 - platform_get_resource(pdev, IORESOURCE_IO, 0), 1172 - platform_get_irq(pdev, 0)); 1151 + 1152 + if (RTC_IOMAPPED) 1153 + resource = platform_get_resource(pdev, IORESOURCE_IO, 0); 1154 + else 1155 + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1156 + irq = platform_get_irq(pdev, 0); 1157 + if (irq < 0) 1158 + irq = -1; 1159 + 1160 + return cmos_do_probe(&pdev->dev, resource, irq); 1173 1161 } 1174 1162 1175 1163 static int __exit cmos_platform_remove(struct platform_device *pdev) ··· 1190 1158 1191 1159 static void cmos_platform_shutdown(struct platform_device *pdev) 1192 1160 { 1193 - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) 1161 + struct device *dev = &pdev->dev; 1162 + struct cmos_rtc *cmos = dev_get_drvdata(dev); 1163 + 1164 + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) 1194 1165 return; 1195 1166 1196 - cmos_do_shutdown(); 1167 + cmos_do_shutdown(cmos->irq); 1197 1168 } 1198 1169 1199 1170 /* work with hotplug and coldplug */
+4
include/linux/mc146818rtc.h
··· 31 31 void (*wake_on)(struct device *dev); 32 32 void (*wake_off)(struct device *dev); 33 33 34 + u32 flags; 35 + #define CMOS_RTC_FLAGS_NOFREQ (1 << 0) 36 + int address_space; 37 + 34 38 u8 rtc_day_alarm; /* zero, or register index */ 35 39 u8 rtc_mon_alarm; /* zero, or register index */ 36 40 u8 rtc_century; /* zero, or register index */