blob: 24e23f3dd6a889b5df44a9310d308558d8caa283 [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>
Bryan Wudafbead2012-03-14 02:14:39 +080017#include <linux/slab.h>
David Brownell994c84e2006-12-06 17:14:03 -080018
Russell Kinga09e64f2008-08-05 16:14:15 +010019#include <mach/hardware.h>
David Brownell994c84e2006-12-06 17:14:03 -080020#include <asm/mach-types.h>
21
Tony Lindgrence491cf2009-10-20 09:40:47 -070022#include <plat/fpga.h>
David Brownell994c84e2006-12-06 17:14:03 -080023
David Brownell994c84e2006-12-06 17:14:03 -080024/* Many OMAP development platforms reuse the same "debug board"; these
25 * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the
26 * debug board (all green), accessed through FPGA registers.
David Brownell994c84e2006-12-06 17:14:03 -080027 */
28
Bryan Wudafbead2012-03-14 02:14:39 +080029static struct h2p2_dbg_fpga __iomem *fpga;
David Brownell994c84e2006-12-06 17:14:03 -080030
Bryan Wudafbead2012-03-14 02:14:39 +080031static u16 fpga_led_state;
David Brownell994c84e2006-12-06 17:14:03 -080032
33struct dbg_led {
34 struct led_classdev cdev;
35 u16 mask;
36};
37
Bryan Wudafbead2012-03-14 02:14:39 +080038static const struct {
39 const char *name;
40 const char *trigger;
41} dbg_leds[] = {
42 { "dbg:d4", "heartbeat", },
43 { "dbg:d5", "cpu0", },
44 { "dbg:d6", "default-on", },
45 { "dbg:d7", },
46 { "dbg:d8", },
47 { "dbg:d9", },
48 { "dbg:d10", },
49 { "dbg:d11", },
50 { "dbg:d12", },
51 { "dbg:d13", },
52 { "dbg:d14", },
53 { "dbg:d15", },
54 { "dbg:d16", },
55 { "dbg:d17", },
56 { "dbg:d18", },
57 { "dbg:d19", },
David Brownell994c84e2006-12-06 17:14:03 -080058};
59
Bryan Wudafbead2012-03-14 02:14:39 +080060/*
61 * The triggers lines up below will only be used if the
62 * LED triggers are compiled in.
63 */
64static void dbg_led_set(struct led_classdev *cdev,
65 enum led_brightness b)
David Brownell994c84e2006-12-06 17:14:03 -080066{
Bryan Wudafbead2012-03-14 02:14:39 +080067 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
68 u16 reg;
David Brownell994c84e2006-12-06 17:14:03 -080069
Bryan Wudafbead2012-03-14 02:14:39 +080070 reg = __raw_readw(&fpga->leds);
71 if (b != LED_OFF)
72 reg |= led->mask;
David Brownell994c84e2006-12-06 17:14:03 -080073 else
Bryan Wudafbead2012-03-14 02:14:39 +080074 reg &= ~led->mask;
75 __raw_writew(reg, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -080076}
77
Bryan Wudafbead2012-03-14 02:14:39 +080078static enum led_brightness dbg_led_get(struct led_classdev *cdev)
David Brownell994c84e2006-12-06 17:14:03 -080079{
Bryan Wudafbead2012-03-14 02:14:39 +080080 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
81 u16 reg;
David Brownell994c84e2006-12-06 17:14:03 -080082
Bryan Wudafbead2012-03-14 02:14:39 +080083 reg = __raw_readw(&fpga->leds);
84 return (reg & led->mask) ? LED_FULL : LED_OFF;
David Brownell994c84e2006-12-06 17:14:03 -080085}
86
Bryan Wudafbead2012-03-14 02:14:39 +080087static int fpga_probe(struct platform_device *pdev)
David Brownell994c84e2006-12-06 17:14:03 -080088{
89 struct resource *iomem;
Bryan Wudafbead2012-03-14 02:14:39 +080090 int i;
David Brownell994c84e2006-12-06 17:14:03 -080091
92 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
93 if (!iomem)
94 return -ENODEV;
95
96 fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
Bryan Wudafbead2012-03-14 02:14:39 +080097 __raw_writew(0xff, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -080098
Bryan Wudafbead2012-03-14 02:14:39 +080099 for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
100 struct dbg_led *led;
David Brownell994c84e2006-12-06 17:14:03 -0800101
Bryan Wudafbead2012-03-14 02:14:39 +0800102 led = kzalloc(sizeof(*led), GFP_KERNEL);
103 if (!led)
104 break;
105
106 led->cdev.name = dbg_leds[i].name;
107 led->cdev.brightness_set = dbg_led_set;
108 led->cdev.brightness_get = dbg_led_get;
109 led->cdev.default_trigger = dbg_leds[i].trigger;
110 led->mask = BIT(i);
111
112 if (led_classdev_register(NULL, &led->cdev) < 0) {
113 kfree(led);
114 break;
115 }
David Brownell994c84e2006-12-06 17:14:03 -0800116 }
117
118 return 0;
119}
120
Magnus Damm79ee0312009-07-08 13:22:04 +0200121static int fpga_suspend_noirq(struct device *dev)
David Brownell994c84e2006-12-06 17:14:03 -0800122{
Bryan Wudafbead2012-03-14 02:14:39 +0800123 fpga_led_state = __raw_readw(&fpga->leds);
124 __raw_writew(0xff, &fpga->leds);
125
David Brownell994c84e2006-12-06 17:14:03 -0800126 return 0;
127}
128
Magnus Damm79ee0312009-07-08 13:22:04 +0200129static int fpga_resume_noirq(struct device *dev)
David Brownell994c84e2006-12-06 17:14:03 -0800130{
Bryan Wudafbead2012-03-14 02:14:39 +0800131 __raw_writew(~fpga_led_state, &fpga->leds);
David Brownell994c84e2006-12-06 17:14:03 -0800132 return 0;
133}
134
Alexey Dobriyan47145212009-12-14 18:00:08 -0800135static const struct dev_pm_ops fpga_dev_pm_ops = {
Magnus Damm79ee0312009-07-08 13:22:04 +0200136 .suspend_noirq = fpga_suspend_noirq,
137 .resume_noirq = fpga_resume_noirq,
138};
David Brownell994c84e2006-12-06 17:14:03 -0800139
140static struct platform_driver led_driver = {
141 .driver.name = "omap_dbg_led",
Magnus Damm79ee0312009-07-08 13:22:04 +0200142 .driver.pm = &fpga_dev_pm_ops,
David Brownell994c84e2006-12-06 17:14:03 -0800143 .probe = fpga_probe,
David Brownell994c84e2006-12-06 17:14:03 -0800144};
145
146static int __init fpga_init(void)
147{
148 if (machine_is_omap_h4()
149 || machine_is_omap_h3()
150 || machine_is_omap_h2()
151 || machine_is_omap_perseus2()
152 )
153 return platform_driver_register(&led_driver);
154 return 0;
155}
156fs_initcall(fpga_init);