1/* 2 * arch/arm/mach-shark/leds.c 3 * by Alexander Schulz 4 * 5 * derived from: 6 * arch/arm/kernel/leds-footbridge.c 7 * Copyright (C) 1998-1999 Russell King 8 * 9 * DIGITAL Shark LED control routines. 10 * 11 * The leds use is as follows: 12 * - Green front - toggles state every 50 timer interrupts 13 * - Amber front - Unused, this is a dual color led (Amber/Green) 14 * - Amber back - On if system is not idle 15 * 16 * Changelog: 17 */ 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/init.h> 21#include <linux/spinlock.h> 22#include <linux/ioport.h> 23 24#include <asm/hardware.h> 25#include <asm/leds.h> 26#include <asm/io.h> 27#include <asm/system.h> 28 29#define LED_STATE_ENABLED 1 30#define LED_STATE_CLAIMED 2 31static char led_state; 32static short hw_led_state; 33static short saved_state; 34 35static DEFINE_SPINLOCK(leds_lock); 36 37short sequoia_read(int addr) { 38 outw(addr,0x24); 39 return inw(0x26); 40} 41 42void sequoia_write(short value,short addr) { 43 outw(addr,0x24); 44 outw(value,0x26); 45} 46 47static void sequoia_leds_event(led_event_t evt) 48{ 49 unsigned long flags; 50 51 spin_lock_irqsave(&leds_lock, flags); 52 53 hw_led_state = sequoia_read(0x09); 54 55 switch (evt) { 56 case led_start: 57 hw_led_state |= SEQUOIA_LED_GREEN; 58 hw_led_state |= SEQUOIA_LED_AMBER; 59#ifdef CONFIG_LEDS_CPU 60 hw_led_state |= SEQUOIA_LED_BACK; 61#else 62 hw_led_state &= ~SEQUOIA_LED_BACK; 63#endif 64 led_state |= LED_STATE_ENABLED; 65 break; 66 67 case led_stop: 68 hw_led_state &= ~SEQUOIA_LED_BACK; 69 hw_led_state |= SEQUOIA_LED_GREEN; 70 hw_led_state |= SEQUOIA_LED_AMBER; 71 led_state &= ~LED_STATE_ENABLED; 72 break; 73 74 case led_claim: 75 led_state |= LED_STATE_CLAIMED; 76 saved_state = hw_led_state; 77 hw_led_state &= ~SEQUOIA_LED_BACK; 78 hw_led_state |= SEQUOIA_LED_GREEN; 79 hw_led_state |= SEQUOIA_LED_AMBER; 80 break; 81 82 case led_release: 83 led_state &= ~LED_STATE_CLAIMED; 84 hw_led_state = saved_state; 85 break; 86 87#ifdef CONFIG_LEDS_TIMER 88 case led_timer: 89 if (!(led_state & LED_STATE_CLAIMED)) 90 hw_led_state ^= SEQUOIA_LED_GREEN; 91 break; 92#endif 93 94#ifdef CONFIG_LEDS_CPU 95 case led_idle_start: 96 if (!(led_state & LED_STATE_CLAIMED)) 97 hw_led_state &= ~SEQUOIA_LED_BACK; 98 break; 99 100 case led_idle_end: 101 if (!(led_state & LED_STATE_CLAIMED)) 102 hw_led_state |= SEQUOIA_LED_BACK; 103 break; 104#endif 105 106 case led_green_on: 107 if (led_state & LED_STATE_CLAIMED) 108 hw_led_state &= ~SEQUOIA_LED_GREEN; 109 break; 110 111 case led_green_off: 112 if (led_state & LED_STATE_CLAIMED) 113 hw_led_state |= SEQUOIA_LED_GREEN; 114 break; 115 116 case led_amber_on: 117 if (led_state & LED_STATE_CLAIMED) 118 hw_led_state &= ~SEQUOIA_LED_AMBER; 119 break; 120 121 case led_amber_off: 122 if (led_state & LED_STATE_CLAIMED) 123 hw_led_state |= SEQUOIA_LED_AMBER; 124 break; 125 126 case led_red_on: 127 if (led_state & LED_STATE_CLAIMED) 128 hw_led_state |= SEQUOIA_LED_BACK; 129 break; 130 131 case led_red_off: 132 if (led_state & LED_STATE_CLAIMED) 133 hw_led_state &= ~SEQUOIA_LED_BACK; 134 break; 135 136 default: 137 break; 138 } 139 140 if (led_state & LED_STATE_ENABLED) 141 sequoia_write(hw_led_state,0x09); 142 143 spin_unlock_irqrestore(&leds_lock, flags); 144} 145 146static int __init leds_init(void) 147{ 148 extern void (*leds_event)(led_event_t); 149 short temp; 150 151 leds_event = sequoia_leds_event; 152 153 /* Make LEDs independent of power-state */ 154 request_region(0x24,4,"sequoia"); 155 temp = sequoia_read(0x09); 156 temp |= 1<<10; 157 sequoia_write(temp,0x09); 158 leds_event(led_start); 159 return 0; 160} 161 162__initcall(leds_init); 163