diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index cd5fbf6f0784..b905744d7915 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -52,6 +52,7 @@ config BCM47XX select SSB select SSB_DRIVER_MIPS select SSB_DRIVER_EXTIF + select SSB_EMBEDDED select SSB_PCICORE_HOSTMODE if PCI select GENERIC_GPIO select SYS_HAS_EARLY_PRINTK diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c index f5a53acf995a..9b798800258c 100644 --- a/arch/mips/bcm47xx/gpio.c +++ b/arch/mips/bcm47xx/gpio.c @@ -12,68 +12,51 @@ #include #include -int bcm47xx_gpio_to_irq(unsigned gpio) +#if (BCM47XX_CHIPCO_GPIO_LINES > BCM47XX_EXTIF_GPIO_LINES) +static DECLARE_BITMAP(gpio_in_use, BCM47XX_CHIPCO_GPIO_LINES); +#else +static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES); +#endif + +int gpio_request(unsigned gpio, const char *tag) { - if (ssb_bcm47xx.chipco.dev) + if (ssb_chipco_available(&ssb_bcm47xx.chipco) && + ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)) + return -EINVAL; + + if (ssb_extif_available(&ssb_bcm47xx.extif) && + ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES)) + return -EINVAL; + + if (test_and_set_bit(gpio, gpio_in_use)) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + if (ssb_chipco_available(&ssb_bcm47xx.chipco) && + ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)) + return; + + if (ssb_extif_available(&ssb_bcm47xx.extif) && + ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES)) + return; + + clear_bit(gpio, gpio_in_use); +} +EXPORT_SYMBOL(gpio_free); + +int gpio_to_irq(unsigned gpio) +{ + if (ssb_chipco_available(&ssb_bcm47xx.chipco)) return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2; - else if (ssb_bcm47xx.extif.dev) + else if (ssb_extif_available(&ssb_bcm47xx.extif)) return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2; else return -EINVAL; } -EXPORT_SYMBOL_GPL(bcm47xx_gpio_to_irq); - -int bcm47xx_gpio_get_value(unsigned gpio) -{ - if (ssb_bcm47xx.chipco.dev) - return ssb_chipco_gpio_in(&ssb_bcm47xx.chipco, 1 << gpio); - else if (ssb_bcm47xx.extif.dev) - return ssb_extif_gpio_in(&ssb_bcm47xx.extif, 1 << gpio); - else - return 0; -} -EXPORT_SYMBOL_GPL(bcm47xx_gpio_get_value); - -void bcm47xx_gpio_set_value(unsigned gpio, int value) -{ - if (ssb_bcm47xx.chipco.dev) - ssb_chipco_gpio_out(&ssb_bcm47xx.chipco, - 1 << gpio, - value ? 1 << gpio : 0); - else if (ssb_bcm47xx.extif.dev) - ssb_extif_gpio_out(&ssb_bcm47xx.extif, - 1 << gpio, - value ? 1 << gpio : 0); -} -EXPORT_SYMBOL_GPL(bcm47xx_gpio_set_value); - -int bcm47xx_gpio_direction_input(unsigned gpio) -{ - if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) - ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco, - 1 << gpio, 0); - else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES)) - ssb_extif_gpio_outen(&ssb_bcm47xx.extif, - 1 << gpio, 0); - else - return -EINVAL; - return 0; -} -EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_input); - -int bcm47xx_gpio_direction_output(unsigned gpio, int value) -{ - bcm47xx_gpio_set_value(gpio, value); - - if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) - ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco, - 1 << gpio, 1 << gpio); - else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES)) - ssb_extif_gpio_outen(&ssb_bcm47xx.extif, - 1 << gpio, 1 << gpio); - else - return -EINVAL; - return 0; -} -EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_output); +EXPORT_SYMBOL_GPL(gpio_to_irq); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 8d36f186890e..2f580fa160c9 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -41,7 +42,7 @@ static void bcm47xx_machine_restart(char *command) printk(KERN_ALERT "Please stand by while rebooting the system...\n"); local_irq_disable(); /* Set the watchdog timer to reset immediately */ - ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1); + ssb_watchdog_timer_set(&ssb_bcm47xx, 1); while (1) cpu_relax(); } @@ -50,7 +51,7 @@ static void bcm47xx_machine_halt(void) { /* Disable interrupts and watchdog and spin forever */ local_irq_disable(); - ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0); + ssb_watchdog_timer_set(&ssb_bcm47xx, 0); while (1) cpu_relax(); } diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c index d1d90c9ef2fa..ef00e7f58c24 100644 --- a/arch/mips/bcm47xx/wgt634u.c +++ b/arch/mips/bcm47xx/wgt634u.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include /* GPIO definitions for the WGT634U */ @@ -99,6 +102,30 @@ static struct platform_device *wgt634u_devices[] __initdata = { &wgt634u_gpio_leds, }; +static irqreturn_t gpio_interrupt(int irq, void *ignored) +{ + int state; + + /* Interrupts are shared, check if the current one is + a GPIO interrupt. */ + if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco, + SSB_CHIPCO_IRQ_GPIO)) + return IRQ_NONE; + + state = gpio_get_value(WGT634U_GPIO_RESET); + + /* Interrupt are level triggered, revert the interrupt polarity + to clear the interrupt. */ + gpio_polarity(WGT634U_GPIO_RESET, state); + + if (!state) { + printk(KERN_INFO "Reset button pressed"); + ctrl_alt_del(); + } + + return IRQ_HANDLED; +} + static int __init wgt634u_init(void) { /* There is no easy way to detect that we are running on a WGT634U @@ -112,6 +139,19 @@ static int __init wgt634u_init(void) ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) { struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; + + printk(KERN_INFO "WGT634U machine detected.\n"); + + if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET), + gpio_interrupt, IRQF_SHARED, + "WGT634U GPIO", &ssb_bcm47xx.chipco)) { + gpio_direction_input(WGT634U_GPIO_RESET); + gpio_intmask(WGT634U_GPIO_RESET, 1); + ssb_chipco_irq_mask(&ssb_bcm47xx.chipco, + SSB_CHIPCO_IRQ_GPIO, + SSB_CHIPCO_IRQ_GPIO); + } + wgt634u_flash_data.width = mcore->flash_buswidth; wgt634u_flash_resource.start = mcore->flash_window; wgt634u_flash_resource.end = mcore->flash_window diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c index d95604773667..91cbd959ab67 100644 --- a/arch/mips/emma2rh/common/irq.c +++ b/arch/mips/emma2rh/common/irq.c @@ -29,7 +29,6 @@ #include #include -#include #include #include diff --git a/arch/mips/emma2rh/common/prom.c b/arch/mips/emma2rh/common/prom.c index 5e92b3a9c5b8..e14a2e3d8842 100644 --- a/arch/mips/emma2rh/common/prom.c +++ b/arch/mips/emma2rh/common/prom.c @@ -30,7 +30,6 @@ #include #include #include -#include const char *get_system_type(void) { diff --git a/arch/mips/emma2rh/markeins/platform.c b/arch/mips/emma2rh/markeins/platform.c index d70627de7cfe..fb9cda253ab0 100644 --- a/arch/mips/emma2rh/markeins/platform.c +++ b/arch/mips/emma2rh/markeins/platform.c @@ -35,7 +35,6 @@ #include #include #include -#include #include diff --git a/include/asm-mips/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h similarity index 100% rename from include/asm-mips/cevt-r4k.h rename to arch/mips/include/asm/cevt-r4k.h diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h index cfc8f4d618ce..d8ff4cd89ab5 100644 --- a/arch/mips/include/asm/mach-bcm47xx/gpio.h +++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h @@ -9,47 +9,46 @@ #ifndef __BCM47XX_GPIO_H #define __BCM47XX_GPIO_H +#include +#include + #define BCM47XX_EXTIF_GPIO_LINES 5 #define BCM47XX_CHIPCO_GPIO_LINES 16 -extern int bcm47xx_gpio_to_irq(unsigned gpio); -extern int bcm47xx_gpio_get_value(unsigned gpio); -extern void bcm47xx_gpio_set_value(unsigned gpio, int value); -extern int bcm47xx_gpio_direction_input(unsigned gpio); -extern int bcm47xx_gpio_direction_output(unsigned gpio, int value); - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -static inline void gpio_free(unsigned gpio) -{ -} - -static inline int gpio_to_irq(unsigned gpio) -{ - return bcm47xx_gpio_to_irq(gpio); -} +extern int gpio_request(unsigned gpio, const char *label); +extern void gpio_free(unsigned gpio); +extern int gpio_to_irq(unsigned gpio); static inline int gpio_get_value(unsigned gpio) { - return bcm47xx_gpio_get_value(gpio); + return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio); } static inline void gpio_set_value(unsigned gpio, int value) { - bcm47xx_gpio_set_value(gpio, value); + ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0); } static inline int gpio_direction_input(unsigned gpio) { - return bcm47xx_gpio_direction_input(gpio); + return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0); } static inline int gpio_direction_output(unsigned gpio, int value) { - return bcm47xx_gpio_direction_output(gpio, value); + return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio); +} + +static int gpio_intmask(unsigned gpio, int value) +{ + return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio, + value ? 1 << gpio : 0); +} + +static int gpio_polarity(unsigned gpio, int value) +{ + return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio, + value ? 1 << gpio : 0); } diff --git a/arch/mips/include/asm/mach-bcm47xx/war.h b/arch/mips/include/asm/mach-bcm47xx/war.h index 4a2b7986b582..87cd4651dda3 100644 --- a/arch/mips/include/asm/mach-bcm47xx/war.h +++ b/arch/mips/include/asm/mach-bcm47xx/war.h @@ -5,8 +5,8 @@ * * Copyright (C) 2002, 2004, 2007 by Ralf Baechle */ -#ifndef __ASM_MIPS_MACH_BCM947XX_WAR_H -#define __ASM_MIPS_MACH_BCM947XX_WAR_H +#ifndef __ASM_MIPS_MACH_BCM47XX_WAR_H +#define __ASM_MIPS_MACH_BCM47XX_WAR_H #define R4600_V1_INDEX_ICACHEOP_WAR 0 #define R4600_V1_HIT_CACHEOP_WAR 0 @@ -22,4 +22,4 @@ #define R10000_LLSC_WAR 0 #define MIPS34K_MISSED_ITLB_WAR 0 -#endif /* __ASM_MIPS_MACH_BCM947XX_WAR_H */ +#endif /* __ASM_MIPS_MACH_BCM47XX_WAR_H */ diff --git a/arch/mips/include/asm/mach-ip22/ds1286.h b/arch/mips/include/asm/mach-ip22/ds1286.h deleted file mode 100644 index f19f1eafbc71..000000000000 --- a/arch/mips/include/asm/mach-ip22/ds1286.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1998, 2001, 03 by Ralf Baechle - * - * RTC routines for PC style attached Dallas chip. - */ -#ifndef __ASM_MACH_IP22_DS1286_H -#define __ASM_MACH_IP22_DS1286_H - -#include - -#define rtc_read(reg) (hpc3c0->rtcregs[(reg)] & 0xff) -#define rtc_write(data, reg) do { hpc3c0->rtcregs[(reg)] = (data); } while(0) - -#endif /* __ASM_MACH_IP22_DS1286_H */ diff --git a/arch/mips/include/asm/mach-ip28/ds1286.h b/arch/mips/include/asm/mach-ip28/ds1286.h deleted file mode 100644 index 471bb9a33e0f..000000000000 --- a/arch/mips/include/asm/mach-ip28/ds1286.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __ASM_MACH_IP28_DS1286_H -#define __ASM_MACH_IP28_DS1286_H -#include -#endif /* __ASM_MACH_IP28_DS1286_H */ diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 5d98a3cb85b7..1a1f320c30d8 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -147,7 +147,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) " ori %[ticket], %[ticket], 0x2000 \n" " xori %[ticket], %[ticket], 0x2000 \n" " sc %[ticket], %[ticket_ptr] \n" - " beqzl %[ticket], 2f \n" + " beqzl %[ticket], 1b \n" : [ticket_ptr] "+m" (lock->lock), [ticket] "=&r" (tmp)); } else { diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 75bb1300dd7a..26760cad8b69 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -39,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); - seq_printf(m, fmt, __cpu_name[smp_processor_id()], + seq_printf(m, fmt, __cpu_name[n], (version >> 4) & 0x0f, version & 0x0f, (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index afb119f35682..58738c8d754f 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -104,7 +104,7 @@ SECTIONS . = ALIGN(_PAGE_SIZE); __nosave_end = .; - . = ALIGN(32); + . = ALIGN(1 << CONFIG_MIPS_L1_CACHE_SHIFT); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff --git a/arch/mips/pci/fixup-emma2rh.c b/arch/mips/pci/fixup-emma2rh.c index a2705895561d..846eae9cdd05 100644 --- a/arch/mips/pci/fixup-emma2rh.c +++ b/arch/mips/pci/fixup-emma2rh.c @@ -29,7 +29,6 @@ #include #include -#include #include diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c index 0e160d9f07c3..1e6213fa7bdb 100644 --- a/arch/mips/pci/ops-pnx8550.c +++ b/arch/mips/pci/ops-pnx8550.c @@ -29,8 +29,6 @@ #include #include -#include - static inline void clear_status(void) { diff --git a/arch/mips/pci/pci-emma2rh.c b/arch/mips/pci/pci-emma2rh.c index d99591a0cdfe..772e283daa63 100644 --- a/arch/mips/pci/pci-emma2rh.c +++ b/arch/mips/pci/pci-emma2rh.c @@ -29,7 +29,6 @@ #include #include -#include #include diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index c7fe6ec621e6..a377e9d2d029 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -34,6 +34,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head; unsigned long PCIBIOS_MIN_IO = 0x0000; unsigned long PCIBIOS_MIN_MEM = 0; +static int pci_initialized; + /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the @@ -74,6 +76,42 @@ pcibios_align_resource(void *data, struct resource *res, res->start = start; } +static void __devinit pcibios_scanbus(struct pci_controller *hose) +{ + static int next_busno; + static int need_domain_info; + struct pci_bus *bus; + + if (!hose->iommu) + PCI_DMA_BUS_IS_PHYS = 1; + + if (hose->get_busno && pci_probe_only) + next_busno = (*hose->get_busno)(); + + bus = pci_scan_bus(next_busno, hose->pci_ops, hose); + hose->bus = bus; + + need_domain_info = need_domain_info || hose->index; + hose->need_domain_info = need_domain_info; + if (bus) { + next_busno = bus->subordinate + 1; + /* Don't allow 8-bit bus number overflow inside the hose - + reserve some space for bridges. */ + if (next_busno > 224) { + next_busno = 0; + need_domain_info = 1; + } + + if (!pci_probe_only) { + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + pci_enable_bridges(bus); + } + } +} + +static DEFINE_MUTEX(pci_scan_mutex); + void __devinit register_pci_controller(struct pci_controller *hose) { if (request_resource(&iomem_resource, hose->mem_resource) < 0) @@ -93,6 +131,17 @@ void __devinit register_pci_controller(struct pci_controller *hose) printk(KERN_WARNING "registering PCI controller with io_map_base unset\n"); } + + /* + * Scan the bus if it is register after the PCI subsystem + * initialization. + */ + if (pci_initialized) { + mutex_lock(&pci_scan_mutex); + pcibios_scanbus(hose); + mutex_unlock(&pci_scan_mutex); + } + return; out: @@ -125,38 +174,15 @@ static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) static int __init pcibios_init(void) { struct pci_controller *hose; - struct pci_bus *bus; - int next_busno; - int need_domain_info = 0; /* Scan all of the recorded PCI controllers. */ - for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { + for (hose = hose_head; hose; hose = hose->next) + pcibios_scanbus(hose); - if (!hose->iommu) - PCI_DMA_BUS_IS_PHYS = 1; - - if (hose->get_busno && pci_probe_only) - next_busno = (*hose->get_busno)(); - - bus = pci_scan_bus(next_busno, hose->pci_ops, hose); - hose->bus = bus; - need_domain_info = need_domain_info || hose->index; - hose->need_domain_info = need_domain_info; - if (bus) { - next_busno = bus->subordinate + 1; - /* Don't allow 8-bit bus number overflow inside the hose - - reserve some space for bridges. */ - if (next_busno > 224) { - next_busno = 0; - need_domain_info = 1; - } - } - } - - if (!pci_probe_only) - pci_assign_unassigned_resources(); pci_fixup_irqs(common_swizzle, pcibios_map_irq); + pci_initialized = 1; + return 0; } diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c index 8e7a46855b50..1377d599f0e3 100644 --- a/arch/mips/rb532/time.c +++ b/arch/mips/rb532/time.c @@ -28,7 +28,6 @@ #include #include -#include #include #include diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c index 52486c4d2b01..deddbf0ebe5c 100644 --- a/arch/mips/sgi-ip22/ip22-platform.c +++ b/arch/mips/sgi-ip22/ip22-platform.c @@ -192,3 +192,18 @@ static int __init sgi_button_devinit(void) } device_initcall(sgi_button_devinit); + +static int __init sgi_ds1286_devinit(void) +{ + struct resource res; + + memset(&res, 0, sizeof(res)); + res.start = HPC3_CHIP0_BASE + offsetof(struct hpc3_regs, rtcregs); + res.end = res.start + sizeof(hpc3c0->rtcregs) - 1; + res.flags = IORESOURCE_MEM; + + return IS_ERR(platform_device_register_simple("rtc-ds1286", -1, + &res, 1)); +} + +device_initcall(sgi_ds1286_devinit); diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index 896a1ef84829..b9a931358e23 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -4,7 +4,6 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) */ -#include #include #include #include diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 10e505491655..3dcb27ec0c53 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -10,7 +10,6 @@ * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org) */ #include -#include #include #include #include @@ -29,69 +28,6 @@ #include #include -/* - * Note that mktime uses month from 1 to 12 while rtc_time_to_tm - * uses 0 to 11. - */ -unsigned long read_persistent_clock(void) -{ - unsigned int yrs, mon, day, hrs, min, sec; - unsigned int save_control; - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff; - hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE; - - sec = BCD2BIN(hpc3c0->rtcregs[RTC_SECONDS] & 0xff); - min = BCD2BIN(hpc3c0->rtcregs[RTC_MINUTES] & 0xff); - hrs = BCD2BIN(hpc3c0->rtcregs[RTC_HOURS] & 0x3f); - day = BCD2BIN(hpc3c0->rtcregs[RTC_DATE] & 0xff); - mon = BCD2BIN(hpc3c0->rtcregs[RTC_MONTH] & 0x1f); - yrs = BCD2BIN(hpc3c0->rtcregs[RTC_YEAR] & 0xff); - - hpc3c0->rtcregs[RTC_CMD] = save_control; - spin_unlock_irqrestore(&rtc_lock, flags); - - if (yrs < 45) - yrs += 30; - if ((yrs += 40) < 70) - yrs += 100; - - return mktime(yrs + 1900, mon, day, hrs, min, sec); -} - -int rtc_mips_set_time(unsigned long tim) -{ - struct rtc_time tm; - unsigned int save_control; - unsigned long flags; - - rtc_time_to_tm(tim, &tm); - - tm.tm_mon += 1; /* tm_mon starts at zero */ - tm.tm_year -= 40; - if (tm.tm_year >= 100) - tm.tm_year -= 100; - - spin_lock_irqsave(&rtc_lock, flags); - save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff; - hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE; - - hpc3c0->rtcregs[RTC_YEAR] = BIN2BCD(tm.tm_year); - hpc3c0->rtcregs[RTC_MONTH] = BIN2BCD(tm.tm_mon); - hpc3c0->rtcregs[RTC_DATE] = BIN2BCD(tm.tm_mday); - hpc3c0->rtcregs[RTC_HOURS] = BIN2BCD(tm.tm_hour); - hpc3c0->rtcregs[RTC_MINUTES] = BIN2BCD(tm.tm_min); - hpc3c0->rtcregs[RTC_SECONDS] = BIN2BCD(tm.tm_sec); - hpc3c0->rtcregs[RTC_HUNDREDTH_SECOND] = 0; - - hpc3c0->rtcregs[RTC_CMD] = save_control; - spin_unlock_irqrestore(&rtc_lock, flags); - - return 0; -} - static unsigned long dosample(void) { u32 ct0, ct1; diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 8b4e854af925..1327c2746fb7 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -13,12 +13,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -28,51 +28,6 @@ #define TICK_SIZE (tick_nsec / 1000) -#if 0 -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - struct m48t35_rtc *rtc; - nasid_t nid; - - nid = get_nasid(); - rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + - IOC3_BYTEBUS_DEV0); - - rtc->control |= M48T35_RTC_READ; - cmos_minutes = BCD2BIN(rtc->min); - rtc->control &= ~M48T35_RTC_READ; - - /* - * Since we're only adjusting minutes and seconds, don't interfere with - * hour overflow. This avoids messing with unknown time zones but - * requires your RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - real_seconds = BIN2BCD(real_seconds); - real_minutes = BIN2BCD(real_minutes); - rtc->control |= M48T35_RTC_SET; - rtc->sec = real_seconds; - rtc->min = real_minutes; - rtc->control &= ~M48T35_RTC_SET; - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - return retval; -} -#endif - /* Includes for ioc3_init(). */ #include #include @@ -80,37 +35,6 @@ static int set_rtc_mmss(unsigned long nowtime) #include #include -unsigned long read_persistent_clock(void) -{ - unsigned int year, month, date, hour, min, sec; - struct m48t35_rtc *rtc; - nasid_t nid; - - nid = get_nasid(); - rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + - IOC3_BYTEBUS_DEV0); - - rtc->control |= M48T35_RTC_READ; - sec = rtc->sec; - min = rtc->min; - hour = rtc->hour; - date = rtc->date; - month = rtc->month; - year = rtc->year; - rtc->control &= ~M48T35_RTC_READ; - - sec = BCD2BIN(sec); - min = BCD2BIN(min); - hour = BCD2BIN(hour); - date = BCD2BIN(date); - month = BCD2BIN(month); - year = BCD2BIN(year); - - year += 1970; - - return mktime(year, month, date, hour, min, sec); -} - static void enable_rt_irq(unsigned int irq) { } @@ -286,6 +210,7 @@ void __cpuinit cpu_time_init(void) void __cpuinit hub_rtc_init(cnodeid_t cnode) { + /* * We only need to initialize the current node. * If this is not the current node then it is a cpuless @@ -301,3 +226,23 @@ void __cpuinit hub_rtc_init(cnodeid_t cnode) LOCAL_HUB_S(PI_RT_PEND_B, 0); } } + +static int __init sgi_ip27_rtc_devinit(void) +{ + struct resource res; + + memset(&res, 0, sizeof(res)); + res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + + IOC3_BYTEBUS_DEV0); + res.end = res.start + 32767; + res.flags = IORESOURCE_MEM; + + return IS_ERR(platform_device_register_simple("rtc-m48t35", -1, + &res, 1)); +} + +/* + * kludge make this a device_initcall after ioc3 resource conflicts + * are resolved + */ +late_initcall(sgi_ip27_rtc_devinit); diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c index 3d63721e0e80..511e9ff2acfd 100644 --- a/arch/mips/sgi-ip32/ip32-platform.c +++ b/arch/mips/sgi-ip32/ip32-platform.c @@ -90,6 +90,22 @@ static __init int sgio2btns_devinit(void) device_initcall(sgio2btns_devinit); +static struct resource sgio2_cmos_rsrc[] = { + { + .start = 0x70, + .end = 0x71, + .flags = IORESOURCE_IO + } +}; + +static __init int sgio2_cmos_devinit(void) +{ + return IS_ERR(platform_device_register_simple("rtc_cmos", -1, + sgio2_cmos_rsrc, 1)); +} + +device_initcall(sgio2_cmos_devinit); + MODULE_AUTHOR("Ralf Baechle "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2"); diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index 1024bf40bd9e..c5a5d4a31b4b 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -62,11 +62,6 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str) } #endif -unsigned long read_persistent_clock(void) -{ - return mc146818_get_cmos_time(); -} - /* An arbitrary time; this can be decreased if reliability looks good */ #define WAIT_MS 10 diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b57fba5c6d02..f3d7fd3406a6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -352,6 +352,11 @@ config RTC_DRV_DS1216 help If you say yes here you get support for the Dallas DS1216 RTC chips. +config RTC_DRV_DS1286 + tristate "Dallas DS1286" + help + If you say yes here you get support for the Dallas DS1286 RTC chips. + config RTC_DRV_DS1302 tristate "Dallas DS1302" depends on SH_SECUREEDGE5410 @@ -405,6 +410,15 @@ config RTC_DRV_M48T86 This driver can also be built as a module. If so, the module will be called rtc-m48t86. +config RTC_DRV_M48T35 + tristate "ST M48T35" + help + If you say Y here you will get support for the + ST M48T35 RTC chip. + + This driver can also be built as a module, if so, the module + will be called "rtc-m48t35". + config RTC_DRV_M48T59 tristate "ST M48T59/M48T08/M48T02" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 10f41f85c38a..37a71b727262 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o +obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o @@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o +obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c new file mode 100644 index 000000000000..4b4c1b6a4187 --- /dev/null +++ b/drivers/rtc/rtc-ds1286.c @@ -0,0 +1,409 @@ +/* + * DS1286 Real Time Clock interface for Linux + * + * Copyright (C) 1998, 1999, 2000 Ralf Baechle + * Copyright (C) 2008 Thomas Bogendoerfer + * + * Based on code written by Paul Gortmaker. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#define DRV_VERSION "1.0" + +struct ds1286_priv { + struct rtc_device *rtc; + u32 __iomem *rtcregs; + size_t size; + unsigned long baseaddr; + spinlock_t lock; +}; + +static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg) +{ + return __raw_readl(&priv->rtcregs[reg]) & 0xff; +} + +static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg) +{ + __raw_writel(data, &priv->rtcregs[reg]); +} + +#ifdef CONFIG_RTC_INTF_DEV + +static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + unsigned char val; + + switch (cmd) { + case RTC_AIE_OFF: + /* Mask alarm int. enab. bit */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + val |= RTC_TDM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + break; + case RTC_AIE_ON: + /* Allow alarm interrupts. */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + val &= ~RTC_TDM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + break; + case RTC_WIE_OFF: + /* Mask watchdog int. enab. bit */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + val |= RTC_WAM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + break; + case RTC_WIE_ON: + /* Allow watchdog interrupts. */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + val &= ~RTC_WAM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +#else +#define ds1286_ioctl NULL +#endif + +#ifdef CONFIG_PROC_FS + +static int ds1286_proc(struct device *dev, struct seq_file *seq) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned char month, cmd, amode; + const char *s; + + month = ds1286_rtc_read(priv, RTC_MONTH); + seq_printf(seq, + "oscillator\t: %s\n" + "square_wave\t: %s\n", + (month & RTC_EOSC) ? "disabled" : "enabled", + (month & RTC_ESQW) ? "disabled" : "enabled"); + + amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) | + ((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) | + ((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7); + switch (amode) { + case 7: + s = "each minute"; + break; + case 3: + s = "minutes match"; + break; + case 1: + s = "hours and minutes match"; + break; + case 0: + s = "days, hours and minutes match"; + break; + default: + s = "invalid"; + break; + } + seq_printf(seq, "alarm_mode\t: %s\n", s); + + cmd = ds1286_rtc_read(priv, RTC_CMD); + seq_printf(seq, + "alarm_enable\t: %s\n" + "wdog_alarm\t: %s\n" + "alarm_mask\t: %s\n" + "wdog_alarm_mask\t: %s\n" + "interrupt_mode\t: %s\n" + "INTB_mode\t: %s_active\n" + "interrupt_pins\t: %s\n", + (cmd & RTC_TDF) ? "yes" : "no", + (cmd & RTC_WAF) ? "yes" : "no", + (cmd & RTC_TDM) ? "disabled" : "enabled", + (cmd & RTC_WAM) ? "disabled" : "enabled", + (cmd & RTC_PU_LVL) ? "pulse" : "level", + (cmd & RTC_IBH_LO) ? "low" : "high", + (cmd & RTC_IPSW) ? "unswapped" : "swapped"); + return 0; +} + +#else +#define ds1286_proc NULL +#endif + +static int ds1286_read_time(struct device *dev, struct rtc_time *tm) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned char save_control; + unsigned long flags; + unsigned long uip_watchdog = jiffies; + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 10 to 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + + if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE) + while (time_before(jiffies, uip_watchdog + 2*HZ/100)) + barrier(); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&priv->lock, flags); + save_control = ds1286_rtc_read(priv, RTC_CMD); + ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD); + + tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS); + tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES); + tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f; + tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE); + tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f; + tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR); + + ds1286_rtc_write(priv, save_control, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if (tm->tm_year < 45) + tm->tm_year += 30; + tm->tm_year += 40; + if (tm->tm_year < 70) + tm->tm_year += 100; + + tm->tm_mon--; + + return rtc_valid_tm(tm); +} + +static int ds1286_set_time(struct device *dev, struct rtc_time *tm) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned char mon, day, hrs, min, sec; + unsigned char save_control; + unsigned int yrs; + unsigned long flags; + + yrs = tm->tm_year + 1900; + mon = tm->tm_mon + 1; /* tm_mon starts at zero */ + day = tm->tm_mday; + hrs = tm->tm_hour; + min = tm->tm_min; + sec = tm->tm_sec; + + if (yrs < 1970) + return -EINVAL; + + yrs -= 1940; + if (yrs > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + sec = bin2bcd(sec); + min = bin2bcd(min); + hrs = bin2bcd(hrs); + day = bin2bcd(day); + mon = bin2bcd(mon); + yrs = bin2bcd(yrs); + + spin_lock_irqsave(&priv->lock, flags); + save_control = ds1286_rtc_read(priv, RTC_CMD); + ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD); + + ds1286_rtc_write(priv, yrs, RTC_YEAR); + ds1286_rtc_write(priv, mon, RTC_MONTH); + ds1286_rtc_write(priv, day, RTC_DATE); + ds1286_rtc_write(priv, hrs, RTC_HOURS); + ds1286_rtc_write(priv, min, RTC_MINUTES); + ds1286_rtc_write(priv, sec, RTC_SECONDS); + ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND); + + ds1286_rtc_write(priv, save_control, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned char cmd; + unsigned long flags; + + /* + * Only the values that we read from the RTC are set. That + * means only tm_wday, tm_hour, tm_min. + */ + spin_lock_irqsave(&priv->lock, flags); + alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f; + alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f; + alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07; + cmd = ds1286_rtc_read(priv, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + + alm->time.tm_min = bcd2bin(alm->time.tm_min); + alm->time.tm_hour = bcd2bin(alm->time.tm_hour); + alm->time.tm_sec = 0; + return 0; +} + +static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned char hrs, min, sec; + + hrs = alm->time.tm_hour; + min = alm->time.tm_min; + sec = alm->time.tm_sec; + + if (hrs >= 24) + hrs = 0xff; + + if (min >= 60) + min = 0xff; + + if (sec != 0) + return -EINVAL; + + min = bin2bcd(min); + hrs = bin2bcd(hrs); + + spin_lock(&priv->lock); + ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM); + ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM); + spin_unlock(&priv->lock); + + return 0; +} + +static const struct rtc_class_ops ds1286_ops = { + .ioctl = ds1286_ioctl, + .proc = ds1286_proc, + .read_time = ds1286_read_time, + .set_time = ds1286_set_time, + .read_alarm = ds1286_read_alarm, + .set_alarm = ds1286_set_alarm, +}; + +static int __devinit ds1286_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct resource *res; + struct ds1286_priv *priv; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->size = res->end - res->start + 1; + if (!request_mem_region(res->start, priv->size, pdev->name)) { + ret = -EBUSY; + goto out; + } + priv->baseaddr = res->start; + priv->rtcregs = ioremap(priv->baseaddr, priv->size); + if (!priv->rtcregs) { + ret = -ENOMEM; + goto out; + } + spin_lock_init(&priv->lock); + rtc = rtc_device_register("ds1286", &pdev->dev, + &ds1286_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + priv->rtc = rtc; + platform_set_drvdata(pdev, priv); + return 0; + +out: + if (priv->rtc) + rtc_device_unregister(priv->rtc); + if (priv->rtcregs) + iounmap(priv->rtcregs); + if (priv->baseaddr) + release_mem_region(priv->baseaddr, priv->size); + kfree(priv); + return ret; +} + +static int __devexit ds1286_remove(struct platform_device *pdev) +{ + struct ds1286_priv *priv = platform_get_drvdata(pdev); + + rtc_device_unregister(priv->rtc); + iounmap(priv->rtcregs); + release_mem_region(priv->baseaddr, priv->size); + kfree(priv); + return 0; +} + +static struct platform_driver ds1286_platform_driver = { + .driver = { + .name = "rtc-ds1286", + .owner = THIS_MODULE, + }, + .probe = ds1286_probe, + .remove = __devexit_p(ds1286_remove), +}; + +static int __init ds1286_init(void) +{ + return platform_driver_register(&ds1286_platform_driver); +} + +static void __exit ds1286_exit(void) +{ + platform_driver_unregister(&ds1286_platform_driver); +} + +MODULE_AUTHOR("Thomas Bogendoerfer "); +MODULE_DESCRIPTION("DS1286 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("platform:rtc-ds1286"); + +module_init(ds1286_init); +module_exit(ds1286_exit); diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c new file mode 100644 index 000000000000..b9c1fe4a198e --- /dev/null +++ b/drivers/rtc/rtc-m48t35.c @@ -0,0 +1,234 @@ +/* + * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip + * + * Copyright (C) 2000 Silicon Graphics, Inc. + * Written by Ulf Carlsson (ulfc@engr.sgi.com) + * + * Copyright (C) 2008 Thomas Bogendoerfer + * + * Based on code written by Paul Gortmaker. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#define DRV_VERSION "1.0" + +struct m48t35_rtc { + u8 pad[0x7ff8]; /* starts at 0x7ff8 */ + u8 control; + u8 sec; + u8 min; + u8 hour; + u8 day; + u8 date; + u8 month; + u8 year; +}; + +#define M48T35_RTC_SET 0x80 +#define M48T35_RTC_READ 0x40 + +struct m48t35_priv { + struct rtc_device *rtc; + struct m48t35_rtc __iomem *reg; + size_t size; + unsigned long baseaddr; + spinlock_t lock; +}; + +static int m48t35_read_time(struct device *dev, struct rtc_time *tm) +{ + struct m48t35_priv *priv = dev_get_drvdata(dev); + u8 control; + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irq(&priv->lock); + control = readb(&priv->reg->control); + writeb(control | M48T35_RTC_READ, &priv->reg->control); + tm->tm_sec = readb(&priv->reg->sec); + tm->tm_min = readb(&priv->reg->min); + tm->tm_hour = readb(&priv->reg->hour); + tm->tm_mday = readb(&priv->reg->date); + tm->tm_mon = readb(&priv->reg->month); + tm->tm_year = readb(&priv->reg->year); + writeb(control, &priv->reg->control); + spin_unlock_irq(&priv->lock); + + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + tm->tm_year += 70; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + tm->tm_mon--; + return rtc_valid_tm(tm); +} + +static int m48t35_set_time(struct device *dev, struct rtc_time *tm) +{ + struct m48t35_priv *priv = dev_get_drvdata(dev); + unsigned char mon, day, hrs, min, sec; + unsigned int yrs; + u8 control; + + yrs = tm->tm_year + 1900; + mon = tm->tm_mon + 1; /* tm_mon starts at zero */ + day = tm->tm_mday; + hrs = tm->tm_hour; + min = tm->tm_min; + sec = tm->tm_sec; + + if (yrs < 1970) + return -EINVAL; + + yrs -= 1970; + if (yrs > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs > 169) + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + sec = bin2bcd(sec); + min = bin2bcd(min); + hrs = bin2bcd(hrs); + day = bin2bcd(day); + mon = bin2bcd(mon); + yrs = bin2bcd(yrs); + + spin_lock_irq(&priv->lock); + control = readb(&priv->reg->control); + writeb(control | M48T35_RTC_SET, &priv->reg->control); + writeb(yrs, &priv->reg->year); + writeb(mon, &priv->reg->month); + writeb(day, &priv->reg->date); + writeb(hrs, &priv->reg->hour); + writeb(min, &priv->reg->min); + writeb(sec, &priv->reg->sec); + writeb(control, &priv->reg->control); + spin_unlock_irq(&priv->lock); + return 0; +} + +static const struct rtc_class_ops m48t35_ops = { + .read_time = m48t35_read_time, + .set_time = m48t35_set_time, +}; + +static int __devinit m48t35_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct resource *res; + struct m48t35_priv *priv; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + priv = kzalloc(sizeof(struct m48t35_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->size = res->end - res->start + 1; + /* + * kludge: remove the #ifndef after ioc3 resource + * conflicts are resolved + */ +#ifndef CONFIG_SGI_IP27 + if (!request_mem_region(res->start, priv->size, pdev->name)) { + ret = -EBUSY; + goto out; + } +#endif + priv->baseaddr = res->start; + priv->reg = ioremap(priv->baseaddr, priv->size); + if (!priv->reg) { + ret = -ENOMEM; + goto out; + } + spin_lock_init(&priv->lock); + rtc = rtc_device_register("m48t35", &pdev->dev, + &m48t35_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + priv->rtc = rtc; + platform_set_drvdata(pdev, priv); + return 0; + +out: + if (priv->rtc) + rtc_device_unregister(priv->rtc); + if (priv->reg) + iounmap(priv->reg); + if (priv->baseaddr) + release_mem_region(priv->baseaddr, priv->size); + kfree(priv); + return ret; +} + +static int __devexit m48t35_remove(struct platform_device *pdev) +{ + struct m48t35_priv *priv = platform_get_drvdata(pdev); + + rtc_device_unregister(priv->rtc); + iounmap(priv->reg); +#ifndef CONFIG_SGI_IP27 + release_mem_region(priv->baseaddr, priv->size); +#endif + kfree(priv); + return 0; +} + +static struct platform_driver m48t35_platform_driver = { + .driver = { + .name = "rtc-m48t35", + .owner = THIS_MODULE, + }, + .probe = m48t35_probe, + .remove = __devexit_p(m48t35_remove), +}; + +static int __init m48t35_init(void) +{ + return platform_driver_register(&m48t35_platform_driver); +} + +static void __exit m48t35_exit(void) +{ + platform_driver_unregister(&m48t35_platform_driver); +} + +MODULE_AUTHOR("Thomas Bogendoerfer "); +MODULE_DESCRIPTION("M48T35 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("platform:rtc-m48t35"); + +module_init(m48t35_init); +module_exit(m48t35_exit); diff --git a/include/linux/ds1286.h b/include/linux/ds1286.h index d8989860e4ce..45ea0aa0aeb9 100644 --- a/include/linux/ds1286.h +++ b/include/linux/ds1286.h @@ -8,8 +8,6 @@ #ifndef __LINUX_DS1286_H #define __LINUX_DS1286_H -#include - /********************************************************************** * register summary **********************************************************************/