diff options
27 files changed, 644 insertions, 169 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r new file mode 100644 index 000000000000..e4fae6026e79 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | What: /sys/class/leds/<led>/gt683r/mode | ||
| 2 | Date: Jun 2014 | ||
| 3 | KernelVersion: 3.17 | ||
| 4 | Contact: Janne Kanniainen <janne.kanniainen@gmail.com> | ||
| 5 | Description: | ||
| 6 | Set the mode of LEDs. You should notice that changing the mode | ||
| 7 | of one LED will update the mode of its two sibling devices as | ||
| 8 | well. | ||
| 9 | |||
| 10 | 0 - normal | ||
| 11 | 1 - audio | ||
| 12 | 2 - breathing | ||
| 13 | |||
| 14 | Normal: LEDs are fully on when enabled | ||
| 15 | Audio: LEDs brightness depends on sound level | ||
| 16 | Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file | ||
diff --git a/Documentation/devicetree/bindings/leds/pca963x.txt b/Documentation/devicetree/bindings/leds/pca963x.txt index aece3eac1b63..dafbe9931c2b 100644 --- a/Documentation/devicetree/bindings/leds/pca963x.txt +++ b/Documentation/devicetree/bindings/leds/pca963x.txt | |||
| @@ -1,18 +1,19 @@ | |||
| 1 | LEDs connected to pca9632, pca9633 or pca9634 | 1 | LEDs connected to pca9632, pca9633 or pca9634 |
| 2 | 2 | ||
| 3 | Required properties: | 3 | Required properties: |
| 4 | - compatible : should be : "nxp,pca9632", "nxp,pca9633" or "nxp,pca9634" | 4 | - compatible : should be : "nxp,pca9632", "nxp,pca9633", "nxp,pca9634" or "nxp,pca9635" |
| 5 | 5 | ||
| 6 | Optional properties: | 6 | Optional properties: |
| 7 | - nxp,totem-pole : use totem pole (push-pull) instead of default open-drain | 7 | - nxp,totem-pole : use totem pole (push-pull) instead of open-drain (pca9632 defaults |
| 8 | to open-drain, newer chips to totem pole) | ||
| 8 | - nxp,hw-blink : use hardware blinking instead of software blinking | 9 | - nxp,hw-blink : use hardware blinking instead of software blinking |
| 9 | 10 | ||
| 10 | Each led is represented as a sub-node of the nxp,pca963x device. | 11 | Each led is represented as a sub-node of the nxp,pca963x device. |
| 11 | 12 | ||
| 12 | LED sub-node properties: | 13 | LED sub-node properties: |
| 13 | - label : (optional) see Documentation/devicetree/bindings/leds/common.txt | 14 | - label : (optional) see Documentation/devicetree/bindings/leds/common.txt |
| 14 | - reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633 | 15 | - reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633, |
| 15 | or 0 to 7 in pca9634) | 16 | 0 to 7 in pca9634, or 0 to 15 in pca9635) |
| 16 | - linux,default-trigger : (optional) | 17 | - linux,default-trigger : (optional) |
| 17 | see Documentation/devicetree/bindings/leds/common.txt | 18 | see Documentation/devicetree/bindings/leds/common.txt |
| 18 | 19 | ||
diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt index d7221b84987c..bad9102796f3 100644 --- a/Documentation/devicetree/bindings/leds/tca6507.txt +++ b/Documentation/devicetree/bindings/leds/tca6507.txt | |||
| @@ -8,7 +8,7 @@ Required properties: | |||
| 8 | 8 | ||
| 9 | Optional properties: | 9 | Optional properties: |
| 10 | - gpio-controller: allows lines to be used as output-only GPIOs. | 10 | - gpio-controller: allows lines to be used as output-only GPIOs. |
| 11 | - #gpio-cells: if present, must be 0. | 11 | - #gpio-cells: if present, must not be 0. |
| 12 | 12 | ||
| 13 | Each led is represented as a sub-node of the ti,tca6507 device. | 13 | Each led is represented as a sub-node of the ti,tca6507 device. |
| 14 | 14 | ||
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e02cf59b048d..ec48c823b157 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
| @@ -261,6 +261,20 @@ config HOLTEK_FF | |||
| 261 | Say Y here if you have a Holtek On Line Grip based game controller | 261 | Say Y here if you have a Holtek On Line Grip based game controller |
| 262 | and want to have force feedback support for it. | 262 | and want to have force feedback support for it. |
| 263 | 263 | ||
| 264 | config HID_GT683R | ||
| 265 | tristate "MSI GT68xR LED support" | ||
| 266 | depends on LEDS_CLASS && USB_HID | ||
| 267 | ---help--- | ||
| 268 | Say Y here if you want to enable support for the three MSI GT68xR LEDs | ||
| 269 | |||
| 270 | This driver support following modes: | ||
| 271 | - Normal: LEDs are fully on when enabled | ||
| 272 | - Audio: LEDs brightness depends on sound level | ||
| 273 | - Breathing: LEDs brightness varies at human breathing rate | ||
| 274 | |||
| 275 | Currently the following devices are know to be supported: | ||
| 276 | - MSI GT683R | ||
| 277 | |||
| 264 | config HID_HUION | 278 | config HID_HUION |
| 265 | tristate "Huion tablets" | 279 | tristate "Huion tablets" |
| 266 | depends on USB_HID | 280 | depends on USB_HID |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 5e96be3ab280..a69f0adb5c76 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
| @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o | |||
| 48 | obj-$(CONFIG_HID_ELECOM) += hid-elecom.o | 48 | obj-$(CONFIG_HID_ELECOM) += hid-elecom.o |
| 49 | obj-$(CONFIG_HID_ELO) += hid-elo.o | 49 | obj-$(CONFIG_HID_ELO) += hid-elo.o |
| 50 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o | 50 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o |
| 51 | obj-$(CONFIG_HID_GT683R) += hid-gt683r.o | ||
| 51 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o | 52 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o |
| 52 | obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o | 53 | obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o |
| 53 | obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o | 54 | obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6c813c6092f8..b52baa120ffa 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -1849,6 +1849,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1849 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, | 1849 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, |
| 1850 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, | 1850 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, |
| 1851 | { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, | 1851 | { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, |
| 1852 | { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, | ||
| 1852 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, | 1853 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, |
| 1853 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, | 1854 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, |
| 1854 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, | 1855 | { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, |
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 000000000000..0d6f135e266c --- /dev/null +++ b/drivers/hid/hid-gt683r.c | |||
| @@ -0,0 +1,321 @@ | |||
| 1 | /* | ||
| 2 | * MSI GT683R led driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation; either version 2 of | ||
| 9 | * the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/hid.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/leds.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | |||
| 24 | #include "hid-ids.h" | ||
| 25 | |||
| 26 | #define GT683R_BUFFER_SIZE 8 | ||
| 27 | |||
| 28 | /* | ||
| 29 | * GT683R_LED_OFF: all LEDs are off | ||
| 30 | * GT683R_LED_AUDIO: LEDs brightness depends on sound level | ||
| 31 | * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate | ||
| 32 | * GT683R_LED_NORMAL: LEDs are fully on when enabled | ||
| 33 | */ | ||
| 34 | enum gt683r_led_mode { | ||
| 35 | GT683R_LED_OFF = 0, | ||
| 36 | GT683R_LED_AUDIO = 2, | ||
| 37 | GT683R_LED_BREATHING = 3, | ||
| 38 | GT683R_LED_NORMAL = 5 | ||
| 39 | }; | ||
| 40 | |||
| 41 | enum gt683r_panels { | ||
| 42 | GT683R_LED_BACK = 0, | ||
| 43 | GT683R_LED_SIDE = 1, | ||
| 44 | GT683R_LED_FRONT = 2, | ||
| 45 | GT683R_LED_COUNT, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const char * const gt683r_panel_names[] = { | ||
| 49 | "back", | ||
| 50 | "side", | ||
| 51 | "front", | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct gt683r_led { | ||
| 55 | struct hid_device *hdev; | ||
| 56 | struct led_classdev led_devs[GT683R_LED_COUNT]; | ||
| 57 | struct mutex lock; | ||
| 58 | struct work_struct work; | ||
| 59 | enum led_brightness brightnesses[GT683R_LED_COUNT]; | ||
| 60 | enum gt683r_led_mode mode; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static const struct hid_device_id gt683r_led_id[] = { | ||
| 64 | { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, | ||
| 65 | { } | ||
| 66 | }; | ||
| 67 | |||
| 68 | static void gt683r_brightness_set(struct led_classdev *led_cdev, | ||
| 69 | enum led_brightness brightness) | ||
| 70 | { | ||
| 71 | int i; | ||
| 72 | struct device *dev = led_cdev->dev->parent; | ||
| 73 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
| 74 | struct gt683r_led *led = hid_get_drvdata(hdev); | ||
| 75 | |||
| 76 | for (i = 0; i < GT683R_LED_COUNT; i++) { | ||
| 77 | if (led_cdev == &led->led_devs[i]) | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (i < GT683R_LED_COUNT) { | ||
| 82 | led->brightnesses[i] = brightness; | ||
| 83 | schedule_work(&led->work); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | static ssize_t mode_show(struct device *dev, | ||
| 88 | struct device_attribute *attr, | ||
| 89 | char *buf) | ||
| 90 | { | ||
| 91 | u8 sysfs_mode; | ||
| 92 | struct hid_device *hdev = container_of(dev->parent, | ||
| 93 | struct hid_device, dev); | ||
| 94 | struct gt683r_led *led = hid_get_drvdata(hdev); | ||
| 95 | |||
| 96 | if (led->mode == GT683R_LED_NORMAL) | ||
| 97 | sysfs_mode = 0; | ||
| 98 | else if (led->mode == GT683R_LED_AUDIO) | ||
| 99 | sysfs_mode = 1; | ||
| 100 | else | ||
| 101 | sysfs_mode = 2; | ||
| 102 | |||
| 103 | return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); | ||
| 104 | } | ||
| 105 | |||
| 106 | static ssize_t mode_store(struct device *dev, | ||
| 107 | struct device_attribute *attr, | ||
| 108 | const char *buf, size_t count) | ||
| 109 | { | ||
| 110 | u8 sysfs_mode; | ||
| 111 | struct hid_device *hdev = container_of(dev->parent, | ||
| 112 | struct hid_device, dev); | ||
| 113 | struct gt683r_led *led = hid_get_drvdata(hdev); | ||
| 114 | |||
| 115 | |||
| 116 | if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) | ||
| 117 | return -EINVAL; | ||
| 118 | |||
| 119 | mutex_lock(&led->lock); | ||
| 120 | |||
| 121 | if (sysfs_mode == 0) | ||
| 122 | led->mode = GT683R_LED_NORMAL; | ||
| 123 | else if (sysfs_mode == 1) | ||
| 124 | led->mode = GT683R_LED_AUDIO; | ||
| 125 | else | ||
| 126 | led->mode = GT683R_LED_BREATHING; | ||
| 127 | |||
| 128 | mutex_unlock(&led->lock); | ||
| 129 | schedule_work(&led->work); | ||
| 130 | |||
| 131 | return count; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) | ||
| 135 | { | ||
| 136 | int ret; | ||
| 137 | |||
| 138 | ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, | ||
| 139 | HID_FEATURE_REPORT, HID_REQ_SET_REPORT); | ||
| 140 | if (ret != GT683R_BUFFER_SIZE) { | ||
| 141 | hid_err(led->hdev, | ||
| 142 | "failed to send set report request: %i\n", ret); | ||
| 143 | if (ret < 0) | ||
| 144 | return ret; | ||
| 145 | return -EIO; | ||
| 146 | } | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int gt683r_leds_set(struct gt683r_led *led, u8 leds) | ||
| 152 | { | ||
| 153 | int ret; | ||
| 154 | u8 *buffer; | ||
| 155 | |||
| 156 | buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); | ||
| 157 | if (!buffer) | ||
| 158 | return -ENOMEM; | ||
| 159 | |||
| 160 | buffer[0] = 0x01; | ||
| 161 | buffer[1] = 0x02; | ||
| 162 | buffer[2] = 0x30; | ||
| 163 | buffer[3] = leds; | ||
| 164 | ret = gt683r_led_snd_msg(led, buffer); | ||
| 165 | |||
| 166 | kfree(buffer); | ||
| 167 | return ret; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int gt683r_mode_set(struct gt683r_led *led, u8 mode) | ||
| 171 | { | ||
| 172 | int ret; | ||
| 173 | u8 *buffer; | ||
| 174 | |||
| 175 | buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); | ||
| 176 | if (!buffer) | ||
| 177 | return -ENOMEM; | ||
| 178 | |||
| 179 | buffer[0] = 0x01; | ||
| 180 | buffer[1] = 0x02; | ||
| 181 | buffer[2] = 0x20; | ||
| 182 | buffer[3] = mode; | ||
| 183 | buffer[4] = 0x01; | ||
| 184 | ret = gt683r_led_snd_msg(led, buffer); | ||
| 185 | |||
| 186 | kfree(buffer); | ||
| 187 | return ret; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void gt683r_led_work(struct work_struct *work) | ||
| 191 | { | ||
| 192 | int i; | ||
| 193 | u8 leds = 0; | ||
| 194 | u8 mode; | ||
| 195 | struct gt683r_led *led = container_of(work, struct gt683r_led, work); | ||
| 196 | |||
| 197 | mutex_lock(&led->lock); | ||
| 198 | |||
| 199 | for (i = 0; i < GT683R_LED_COUNT; i++) { | ||
| 200 | if (led->brightnesses[i]) | ||
| 201 | leds |= BIT(i); | ||
| 202 | } | ||
| 203 | |||
| 204 | if (gt683r_leds_set(led, leds)) | ||
| 205 | goto fail; | ||
| 206 | |||
| 207 | if (leds) | ||
| 208 | mode = led->mode; | ||
| 209 | else | ||
| 210 | mode = GT683R_LED_OFF; | ||
| 211 | |||
| 212 | gt683r_mode_set(led, mode); | ||
| 213 | fail: | ||
| 214 | mutex_unlock(&led->lock); | ||
| 215 | } | ||
| 216 | |||
| 217 | static DEVICE_ATTR_RW(mode); | ||
| 218 | |||
| 219 | static struct attribute *gt683r_led_attrs[] = { | ||
| 220 | &dev_attr_mode.attr, | ||
| 221 | NULL | ||
| 222 | }; | ||
| 223 | |||
| 224 | static const struct attribute_group gt683r_led_group = { | ||
| 225 | .name = "gt683r", | ||
| 226 | .attrs = gt683r_led_attrs, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static const struct attribute_group *gt683r_led_groups[] = { | ||
| 230 | >683r_led_group, | ||
| 231 | NULL | ||
| 232 | }; | ||
| 233 | |||
| 234 | static int gt683r_led_probe(struct hid_device *hdev, | ||
| 235 | const struct hid_device_id *id) | ||
| 236 | { | ||
| 237 | int i; | ||
| 238 | int ret; | ||
| 239 | int name_sz; | ||
| 240 | char *name; | ||
| 241 | struct gt683r_led *led; | ||
| 242 | |||
| 243 | led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); | ||
| 244 | if (!led) | ||
| 245 | return -ENOMEM; | ||
| 246 | |||
| 247 | mutex_init(&led->lock); | ||
| 248 | INIT_WORK(&led->work, gt683r_led_work); | ||
| 249 | |||
| 250 | led->mode = GT683R_LED_NORMAL; | ||
| 251 | led->hdev = hdev; | ||
| 252 | hid_set_drvdata(hdev, led); | ||
| 253 | |||
| 254 | ret = hid_parse(hdev); | ||
| 255 | if (ret) { | ||
| 256 | hid_err(hdev, "hid parsing failed\n"); | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | |||
| 260 | ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); | ||
| 261 | if (ret) { | ||
| 262 | hid_err(hdev, "hw start failed\n"); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 266 | for (i = 0; i < GT683R_LED_COUNT; i++) { | ||
| 267 | name_sz = strlen(dev_name(&hdev->dev)) + | ||
| 268 | strlen(gt683r_panel_names[i]) + 3; | ||
| 269 | |||
| 270 | name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); | ||
| 271 | if (!name) { | ||
| 272 | ret = -ENOMEM; | ||
| 273 | goto fail; | ||
| 274 | } | ||
| 275 | |||
| 276 | snprintf(name, name_sz, "%s::%s", | ||
| 277 | dev_name(&hdev->dev), gt683r_panel_names[i]); | ||
| 278 | led->led_devs[i].name = name; | ||
| 279 | led->led_devs[i].max_brightness = 1; | ||
| 280 | led->led_devs[i].brightness_set = gt683r_brightness_set; | ||
| 281 | led->led_devs[i].groups = gt683r_led_groups; | ||
| 282 | |||
| 283 | ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); | ||
| 284 | if (ret) { | ||
| 285 | hid_err(hdev, "could not register led device\n"); | ||
| 286 | goto fail; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | |||
| 292 | fail: | ||
| 293 | for (i = i - 1; i >= 0; i--) | ||
| 294 | led_classdev_unregister(&led->led_devs[i]); | ||
| 295 | hid_hw_stop(hdev); | ||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | |||
| 299 | static void gt683r_led_remove(struct hid_device *hdev) | ||
| 300 | { | ||
| 301 | int i; | ||
| 302 | struct gt683r_led *led = hid_get_drvdata(hdev); | ||
| 303 | |||
| 304 | for (i = 0; i < GT683R_LED_COUNT; i++) | ||
| 305 | led_classdev_unregister(&led->led_devs[i]); | ||
| 306 | flush_work(&led->work); | ||
| 307 | hid_hw_stop(hdev); | ||
| 308 | } | ||
| 309 | |||
| 310 | static struct hid_driver gt683r_led_driver = { | ||
| 311 | .probe = gt683r_led_probe, | ||
| 312 | .remove = gt683r_led_remove, | ||
| 313 | .name = "gt683r_led", | ||
| 314 | .id_table = gt683r_led_id, | ||
| 315 | }; | ||
| 316 | |||
| 317 | module_hid_driver(gt683r_led_driver); | ||
| 318 | |||
| 319 | MODULE_AUTHOR("Janne Kanniainen"); | ||
| 320 | MODULE_DESCRIPTION("MSI GT683R led driver"); | ||
| 321 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d53bdda26207..25cd674d6064 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -650,7 +650,7 @@ | |||
| 650 | #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 | 650 | #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 |
| 651 | 651 | ||
| 652 | #define USB_VENDOR_ID_MSI 0x1770 | 652 | #define USB_VENDOR_ID_MSI 0x1770 |
| 653 | #define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 | 653 | #define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 |
| 654 | 654 | ||
| 655 | #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 | 655 | #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 |
| 656 | #define USB_DEVICE_ID_N_S_HARMONY 0xc359 | 656 | #define USB_DEVICE_ID_N_S_HARMONY 0xc359 |
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0dd568170d6e..15225f3eaed1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
| @@ -74,7 +74,7 @@ static const struct hid_blacklist { | |||
| 74 | { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, | 74 | { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, |
| 75 | { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, | 75 | { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, |
| 76 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, | 76 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, |
| 77 | { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, | 77 | { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, |
| 78 | { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, | 78 | { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, |
| 79 | { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, | 79 | { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, |
| 80 | { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET }, | 80 | { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET }, |
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 0b42118cbf8f..cb32e2b506b7 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c | |||
| @@ -558,6 +558,12 @@ static ssize_t lm8323_pwm_store_time(struct device *dev, | |||
| 558 | } | 558 | } |
| 559 | static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time); | 559 | static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time); |
| 560 | 560 | ||
| 561 | static struct attribute *lm8323_pwm_attrs[] = { | ||
| 562 | &dev_attr_time.attr, | ||
| 563 | NULL | ||
| 564 | }; | ||
| 565 | ATTRIBUTE_GROUPS(lm8323_pwm); | ||
| 566 | |||
| 561 | static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, | 567 | static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, |
| 562 | const char *name) | 568 | const char *name) |
| 563 | { | 569 | { |
| @@ -580,16 +586,11 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, | |||
| 580 | if (name) { | 586 | if (name) { |
| 581 | pwm->cdev.name = name; | 587 | pwm->cdev.name = name; |
| 582 | pwm->cdev.brightness_set = lm8323_pwm_set_brightness; | 588 | pwm->cdev.brightness_set = lm8323_pwm_set_brightness; |
| 589 | pwm->cdev.groups = lm8323_pwm_groups; | ||
| 583 | if (led_classdev_register(dev, &pwm->cdev) < 0) { | 590 | if (led_classdev_register(dev, &pwm->cdev) < 0) { |
| 584 | dev_err(dev, "couldn't register PWM %d\n", id); | 591 | dev_err(dev, "couldn't register PWM %d\n", id); |
| 585 | return -1; | 592 | return -1; |
| 586 | } | 593 | } |
| 587 | if (device_create_file(pwm->cdev.dev, | ||
| 588 | &dev_attr_time) < 0) { | ||
| 589 | dev_err(dev, "couldn't register time attribute\n"); | ||
| 590 | led_classdev_unregister(&pwm->cdev); | ||
| 591 | return -1; | ||
| 592 | } | ||
| 593 | pwm->enabled = true; | 594 | pwm->enabled = true; |
| 594 | } | 595 | } |
| 595 | 596 | ||
| @@ -753,11 +754,8 @@ fail3: | |||
| 753 | device_remove_file(&client->dev, &dev_attr_disable_kp); | 754 | device_remove_file(&client->dev, &dev_attr_disable_kp); |
| 754 | fail2: | 755 | fail2: |
| 755 | while (--pwm >= 0) | 756 | while (--pwm >= 0) |
| 756 | if (lm->pwm[pwm].enabled) { | 757 | if (lm->pwm[pwm].enabled) |
| 757 | device_remove_file(lm->pwm[pwm].cdev.dev, | ||
| 758 | &dev_attr_time); | ||
| 759 | led_classdev_unregister(&lm->pwm[pwm].cdev); | 758 | led_classdev_unregister(&lm->pwm[pwm].cdev); |
| 760 | } | ||
| 761 | fail1: | 759 | fail1: |
| 762 | input_free_device(idev); | 760 | input_free_device(idev); |
| 763 | kfree(lm); | 761 | kfree(lm); |
| @@ -777,10 +775,8 @@ static int lm8323_remove(struct i2c_client *client) | |||
| 777 | device_remove_file(&lm->client->dev, &dev_attr_disable_kp); | 775 | device_remove_file(&lm->client->dev, &dev_attr_disable_kp); |
| 778 | 776 | ||
| 779 | for (i = 0; i < 3; i++) | 777 | for (i = 0; i < 3; i++) |
| 780 | if (lm->pwm[i].enabled) { | 778 | if (lm->pwm[i].enabled) |
| 781 | device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time); | ||
| 782 | led_classdev_unregister(&lm->pwm[i].cdev); | 779 | led_classdev_unregister(&lm->pwm[i].cdev); |
| 783 | } | ||
| 784 | 780 | ||
| 785 | kfree(lm); | 781 | kfree(lm); |
| 786 | 782 | ||
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/led-class.c b/drivers/leds/led-class.c index f37d63cf726b..129729d35478 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c | |||
| @@ -15,10 +15,10 @@ | |||
| 15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/timer.h> | ||
| 19 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 20 | #include <linux/ctype.h> | 19 | #include <linux/ctype.h> |
| 21 | #include <linux/leds.h> | 20 | #include <linux/leds.h> |
| 21 | #include <linux/workqueue.h> | ||
| 22 | #include "leds.h" | 22 | #include "leds.h" |
| 23 | 23 | ||
| 24 | static struct class *leds_class; | 24 | static struct class *leds_class; |
| @@ -97,9 +97,10 @@ static const struct attribute_group *led_groups[] = { | |||
| 97 | NULL, | 97 | NULL, |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | static void led_timer_function(unsigned long data) | 100 | static void led_work_function(struct work_struct *ws) |
| 101 | { | 101 | { |
| 102 | struct led_classdev *led_cdev = (void *)data; | 102 | struct led_classdev *led_cdev = |
| 103 | container_of(ws, struct led_classdev, blink_work.work); | ||
| 103 | unsigned long brightness; | 104 | unsigned long brightness; |
| 104 | unsigned long delay; | 105 | unsigned long delay; |
| 105 | 106 | ||
| @@ -143,7 +144,8 @@ static void led_timer_function(unsigned long data) | |||
| 143 | } | 144 | } |
| 144 | } | 145 | } |
| 145 | 146 | ||
| 146 | mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); | 147 | queue_delayed_work(system_wq, &led_cdev->blink_work, |
| 148 | msecs_to_jiffies(delay)); | ||
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | static void set_brightness_delayed(struct work_struct *ws) | 151 | static void set_brightness_delayed(struct work_struct *ws) |
| @@ -210,8 +212,9 @@ static const struct dev_pm_ops leds_class_dev_pm_ops = { | |||
| 210 | */ | 212 | */ |
| 211 | int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | 213 | int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) |
| 212 | { | 214 | { |
| 213 | led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, | 215 | led_cdev->dev = device_create_with_groups(leds_class, parent, 0, |
| 214 | "%s", led_cdev->name); | 216 | led_cdev, led_cdev->groups, |
| 217 | "%s", led_cdev->name); | ||
| 215 | if (IS_ERR(led_cdev->dev)) | 218 | if (IS_ERR(led_cdev->dev)) |
| 216 | return PTR_ERR(led_cdev->dev); | 219 | return PTR_ERR(led_cdev->dev); |
| 217 | 220 | ||
| @@ -230,9 +233,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | |||
| 230 | 233 | ||
| 231 | INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed); | 234 | INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed); |
| 232 | 235 | ||
| 233 | init_timer(&led_cdev->blink_timer); | 236 | INIT_DELAYED_WORK(&led_cdev->blink_work, led_work_function); |
| 234 | led_cdev->blink_timer.function = led_timer_function; | ||
| 235 | led_cdev->blink_timer.data = (unsigned long)led_cdev; | ||
| 236 | 237 | ||
| 237 | #ifdef CONFIG_LEDS_TRIGGERS | 238 | #ifdef CONFIG_LEDS_TRIGGERS |
| 238 | led_trigger_set_default(led_cdev); | 239 | led_trigger_set_default(led_cdev); |
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 71b40d3bf776..4bb116867b88 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/rwsem.h> | 17 | #include <linux/rwsem.h> |
| 18 | #include <linux/leds.h> | 18 | #include <linux/leds.h> |
| 19 | #include <linux/workqueue.h> | ||
| 19 | #include "leds.h" | 20 | #include "leds.h" |
| 20 | 21 | ||
| 21 | DECLARE_RWSEM(leds_list_lock); | 22 | DECLARE_RWSEM(leds_list_lock); |
| @@ -51,7 +52,7 @@ static void led_set_software_blink(struct led_classdev *led_cdev, | |||
| 51 | return; | 52 | return; |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | mod_timer(&led_cdev->blink_timer, jiffies + 1); | 55 | queue_delayed_work(system_wq, &led_cdev->blink_work, 1); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | 58 | ||
| @@ -75,7 +76,7 @@ void led_blink_set(struct led_classdev *led_cdev, | |||
| 75 | unsigned long *delay_on, | 76 | unsigned long *delay_on, |
| 76 | unsigned long *delay_off) | 77 | unsigned long *delay_off) |
| 77 | { | 78 | { |
| 78 | del_timer_sync(&led_cdev->blink_timer); | 79 | cancel_delayed_work_sync(&led_cdev->blink_work); |
| 79 | 80 | ||
| 80 | led_cdev->flags &= ~LED_BLINK_ONESHOT; | 81 | led_cdev->flags &= ~LED_BLINK_ONESHOT; |
| 81 | led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; | 82 | led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; |
| @@ -90,7 +91,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev, | |||
| 90 | int invert) | 91 | int invert) |
| 91 | { | 92 | { |
| 92 | if ((led_cdev->flags & LED_BLINK_ONESHOT) && | 93 | if ((led_cdev->flags & LED_BLINK_ONESHOT) && |
| 93 | timer_pending(&led_cdev->blink_timer)) | 94 | delayed_work_pending(&led_cdev->blink_work)) |
| 94 | return; | 95 | return; |
| 95 | 96 | ||
| 96 | led_cdev->flags |= LED_BLINK_ONESHOT; | 97 | led_cdev->flags |= LED_BLINK_ONESHOT; |
| @@ -107,7 +108,7 @@ EXPORT_SYMBOL(led_blink_set_oneshot); | |||
| 107 | 108 | ||
| 108 | void led_stop_software_blink(struct led_classdev *led_cdev) | 109 | void led_stop_software_blink(struct led_classdev *led_cdev) |
| 109 | { | 110 | { |
| 110 | del_timer_sync(&led_cdev->blink_timer); | 111 | cancel_delayed_work_sync(&led_cdev->blink_work); |
| 111 | led_cdev->blink_delay_on = 0; | 112 | led_cdev->blink_delay_on = 0; |
| 112 | led_cdev->blink_delay_off = 0; | 113 | led_cdev->blink_delay_off = 0; |
| 113 | } | 114 | } |
| @@ -116,7 +117,7 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink); | |||
| 116 | void led_set_brightness(struct led_classdev *led_cdev, | 117 | void led_set_brightness(struct led_classdev *led_cdev, |
| 117 | enum led_brightness brightness) | 118 | enum led_brightness brightness) |
| 118 | { | 119 | { |
| 119 | /* delay brightness setting if need to stop soft-blink timer */ | 120 | /* delay brightness setting if need to stop soft-blink work */ |
| 120 | if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { | 121 | if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { |
| 121 | led_cdev->delayed_set_value = brightness; | 122 | led_cdev->delayed_set_value = brightness; |
| 122 | schedule_work(&led_cdev->set_brightness_work); | 123 | schedule_work(&led_cdev->set_brightness_work); |
diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c new file mode 100644 index 000000000000..3776f516cd88 --- /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 | static 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"); | ||
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 652368c2ea9a..91325de3cd33 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c | |||
| @@ -400,6 +400,12 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute | |||
| 400 | } | 400 | } |
| 401 | static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set); | 401 | static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set); |
| 402 | 402 | ||
| 403 | static struct attribute *lm3530_attrs[] = { | ||
| 404 | &dev_attr_mode.attr, | ||
| 405 | NULL | ||
| 406 | }; | ||
| 407 | ATTRIBUTE_GROUPS(lm3530); | ||
| 408 | |||
| 403 | static int lm3530_probe(struct i2c_client *client, | 409 | static int lm3530_probe(struct i2c_client *client, |
| 404 | const struct i2c_device_id *id) | 410 | const struct i2c_device_id *id) |
| 405 | { | 411 | { |
| @@ -436,6 +442,7 @@ static int lm3530_probe(struct i2c_client *client, | |||
| 436 | drvdata->led_dev.name = LM3530_LED_DEV; | 442 | drvdata->led_dev.name = LM3530_LED_DEV; |
| 437 | drvdata->led_dev.brightness_set = lm3530_brightness_set; | 443 | drvdata->led_dev.brightness_set = lm3530_brightness_set; |
| 438 | drvdata->led_dev.max_brightness = MAX_BRIGHTNESS; | 444 | drvdata->led_dev.max_brightness = MAX_BRIGHTNESS; |
| 445 | drvdata->led_dev.groups = lm3530_groups; | ||
| 439 | 446 | ||
| 440 | i2c_set_clientdata(client, drvdata); | 447 | i2c_set_clientdata(client, drvdata); |
| 441 | 448 | ||
| @@ -461,26 +468,13 @@ static int lm3530_probe(struct i2c_client *client, | |||
| 461 | return err; | 468 | return err; |
| 462 | } | 469 | } |
| 463 | 470 | ||
| 464 | err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode); | ||
| 465 | if (err < 0) { | ||
| 466 | dev_err(&client->dev, "File device creation failed: %d\n", err); | ||
| 467 | err = -ENODEV; | ||
| 468 | goto err_create_file; | ||
| 469 | } | ||
| 470 | |||
| 471 | return 0; | 471 | return 0; |
| 472 | |||
| 473 | err_create_file: | ||
| 474 | led_classdev_unregister(&drvdata->led_dev); | ||
| 475 | return err; | ||
| 476 | } | 472 | } |
| 477 | 473 | ||
| 478 | static int lm3530_remove(struct i2c_client *client) | 474 | static int lm3530_remove(struct i2c_client *client) |
| 479 | { | 475 | { |
| 480 | struct lm3530_data *drvdata = i2c_get_clientdata(client); | 476 | struct lm3530_data *drvdata = i2c_get_clientdata(client); |
| 481 | 477 | ||
| 482 | device_remove_file(drvdata->led_dev.dev, &dev_attr_mode); | ||
| 483 | |||
| 484 | lm3530_led_disable(drvdata); | 478 | lm3530_led_disable(drvdata); |
| 485 | led_classdev_unregister(&drvdata->led_dev); | 479 | led_classdev_unregister(&drvdata->led_dev); |
| 486 | return 0; | 480 | return 0; |
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index e2c642c1169b..cbf61a40137d 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c | |||
| @@ -645,6 +645,11 @@ static struct attribute_group lm3533_led_attribute_group = { | |||
| 645 | .attrs = lm3533_led_attributes | 645 | .attrs = lm3533_led_attributes |
| 646 | }; | 646 | }; |
| 647 | 647 | ||
| 648 | static const struct attribute_group *lm3533_led_attribute_groups[] = { | ||
| 649 | &lm3533_led_attribute_group, | ||
| 650 | NULL | ||
| 651 | }; | ||
| 652 | |||
| 648 | static int lm3533_led_setup(struct lm3533_led *led, | 653 | static int lm3533_led_setup(struct lm3533_led *led, |
| 649 | struct lm3533_led_platform_data *pdata) | 654 | struct lm3533_led_platform_data *pdata) |
| 650 | { | 655 | { |
| @@ -692,6 +697,7 @@ static int lm3533_led_probe(struct platform_device *pdev) | |||
| 692 | led->cdev.brightness_get = lm3533_led_get; | 697 | led->cdev.brightness_get = lm3533_led_get; |
| 693 | led->cdev.blink_set = lm3533_led_blink_set; | 698 | led->cdev.blink_set = lm3533_led_blink_set; |
| 694 | led->cdev.brightness = LED_OFF; | 699 | led->cdev.brightness = LED_OFF; |
| 700 | led->cdev.groups = lm3533_led_attribute_groups, | ||
| 695 | led->id = pdev->id; | 701 | led->id = pdev->id; |
| 696 | 702 | ||
| 697 | mutex_init(&led->mutex); | 703 | mutex_init(&led->mutex); |
| @@ -715,25 +721,16 @@ static int lm3533_led_probe(struct platform_device *pdev) | |||
| 715 | 721 | ||
| 716 | led->cb.dev = led->cdev.dev; | 722 | led->cb.dev = led->cdev.dev; |
| 717 | 723 | ||
| 718 | ret = sysfs_create_group(&led->cdev.dev->kobj, | ||
| 719 | &lm3533_led_attribute_group); | ||
| 720 | if (ret < 0) { | ||
| 721 | dev_err(&pdev->dev, "failed to create sysfs attributes\n"); | ||
| 722 | goto err_unregister; | ||
| 723 | } | ||
| 724 | |||
| 725 | ret = lm3533_led_setup(led, pdata); | 724 | ret = lm3533_led_setup(led, pdata); |
| 726 | if (ret) | 725 | if (ret) |
| 727 | goto err_sysfs_remove; | 726 | goto err_unregister; |
| 728 | 727 | ||
| 729 | ret = lm3533_ctrlbank_enable(&led->cb); | 728 | ret = lm3533_ctrlbank_enable(&led->cb); |
| 730 | if (ret) | 729 | if (ret) |
| 731 | goto err_sysfs_remove; | 730 | goto err_unregister; |
| 732 | 731 | ||
| 733 | return 0; | 732 | return 0; |
| 734 | 733 | ||
| 735 | err_sysfs_remove: | ||
| 736 | sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group); | ||
| 737 | err_unregister: | 734 | err_unregister: |
| 738 | led_classdev_unregister(&led->cdev); | 735 | led_classdev_unregister(&led->cdev); |
| 739 | flush_work(&led->work); | 736 | flush_work(&led->work); |
| @@ -748,7 +745,6 @@ static int lm3533_led_remove(struct platform_device *pdev) | |||
| 748 | dev_dbg(&pdev->dev, "%s\n", __func__); | 745 | dev_dbg(&pdev->dev, "%s\n", __func__); |
| 749 | 746 | ||
| 750 | lm3533_ctrlbank_disable(&led->cb); | 747 | lm3533_ctrlbank_disable(&led->cb); |
| 751 | sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group); | ||
| 752 | led_classdev_unregister(&led->cdev); | 748 | led_classdev_unregister(&led->cdev); |
| 753 | flush_work(&led->work); | 749 | flush_work(&led->work); |
| 754 | 750 | ||
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index 591eb5e58ae3..f5112cb2d991 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c | |||
| @@ -413,6 +413,12 @@ out: | |||
| 413 | 413 | ||
| 414 | static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store); | 414 | static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store); |
| 415 | 415 | ||
| 416 | static struct attribute *lm355x_indicator_attrs[] = { | ||
| 417 | &dev_attr_pattern.attr, | ||
| 418 | NULL | ||
| 419 | }; | ||
| 420 | ATTRIBUTE_GROUPS(lm355x_indicator); | ||
| 421 | |||
| 416 | static const struct regmap_config lm355x_regmap = { | 422 | static const struct regmap_config lm355x_regmap = { |
| 417 | .reg_bits = 8, | 423 | .reg_bits = 8, |
| 418 | .val_bits = 8, | 424 | .val_bits = 8, |
| @@ -501,25 +507,18 @@ static int lm355x_probe(struct i2c_client *client, | |||
| 501 | else | 507 | else |
| 502 | chip->cdev_indicator.max_brightness = 8; | 508 | chip->cdev_indicator.max_brightness = 8; |
| 503 | chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set; | 509 | chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set; |
| 510 | /* indicator pattern control only for LM3556 */ | ||
| 511 | if (id->driver_data == CHIP_LM3556) | ||
| 512 | chip->cdev_indicator.groups = lm355x_indicator_groups; | ||
| 504 | err = led_classdev_register((struct device *) | 513 | err = led_classdev_register((struct device *) |
| 505 | &client->dev, &chip->cdev_indicator); | 514 | &client->dev, &chip->cdev_indicator); |
| 506 | if (err < 0) | 515 | if (err < 0) |
| 507 | goto err_create_indicator_file; | 516 | goto err_create_indicator_file; |
| 508 | /* indicator pattern control only for LM3554 */ | ||
| 509 | if (id->driver_data == CHIP_LM3556) { | ||
| 510 | err = | ||
| 511 | device_create_file(chip->cdev_indicator.dev, | ||
| 512 | &dev_attr_pattern); | ||
| 513 | if (err < 0) | ||
| 514 | goto err_create_pattern_file; | ||
| 515 | } | ||
| 516 | 517 | ||
| 517 | dev_info(&client->dev, "%s is initialized\n", | 518 | dev_info(&client->dev, "%s is initialized\n", |
| 518 | lm355x_name[id->driver_data]); | 519 | lm355x_name[id->driver_data]); |
| 519 | return 0; | 520 | return 0; |
| 520 | 521 | ||
| 521 | err_create_pattern_file: | ||
| 522 | led_classdev_unregister(&chip->cdev_indicator); | ||
| 523 | err_create_indicator_file: | 522 | err_create_indicator_file: |
| 524 | led_classdev_unregister(&chip->cdev_torch); | 523 | led_classdev_unregister(&chip->cdev_torch); |
| 525 | err_create_torch_file: | 524 | err_create_torch_file: |
| @@ -534,8 +533,6 @@ static int lm355x_remove(struct i2c_client *client) | |||
| 534 | struct lm355x_reg_data *preg = chip->regs; | 533 | struct lm355x_reg_data *preg = chip->regs; |
| 535 | 534 | ||
| 536 | regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0); | 535 | regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0); |
| 537 | if (chip->type == CHIP_LM3556) | ||
| 538 | device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern); | ||
| 539 | led_classdev_unregister(&chip->cdev_indicator); | 536 | led_classdev_unregister(&chip->cdev_indicator); |
| 540 | flush_work(&chip->work_indicator); | 537 | flush_work(&chip->work_indicator); |
| 541 | led_classdev_unregister(&chip->cdev_torch); | 538 | led_classdev_unregister(&chip->cdev_torch); |
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c index ceb6b3cde6fe..d3dec0132769 100644 --- a/drivers/leds/leds-lm3642.c +++ b/drivers/leds/leds-lm3642.c | |||
| @@ -313,6 +313,18 @@ static const struct regmap_config lm3642_regmap = { | |||
| 313 | .max_register = REG_MAX, | 313 | .max_register = REG_MAX, |
| 314 | }; | 314 | }; |
| 315 | 315 | ||
| 316 | static struct attribute *lm3642_flash_attrs[] = { | ||
| 317 | &dev_attr_strobe_pin.attr, | ||
| 318 | NULL | ||
| 319 | }; | ||
| 320 | ATTRIBUTE_GROUPS(lm3642_flash); | ||
| 321 | |||
| 322 | static struct attribute *lm3642_torch_attrs[] = { | ||
| 323 | &dev_attr_torch_pin.attr, | ||
| 324 | NULL | ||
| 325 | }; | ||
| 326 | ATTRIBUTE_GROUPS(lm3642_torch); | ||
| 327 | |||
| 316 | static int lm3642_probe(struct i2c_client *client, | 328 | static int lm3642_probe(struct i2c_client *client, |
| 317 | const struct i2c_device_id *id) | 329 | const struct i2c_device_id *id) |
| 318 | { | 330 | { |
| @@ -364,17 +376,13 @@ static int lm3642_probe(struct i2c_client *client, | |||
| 364 | chip->cdev_flash.max_brightness = 16; | 376 | chip->cdev_flash.max_brightness = 16; |
| 365 | chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set; | 377 | chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set; |
| 366 | chip->cdev_flash.default_trigger = "flash"; | 378 | chip->cdev_flash.default_trigger = "flash"; |
| 379 | chip->cdev_flash.groups = lm3642_flash_groups, | ||
| 367 | err = led_classdev_register((struct device *) | 380 | err = led_classdev_register((struct device *) |
| 368 | &client->dev, &chip->cdev_flash); | 381 | &client->dev, &chip->cdev_flash); |
| 369 | if (err < 0) { | 382 | if (err < 0) { |
| 370 | dev_err(chip->dev, "failed to register flash\n"); | 383 | dev_err(chip->dev, "failed to register flash\n"); |
| 371 | goto err_out; | 384 | goto err_out; |
| 372 | } | 385 | } |
| 373 | err = device_create_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); | ||
| 374 | if (err < 0) { | ||
| 375 | dev_err(chip->dev, "failed to create strobe-pin file\n"); | ||
| 376 | goto err_create_flash_pin_file; | ||
| 377 | } | ||
| 378 | 386 | ||
| 379 | /* torch */ | 387 | /* torch */ |
| 380 | INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set); | 388 | INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set); |
| @@ -382,17 +390,13 @@ static int lm3642_probe(struct i2c_client *client, | |||
| 382 | chip->cdev_torch.max_brightness = 8; | 390 | chip->cdev_torch.max_brightness = 8; |
| 383 | chip->cdev_torch.brightness_set = lm3642_torch_brightness_set; | 391 | chip->cdev_torch.brightness_set = lm3642_torch_brightness_set; |
| 384 | chip->cdev_torch.default_trigger = "torch"; | 392 | chip->cdev_torch.default_trigger = "torch"; |
| 393 | chip->cdev_torch.groups = lm3642_torch_groups, | ||
| 385 | err = led_classdev_register((struct device *) | 394 | err = led_classdev_register((struct device *) |
| 386 | &client->dev, &chip->cdev_torch); | 395 | &client->dev, &chip->cdev_torch); |
| 387 | if (err < 0) { | 396 | if (err < 0) { |
| 388 | dev_err(chip->dev, "failed to register torch\n"); | 397 | dev_err(chip->dev, "failed to register torch\n"); |
| 389 | goto err_create_torch_file; | 398 | goto err_create_torch_file; |
| 390 | } | 399 | } |
| 391 | err = device_create_file(chip->cdev_torch.dev, &dev_attr_torch_pin); | ||
| 392 | if (err < 0) { | ||
| 393 | dev_err(chip->dev, "failed to create torch-pin file\n"); | ||
| 394 | goto err_create_torch_pin_file; | ||
| 395 | } | ||
| 396 | 400 | ||
| 397 | /* indicator */ | 401 | /* indicator */ |
| 398 | INIT_WORK(&chip->work_indicator, | 402 | INIT_WORK(&chip->work_indicator, |
| @@ -411,12 +415,8 @@ static int lm3642_probe(struct i2c_client *client, | |||
| 411 | return 0; | 415 | return 0; |
| 412 | 416 | ||
| 413 | err_create_indicator_file: | 417 | err_create_indicator_file: |
| 414 | device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); | ||
| 415 | err_create_torch_pin_file: | ||
| 416 | led_classdev_unregister(&chip->cdev_torch); | 418 | led_classdev_unregister(&chip->cdev_torch); |
| 417 | err_create_torch_file: | 419 | err_create_torch_file: |
| 418 | device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); | ||
| 419 | err_create_flash_pin_file: | ||
| 420 | led_classdev_unregister(&chip->cdev_flash); | 420 | led_classdev_unregister(&chip->cdev_flash); |
| 421 | err_out: | 421 | err_out: |
| 422 | return err; | 422 | return err; |
| @@ -428,10 +428,8 @@ static int lm3642_remove(struct i2c_client *client) | |||
| 428 | 428 | ||
| 429 | led_classdev_unregister(&chip->cdev_indicator); | 429 | led_classdev_unregister(&chip->cdev_indicator); |
| 430 | flush_work(&chip->work_indicator); | 430 | flush_work(&chip->work_indicator); |
| 431 | device_remove_file(chip->cdev_torch.dev, &dev_attr_torch_pin); | ||
| 432 | led_classdev_unregister(&chip->cdev_torch); | 431 | led_classdev_unregister(&chip->cdev_torch); |
| 433 | flush_work(&chip->work_torch); | 432 | flush_work(&chip->work_torch); |
| 434 | device_remove_file(chip->cdev_flash.dev, &dev_attr_strobe_pin); | ||
| 435 | led_classdev_unregister(&chip->cdev_flash); | 433 | led_classdev_unregister(&chip->cdev_flash); |
| 436 | flush_work(&chip->work_flash); | 434 | flush_work(&chip->work_flash); |
| 437 | regmap_write(chip->regmap, REG_ENABLE, 0); | 435 | regmap_write(chip->regmap, REG_ENABLE, 0); |
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 88317b4f7bf3..77c26bc32eed 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c | |||
| @@ -127,15 +127,12 @@ static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, lp55xx_show_current, | |||
| 127 | lp55xx_store_current); | 127 | lp55xx_store_current); |
| 128 | static DEVICE_ATTR(max_current, S_IRUGO , lp55xx_show_max_current, NULL); | 128 | static DEVICE_ATTR(max_current, S_IRUGO , lp55xx_show_max_current, NULL); |
| 129 | 129 | ||
| 130 | static struct attribute *lp55xx_led_attributes[] = { | 130 | static struct attribute *lp55xx_led_attrs[] = { |
| 131 | &dev_attr_led_current.attr, | 131 | &dev_attr_led_current.attr, |
| 132 | &dev_attr_max_current.attr, | 132 | &dev_attr_max_current.attr, |
| 133 | NULL, | 133 | NULL, |
| 134 | }; | 134 | }; |
| 135 | 135 | ATTRIBUTE_GROUPS(lp55xx_led); | |
| 136 | static struct attribute_group lp55xx_led_attr_group = { | ||
| 137 | .attrs = lp55xx_led_attributes | ||
| 138 | }; | ||
| 139 | 136 | ||
| 140 | static void lp55xx_set_brightness(struct led_classdev *cdev, | 137 | static void lp55xx_set_brightness(struct led_classdev *cdev, |
| 141 | enum led_brightness brightness) | 138 | enum led_brightness brightness) |
| @@ -176,6 +173,7 @@ static int lp55xx_init_led(struct lp55xx_led *led, | |||
| 176 | } | 173 | } |
| 177 | 174 | ||
| 178 | led->cdev.brightness_set = lp55xx_set_brightness; | 175 | led->cdev.brightness_set = lp55xx_set_brightness; |
| 176 | led->cdev.groups = lp55xx_led_groups; | ||
| 179 | 177 | ||
| 180 | if (pdata->led_config[chan].name) { | 178 | if (pdata->led_config[chan].name) { |
| 181 | led->cdev.name = pdata->led_config[chan].name; | 179 | led->cdev.name = pdata->led_config[chan].name; |
| @@ -185,24 +183,12 @@ static int lp55xx_init_led(struct lp55xx_led *led, | |||
| 185 | led->cdev.name = name; | 183 | led->cdev.name = name; |
| 186 | } | 184 | } |
| 187 | 185 | ||
| 188 | /* | ||
| 189 | * register led class device for each channel and | ||
| 190 | * add device attributes | ||
| 191 | */ | ||
| 192 | |||
| 193 | ret = led_classdev_register(dev, &led->cdev); | 186 | ret = led_classdev_register(dev, &led->cdev); |
| 194 | if (ret) { | 187 | if (ret) { |
| 195 | dev_err(dev, "led register err: %d\n", ret); | 188 | dev_err(dev, "led register err: %d\n", ret); |
| 196 | return ret; | 189 | return ret; |
| 197 | } | 190 | } |
| 198 | 191 | ||
| 199 | ret = sysfs_create_group(&led->cdev.dev->kobj, &lp55xx_led_attr_group); | ||
| 200 | if (ret) { | ||
| 201 | dev_err(dev, "led sysfs err: %d\n", ret); | ||
| 202 | led_classdev_unregister(&led->cdev); | ||
| 203 | return ret; | ||
| 204 | } | ||
| 205 | |||
| 206 | return 0; | 192 | return 0; |
| 207 | } | 193 | } |
| 208 | 194 | ||
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c index f449a8bdddc7..607bc2755aba 100644 --- a/drivers/leds/leds-max8997.c +++ b/drivers/leds/leds-max8997.c | |||
| @@ -229,6 +229,12 @@ static ssize_t max8997_led_store_mode(struct device *dev, | |||
| 229 | 229 | ||
| 230 | static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); | 230 | static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); |
| 231 | 231 | ||
| 232 | static struct attribute *max8997_attrs[] = { | ||
| 233 | &dev_attr_mode.attr, | ||
| 234 | NULL | ||
| 235 | }; | ||
| 236 | ATTRIBUTE_GROUPS(max8997); | ||
| 237 | |||
| 232 | static int max8997_led_probe(struct platform_device *pdev) | 238 | static int max8997_led_probe(struct platform_device *pdev) |
| 233 | { | 239 | { |
| 234 | struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 240 | struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
| @@ -253,6 +259,7 @@ static int max8997_led_probe(struct platform_device *pdev) | |||
| 253 | led->cdev.brightness_set = max8997_led_brightness_set; | 259 | led->cdev.brightness_set = max8997_led_brightness_set; |
| 254 | led->cdev.flags |= LED_CORE_SUSPENDRESUME; | 260 | led->cdev.flags |= LED_CORE_SUSPENDRESUME; |
| 255 | led->cdev.brightness = 0; | 261 | led->cdev.brightness = 0; |
| 262 | led->cdev.groups = max8997_groups; | ||
| 256 | led->iodev = iodev; | 263 | led->iodev = iodev; |
| 257 | 264 | ||
| 258 | /* initialize mode and brightness according to platform_data */ | 265 | /* initialize mode and brightness according to platform_data */ |
| @@ -281,14 +288,6 @@ static int max8997_led_probe(struct platform_device *pdev) | |||
| 281 | if (ret < 0) | 288 | if (ret < 0) |
| 282 | return ret; | 289 | return ret; |
| 283 | 290 | ||
| 284 | ret = device_create_file(led->cdev.dev, &dev_attr_mode); | ||
| 285 | if (ret != 0) { | ||
| 286 | dev_err(&pdev->dev, | ||
| 287 | "failed to create file: %d\n", ret); | ||
| 288 | led_classdev_unregister(&led->cdev); | ||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | return 0; | 291 | return 0; |
| 293 | } | 292 | } |
| 294 | 293 | ||
| @@ -296,7 +295,6 @@ static int max8997_led_remove(struct platform_device *pdev) | |||
| 296 | { | 295 | { |
| 297 | struct max8997_led *led = platform_get_drvdata(pdev); | 296 | struct max8997_led *led = platform_get_drvdata(pdev); |
| 298 | 297 | ||
| 299 | device_remove_file(led->cdev.dev, &dev_attr_mode); | ||
| 300 | led_classdev_unregister(&led->cdev); | 298 | led_classdev_unregister(&led->cdev); |
| 301 | 299 | ||
| 302 | return 0; | 300 | return 0; |
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index e97f443a6e07..64fde485dcaa 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c | |||
| @@ -293,10 +293,14 @@ static ssize_t netxbig_led_sata_show(struct device *dev, | |||
| 293 | 293 | ||
| 294 | static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store); | 294 | static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store); |
| 295 | 295 | ||
| 296 | static struct attribute *netxbig_led_attrs[] = { | ||
| 297 | &dev_attr_sata.attr, | ||
| 298 | NULL | ||
| 299 | }; | ||
| 300 | ATTRIBUTE_GROUPS(netxbig_led); | ||
| 301 | |||
| 296 | static void delete_netxbig_led(struct netxbig_led_data *led_dat) | 302 | static void delete_netxbig_led(struct netxbig_led_data *led_dat) |
| 297 | { | 303 | { |
| 298 | if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) | ||
| 299 | device_remove_file(led_dat->cdev.dev, &dev_attr_sata); | ||
| 300 | led_classdev_unregister(&led_dat->cdev); | 304 | led_classdev_unregister(&led_dat->cdev); |
| 301 | } | 305 | } |
| 302 | 306 | ||
| @@ -306,7 +310,6 @@ create_netxbig_led(struct platform_device *pdev, | |||
| 306 | const struct netxbig_led *template) | 310 | const struct netxbig_led *template) |
| 307 | { | 311 | { |
| 308 | struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev); | 312 | struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev); |
| 309 | int ret; | ||
| 310 | 313 | ||
| 311 | spin_lock_init(&led_dat->lock); | 314 | spin_lock_init(&led_dat->lock); |
| 312 | led_dat->gpio_ext = pdata->gpio_ext; | 315 | led_dat->gpio_ext = pdata->gpio_ext; |
| @@ -327,6 +330,12 @@ create_netxbig_led(struct platform_device *pdev, | |||
| 327 | led_dat->sata = 0; | 330 | led_dat->sata = 0; |
| 328 | led_dat->cdev.brightness = LED_OFF; | 331 | led_dat->cdev.brightness = LED_OFF; |
| 329 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; | 332 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; |
| 333 | /* | ||
| 334 | * If available, expose the SATA activity blink capability through | ||
| 335 | * a "sata" sysfs attribute. | ||
| 336 | */ | ||
| 337 | if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) | ||
| 338 | led_dat->cdev.groups = netxbig_led_groups; | ||
| 330 | led_dat->mode_addr = template->mode_addr; | 339 | led_dat->mode_addr = template->mode_addr; |
| 331 | led_dat->mode_val = template->mode_val; | 340 | led_dat->mode_val = template->mode_val; |
| 332 | led_dat->bright_addr = template->bright_addr; | 341 | led_dat->bright_addr = template->bright_addr; |
| @@ -334,21 +343,7 @@ create_netxbig_led(struct platform_device *pdev, | |||
| 334 | led_dat->timer = pdata->timer; | 343 | led_dat->timer = pdata->timer; |
| 335 | led_dat->num_timer = pdata->num_timer; | 344 | led_dat->num_timer = pdata->num_timer; |
| 336 | 345 | ||
| 337 | ret = led_classdev_register(&pdev->dev, &led_dat->cdev); | 346 | return led_classdev_register(&pdev->dev, &led_dat->cdev); |
| 338 | if (ret < 0) | ||
| 339 | return ret; | ||
| 340 | |||
| 341 | /* | ||
| 342 | * If available, expose the SATA activity blink capability through | ||
| 343 | * a "sata" sysfs attribute. | ||
| 344 | */ | ||
| 345 | if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) { | ||
| 346 | ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); | ||
| 347 | if (ret) | ||
| 348 | led_classdev_unregister(&led_dat->cdev); | ||
| 349 | } | ||
| 350 | |||
| 351 | return ret; | ||
| 352 | } | 347 | } |
| 353 | 348 | ||
| 354 | static int netxbig_led_probe(struct platform_device *pdev) | 349 | static int netxbig_led_probe(struct platform_device *pdev) |
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index efa625883c83..231993d1fe21 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c | |||
| @@ -185,6 +185,12 @@ static ssize_t ns2_led_sata_show(struct device *dev, | |||
| 185 | 185 | ||
| 186 | static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); | 186 | static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); |
| 187 | 187 | ||
| 188 | static struct attribute *ns2_led_attrs[] = { | ||
| 189 | &dev_attr_sata.attr, | ||
| 190 | NULL | ||
| 191 | }; | ||
| 192 | ATTRIBUTE_GROUPS(ns2_led); | ||
| 193 | |||
| 188 | static int | 194 | static int |
| 189 | create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, | 195 | create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, |
| 190 | const struct ns2_led *template) | 196 | const struct ns2_led *template) |
| @@ -219,6 +225,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, | |||
| 219 | led_dat->cdev.blink_set = NULL; | 225 | led_dat->cdev.blink_set = NULL; |
| 220 | led_dat->cdev.brightness_set = ns2_led_set; | 226 | led_dat->cdev.brightness_set = ns2_led_set; |
| 221 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; | 227 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; |
| 228 | led_dat->cdev.groups = ns2_led_groups; | ||
| 222 | led_dat->cmd = template->cmd; | 229 | led_dat->cmd = template->cmd; |
| 223 | led_dat->slow = template->slow; | 230 | led_dat->slow = template->slow; |
| 224 | 231 | ||
| @@ -235,20 +242,11 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, | |||
| 235 | if (ret < 0) | 242 | if (ret < 0) |
| 236 | return ret; | 243 | return ret; |
| 237 | 244 | ||
| 238 | ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata); | ||
| 239 | if (ret < 0) | ||
| 240 | goto err_free_cdev; | ||
| 241 | |||
| 242 | return 0; | 245 | return 0; |
| 243 | |||
| 244 | err_free_cdev: | ||
| 245 | led_classdev_unregister(&led_dat->cdev); | ||
| 246 | return ret; | ||
| 247 | } | 246 | } |
| 248 | 247 | ||
| 249 | static void delete_ns2_led(struct ns2_led_data *led_dat) | 248 | static void delete_ns2_led(struct ns2_led_data *led_dat) |
| 250 | { | 249 | { |
| 251 | device_remove_file(led_dat->cdev.dev, &dev_attr_sata); | ||
| 252 | led_classdev_unregister(&led_dat->cdev); | 250 | led_classdev_unregister(&led_dat->cdev); |
| 253 | } | 251 | } |
| 254 | 252 | ||
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 82589c0a5689..f110b4c456ba 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | * directory of this archive for more details. | 12 | * directory of this archive for more details. |
| 13 | * | 13 | * |
| 14 | * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) | 14 | * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) |
| 15 | * LED driver for the PCA9634 I2C LED driver (7-bit slave address set by hw.) | 15 | * LED driver for the PCA9634/5 I2C LED driver (7-bit slave address set by hw.) |
| 16 | * | 16 | * |
| 17 | * Note that hardware blinking violates the leds infrastructure driver | 17 | * Note that hardware blinking violates the leds infrastructure driver |
| 18 | * interface since the hardware only supports blinking all LEDs with the | 18 | * interface since the hardware only supports blinking all LEDs with the |
| @@ -52,6 +52,7 @@ | |||
| 52 | enum pca963x_type { | 52 | enum pca963x_type { |
| 53 | pca9633, | 53 | pca9633, |
| 54 | pca9634, | 54 | pca9634, |
| 55 | pca9635, | ||
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | struct pca963x_chipdef { | 58 | struct pca963x_chipdef { |
| @@ -74,6 +75,12 @@ static struct pca963x_chipdef pca963x_chipdefs[] = { | |||
| 74 | .ledout_base = 0xc, | 75 | .ledout_base = 0xc, |
| 75 | .n_leds = 8, | 76 | .n_leds = 8, |
| 76 | }, | 77 | }, |
| 78 | [pca9635] = { | ||
| 79 | .grppwm = 0x12, | ||
| 80 | .grpfreq = 0x13, | ||
| 81 | .ledout_base = 0x14, | ||
| 82 | .n_leds = 16, | ||
| 83 | }, | ||
| 77 | }; | 84 | }; |
| 78 | 85 | ||
| 79 | /* Total blink period in milliseconds */ | 86 | /* Total blink period in milliseconds */ |
| @@ -84,6 +91,7 @@ static const struct i2c_device_id pca963x_id[] = { | |||
| 84 | { "pca9632", pca9633 }, | 91 | { "pca9632", pca9633 }, |
| 85 | { "pca9633", pca9633 }, | 92 | { "pca9633", pca9633 }, |
| 86 | { "pca9634", pca9634 }, | 93 | { "pca9634", pca9634 }, |
| 94 | { "pca9635", pca9635 }, | ||
| 87 | { } | 95 | { } |
| 88 | }; | 96 | }; |
| 89 | MODULE_DEVICE_TABLE(i2c, pca963x_id); | 97 | MODULE_DEVICE_TABLE(i2c, pca963x_id); |
| @@ -107,7 +115,7 @@ struct pca963x_led { | |||
| 107 | struct work_struct work; | 115 | struct work_struct work; |
| 108 | enum led_brightness brightness; | 116 | enum led_brightness brightness; |
| 109 | struct led_classdev led_cdev; | 117 | struct led_classdev led_cdev; |
| 110 | int led_num; /* 0 .. 7 potentially */ | 118 | int led_num; /* 0 .. 15 potentially */ |
| 111 | enum pca963x_cmd cmd; | 119 | enum pca963x_cmd cmd; |
| 112 | char name[32]; | 120 | char name[32]; |
| 113 | u8 gdc; | 121 | u8 gdc; |
| @@ -321,6 +329,7 @@ static const struct of_device_id of_pca963x_match[] = { | |||
| 321 | { .compatible = "nxp,pca9632", }, | 329 | { .compatible = "nxp,pca9632", }, |
| 322 | { .compatible = "nxp,pca9633", }, | 330 | { .compatible = "nxp,pca9633", }, |
| 323 | { .compatible = "nxp,pca9634", }, | 331 | { .compatible = "nxp,pca9634", }, |
| 332 | { .compatible = "nxp,pca9635", }, | ||
| 324 | {}, | 333 | {}, |
| 325 | }; | 334 | }; |
| 326 | #else | 335 | #else |
| @@ -375,9 +384,8 @@ static int pca963x_probe(struct i2c_client *client, | |||
| 375 | pca963x_chip->leds = pca963x; | 384 | pca963x_chip->leds = pca963x; |
| 376 | 385 | ||
| 377 | /* Turn off LEDs by default*/ | 386 | /* Turn off LEDs by default*/ |
| 378 | i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00); | 387 | for (i = 0; i < chip->n_leds / 4; i++) |
| 379 | if (chip->n_leds > 4) | 388 | i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); |
| 380 | i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00); | ||
| 381 | 389 | ||
| 382 | for (i = 0; i < chip->n_leds; i++) { | 390 | for (i = 0; i < chip->n_leds; i++) { |
| 383 | pca963x[i].led_num = i; | 391 | pca963x[i].led_num = i; |
| @@ -415,9 +423,13 @@ static int pca963x_probe(struct i2c_client *client, | |||
| 415 | /* Disable LED all-call address and set normal mode */ | 423 | /* Disable LED all-call address and set normal mode */ |
| 416 | i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00); | 424 | i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00); |
| 417 | 425 | ||
| 418 | /* Configure output: open-drain or totem pole (push-pull) */ | 426 | if (pdata) { |
| 419 | if (pdata && pdata->outdrv == PCA963X_OPEN_DRAIN) | 427 | /* Configure output: open-drain or totem pole (push-pull) */ |
| 420 | i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01); | 428 | if (pdata->outdrv == PCA963X_OPEN_DRAIN) |
| 429 | i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01); | ||
| 430 | else | ||
| 431 | i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x05); | ||
| 432 | } | ||
| 421 | 433 | ||
| 422 | return 0; | 434 | return 0; |
| 423 | 435 | ||
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 2eb3ef62962b..046cb7008745 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c | |||
| @@ -469,6 +469,12 @@ static ssize_t nas_led_blink_store(struct device *dev, | |||
| 469 | 469 | ||
| 470 | static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store); | 470 | static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store); |
| 471 | 471 | ||
| 472 | static struct attribute *nasgpio_led_attrs[] = { | ||
| 473 | &dev_attr_blink.attr, | ||
| 474 | NULL | ||
| 475 | }; | ||
| 476 | ATTRIBUTE_GROUPS(nasgpio_led); | ||
| 477 | |||
| 472 | static int register_nasgpio_led(int led_nr) | 478 | static int register_nasgpio_led(int led_nr) |
| 473 | { | 479 | { |
| 474 | int ret; | 480 | int ret; |
| @@ -481,20 +487,18 @@ static int register_nasgpio_led(int led_nr) | |||
| 481 | led->brightness = LED_FULL; | 487 | led->brightness = LED_FULL; |
| 482 | led->brightness_set = nasgpio_led_set_brightness; | 488 | led->brightness_set = nasgpio_led_set_brightness; |
| 483 | led->blink_set = nasgpio_led_set_blink; | 489 | led->blink_set = nasgpio_led_set_blink; |
| 490 | led->groups = nasgpio_led_groups; | ||
| 484 | ret = led_classdev_register(&nas_gpio_pci_dev->dev, led); | 491 | ret = led_classdev_register(&nas_gpio_pci_dev->dev, led); |
| 485 | if (ret) | 492 | if (ret) |
| 486 | return ret; | 493 | return ret; |
| 487 | ret = device_create_file(led->dev, &dev_attr_blink); | 494 | |
| 488 | if (ret) | 495 | return 0; |
| 489 | led_classdev_unregister(led); | ||
| 490 | return ret; | ||
| 491 | } | 496 | } |
| 492 | 497 | ||
| 493 | static void unregister_nasgpio_led(int led_nr) | 498 | static void unregister_nasgpio_led(int led_nr) |
| 494 | { | 499 | { |
| 495 | struct led_classdev *led = get_classdev_for_led_nr(led_nr); | 500 | struct led_classdev *led = get_classdev_for_led_nr(led_nr); |
| 496 | led_classdev_unregister(led); | 501 | led_classdev_unregister(led); |
| 497 | device_remove_file(led->dev, &dev_attr_blink); | ||
| 498 | } | 502 | } |
| 499 | /* | 503 | /* |
| 500 | * module load/initialization | 504 | * module load/initialization |
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index e72c974142d0..1b71e0701002 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c | |||
| @@ -219,6 +219,12 @@ static ssize_t wm831x_status_src_store(struct device *dev, | |||
| 219 | 219 | ||
| 220 | static DEVICE_ATTR(src, 0644, wm831x_status_src_show, wm831x_status_src_store); | 220 | static DEVICE_ATTR(src, 0644, wm831x_status_src_show, wm831x_status_src_store); |
| 221 | 221 | ||
| 222 | static struct attribute *wm831x_status_attrs[] = { | ||
| 223 | &dev_attr_src.attr, | ||
| 224 | NULL | ||
| 225 | }; | ||
| 226 | ATTRIBUTE_GROUPS(wm831x_status); | ||
| 227 | |||
| 222 | static int wm831x_status_probe(struct platform_device *pdev) | 228 | static int wm831x_status_probe(struct platform_device *pdev) |
| 223 | { | 229 | { |
| 224 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | 230 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); |
| @@ -232,8 +238,7 @@ static int wm831x_status_probe(struct platform_device *pdev) | |||
| 232 | res = platform_get_resource(pdev, IORESOURCE_REG, 0); | 238 | res = platform_get_resource(pdev, IORESOURCE_REG, 0); |
| 233 | if (res == NULL) { | 239 | if (res == NULL) { |
| 234 | dev_err(&pdev->dev, "No register resource\n"); | 240 | dev_err(&pdev->dev, "No register resource\n"); |
| 235 | ret = -EINVAL; | 241 | return -EINVAL; |
| 236 | goto err; | ||
| 237 | } | 242 | } |
| 238 | 243 | ||
| 239 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_status), | 244 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_status), |
| @@ -284,31 +289,21 @@ static int wm831x_status_probe(struct platform_device *pdev) | |||
| 284 | drvdata->cdev.default_trigger = pdata.default_trigger; | 289 | drvdata->cdev.default_trigger = pdata.default_trigger; |
| 285 | drvdata->cdev.brightness_set = wm831x_status_set; | 290 | drvdata->cdev.brightness_set = wm831x_status_set; |
| 286 | drvdata->cdev.blink_set = wm831x_status_blink_set; | 291 | drvdata->cdev.blink_set = wm831x_status_blink_set; |
| 292 | drvdata->cdev.groups = wm831x_status_groups; | ||
| 287 | 293 | ||
| 288 | ret = led_classdev_register(wm831x->dev, &drvdata->cdev); | 294 | ret = led_classdev_register(wm831x->dev, &drvdata->cdev); |
| 289 | if (ret < 0) { | 295 | if (ret < 0) { |
| 290 | dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); | 296 | dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); |
| 291 | goto err_led; | 297 | return ret; |
| 292 | } | 298 | } |
| 293 | 299 | ||
| 294 | ret = device_create_file(drvdata->cdev.dev, &dev_attr_src); | ||
| 295 | if (ret != 0) | ||
| 296 | dev_err(&pdev->dev, | ||
| 297 | "No source control for LED: %d\n", ret); | ||
| 298 | |||
| 299 | return 0; | 300 | return 0; |
| 300 | |||
| 301 | err_led: | ||
| 302 | led_classdev_unregister(&drvdata->cdev); | ||
| 303 | err: | ||
| 304 | return ret; | ||
| 305 | } | 301 | } |
| 306 | 302 | ||
| 307 | static int wm831x_status_remove(struct platform_device *pdev) | 303 | static int wm831x_status_remove(struct platform_device *pdev) |
| 308 | { | 304 | { |
| 309 | struct wm831x_status *drvdata = platform_get_drvdata(pdev); | 305 | struct wm831x_status *drvdata = platform_get_drvdata(pdev); |
| 310 | 306 | ||
| 311 | device_remove_file(drvdata->cdev.dev, &dev_attr_src); | ||
| 312 | led_classdev_unregister(&drvdata->cdev); | 307 | led_classdev_unregister(&drvdata->cdev); |
| 313 | 308 | ||
| 314 | return 0; | 309 | return 0; |
diff --git a/include/linux/leds.h b/include/linux/leds.h index 0287ab296689..6a599dce7f9d 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| 17 | #include <linux/rwsem.h> | 17 | #include <linux/rwsem.h> |
| 18 | #include <linux/timer.h> | ||
| 19 | #include <linux/workqueue.h> | 18 | #include <linux/workqueue.h> |
| 20 | 19 | ||
| 21 | struct device; | 20 | struct device; |
| @@ -63,11 +62,13 @@ struct led_classdev { | |||
| 63 | unsigned long *delay_off); | 62 | unsigned long *delay_off); |
| 64 | 63 | ||
| 65 | struct device *dev; | 64 | struct device *dev; |
| 65 | const struct attribute_group **groups; | ||
| 66 | |||
| 66 | struct list_head node; /* LED Device list */ | 67 | struct list_head node; /* LED Device list */ |
| 67 | const char *default_trigger; /* Trigger to use */ | 68 | const char *default_trigger; /* Trigger to use */ |
| 68 | 69 | ||
| 69 | unsigned long blink_delay_on, blink_delay_off; | 70 | unsigned long blink_delay_on, blink_delay_off; |
| 70 | struct timer_list blink_timer; | 71 | struct delayed_work blink_work; |
| 71 | int blink_brightness; | 72 | int blink_brightness; |
| 72 | 73 | ||
| 73 | struct work_struct set_brightness_work; | 74 | struct work_struct set_brightness_work; |
