linux/arch/arm/plat-omap/debug-leds.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/plat-omap/debug-leds.c
   3 *
   4 * Copyright 2003 by Texas Instruments Incorporated
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/init.h>
  12#include <linux/platform_device.h>
  13#include <linux/leds.h>
  14#include <linux/io.h>
  15
  16#include <mach/hardware.h>
  17#include <asm/leds.h>
  18#include <asm/system.h>
  19#include <asm/mach-types.h>
  20
  21#include <plat/fpga.h>
  22#include <mach/gpio.h>
  23
  24
  25/* Many OMAP development platforms reuse the same "debug board"; these
  26 * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
  27 * debug board (all green), accessed through FPGA registers.
  28 *
  29 * The "surfer" expansion board and H2 sample board also have two-color
  30 * green+red LEDs (in parallel), used here for timer and idle indicators
  31 * in preference to the ones on the debug board, for a "Disco LED" effect.
  32 *
  33 * This driver exports either the original ARM LED API, the new generic
  34 * one, or both.
  35 */
  36
  37static spinlock_t                       lock;
  38static struct h2p2_dbg_fpga __iomem     *fpga;
  39static u16                              led_state, hw_led_state;
  40
  41
  42#ifdef  CONFIG_OMAP_DEBUG_LEDS
  43#define new_led_api()   1
  44#else
  45#define new_led_api()   0
  46#endif
  47
  48
  49/*-------------------------------------------------------------------------*/
  50
  51/* original ARM debug LED API:
  52 *  - timer and idle leds (some boards use non-FPGA leds here);
  53 *  - up to 4 generic leds, easily accessed in-kernel (any context)
  54 */
  55
  56#define GPIO_LED_RED            3
  57#define GPIO_LED_GREEN          OMAP_MPUIO(4)
  58
  59#define LED_STATE_ENABLED       0x01
  60#define LED_STATE_CLAIMED       0x02
  61#define LED_TIMER_ON            0x04
  62
  63#define GPIO_IDLE               GPIO_LED_GREEN
  64#define GPIO_TIMER              GPIO_LED_RED
  65
  66static void h2p2_dbg_leds_event(led_event_t evt)
  67{
  68        unsigned long flags;
  69
  70        spin_lock_irqsave(&lock, flags);
  71
  72        if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
  73                goto done;
  74
  75        switch (evt) {
  76        case led_start:
  77                if (fpga)
  78                        led_state |= LED_STATE_ENABLED;
  79                break;
  80
  81        case led_stop:
  82        case led_halted:
  83                /* all leds off during suspend or shutdown */
  84
  85                if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
  86                        gpio_set_value(GPIO_TIMER, 0);
  87                        gpio_set_value(GPIO_IDLE, 0);
  88                }
  89
  90                __raw_writew(~0, &fpga->leds);
  91                led_state &= ~LED_STATE_ENABLED;
  92                goto done;
  93
  94        case led_claim:
  95                led_state |= LED_STATE_CLAIMED;
  96                hw_led_state = 0;
  97                break;
  98
  99        case led_release:
 100                led_state &= ~LED_STATE_CLAIMED;
 101                break;
 102
 103#ifdef CONFIG_LEDS_TIMER
 104        case led_timer:
 105                led_state ^= LED_TIMER_ON;
 106
 107                if (machine_is_omap_perseus2() || machine_is_omap_h4())
 108                        hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
 109                else {
 110                        gpio_set_value(GPIO_TIMER,
 111                                        led_state & LED_TIMER_ON);
 112                        goto done;
 113                }
 114
 115                break;
 116#endif
 117
 118#ifdef CONFIG_LEDS_CPU
 119        /* LED lit iff busy */
 120        case led_idle_start:
 121                if (machine_is_omap_perseus2() || machine_is_omap_h4())
 122                        hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
 123                else {
 124                        gpio_set_value(GPIO_IDLE, 1);
 125                        goto done;
 126                }
 127
 128                break;
 129
 130        case led_idle_end:
 131                if (machine_is_omap_perseus2() || machine_is_omap_h4())
 132                        hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
 133                else {
 134                        gpio_set_value(GPIO_IDLE, 0);
 135                        goto done;
 136                }
 137
 138                break;
 139#endif
 140
 141        case led_green_on:
 142                hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
 143                break;
 144        case led_green_off:
 145                hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
 146                break;
 147
 148        case led_amber_on:
 149                hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
 150                break;
 151        case led_amber_off:
 152                hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
 153                break;
 154
 155        case led_red_on:
 156                hw_led_state |= H2P2_DBG_FPGA_LED_RED;
 157                break;
 158        case led_red_off:
 159                hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
 160                break;
 161
 162        case led_blue_on:
 163                hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
 164                break;
 165        case led_blue_off:
 166                hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
 167                break;
 168
 169        default:
 170                break;
 171        }
 172
 173
 174        /*
 175         *  Actually burn the LEDs
 176         */
 177        if (led_state & LED_STATE_ENABLED)
 178                __raw_writew(~hw_led_state, &fpga->leds);
 179
 180done:
 181        spin_unlock_irqrestore(&lock, flags);
 182}
 183
 184/*-------------------------------------------------------------------------*/
 185
 186/* "new" LED API
 187 *  - with syfs access and generic triggering
 188 *  - not readily accessible to in-kernel drivers
 189 */
 190
 191struct dbg_led {
 192        struct led_classdev     cdev;
 193        u16                     mask;
 194};
 195
 196static struct dbg_led dbg_leds[] = {
 197        /* REVISIT at least H2 uses different timer & cpu leds... */
 198#ifndef CONFIG_LEDS_TIMER
 199        { .mask = 1 << 0,  .cdev.name =  "d4:green",
 200                .cdev.default_trigger = "heartbeat", },
 201#endif
 202#ifndef CONFIG_LEDS_CPU
 203        { .mask = 1 << 1,  .cdev.name =  "d5:green", },         /* !idle */
 204#endif
 205        { .mask = 1 << 2,  .cdev.name =  "d6:green", },
 206        { .mask = 1 << 3,  .cdev.name =  "d7:green", },
 207
 208        { .mask = 1 << 4,  .cdev.name =  "d8:green", },
 209        { .mask = 1 << 5,  .cdev.name =  "d9:green", },
 210        { .mask = 1 << 6,  .cdev.name = "d10:green", },
 211        { .mask = 1 << 7,  .cdev.name = "d11:green", },
 212
 213        { .mask = 1 << 8,  .cdev.name = "d12:green", },
 214        { .mask = 1 << 9,  .cdev.name = "d13:green", },
 215        { .mask = 1 << 10, .cdev.name = "d14:green", },
 216        { .mask = 1 << 11, .cdev.name = "d15:green", },
 217
 218#ifndef CONFIG_LEDS
 219        { .mask = 1 << 12, .cdev.name = "d16:green", },
 220        { .mask = 1 << 13, .cdev.name = "d17:green", },
 221        { .mask = 1 << 14, .cdev.name = "d18:green", },
 222        { .mask = 1 << 15, .cdev.name = "d19:green", },
 223#endif
 224};
 225
 226static void
 227fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
 228{
 229        struct dbg_led  *led = container_of(cdev, struct dbg_led, cdev);
 230        unsigned long   flags;
 231
 232        spin_lock_irqsave(&lock, flags);
 233        if (value == LED_OFF)
 234                hw_led_state &= ~led->mask;
 235        else
 236                hw_led_state |= led->mask;
 237        __raw_writew(~hw_led_state, &fpga->leds);
 238        spin_unlock_irqrestore(&lock, flags);
 239}
 240
 241static void __init newled_init(struct device *dev)
 242{
 243        unsigned        i;
 244        struct dbg_led  *led;
 245        int             status;
 246
 247        for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
 248                led->cdev.brightness_set = fpga_led_set;
 249                status = led_classdev_register(dev, &led->cdev);
 250                if (status < 0)
 251                        break;
 252        }
 253        return;
 254}
 255
 256
 257/*-------------------------------------------------------------------------*/
 258
 259static int /* __init */ fpga_probe(struct platform_device *pdev)
 260{
 261        struct resource *iomem;
 262
 263        spin_lock_init(&lock);
 264
 265        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 266        if (!iomem)
 267                return -ENODEV;
 268
 269        fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
 270        __raw_writew(~0, &fpga->leds);
 271
 272#ifdef  CONFIG_LEDS
 273        leds_event = h2p2_dbg_leds_event;
 274        leds_event(led_start);
 275#endif
 276
 277        if (new_led_api()) {
 278                newled_init(&pdev->dev);
 279        }
 280
 281        return 0;
 282}
 283
 284static int fpga_suspend_noirq(struct device *dev)
 285{
 286        __raw_writew(~0, &fpga->leds);
 287        return 0;
 288}
 289
 290static int fpga_resume_noirq(struct device *dev)
 291{
 292        __raw_writew(~hw_led_state, &fpga->leds);
 293        return 0;
 294}
 295
 296static const struct dev_pm_ops fpga_dev_pm_ops = {
 297        .suspend_noirq = fpga_suspend_noirq,
 298        .resume_noirq = fpga_resume_noirq,
 299};
 300
 301static struct platform_driver led_driver = {
 302        .driver.name    = "omap_dbg_led",
 303        .driver.pm      = &fpga_dev_pm_ops,
 304        .probe          = fpga_probe,
 305};
 306
 307static int __init fpga_init(void)
 308{
 309        if (machine_is_omap_h4()
 310                        || machine_is_omap_h3()
 311                        || machine_is_omap_h2()
 312                        || machine_is_omap_perseus2()
 313                        )
 314                return platform_driver_register(&led_driver);
 315        return 0;
 316}
 317fs_initcall(fpga_init);
 318