aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-footbridge/netwinder-hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-footbridge/netwinder-hw.c')
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c157
1 files changed, 134 insertions, 23 deletions
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 06e514f372d..cdee08c6d23 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -12,11 +12,13 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
#include <asm/hardware/dec21285.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
+#include <asm/system_misc.h>
#include <asm/mach/arch.h>
@@ -26,13 +28,6 @@
#define GP1_IO_BASE 0x338
#define GP2_IO_BASE 0x33a
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS 0
-#else
-#define DEFAULT_LEDS GPIO_GREEN_LED
-#endif
-
/*
* Winbond WB83977F accessibility stuff
*/
@@ -68,7 +63,7 @@ static inline void wb977_ww(int reg, int val)
/*
* This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE
*/
-DEFINE_SPINLOCK(nw_gpio_lock);
+DEFINE_RAW_SPINLOCK(nw_gpio_lock);
EXPORT_SYMBOL(nw_gpio_lock);
static unsigned int current_gpio_op;
@@ -327,9 +322,9 @@ static inline void wb977_init_gpio(void)
/*
* Set Group1/Group2 outputs
*/
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
/*
@@ -390,9 +385,9 @@ static void __init cpld_init(void)
{
unsigned long flags;
- spin_lock_irqsave(&nw_gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
static unsigned char rwa_unlock[] __initdata =
@@ -610,15 +605,9 @@ static void __init rwa010_init(void)
static int __init nw_hw_init(void)
{
if (machine_is_netwinder()) {
- unsigned long flags;
-
wb977_init();
cpld_init();
rwa010_init();
-
- spin_lock_irqsave(&nw_gpio_lock, flags);
- nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
- spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
return 0;
}
@@ -631,8 +620,7 @@ __initcall(nw_hw_init);
* the parameter page.
*/
static void __init
-fixup_netwinder(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_netwinder(struct tag *tags, char **cmdline)
{
#ifdef CONFIG_ISAPNP
extern int isapnp_disable;
@@ -646,9 +634,131 @@ fixup_netwinder(struct machine_desc *desc, struct tag *tags,
#endif
}
+static void netwinder_restart(enum reboot_mode mode, const char *cmd)
+{
+ if (mode == REBOOT_SOFT) {
+ /* Jump into the ROM */
+ soft_restart(0x41000000);
+ } else {
+ local_irq_disable();
+ local_fiq_disable();
+
+ /* open up the SuperIO chip */
+ outb(0x87, 0x370);
+ outb(0x87, 0x370);
+
+ /* aux function group 1 (logical device 7) */
+ outb(0x07, 0x370);
+ outb(0x07, 0x371);
+
+ /* set GP16 for WD-TIMER output */
+ outb(0xe6, 0x370);
+ outb(0x00, 0x371);
+
+ /* set a RED LED and toggle WD_TIMER for rebooting */
+ outb(0xc4, 0x338);
+ }
+}
+
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct netwinder_led {
+ struct led_classdev cdev;
+ u8 mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+ const char *name;
+ const char *trigger;
+} netwinder_leds[] = {
+ { "netwinder:green", "heartbeat", },
+ { "netwinder:red", "cpu0", },
+};
+
+/*
+ * The LED control in Netwinder is reversed:
+ * - setting bit means turn off LED
+ * - clearing bit means turn on LED
+ */
+static void netwinder_led_set(struct led_classdev *cdev,
+ enum led_brightness b)
+{
+ struct netwinder_led *led = container_of(cdev,
+ struct netwinder_led, cdev);
+ unsigned long flags;
+ u32 reg;
+
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
+ reg = nw_gpio_read();
+ if (b != LED_OFF)
+ reg &= ~led->mask;
+ else
+ reg |= led->mask;
+ nw_gpio_modify_op(led->mask, reg);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
+}
+
+static enum led_brightness netwinder_led_get(struct led_classdev *cdev)
+{
+ struct netwinder_led *led = container_of(cdev,
+ struct netwinder_led, cdev);
+ unsigned long flags;
+ u32 reg;
+
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
+ reg = nw_gpio_read();
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
+
+ return (reg & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init netwinder_leds_init(void)
+{
+ int i;
+
+ if (!machine_is_netwinder())
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) {
+ struct netwinder_led *led;
+
+ led = kzalloc(sizeof(*led), GFP_KERNEL);
+ if (!led)
+ break;
+
+ led->cdev.name = netwinder_leds[i].name;
+ led->cdev.brightness_set = netwinder_led_set;
+ led->cdev.brightness_get = netwinder_led_get;
+ led->cdev.default_trigger = netwinder_leds[i].trigger;
+
+ if (i == 0)
+ led->mask = GPIO_GREEN_LED;
+ else
+ led->mask = GPIO_RED_LED;
+
+ if (led_classdev_register(NULL, &led->cdev) < 0) {
+ kfree(led);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(netwinder_leds_init);
+#endif
+
MACHINE_START(NETWINDER, "Rebel-NetWinder")
/* Maintainer: Russell King/Rebel.com */
- .boot_params = 0x00000100,
+ .atag_offset = 0x100,
.video_start = 0x000a0000,
.video_end = 0x000bffff,
.reserve_lp0 = 1,
@@ -656,5 +766,6 @@ MACHINE_START(NETWINDER, "Rebel-NetWinder")
.fixup = fixup_netwinder,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
- .timer = &isa_timer,
+ .init_time = isa_timer_init,
+ .restart = netwinder_restart,
MACHINE_END