blob: ea29bbe8e5cfd5168a864e9fa53783376dcfefab [file] [log] [blame]
David Brownell994c84e2006-12-06 17:14:03 -08001/*
2 * linux/arch/arm/plat-omap/debug-leds.c
3 *
Bryan Wudafbead2012-03-14 02:14:39 +08004 * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
David Brownell994c84e2006-12-06 17:14:03 -08005 * 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 */
Bryan Wudafbead2012-03-14 02:14:39 +080011
12#include <linux/kernel.h>
David Brownell994c84e2006-12-06 17:14:03 -080013#include <linux/init.h>
14#include <linux/platform_device.h>
15#include <linux/leds.h>
Russell Kingfced80c2008-09-06 12:10:45 +010016#include <linux/io.h>
Tony Lindgren4b254082012-08-30 15:37:24 -070017#include <linux/platform_data/gpio-omap.h>
Bryan Wudafbead2012-03-14 02:14:39 +080018#include <linux/slab.h>
David Brownell994c84e2006-12-06 17:14:03 -080019
Russell Kinga09e64f2008-08-05 16:14:15 +010020#include <mach/hardware.h>
David Brownell994c84e2006-12-06 17:14:03 -080021#include <asm/mach-types.h>
22
Tony Lindgrence491cf2009-10-20 09:40:47 -070023#include <plat/fpga.h>
David Brownell994c84e2006-12-06 17:14:03 -080024
David Brownell994c84e2006-12-06 17:14:03 -080025/* 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.
David Brownell994c84e2006-12-06 17:14:03 -080028 */
29
Bryan Wudafbead2012-03-14 02:14:39 +080030static struct h2p2_dbg_fpga __iomem *fpga;
David Brownell994c84e2006-12-06 17:14:03 -080031
Bryan Wudafbead2012-03-14 02:14:39 +080032static u16 fpga_led_state;
David Brownell994c84e2006-12-06 17:14:03 -080033
34struct dbg_led {
35 struct led_classdev cdev;
36 u16 mask;
37};
38
Bryan Wudafbead2012-03-14 02:14:39 +080039static const struct {
40 const char *name;
41 const char *trigger;
42} dbg_leds[] = {
43 { "dbg:d4", "heartbeat", },
44 { "dbg:d5", "cpu0", },
45 { "dbg:d6", "default-on", },
46 { "dbg:d7", },
47 { "dbg:d8", },
48 { "dbg:d9", },
49 { "dbg:d10", },
50 { "dbg:d11", },
51 { "dbg:d12", },
52 { "dbg:d13", },
53 { "dbg:d14", },
54 { "dbg:d15", },
55 { "dbg:d16", },
56 { "dbg:d17", },
57 { "dbg:d18", },
58 { "dbg:d19", },
David Brownell994c84e2006-12-06 17:14:03 -080059};
60
Bryan Wudafbead2012-03-14 02:14:39 +080061/*
62 * The triggers lines up below will only be used if the
63 * LED triggers are compiled in.
64 */
65static void dbg_led_set(struct led_classdev *cdev,
66 enum led_brightness b)
David Brownell994c84e2006-12-06 17:14:03 -080067{
Bryan Wudafbead2012-03-14 02:14:39 +080068 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
69 u16 reg;
David Brownell994c84e2006-12-06 17:14:03 -080070
Bryan Wudafbead2012-03-14 02:14:39 +080071 reg = __raw_readw(&fpga->leds);
72 if (b != LED_OFF)
73 reg |= led->mask;
David Brownell994c84e2006-12-06 17:14:03 -080074 else
Bryan Wudafbead2012-03-14 02:14:39 +080075 reg &= ~led->mask;
76 __raw_writew(reg, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -080077}
78
Bryan Wudafbead2012-03-14 02:14:39 +080079static enum led_brightness dbg_led_get(struct led_classdev *cdev)
David Brownell994c84e2006-12-06 17:14:03 -080080{
Bryan Wudafbead2012-03-14 02:14:39 +080081 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
82 u16 reg;
David Brownell994c84e2006-12-06 17:14:03 -080083
Bryan Wudafbead2012-03-14 02:14:39 +080084 reg = __raw_readw(&fpga->leds);
85 return (reg & led->mask) ? LED_FULL : LED_OFF;
David Brownell994c84e2006-12-06 17:14:03 -080086}
87
Bryan Wudafbead2012-03-14 02:14:39 +080088static int fpga_probe(struct platform_device *pdev)
David Brownell994c84e2006-12-06 17:14:03 -080089{
90 struct resource *iomem;
Bryan Wudafbead2012-03-14 02:14:39 +080091 int i;
David Brownell994c84e2006-12-06 17:14:03 -080092
93 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
94 if (!iomem)
95 return -ENODEV;
96
97 fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
Bryan Wudafbead2012-03-14 02:14:39 +080098 __raw_writew(0xff, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -080099
Bryan Wudafbead2012-03-14 02:14:39 +0800100 for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
101 struct dbg_led *led;
David Brownell994c84e2006-12-06 17:14:03 -0800102
Bryan Wudafbead2012-03-14 02:14:39 +0800103 led = kzalloc(sizeof(*led), GFP_KERNEL);
104 if (!led)
105 break;
106
107 led->cdev.name = dbg_leds[i].name;
108 led->cdev.brightness_set = dbg_led_set;
109 led->cdev.brightness_get = dbg_led_get;
110 led->cdev.default_trigger = dbg_leds[i].trigger;
111 led->mask = BIT(i);
112
113 if (led_classdev_register(NULL, &led->cdev) < 0) {
114 kfree(led);
115 break;
116 }
David Brownell994c84e2006-12-06 17:14:03 -0800117 }
118
119 return 0;
120}
121
Magnus Damm79ee0312009-07-08 13:22:04 +0200122static int fpga_suspend_noirq(struct device *dev)
David Brownell994c84e2006-12-06 17:14:03 -0800123{
Bryan Wudafbead2012-03-14 02:14:39 +0800124 fpga_led_state = __raw_readw(&fpga->leds);
125 __raw_writew(0xff, &fpga->leds);
126
David Brownell994c84e2006-12-06 17:14:03 -0800127 return 0;
128}
129
Magnus Damm79ee0312009-07-08 13:22:04 +0200130static int fpga_resume_noirq(struct device *dev)
David Brownell994c84e2006-12-06 17:14:03 -0800131{
Bryan Wudafbead2012-03-14 02:14:39 +0800132 __raw_writew(~fpga_led_state, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -0800133 return 0;
134}
135
Alexey Dobriyan47145212009-12-14 18:00:08 -0800136static const struct dev_pm_ops fpga_dev_pm_ops = {
Magnus Damm79ee0312009-07-08 13:22:04 +0200137 .suspend_noirq = fpga_suspend_noirq,
138 .resume_noirq = fpga_resume_noirq,
139};
David Brownell994c84e2006-12-06 17:14:03 -0800140
141static struct platform_driver led_driver = {
142 .driver.name = "omap_dbg_led",
Magnus Damm79ee0312009-07-08 13:22:04 +0200143 .driver.pm = &fpga_dev_pm_ops,
David Brownell994c84e2006-12-06 17:14:03 -0800144 .probe = fpga_probe,
David Brownell994c84e2006-12-06 17:14:03 -0800145};
146
147static int __init fpga_init(void)
148{
149 if (machine_is_omap_h4()
150 || machine_is_omap_h3()
151 || machine_is_omap_h2()
152 || machine_is_omap_perseus2()
153 )
154 return platform_driver_register(&led_driver);
155 return 0;
156}
157fs_initcall(fpga_init);