linux/arch/arm/plat-omap/debug-leds.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/arch/arm/plat-omap/debug-leds.c
   4 *
   5 * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
   6 * Copyright 2003 by Texas Instruments Incorporated
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/platform_device.h>
  12#include <linux/leds.h>
  13#include <linux/io.h>
  14#include <linux/platform_data/gpio-omap.h>
  15#include <linux/slab.h>
  16
  17#include <asm/mach-types.h>
  18
  19/* Many OMAP development platforms reuse the same "debug board"; these
  20 * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
  21 * debug board (all green), accessed through FPGA registers.
  22 */
  23
  24/* NOTE:  most boards don't have a static mapping for the FPGA ... */
  25struct h2p2_dbg_fpga {
  26        /* offset 0x00 */
  27        u16             smc91x[8];
  28        /* offset 0x10 */
  29        u16             fpga_rev;
  30        u16             board_rev;
  31        u16             gpio_outputs;
  32        u16             leds;
  33        /* offset 0x18 */
  34        u16             misc_inputs;
  35        u16             lan_status;
  36        u16             lan_reset;
  37        u16             reserved0;
  38        /* offset 0x20 */
  39        u16             ps2_data;
  40        u16             ps2_ctrl;
  41        /* plus also 4 rs232 ports ... */
  42};
  43
  44static struct h2p2_dbg_fpga __iomem *fpga;
  45
  46static u16 fpga_led_state;
  47
  48struct dbg_led {
  49        struct led_classdev     cdev;
  50        u16                     mask;
  51};
  52
  53static const struct {
  54        const char *name;
  55        const char *trigger;
  56} dbg_leds[] = {
  57        { "dbg:d4", "heartbeat", },
  58        { "dbg:d5", "cpu0", },
  59        { "dbg:d6", "default-on", },
  60        { "dbg:d7", },
  61        { "dbg:d8", },
  62        { "dbg:d9", },
  63        { "dbg:d10", },
  64        { "dbg:d11", },
  65        { "dbg:d12", },
  66        { "dbg:d13", },
  67        { "dbg:d14", },
  68        { "dbg:d15", },
  69        { "dbg:d16", },
  70        { "dbg:d17", },
  71        { "dbg:d18", },
  72        { "dbg:d19", },
  73};
  74
  75/*
  76 * The triggers lines up below will only be used if the
  77 * LED triggers are compiled in.
  78 */
  79static void dbg_led_set(struct led_classdev *cdev,
  80                              enum led_brightness b)
  81{
  82        struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
  83        u16 reg;
  84
  85        reg = readw_relaxed(&fpga->leds);
  86        if (b != LED_OFF)
  87                reg |= led->mask;
  88        else
  89                reg &= ~led->mask;
  90        writew_relaxed(reg, &fpga->leds);
  91}
  92
  93static enum led_brightness dbg_led_get(struct led_classdev *cdev)
  94{
  95        struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
  96        u16 reg;
  97
  98        reg = readw_relaxed(&fpga->leds);
  99        return (reg & led->mask) ? LED_FULL : LED_OFF;
 100}
 101
 102static int fpga_probe(struct platform_device *pdev)
 103{
 104        struct resource *iomem;
 105        int i;
 106
 107        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 108        if (!iomem)
 109                return -ENODEV;
 110
 111        fpga = ioremap(iomem->start, resource_size(iomem));
 112        writew_relaxed(0xff, &fpga->leds);
 113
 114        for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
 115                struct dbg_led *led;
 116
 117                led = kzalloc(sizeof(*led), GFP_KERNEL);
 118                if (!led)
 119                        break;
 120
 121                led->cdev.name = dbg_leds[i].name;
 122                led->cdev.brightness_set = dbg_led_set;
 123                led->cdev.brightness_get = dbg_led_get;
 124                led->cdev.default_trigger = dbg_leds[i].trigger;
 125                led->mask = BIT(i);
 126
 127                if (led_classdev_register(NULL, &led->cdev) < 0) {
 128                        kfree(led);
 129                        break;
 130                }
 131        }
 132
 133        return 0;
 134}
 135
 136static int fpga_suspend_noirq(struct device *dev)
 137{
 138        fpga_led_state = readw_relaxed(&fpga->leds);
 139        writew_relaxed(0xff, &fpga->leds);
 140
 141        return 0;
 142}
 143
 144static int fpga_resume_noirq(struct device *dev)
 145{
 146        writew_relaxed(~fpga_led_state, &fpga->leds);
 147        return 0;
 148}
 149
 150static const struct dev_pm_ops fpga_dev_pm_ops = {
 151        .suspend_noirq = fpga_suspend_noirq,
 152        .resume_noirq = fpga_resume_noirq,
 153};
 154
 155static struct platform_driver led_driver = {
 156        .driver.name    = "omap_dbg_led",
 157        .driver.pm      = &fpga_dev_pm_ops,
 158        .probe          = fpga_probe,
 159};
 160
 161static int __init fpga_init(void)
 162{
 163        if (machine_is_omap_h4()
 164                        || machine_is_omap_h3()
 165                        || machine_is_omap_h2()
 166                        || machine_is_omap_perseus2()
 167                        )
 168                return platform_driver_register(&led_driver);
 169        return 0;
 170}
 171fs_initcall(fpga_init);
 172