Commit 04ab5918 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  MIPS: Kill unused <asm/debug.h> inclusions
  MIPS: IP32: Add platform device for CMOS RTC; remove dead code
  RTC: M48T35: new RTC driver
  MIPS: IP27: Switch over to RTC class driver
  MIPS: DS1286: New RTC driver
  MIPS: IP22/28: Switch over to RTC class driver
  MIPS: PCI: Scan busses when they are registered
  MIPS: WGT634U: Add reset button support
  MIPS: BCM47xx: Use the new SSB GPIO API
  MIPS: BCM47xx: Remove references to BCM947XX
  MIPS: WGT634U: Add machine detection message
  MIPS: Align .data.cacheline_aligned based on CONFIG_MIPS_L1_CACHE_SHIFT
  MIPS: show_cpuinfo prints the type of the calling CPU
  MIPS: Fix wrong branch target in new spin_lock code.
  MIPS: Have a heart for a lonely, lost header file ...
parents 7c3b1dcf 08da6f1b
...@@ -52,6 +52,7 @@ config BCM47XX ...@@ -52,6 +52,7 @@ config BCM47XX
select SSB select SSB
select SSB_DRIVER_MIPS select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF select SSB_DRIVER_EXTIF
select SSB_EMBEDDED
select SSB_PCICORE_HOSTMODE if PCI select SSB_PCICORE_HOSTMODE if PCI
select GENERIC_GPIO select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK select SYS_HAS_EARLY_PRINTK
......
...@@ -12,68 +12,51 @@ ...@@ -12,68 +12,51 @@
#include <asm/mach-bcm47xx/bcm47xx.h> #include <asm/mach-bcm47xx/bcm47xx.h>
#include <asm/mach-bcm47xx/gpio.h> #include <asm/mach-bcm47xx/gpio.h>
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) &&
return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2; ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
else if (ssb_bcm47xx.extif.dev)
return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
else
return -EINVAL; return -EINVAL;
}
EXPORT_SYMBOL_GPL(bcm47xx_gpio_to_irq);
int bcm47xx_gpio_get_value(unsigned gpio) if (ssb_extif_available(&ssb_bcm47xx.extif) &&
{ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
if (ssb_bcm47xx.chipco.dev) return -EINVAL;
return ssb_chipco_gpio_in(&ssb_bcm47xx.chipco, 1 << gpio);
else if (ssb_bcm47xx.extif.dev) if (test_and_set_bit(gpio, gpio_in_use))
return ssb_extif_gpio_in(&ssb_bcm47xx.extif, 1 << gpio); return -EBUSY;
else
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(bcm47xx_gpio_get_value); EXPORT_SYMBOL(gpio_request);
void bcm47xx_gpio_set_value(unsigned gpio, int value) void gpio_free(unsigned gpio)
{ {
if (ssb_bcm47xx.chipco.dev) if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
ssb_chipco_gpio_out(&ssb_bcm47xx.chipco, ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
1 << gpio, return;
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_extif_available(&ssb_bcm47xx.extif) &&
{ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) return;
ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco,
1 << gpio, 0); clear_bit(gpio, gpio_in_use);
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); EXPORT_SYMBOL(gpio_free);
int bcm47xx_gpio_direction_output(unsigned gpio, int value) int gpio_to_irq(unsigned gpio)
{ {
bcm47xx_gpio_set_value(gpio, value); if (ssb_chipco_available(&ssb_bcm47xx.chipco))
return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES)) else if (ssb_extif_available(&ssb_bcm47xx.extif))
ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco, return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
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 else
return -EINVAL; return -EINVAL;
return 0;
} }
EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_output); EXPORT_SYMBOL_GPL(gpio_to_irq);
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/ssb/ssb.h> #include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/reboot.h> #include <asm/reboot.h>
#include <asm/time.h> #include <asm/time.h>
...@@ -41,7 +42,7 @@ static void bcm47xx_machine_restart(char *command) ...@@ -41,7 +42,7 @@ static void bcm47xx_machine_restart(char *command)
printk(KERN_ALERT "Please stand by while rebooting the system...\n"); printk(KERN_ALERT "Please stand by while rebooting the system...\n");
local_irq_disable(); local_irq_disable();
/* Set the watchdog timer to reset immediately */ /* 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) while (1)
cpu_relax(); cpu_relax();
} }
...@@ -50,7 +51,7 @@ static void bcm47xx_machine_halt(void) ...@@ -50,7 +51,7 @@ static void bcm47xx_machine_halt(void)
{ {
/* Disable interrupts and watchdog and spin forever */ /* Disable interrupts and watchdog and spin forever */
local_irq_disable(); local_irq_disable();
ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0); ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
while (1) while (1)
cpu_relax(); cpu_relax();
} }
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/ssb/ssb.h> #include <linux/ssb/ssb.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/gpio.h>
#include <asm/mach-bcm47xx/bcm47xx.h> #include <asm/mach-bcm47xx/bcm47xx.h>
/* GPIO definitions for the WGT634U */ /* GPIO definitions for the WGT634U */
...@@ -99,6 +102,30 @@ static struct platform_device *wgt634u_devices[] __initdata = { ...@@ -99,6 +102,30 @@ static struct platform_device *wgt634u_devices[] __initdata = {
&wgt634u_gpio_leds, &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) static int __init wgt634u_init(void)
{ {
/* There is no easy way to detect that we are running on a WGT634U /* There is no easy way to detect that we are running on a WGT634U
...@@ -112,6 +139,19 @@ static int __init wgt634u_init(void) ...@@ -112,6 +139,19 @@ static int __init wgt634u_init(void)
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) || ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) { (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; 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_data.width = mcore->flash_buswidth;
wgt634u_flash_resource.start = mcore->flash_window; wgt634u_flash_resource.start = mcore->flash_window;
wgt634u_flash_resource.end = mcore->flash_window wgt634u_flash_resource.end = mcore->flash_window
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/debug.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/emma2rh/emma2rh.h> #include <asm/emma2rh/emma2rh.h>
#include <asm/debug.h>
const char *get_system_type(void) const char *get_system_type(void)
{ {
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/reboot.h> #include <asm/reboot.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h> #include <asm/emma2rh/emma2rh.h>
......
...@@ -9,47 +9,46 @@ ...@@ -9,47 +9,46 @@
#ifndef __BCM47XX_GPIO_H #ifndef __BCM47XX_GPIO_H
#define __BCM47XX_GPIO_H #define __BCM47XX_GPIO_H
#include <linux/ssb/ssb_embedded.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
#define BCM47XX_EXTIF_GPIO_LINES 5 #define BCM47XX_EXTIF_GPIO_LINES 5
#define BCM47XX_CHIPCO_GPIO_LINES 16 #define BCM47XX_CHIPCO_GPIO_LINES 16
extern int bcm47xx_gpio_to_irq(unsigned gpio); extern int gpio_request(unsigned gpio, const char *label);
extern int bcm47xx_gpio_get_value(unsigned gpio); extern void gpio_free(unsigned gpio);
extern void bcm47xx_gpio_set_value(unsigned gpio, int value); extern int gpio_to_irq(unsigned gpio);
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_get_value(unsigned gpio)
{ {
return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
} }
static inline int gpio_to_irq(unsigned gpio) static inline void gpio_set_value(unsigned gpio, int value)
{ {
return bcm47xx_gpio_to_irq(gpio); ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
} }
static inline int gpio_get_value(unsigned gpio) static inline int gpio_direction_input(unsigned gpio)
{ {
return bcm47xx_gpio_get_value(gpio); return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
} }
static inline void gpio_set_value(unsigned gpio, int value) static inline int gpio_direction_output(unsigned gpio, int value)
{ {
bcm47xx_gpio_set_value(gpio, value); return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
} }
static inline int gpio_direction_input(unsigned gpio) static int gpio_intmask(unsigned gpio, int value)
{ {
return bcm47xx_gpio_direction_input(gpio); return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
value ? 1 << gpio : 0);
} }
static inline int gpio_direction_output(unsigned gpio, int value) static int gpio_polarity(unsigned gpio, int value)
{ {
return bcm47xx_gpio_direction_output(gpio, value); return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
value ? 1 << gpio : 0);
} }
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
* *
* Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
*/ */
#ifndef __ASM_MIPS_MACH_BCM947XX_WAR_H #ifndef __ASM_MIPS_MACH_BCM47XX_WAR_H
#define __ASM_MIPS_MACH_BCM947XX_WAR_H #define __ASM_MIPS_MACH_BCM47XX_WAR_H
#define R4600_V1_INDEX_ICACHEOP_WAR 0 #define R4600_V1_INDEX_ICACHEOP_WAR 0
#define R4600_V1_HIT_CACHEOP_WAR 0 #define R4600_V1_HIT_CACHEOP_WAR 0
...@@ -22,4 +22,4 @@ ...@@ -22,4 +22,4 @@
#define R10000_LLSC_WAR 0 #define R10000_LLSC_WAR 0
#define MIPS34K_MISSED_ITLB_WAR 0 #define MIPS34K_MISSED_ITLB_WAR 0
#endif /* __ASM_MIPS_MACH_BCM947XX_WAR_H */ #endif /* __ASM_MIPS_MACH_BCM47XX_WAR_H */
/*
* 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 <asm/sgi/hpc3.h>
#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 */
#ifndef __ASM_MACH_IP28_DS1286_H
#define __ASM_MACH_IP28_DS1286_H
#include <asm/mach-ip22/ds1286.h>
#endif /* __ASM_MACH_IP28_DS1286_H */
...@@ -147,7 +147,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) ...@@ -147,7 +147,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
" ori %[ticket], %[ticket], 0x2000 \n" " ori %[ticket], %[ticket], 0x2000 \n"
" xori %[ticket], %[ticket], 0x2000 \n" " xori %[ticket], %[ticket], 0x2000 \n"
" sc %[ticket], %[ticket_ptr] \n" " sc %[ticket], %[ticket_ptr] \n"
" beqzl %[ticket], 2f \n" " beqzl %[ticket], 1b \n"
: [ticket_ptr] "+m" (lock->lock), : [ticket_ptr] "+m" (lock->lock),
[ticket] "=&r" (tmp)); [ticket] "=&r" (tmp));
} else { } else {
......
...@@ -39,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) ...@@ -39,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "processor\t\t: %ld\n", n); seq_printf(m, "processor\t\t: %ld\n", n);
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); 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, (version >> 4) & 0x0f, version & 0x0f,
(fp_vers >> 4) & 0x0f, fp_vers & 0x0f); (fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
......
...@@ -104,7 +104,7 @@ SECTIONS ...@@ -104,7 +104,7 @@ SECTIONS
. = ALIGN(_PAGE_SIZE); . = ALIGN(_PAGE_SIZE);
__nosave_end = .; __nosave_end = .;
. = ALIGN(32); . = ALIGN(1 << CONFIG_MIPS_L1_CACHE_SHIFT);
.data.cacheline_aligned : { .data.cacheline_aligned : {
*(.data.cacheline_aligned) *(.data.cacheline_aligned)
} }
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h> #include <asm/emma2rh/emma2rh.h>
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
#include <asm/mach-pnx8550/pci.h> #include <asm/mach-pnx8550/pci.h>
#include <asm/mach-pnx8550/glb.h> #include <asm/mach-pnx8550/glb.h>
#include <asm/debug.h>
static inline void clear_status(void) static inline void clear_status(void)
{ {
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h> #include <asm/emma2rh/emma2rh.h>
......
...@@ -34,6 +34,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head; ...@@ -34,6 +34,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head;
unsigned long PCIBIOS_MIN_IO = 0x0000; unsigned long PCIBIOS_MIN_IO = 0x0000;
unsigned long PCIBIOS_MIN_MEM = 0; unsigned long PCIBIOS_MIN_MEM = 0;
static int pci_initialized;
/* /*
* We need to avoid collisions with `mirrored' VGA ports * We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the * and other strange ISA hardware, so we always want the
...@@ -74,6 +76,42 @@ pcibios_align_resource(void *data, struct resource *res, ...@@ -74,6 +76,42 @@ pcibios_align_resource(void *data, struct resource *res,
res->start = start; 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) void __devinit register_pci_controller(struct pci_controller *hose)
{ {
if (request_resource(&iomem_resource, hose->mem_resource) < 0) if (request_resource(&iomem_resource, hose->mem_resource) < 0)
...@@ -93,6 +131,17 @@ void __devinit register_pci_controller(struct pci_controller *hose) ...@@ -93,6 +131,17 @@ void __devinit register_pci_controller(struct pci_controller *hose)
printk(KERN_WARNING printk(KERN_WARNING
"registering PCI controller with io_map_base unset\n"); "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; return;
out: out:
...@@ -125,38 +174,15 @@ static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) ...@@ -125,38 +174,15 @@ static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
static int __init pcibios_init(void) static int __init pcibios_init(void)
{ {
struct pci_controller *hose; struct pci_controller *hose;
struct pci_bus *bus;
int next_busno;
int need_domain_info = 0;
/* Scan all of the recorded PCI controllers. */ /* 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_fixup_irqs(common_swizzle, pcibios_map_irq);
pci_initialized = 1;
return 0; return 0;
} }
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <linux/timex.h> #include <linux/timex.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/debug.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/mach-rc32434/rc32434.h> #include <asm/mach-rc32434/rc32434.h>
......
...@@ -192,3 +192,18 @@ static int __init sgi_button_devinit(void) ...@@ -192,3 +192,18 @@ static int __init sgi_button_devinit(void)
} }
device_initcall(sgi_button_devinit); 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);
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
*/ */
#include <linux/ds1286.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
* Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
*/ */
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/ds1286.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -29,69 +28,6 @@ ...@@ -29,69 +28,6 @@
#include <asm/sgi/hpc3.h> #include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h> #include <asm/sgi/ip22.h>
/*
* 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) static unsigned long dosample(void)
{ {
u32 ct0, ct1; u32 ct0, ct1;
......
...@@ -13,12 +13,12 @@ ...@@ -13,12 +13,12 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/platform_device.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/sgialib.h> #include <asm/sgialib.h>
#include <asm/sn/ioc3.h> #include <asm/sn/ioc3.h>
#include <asm/m48t35.h>
#include <asm/sn/klconfig.h> #include <asm/sn/klconfig.h>
#include <asm/sn/arch.h> #include <asm/sn/arch.h>
#include <asm/sn/addrs.h> #include <asm/sn/addrs.h>
...@@ -28,51 +28,6 @@ ...@@ -28,51 +28,6 @@
#define TICK_SIZE (tick_nsec / 1000) #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(). */ /* Includes for ioc3_init(). */
#include <asm/sn/types.h> #include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h> #include <asm/sn/sn0/addrs.h>
...@@ -80,37 +35,6 @@ static int set_rtc_mmss(unsigned long nowtime) ...@@ -80,37 +35,6 @@ static int set_rtc_mmss(unsigned long nowtime)
#include <asm/sn/sn0/hubio.h> #include <asm/sn/sn0/hubio.h>
#include <asm/pci/bridge.h> #include <asm/pci/bridge.h>
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) static void enable_rt_irq(unsigned int irq)
{ {
} }
...@@ -286,6 +210,7 @@ void __cpuinit cpu_time_init(void) ...@@ -286,6 +210,7 @@ void __cpuinit cpu_time_init(void)
void __cpuinit hub_rtc_init(cnodeid_t cnode) void __cpuinit hub_rtc_init(cnodeid_t cnode)
{ {
/* /*
* We only need to initialize the current node. * We only need to initialize the current node.
* If this is not the current node then it is a cpuless * If this is not the current node then it is a cpuless
...@@ -301,3 +226,23 @@ void __cpuinit hub_rtc_init(cnodeid_t cnode) ...@@ -301,3 +226,23 @@ void __cpuinit hub_rtc_init(cnodeid_t cnode)
LOCAL_HUB_S(PI_RT_PEND_B, 0); 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);
...@@ -90,6 +90,22 @@ static __init int sgio2btns_devinit(void) ...@@ -90,6 +90,22 @@ static __init int sgio2btns_devinit(void)
device_initcall(sgio2btns_devinit); 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 <ralf@linux-mips.org>"); MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2"); MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2");
...@@ -62,11 +62,6 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str) ...@@ -62,11 +62,6 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str)
} }
#endif #endif
unsigned long read_persistent_clock(void)
{
return mc146818_get_cmos_time();
}
/* An arbitrary time; this can be decreased if reliability looks good */ /* An arbitrary time; this can be decreased if reliability looks good */
#define WAIT_MS 10 #define WAIT_MS 10
......
...@@ -352,6 +352,11 @@ config RTC_DRV_DS1216 ...@@ -352,6 +352,11 @@ config RTC_DRV_DS1216
help help
If you say yes here you get support for the Dallas DS1216 RTC chips. 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 config RTC_DRV_DS1302
tristate "Dallas DS1302" tristate "Dallas DS1302"
depends on SH_SECUREEDGE5410 depends on SH_SECUREEDGE5410
...@@ -405,6 +410,15 @@ config RTC_DRV_M48T86 ...@@ -405,6 +410,15 @@ config RTC_DRV_M48T86
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-m48t86. 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 config RTC_DRV_M48T59
tristate "ST M48T59/M48T08/M48T02" tristate "ST M48T59/M48T08/M48T02"
help help
......
...@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o ...@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.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_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
...@@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.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_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.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_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
......
/*
* 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 <linux/module.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
#include <linux/ds1286.h>
#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 <tsbogend@alpha.franken.de>");
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);
/*
* 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 <linux/module.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
#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 <tsbogend@alpha.franken.de>");
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);
...@@ -8,8 +8,6 @@ ...@@ -8,8 +8,6 @@
#ifndef __LINUX_DS1286_H #ifndef __LINUX_DS1286_H
#define __LINUX_DS1286_H #define __LINUX_DS1286_H
#include <asm/ds1286.h>
/********************************************************************** /**********************************************************************
* register summary * register summary
**********************************************************************/ **********************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment