diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2014-07-23 08:36:00 -0400 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2014-07-23 16:33:04 -0400 |
commit | 4da498fc65de321682396401393340fef5b9c2f6 (patch) | |
tree | 424629560a1b432dd2a39b480bfdc6e2daa7c9c0 /drivers/leds | |
parent | 5995eb6d58cf2b5c18a292f611364aefb4892aa8 (diff) |
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>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r-- | drivers/leds/Kconfig | 7 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-ipaq-micro.c | 141 |
3 files changed, 149 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index a1b044e7eaad..30e82860567a 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -143,6 +143,13 @@ config LEDS_SUNFIRE | |||
143 | This option enables support for the Left, Middle, and Right | 143 | This option enables support for the Left, Middle, and Right |
144 | LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. | 144 | LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. |
145 | 145 | ||
146 | config LEDS_IPAQ_MICRO | ||
147 | tristate "LED Support for the Compaq iPAQ h3xxx" | ||
148 | depends on MFD_IPAQ_MICRO | ||
149 | help | ||
150 | Choose this option if you want to use the notification LED on | ||
151 | Compaq/HP iPAQ h3100 and h3600. | ||
152 | |||
146 | config LEDS_HP6XX | 153 | config LEDS_HP6XX |
147 | tristate "LED Support for the HP Jornada 6xx" | 154 | tristate "LED Support for the HP Jornada 6xx" |
148 | depends on LEDS_CLASS | 155 | depends on LEDS_CLASS |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 79c5155199a7..b2a62959ff8f 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o | |||
31 | obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o | 31 | obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o |
32 | obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o | 32 | obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o |
33 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o | 33 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o |
34 | obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o | ||
34 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o | 35 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o |
35 | obj-$(CONFIG_LEDS_OT200) += leds-ot200.o | 36 | obj-$(CONFIG_LEDS_OT200) += leds-ot200.o |
36 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o | 37 | 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..3210a47f0812 --- /dev/null +++ b/drivers/leds/leds-ipaq-micro.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * h3xxx atmel micro companion support, notification LED subdevice | ||
7 | * | ||
8 | * Author : Linus Walleij <linus.walleij@linaro.org> | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/mfd/ipaq-micro.h> | ||
14 | #include <linux/leds.h> | ||
15 | |||
16 | #define LED_YELLOW 0x00 | ||
17 | #define LED_GREEN 0x01 | ||
18 | |||
19 | #define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */ | ||
20 | #define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */ | ||
21 | #define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */ | ||
22 | |||
23 | static void micro_leds_brightness_set(struct led_classdev *led_cdev, | ||
24 | enum led_brightness value) | ||
25 | { | ||
26 | struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); | ||
27 | /* | ||
28 | * In this message: | ||
29 | * Byte 0 = LED color: 0 = yellow, 1 = green | ||
30 | * yellow LED is always ~30 blinks per minute | ||
31 | * Byte 1 = duration (flags?) appears to be ignored | ||
32 | * Byte 2 = green ontime in 1/10 sec (deciseconds) | ||
33 | * 1 = 1/10 second | ||
34 | * 0 = 256/10 second | ||
35 | * Byte 3 = green offtime in 1/10 sec (deciseconds) | ||
36 | * 1 = 1/10 second | ||
37 | * 0 = 256/10 seconds | ||
38 | */ | ||
39 | struct ipaq_micro_msg msg = { | ||
40 | .id = MSG_NOTIFY_LED, | ||
41 | .tx_len = 4, | ||
42 | }; | ||
43 | |||
44 | msg.tx_data[0] = LED_GREEN; | ||
45 | msg.tx_data[1] = 0; | ||
46 | if (value) { | ||
47 | msg.tx_data[2] = 0; /* Duty cycle 256 */ | ||
48 | msg.tx_data[3] = 1; | ||
49 | } else { | ||
50 | msg.tx_data[2] = 1; | ||
51 | msg.tx_data[3] = 0; /* Duty cycle 256 */ | ||
52 | } | ||
53 | ipaq_micro_tx_msg_sync(micro, &msg); | ||
54 | } | ||
55 | |||
56 | /* Maximum duty cycle in ms 256/10 sec = 25600 ms */ | ||
57 | #define IPAQ_LED_MAX_DUTY 25600 | ||
58 | |||
59 | static int micro_leds_blink_set(struct led_classdev *led_cdev, | ||
60 | unsigned long *delay_on, | ||
61 | unsigned long *delay_off) | ||
62 | { | ||
63 | struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); | ||
64 | /* | ||
65 | * In this message: | ||
66 | * Byte 0 = LED color: 0 = yellow, 1 = green | ||
67 | * yellow LED is always ~30 blinks per minute | ||
68 | * Byte 1 = duration (flags?) appears to be ignored | ||
69 | * Byte 2 = green ontime in 1/10 sec (deciseconds) | ||
70 | * 1 = 1/10 second | ||
71 | * 0 = 256/10 second | ||
72 | * Byte 3 = green offtime in 1/10 sec (deciseconds) | ||
73 | * 1 = 1/10 second | ||
74 | * 0 = 256/10 seconds | ||
75 | */ | ||
76 | struct ipaq_micro_msg msg = { | ||
77 | .id = MSG_NOTIFY_LED, | ||
78 | .tx_len = 4, | ||
79 | }; | ||
80 | |||
81 | msg.tx_data[0] = LED_GREEN; | ||
82 | if (*delay_on > IPAQ_LED_MAX_DUTY || | ||
83 | *delay_off > IPAQ_LED_MAX_DUTY) | ||
84 | return -EINVAL; | ||
85 | |||
86 | if (*delay_on == 0 && *delay_off == 0) { | ||
87 | *delay_on = 100; | ||
88 | *delay_off = 100; | ||
89 | } | ||
90 | |||
91 | msg.tx_data[1] = 0; | ||
92 | if (*delay_on >= IPAQ_LED_MAX_DUTY) | ||
93 | msg.tx_data[2] = 0; | ||
94 | else | ||
95 | msg.tx_data[2] = (u8) DIV_ROUND_CLOSEST(*delay_on, 100); | ||
96 | if (*delay_off >= IPAQ_LED_MAX_DUTY) | ||
97 | msg.tx_data[3] = 0; | ||
98 | else | ||
99 | msg.tx_data[3] = (u8) DIV_ROUND_CLOSEST(*delay_off, 100); | ||
100 | return ipaq_micro_tx_msg_sync(micro, &msg); | ||
101 | } | ||
102 | |||
103 | static struct led_classdev micro_led = { | ||
104 | .name = "led-ipaq-micro", | ||
105 | .brightness_set = micro_leds_brightness_set, | ||
106 | .blink_set = micro_leds_blink_set, | ||
107 | .flags = LED_CORE_SUSPENDRESUME, | ||
108 | }; | ||
109 | |||
110 | static int micro_leds_probe(struct platform_device *pdev) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | ret = led_classdev_register(&pdev->dev, µ_led); | ||
115 | if (ret) { | ||
116 | dev_err(&pdev->dev, "registering led failed: %d\n", ret); | ||
117 | return ret; | ||
118 | } | ||
119 | dev_info(&pdev->dev, "iPAQ micro notification LED driver\n"); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int micro_leds_remove(struct platform_device *pdev) | ||
125 | { | ||
126 | led_classdev_unregister(µ_led); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | struct platform_driver micro_leds_device_driver = { | ||
131 | .driver = { | ||
132 | .name = "ipaq-micro-leds", | ||
133 | }, | ||
134 | .probe = micro_leds_probe, | ||
135 | .remove = micro_leds_remove, | ||
136 | }; | ||
137 | module_platform_driver(micro_leds_device_driver); | ||
138 | |||
139 | MODULE_LICENSE("GPL"); | ||
140 | MODULE_DESCRIPTION("driver for iPAQ Atmel micro leds"); | ||
141 | MODULE_ALIAS("platform:ipaq-micro-leds"); | ||