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