aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-yocto-dev/h3600/0006-leds-add-driver-for-the-iPAQ-micro.patch
blob: 212d3660ee45b118e49ab14eafc7341c857bbe47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
From b4c8a1cdfbbaf615a6d9da3e46f1b788fc0f1568 Mon Sep 17 00:00:00 2001
From: Linus Walleij <linus.walleij@linaro.org>
Date: Thu, 31 Oct 2013 10:53:06 -0700
Subject: [PATCH 6/7] leds: add driver for the iPAQ micro

This adds a driver for the iPAQ microcontroller LED.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/leds/Kconfig           |   7 +++
 drivers/leds/Makefile          |   1 +
 drivers/leds/leds-ipaq-micro.c | 139 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+)
 create mode 100644 drivers/leds/leds-ipaq-micro.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 72156c123033..39dae8a15297 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -143,6 +143,13 @@ config LEDS_SUNFIRE
 	  This option enables support for the Left, Middle, and Right
 	  LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
 
+config LEDS_IPAQ_MICRO
+	tristate "LED Support for the Compaq iPAQ h3xxx"
+	depends on MFD_IPAQ_MICRO
+	help
+	  Choose this option if you want to use the notification LED on
+	  Compaq/HP iPAQ h3100 and h3600.
+
 config LEDS_HP6XX
 	tristate "LED Support for the HP Jornada 6xx"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3cd76dbd9be2..db0e6e856ca9 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS_LP8501)		+= leds-lp8501.o
 obj-$(CONFIG_LEDS_LP8788)		+= leds-lp8788.o
 obj-$(CONFIG_LEDS_TCA6507)		+= leds-tca6507.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)		+= leds-clevo-mail.o
+obj-$(CONFIG_LEDS_IPAQ_MICRO)		+= leds-ipaq-micro.o
 obj-$(CONFIG_LEDS_HP6XX)		+= leds-hp6xx.o
 obj-$(CONFIG_LEDS_OT200)		+= leds-ot200.o
 obj-$(CONFIG_LEDS_FSG)			+= leds-fsg.o
diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c
new file mode 100644
index 000000000000..a716ec27f066
--- /dev/null
+++ b/drivers/leds/leds-ipaq-micro.c
@@ -0,0 +1,139 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * h3xxx atmel micro companion support, notification LED subdevice
+ *
+ * Author : Linus Walleij <linus.walleij@linaro.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ipaq-micro.h>
+#include <linux/leds.h>
+
+#define LED_YELLOW	0x00
+#define LED_GREEN	0x01
+
+#define LED_EN          (1 << 4)        /* LED ON/OFF 0:off, 1:on                       */
+#define LED_AUTOSTOP    (1 << 5)        /* LED ON/OFF auto stop set 0:disable, 1:enable */
+#define LED_ALWAYS      (1 << 6)        /* LED Interrupt Mask 0:No mask, 1:mask         */
+
+static void micro_leds_brightness_set(struct led_classdev *led_cdev,
+				      enum led_brightness value)
+{
+	struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent);
+	/*
+	 * In this message:
+	 * Byte 0 = LED color: 0 = yellow, 1 = green
+	 *          yellow LED is always ~30 blinks per minute
+	 * Byte 1 = duration (flags?) appears to be ignored
+	 * Byte 2 = green ontime in 1/10 sec (deciseconds)
+	 *          1 = 1/10 second
+	 *          0 = 256/10 second
+	 * Byte 3 = green offtime in 1/10 sec (deciseconds)
+	 *          1 = 1/10 second
+	 *          0 = 256/10 seconds
+	 */
+	struct ipaq_micro_msg msg = {
+		.id = MSG_NOTIFY_LED,
+		.tx_len = 4,
+	};
+
+	msg.tx_data[0] = LED_GREEN;
+	msg.tx_data[1] = 0;
+	if (value) {
+		msg.tx_data[2] = 0; /* Duty cycle 256 */
+		msg.tx_data[3] = 1;
+	} else {
+		msg.tx_data[2] = 1;
+		msg.tx_data[3] = 0; /* Duty cycle 256 */
+	}
+	ipaq_micro_tx_msg_sync(micro, &msg);
+}
+
+/* Maximum duty cycle in ms 256/10 sec = 25600 ms */
+#define IPAQ_LED_MAX_DUTY 25600
+
+static int micro_leds_blink_set(struct led_classdev *led_cdev,
+				unsigned long *delay_on,
+				unsigned long *delay_off)
+{
+	struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent);
+	/*
+	 * In this message:
+	 * Byte 0 = LED color: 0 = yellow, 1 = green
+	 *          yellow LED is always ~30 blinks per minute
+	 * Byte 1 = duration (flags?) appears to be ignored
+	 * Byte 2 = green ontime in 1/10 sec (deciseconds)
+	 *          1 = 1/10 second
+	 *          0 = 256/10 second
+	 * Byte 3 = green offtime in 1/10 sec (deciseconds)
+	 *          1 = 1/10 second
+	 *          0 = 256/10 seconds
+	 */
+	struct ipaq_micro_msg msg = {
+		.id = MSG_NOTIFY_LED,
+		.tx_len = 4,
+	};
+
+	msg.tx_data[0] = LED_GREEN;
+        if (*delay_on > IPAQ_LED_MAX_DUTY ||
+	    *delay_off > IPAQ_LED_MAX_DUTY)
+                return -EINVAL;
+
+        if (*delay_on == 0 && *delay_off == 0) {
+                *delay_on = 100;
+                *delay_off = 100;
+        }
+
+	msg.tx_data[1] = 0;
+	if (*delay_on >= IPAQ_LED_MAX_DUTY)
+		msg.tx_data[2] = 0;
+	else
+		msg.tx_data[2] = (u8) DIV_ROUND_CLOSEST(*delay_on, 100);
+	if (*delay_off >= IPAQ_LED_MAX_DUTY)
+		msg.tx_data[3] = 0;
+	else
+		msg.tx_data[3] = (u8) DIV_ROUND_CLOSEST(*delay_off, 100);
+	return ipaq_micro_tx_msg_sync(micro, &msg);
+}
+
+static struct led_classdev micro_led = {
+	.name			= "notify",
+	.brightness_set		= micro_leds_brightness_set,
+	.blink_set		= micro_leds_blink_set,
+	.flags			= LED_CORE_SUSPENDRESUME,
+};
+
+static int micro_leds_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = led_classdev_register(&pdev->dev, &micro_led);
+	if (ret)
+		dev_err(&pdev->dev, "registering led failed: %d\n", ret);
+	dev_info(&pdev->dev, "iPAQ micro notification LED driver\n");
+
+	return 0;
+}
+
+static int micro_leds_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&micro_led);
+	return 0;
+}
+
+struct platform_driver micro_leds_device_driver = {
+	.driver = {
+		.name    = "ipaq-micro-leds",
+	},
+	.probe   = micro_leds_probe,
+	.remove  = micro_leds_remove,
+};
+module_platform_driver(micro_leds_device_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("driver for iPAQ Atmel micro leds");
+MODULE_ALIAS("platform:ipaq-micro-leds");
-- 
1.9.0