blob: f1dcb57a59e2feae26a54d29ee06f54caffc767f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Bryan Wu95f49652012-03-14 01:50:00 +08002 * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
3 * Based on Versatile and RealView machine LED code
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Bryan Wu95f49652012-03-14 01:50:00 +08005 * License terms: GNU General Public License (GPL) version 2
6 * Author: Bryan Wu <bryan.wu@canonical.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8#include <linux/kernel.h>
9#include <linux/init.h>
Russell Kingfced80c2008-09-06 12:10:45 +010010#include <linux/io.h>
Bryan Wu95f49652012-03-14 01:50:00 +080011#include <linux/slab.h>
12#include <linux/leds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
Linus Walleij1b1ef752014-02-13 21:26:24 +010014#include "hardware.h"
Linus Walleijbb4dbef2013-06-16 02:44:27 +020015#include "cm.h"
16
Bryan Wu95f49652012-03-14 01:50:00 +080017#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Bryan Wu95f49652012-03-14 01:50:00 +080019#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
20#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
21
22struct integrator_led {
23 struct led_classdev cdev;
24 u8 mask;
25};
26
27/*
28 * The triggers lines up below will only be used if the
29 * LED triggers are compiled in.
30 */
31static const struct {
32 const char *name;
33 const char *trigger;
34} integrator_leds[] = {
35 { "integrator:green0", "heartbeat", },
36 { "integrator:yellow", },
37 { "integrator:red", },
38 { "integrator:green1", },
39 { "integrator:core_module", "cpu0", },
40};
41
42static void integrator_led_set(struct led_classdev *cdev,
43 enum led_brightness b)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044{
Bryan Wu95f49652012-03-14 01:50:00 +080045 struct integrator_led *led = container_of(cdev,
46 struct integrator_led, cdev);
47 u32 reg = __raw_readl(LEDREG);
Russell King1f9c3812005-05-03 12:22:19 +010048
Bryan Wu95f49652012-03-14 01:50:00 +080049 if (b != LED_OFF)
50 reg |= led->mask;
51 else
52 reg &= ~led->mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Bryan Wu95f49652012-03-14 01:50:00 +080054 while (__raw_readl(ALPHA_REG) & 1)
55 cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Bryan Wu95f49652012-03-14 01:50:00 +080057 __raw_writel(reg, LEDREG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058}
59
Bryan Wu95f49652012-03-14 01:50:00 +080060static enum led_brightness integrator_led_get(struct led_classdev *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
Bryan Wu95f49652012-03-14 01:50:00 +080062 struct integrator_led *led = container_of(cdev,
63 struct integrator_led, cdev);
64 u32 reg = __raw_readl(LEDREG);
65
66 return (reg & led->mask) ? LED_FULL : LED_OFF;
67}
68
69static void cm_led_set(struct led_classdev *cdev,
70 enum led_brightness b)
71{
72 if (b != LED_OFF)
73 cm_control(CM_CTRL_LED, CM_CTRL_LED);
74 else
75 cm_control(CM_CTRL_LED, 0);
76}
77
78static enum led_brightness cm_led_get(struct led_classdev *cdev)
79{
Linus Walleijfb61f862013-10-10 14:11:18 +020080 u32 reg = cm_get();
Bryan Wu95f49652012-03-14 01:50:00 +080081
82 return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
83}
84
85static int __init integrator_leds_init(void)
86{
87 int i;
88
89 for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
90 struct integrator_led *led;
91
92 led = kzalloc(sizeof(*led), GFP_KERNEL);
93 if (!led)
94 break;
95
96
97 led->cdev.name = integrator_leds[i].name;
98
99 if (i == 4) { /* Setting for LED in core module */
100 led->cdev.brightness_set = cm_led_set;
101 led->cdev.brightness_get = cm_led_get;
102 } else {
103 led->cdev.brightness_set = integrator_led_set;
104 led->cdev.brightness_get = integrator_led_get;
105 }
106
107 led->cdev.default_trigger = integrator_leds[i].trigger;
108 led->mask = BIT(i);
109
110 if (led_classdev_register(NULL, &led->cdev) < 0) {
111 kfree(led);
112 break;
113 }
114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 return 0;
117}
118
Bryan Wu95f49652012-03-14 01:50:00 +0800119/*
120 * Since we may have triggers on any subsystem, defer registration
121 * until after subsystem_init.
122 */
123fs_initcall(integrator_leds_init);
124#endif