Pull LED subsystem update from Bryan Wu. * 'for-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds: (50 commits) leds-lp8788: forgotten unlock at lp8788_led_work LEDS: propagate error codes in blinkm_detect() LEDS: memory leak in blinkm_led_common_set() leds: add new lp8788 led driver LEDS: add BlinkM RGB LED driver, documentation and update MAINTAINERS leds: max8997: Simplify max8997_led_set_mode implementation leds/leds-s3c24xx: use devm_gpio_request leds: convert Network Space v2 LED driver to devm_kzalloc() and cleanup error exit path leds: convert DAC124S085 LED driver to devm_kzalloc() leds: convert LM3530 LED driver to devm_kzalloc() and cleanup error exit path leds: convert TCA6507 LED driver to devm_kzalloc() leds: convert Freescale MC13783 LED driver to devm_kzalloc() and cleanup error exit path leds: convert ADP5520 LED driver to devm_kzalloc() and cleanup error exit path leds: convert PCA955x LED driver to devm_kzalloc() and cleanup error exit path leds: convert Sun Fire LED driver to devm_kzalloc() and cleanup error exit path leds: convert PCA9532 LED driver to devm_kzalloc() leds: convert LT3593 LED driver to devm_kzalloc() leds: convert Renesas TPU LED driver to devm_kzalloc() and cleanup error exit path leds: convert LP5523 LED driver to devm_kzalloc() and cleanup error exit path leds: convert PCA9633 LED driver to devm_kzalloc() ...
Unified · Split
| @@ -6,3 +6,5 @@ leds-lp5521.txt · 5 unmodified lines | ||
| 6 | 6 | - notes on how to use the leds-lp5521 driver. |
| 7 | 7 | leds-lp5523.txt |
| 8 | 8 | - notes on how to use the leds-lp5523 driver. |
| 9 | +leds-lm3556.txt | |
| 10 | + - notes on how to use the leds-lm3556 driver. | |
| @@ -0,0 +1,80 @@ | ||
| 1 | +The leds-blinkm driver supports the devices of the BlinkM family. | |
| 2 | + | |
| 3 | +They are RGB-LED modules driven by a (AT)tiny microcontroller and | |
| 4 | +communicate through I2C. The default address of these modules is | |
| 5 | +0x09 but this can be changed through a command. By this you could | |
| 6 | +dasy-chain up to 127 BlinkMs on an I2C bus. | |
| 7 | + | |
| 8 | +The device accepts RGB and HSB color values through separate commands. | |
| 9 | +Also you can store blinking sequences as "scripts" in | |
| 10 | +the controller and run them. Also fading is an option. | |
| 11 | + | |
| 12 | +The interface this driver provides is 2-fold: | |
| 13 | + | |
| 14 | +a) LED class interface for use with triggers | |
| 15 | +############################################ | |
| 16 | + | |
| 17 | +The registration follows the scheme: | |
| 18 | +blinkm-<i2c-bus-nr>-<i2c-device-nr>-<color> | |
| 19 | + | |
| 20 | +$ ls -h /sys/class/leds/blinkm-6-* | |
| 21 | +/sys/class/leds/blinkm-6-9-blue: | |
| 22 | +brightness device max_brightness power subsystem trigger uevent | |
| 23 | + | |
| 24 | +/sys/class/leds/blinkm-6-9-green: | |
| 25 | +brightness device max_brightness power subsystem trigger uevent | |
| 26 | + | |
| 27 | +/sys/class/leds/blinkm-6-9-red: | |
| 28 | +brightness device max_brightness power subsystem trigger uevent | |
| 29 | + | |
| 30 | +(same is /sys/bus/i2c/devices/6-0009/leds) | |
| 31 | + | |
| 32 | +We can control the colors separated into red, green and blue and | |
| 33 | +assign triggers on each color. | |
| 34 | + | |
| 35 | +E.g.: | |
| 36 | + | |
| 37 | +$ cat blinkm-6-9-blue/brightness | |
| 38 | +05 | |
| 39 | + | |
| 40 | +$ echo 200 > blinkm-6-9-blue/brightness | |
| 41 | +$ | |
| 42 | + | |
| 43 | +$ modprobe ledtrig-heartbeat | |
| 44 | +$ echo heartbeat > blinkm-6-9-green/trigger | |
| 45 | +$ | |
| 46 | + | |
| 47 | + | |
| 48 | +b) Sysfs group to control rgb, fade, hsb, scripts ... | |
| 49 | +##################################################### | |
| 50 | + | |
| 51 | +This extended interface is available as folder blinkm | |
| 52 | +in the sysfs folder of the I2C device. | |
| 53 | +E.g. below /sys/bus/i2c/devices/6-0009/blinkm | |
| 54 | + | |
| 55 | +$ ls -h /sys/bus/i2c/devices/6-0009/blinkm/ | |
| 56 | +blue green red test | |
| 57 | + | |
| 58 | +Currently supported is just setting red, green, blue | |
| 59 | +and a test sequence. | |
| 60 | + | |
| 61 | +E.g.: | |
| 62 | + | |
| 63 | +$ cat * | |
| 64 | +00 | |
| 65 | +00 | |
| 66 | +00 | |
| 67 | +#Write into test to start test sequence!# | |
| 68 | + | |
| 69 | +$ echo 1 > test | |
| 70 | +$ | |
| 71 | + | |
| 72 | +$ echo 255 > red | |
| 73 | +$ | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | +as of 6/2012 | |
| 78 | + | |
| 79 | +dl9pf <at> gmx <dot> de | |
| 80 | + | |
| @@ -0,0 +1,85 @@ | ||
| 1 | +Kernel driver for lm3556 | |
| 2 | +======================== | |
| 3 | + | |
| 4 | +*Texas Instrument: | |
| 5 | + 1.5 A Synchronous Boost LED Flash Driver w/ High-Side Current Source | |
| 6 | +* Datasheet: http://www.national.com/ds/LM/LM3556.pdf | |
| 7 | + | |
| 8 | +Authors: | |
| 9 | + Daniel Jeong | |
| 10 | + Contact:Daniel Jeong(daniel.jeong-at-ti.com, gshark.jeong-at-gmail.com) | |
| 11 | + | |
| 12 | +Description | |
| 13 | +----------- | |
| 14 | +There are 3 functions in LM3556, Flash, Torch and Indicator. | |
| 15 | + | |
| 16 | +FLASH MODE | |
| 17 | +In Flash Mode, the LED current source(LED) provides 16 target current levels | |
| 18 | +from 93.75 mA to 1500 mA.The Flash currents are adjusted via the CURRENT | |
| 19 | +CONTROL REGISTER(0x09).Flash mode is activated by the ENABLE REGISTER(0x0A), | |
| 20 | +or by pulling the STROBE pin HIGH. | |
| 21 | +LM3556 Flash can be controlled through sys/class/leds/flash/brightness file | |
| 22 | +* if STROBE pin is enabled, below example control brightness only, and | |
| 23 | +ON / OFF will be controlled by STROBE pin. | |
| 24 | + | |
| 25 | +Flash Example: | |
| 26 | +OFF : #echo 0 > sys/class/leds/flash/brightness | |
| 27 | +93.75 mA: #echo 1 > sys/class/leds/flash/brightness | |
| 28 | +... ..... | |
| 29 | +1500 mA: #echo 16 > sys/class/leds/flash/brightness | |
| 30 | + | |
| 31 | +TORCH MODE | |
| 32 | +In Torch Mode, the current source(LED) is programmed via the CURRENT CONTROL | |
| 33 | +REGISTER(0x09).Torch Mode is activated by the ENABLE REGISTER(0x0A) or by the | |
| 34 | +hardware TORCH input. | |
| 35 | +LM3556 torch can be controlled through sys/class/leds/torch/brightness file. | |
| 36 | +* if TORCH pin is enabled, below example control brightness only, | |
| 37 | +and ON / OFF will be controlled by TORCH pin. | |
| 38 | + | |
| 39 | +Torch Example: | |
| 40 | +OFF : #echo 0 > sys/class/leds/torch/brightness | |
| 41 | +46.88 mA: #echo 1 > sys/class/leds/torch/brightness | |
| 42 | +... ..... | |
| 43 | +375 mA : #echo 8 > sys/class/leds/torch/brightness | |
| 44 | + | |
| 45 | +INDICATOR MODE | |
| 46 | +Indicator pattern can be set through sys/class/leds/indicator/pattern file, | |
| 47 | +and 4 patterns are pre-defined in indicator_pattern array. | |
| 48 | +According to N-lank, Pulse time and N Period values, different pattern wiill | |
| 49 | +be generated.If you want new patterns for your own device, change | |
| 50 | +indicator_pattern array with your own values and INDIC_PATTERN_SIZE. | |
| 51 | +Please refer datasheet for more detail about N-Blank, Pulse time and N Period. | |
| 52 | + | |
| 53 | +Indicator pattern example: | |
| 54 | +pattern 0: #echo 0 > sys/class/leds/indicator/pattern | |
| 55 | +.... | |
| 56 | +pattern 3: #echo 3 > sys/class/leds/indicator/pattern | |
| 57 | + | |
| 58 | +Indicator brightness can be controlled through | |
| 59 | +sys/class/leds/indicator/brightness file. | |
| 60 | + | |
| 61 | +Example: | |
| 62 | +OFF : #echo 0 > sys/class/leds/indicator/brightness | |
| 63 | +5.86 mA : #echo 1 > sys/class/leds/indicator/brightness | |
| 64 | +........ | |
| 65 | +46.875mA : #echo 8 > sys/class/leds/indicator/brightness | |
| 66 | + | |
| 67 | +Notes | |
| 68 | +----- | |
| 69 | +Driver expects it is registered using the i2c_board_info mechanism. | |
| 70 | +To register the chip at address 0x63 on specific adapter, set the platform data | |
| 71 | +according to include/linux/platform_data/leds-lm3556.h, set the i2c board info | |
| 72 | + | |
| 73 | +Example: | |
| 74 | + static struct i2c_board_info __initdata board_i2c_ch4[] = { | |
| 75 | + { | |
| 76 | + I2C_BOARD_INFO(LM3556_NAME, 0x63), | |
| 77 | + .platform_data = &lm3556_pdata, | |
| 78 | + }, | |
| 79 | + }; | |
| 80 | + | |
| 81 | +and register it in the platform init function | |
| 82 | + | |
| 83 | +Example: | |
| 84 | + board_register_i2c_bus(4, 400, | |
| 85 | + board_i2c_ch4, ARRAY_SIZE(board_i2c_ch4)); | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +One-shot LED Trigger | |
| 2 | +==================== | |
| 3 | + | |
| 4 | +This is a LED trigger useful for signaling the user of an event where there are | |
| 5 | +no clear trap points to put standard led-on and led-off settings. Using this | |
| 6 | +trigger, the application needs only to signal the trigger when an event has | |
| 7 | +happened, than the trigger turns the LED on and than keeps it off for a | |
| 8 | +specified amount of time. | |
| 9 | + | |
| 10 | +This trigger is meant to be usable both for sporadic and dense events. In the | |
| 11 | +first case, the trigger produces a clear single controlled blink for each | |
| 12 | +event, while in the latter it keeps blinking at constant rate, as to signal | |
| 13 | +that the events are arriving continuously. | |
| 14 | + | |
| 15 | +A one-shot LED only stays in a constant state when there are no events. An | |
| 16 | +additional "invert" property specifies if the LED has to stay off (normal) or | |
| 17 | +on (inverted) when not rearmed. | |
| 18 | + | |
| 19 | +The trigger can be activated from user space on led class devices as shown | |
| 20 | +below: | |
| 21 | + | |
| 22 | + echo oneshot > trigger | |
| 23 | + | |
| 24 | +This adds the following sysfs attributes to the LED: | |
| 25 | + | |
| 26 | + delay_on - specifies for how many milliseconds the LED has to stay at | |
| 27 | + LED_FULL brightness after it has been armed. | |
| 28 | + Default to 100 ms. | |
| 29 | + | |
| 30 | + delay_off - specifies for how many milliseconds the LED has to stay at | |
| 31 | + LED_OFF brightness after it has been armed. | |
| 32 | + Default to 100 ms. | |
| 33 | + | |
| 34 | + invert - reverse the blink logic. If set to 0 (default) blink on for delay_on | |
| 35 | + ms, then blink off for delay_off ms, leaving the LED normally off. If | |
| 36 | + set to 1, blink off for delay_off ms, then blink on for delay_on ms, | |
| 37 | + leaving the LED normally on. | |
| 38 | + Setting this value also immediately change the LED state. | |
| 39 | + | |
| 40 | + shot - write any non-empty string to signal an events, this starts a blink | |
| 41 | + sequence if not already running. | |
| 42 | + | |
| 43 | +Example use-case: network devices, initialization: | |
| 44 | + | |
| 45 | + echo oneshot > trigger # set trigger for this led | |
| 46 | + echo 33 > delay_on # blink at 1 / (33 + 33) Hz on continuous traffic | |
| 47 | + echo 33 > delay_off | |
| 48 | + | |
| 49 | +interface goes up: | |
| 50 | + | |
| 51 | + echo 1 > invert # set led as normally-on, turn the led on | |
| 52 | + | |
| 53 | +packet received/transmitted: | |
| 54 | + | |
| 55 | + echo 1 > shot # led starts blinking, ignored if already blinking | |
| 56 | + | |
| 57 | +interface goes down | |
| 58 | + | |
| 59 | + echo 0 > invert # set led as normally-off, turn the led off | |
| @@ -1529,6 +1529,11 @@ W: http://blackfin.uclinux.org/ · 1528 unmodified lines | ||
| 1529 | 1529 | S: Supported |
| 1530 | 1530 | F: drivers/i2c/busses/i2c-bfin-twi.c |
| 1531 | 1531 | |
| 1532 | +BLINKM RGB LED DRIVER | |
| 1533 | +M: Jan-Simon Moeller <jansimon.moeller@gmx.de> | |
| 1534 | +S: Maintained | |
| 1535 | +F: drivers/leds/leds-blinkm.c | |
| 1536 | + | |
| 1532 | 1537 | BLOCK LAYER |
| 1533 | 1538 | M: Jens Axboe <axboe@kernel.dk> |
| 1534 | 1539 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git |
| @@ -200,6 +200,13 @@ config LEDS_LP5523 · 199 unmodified lines | ||
| 200 | 200 | Driver provides direct control via LED class and interface for |
| 201 | 201 | programming the engines. |
| 202 | 202 | |
| 203 | +config LEDS_LP8788 | |
| 204 | + tristate "LED support for the TI LP8788 PMIC" | |
| 205 | + depends on LEDS_CLASS | |
| 206 | + depends on MFD_LP8788 | |
| 207 | + help | |
| 208 | + This option enables support for the Keyboard LEDs on the LP8788 PMIC. | |
| 209 | + | |
| 203 | 210 | config LEDS_CLEVO_MAIL |
| 204 | 211 | tristate "Mail LED on Clevo notebook" |
| 205 | 212 | depends on LEDS_CLASS |
| @@ -415,6 +422,14 @@ config LEDS_MAX8997 · 209 unmodified lines | ||
| 415 | 422 | This option enables support for on-chip LED drivers on |
| 416 | 423 | MAXIM MAX8997 PMIC. |
| 417 | 424 | |
| 425 | +config LEDS_LM3556 | |
| 426 | + tristate "LED support for LM3556 Chip" | |
| 427 | + depends on LEDS_CLASS && I2C | |
| 428 | + select REGMAP_I2C | |
| 429 | + help | |
| 430 | + This option enables support for LEDs connected to LM3556. | |
| 431 | + LM3556 includes Torch, Flash and Indicator functions. | |
| 432 | + | |
| 418 | 433 | config LEDS_OT200 |
| 419 | 434 | tristate "LED support for the Bachmann OT200" |
| 420 | 435 | depends on LEDS_CLASS && HAS_IOMEM |
| @@ -422,6 +437,14 @@ config LEDS_OT200 · 1 unmodified line | ||
| 422 | 437 | This option enables support for the LEDs on the Bachmann OT200. |
| 423 | 438 | Say Y to enable LEDs on the Bachmann OT200. |
| 424 | 439 | |
| 440 | +config LEDS_BLINKM | |
| 441 | + tristate "LED support for the BlinkM I2C RGB LED" | |
| 442 | + depends on LEDS_CLASS | |
| 443 | + depends on I2C | |
| 444 | + help | |
| 445 | + This option enables support for the BlinkM RGB LED connected | |
| 446 | + through I2C. Say Y to enable support for the BlinkM LED. | |
| 447 | + | |
| 425 | 448 | config LEDS_TRIGGERS |
| 426 | 449 | bool "LED Trigger support" |
| 427 | 450 | depends on LEDS_CLASS |
| @@ -443,6 +466,20 @@ config LEDS_TRIGGER_TIMER · 15 unmodified lines | ||
| 443 | 466 | |
| 444 | 467 | If unsure, say Y. |
| 445 | 468 | |
| 469 | +config LEDS_TRIGGER_ONESHOT | |
| 470 | + tristate "LED One-shot Trigger" | |
| 471 | + depends on LEDS_TRIGGERS | |
| 472 | + help | |
| 473 | + This allows LEDs to blink in one-shot pulses with parameters | |
| 474 | + controlled via sysfs. It's useful to notify the user on | |
| 475 | + sporadic events, when there are no clear begin and end trap points, | |
| 476 | + or on dense events, where this blinks the LED at constant rate if | |
| 477 | + rearmed continuously. | |
| 478 | + | |
| 479 | + It also shows how to use the led_blink_set_oneshot() function. | |
| 480 | + | |
| 481 | + If unsure, say Y. | |
| 482 | + | |
| 446 | 483 | config LEDS_TRIGGER_IDE_DISK |
| 447 | 484 | bool "LED IDE Disk Trigger" |
| 448 | 485 | depends on IDE_GD_ATA |
| @@ -497,7 +534,7 @@ config LEDS_TRIGGER_TRANSIENT · 48 unmodified lines | ||
| 497 | 534 | depends on LEDS_TRIGGERS |
| 498 | 535 | help |
| 499 | 536 | This allows one time activation of a transient state on |
| 500 | − GPIO/PWM based hadrware. | |
| 537 | + GPIO/PWM based hardware. | |
| 501 | 538 | If unsure, say Y. |
| 502 | 539 | |
| 503 | 540 | endif # NEW_LEDS |
| @@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o · 23 unmodified lines | ||
| 24 | 24 | obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o |
| 25 | 25 | obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o |
| 26 | 26 | obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o |
| 27 | +obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o | |
| 27 | 28 | obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o |
| 28 | 29 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o |
| 29 | 30 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o |
| @@ -47,12 +48,15 @@ obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o · 17 unmodified lines | ||
| 47 | 48 | obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o |
| 48 | 49 | obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o |
| 49 | 50 | obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o |
| 51 | +obj-$(CONFIG_LEDS_LM3556) += leds-lm3556.o | |
| 52 | +obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o | |
| 50 | 53 | |
| 51 | 54 | # LED SPI Drivers |
| 52 | 55 | obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o |
| 53 | 56 | |
| 54 | 57 | # LED Triggers |
| 55 | 58 | obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o |
| 59 | +obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o | |
| 56 | 60 | obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o |
| 57 | 61 | obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o |
| 58 | 62 | obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o |
| @@ -53,7 +53,7 @@ static ssize_t led_brightness_store(struct device *dev, · 52 unmodified lines | ||
| 53 | 53 | |
| 54 | 54 | if (state == LED_OFF) |
| 55 | 55 | led_trigger_remove(led_cdev); |
| 56 | − led_set_brightness(led_cdev, state); | |
| 56 | + __led_set_brightness(led_cdev, state); | |
| 57 | 57 | |
| 58 | 58 | return size; |
| 59 | 59 | } |
| @@ -82,7 +82,12 @@ static void led_timer_function(unsigned long data) · 22 unmodified lines | ||
| 82 | 82 | unsigned long delay; |
| 83 | 83 | |
| 84 | 84 | if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) { |
| 85 | − led_set_brightness(led_cdev, LED_OFF); | |
| 85 | + __led_set_brightness(led_cdev, LED_OFF); | |
| 86 | + return; | |
| 87 | + } | |
| 88 | + | |
| 89 | + if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) { | |
| 90 | + led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; | |
| 86 | 91 | return; |
| 87 | 92 | } |
| 88 | 93 | |
| @@ -100,7 +105,21 @@ static void led_timer_function(unsigned long data) · 11 unmodified lines | ||
| 100 | 105 | delay = led_cdev->blink_delay_off; |
| 101 | 106 | } |
| 102 | 107 | |
| 103 | − led_set_brightness(led_cdev, brightness); | |
| 108 | + __led_set_brightness(led_cdev, brightness); | |
| 109 | + | |
| 110 | + /* Return in next iteration if led is in one-shot mode and we are in | |
| 111 | + * the final blink state so that the led is toggled each delay_on + | |
| 112 | + * delay_off milliseconds in worst case. | |
| 113 | + */ | |
| 114 | + if (led_cdev->flags & LED_BLINK_ONESHOT) { | |
| 115 | + if (led_cdev->flags & LED_BLINK_INVERT) { | |
| 116 | + if (brightness) | |
| 117 | + led_cdev->flags |= LED_BLINK_ONESHOT_STOP; | |
| 118 | + } else { | |
| 119 | + if (!brightness) | |
| 120 | + led_cdev->flags |= LED_BLINK_ONESHOT_STOP; | |
| 121 | + } | |
| 122 | + } | |
| 104 | 123 | |
| 105 | 124 | mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); |
| 106 | 125 | } |
| @@ -203,7 +222,7 @@ void led_classdev_unregister(struct led_classdev *led_cdev) · 96 unmodified lines | ||
| 203 | 222 | #endif |
| 204 | 223 | |
| 205 | 224 | /* Stop blinking */ |
| 206 | − led_brightness_set(led_cdev, LED_OFF); | |
| 225 | + led_set_brightness(led_cdev, LED_OFF); | |
| 207 | 226 | |
| 208 | 227 | device_unregister(led_cdev->dev); |
| 209 | 228 | |
| @@ -24,14 +24,6 @@ EXPORT_SYMBOL_GPL(leds_list_lock); · 23 unmodified lines | ||
| 24 | 24 | LIST_HEAD(leds_list); |
| 25 | 25 | EXPORT_SYMBOL_GPL(leds_list); |
| 26 | 26 | |
| 27 | −static void led_stop_software_blink(struct led_classdev *led_cdev) | |
| 28 | −{ | |
| 29 | − /* deactivate previous settings */ | |
| 30 | − del_timer_sync(&led_cdev->blink_timer); | |
| 31 | − led_cdev->blink_delay_on = 0; | |
| 32 | − led_cdev->blink_delay_off = 0; | |
| 33 | −} | |
| 34 | − | |
| 35 | 27 | static void led_set_software_blink(struct led_classdev *led_cdev, |
| 36 | 28 | unsigned long delay_on, |
| 37 | 29 | unsigned long delay_off) |
| @@ -53,7 +45,7 @@ static void led_set_software_blink(struct led_classdev *led_cdev, · 15 unmodified lines | ||
| 53 | 45 | |
| 54 | 46 | /* never off - just set to brightness */ |
| 55 | 47 | if (!delay_off) { |
| 56 | − led_set_brightness(led_cdev, led_cdev->blink_brightness); | |
| 48 | + __led_set_brightness(led_cdev, led_cdev->blink_brightness); | |
| 57 | 49 | return; |
| 58 | 50 | } |
| 59 | 51 | |
| @@ -61,13 +53,12 @@ static void led_set_software_blink(struct led_classdev *led_cdev, · 1 unmodified line | ||
| 61 | 53 | } |
| 62 | 54 | |
| 63 | 55 | |
| 64 | −void led_blink_set(struct led_classdev *led_cdev, | |
| 65 | − unsigned long *delay_on, | |
| 66 | − unsigned long *delay_off) | |
| 56 | +static void led_blink_setup(struct led_classdev *led_cdev, | |
| 57 | + unsigned long *delay_on, | |
| 58 | + unsigned long *delay_off) | |
| 67 | 59 | { |
| 68 | − del_timer_sync(&led_cdev->blink_timer); | |
| 69 | − | |
| 70 | − if (led_cdev->blink_set && | |
| 60 | + if (!(led_cdev->flags & LED_BLINK_ONESHOT) && | |
| 61 | + led_cdev->blink_set && | |
| 71 | 62 | !led_cdev->blink_set(led_cdev, delay_on, delay_off)) |
| 72 | 63 | return; |
| 73 | 64 | |
| @@ -77,12 +68,49 @@ void led_blink_set(struct led_classdev *led_cdev, · 3 unmodified lines | ||
| 77 | 68 | |
| 78 | 69 | led_set_software_blink(led_cdev, *delay_on, *delay_off); |
| 79 | 70 | } |
| 71 | + | |
| 72 | +void led_blink_set(struct led_classdev *led_cdev, | |
| 73 | + unsigned long *delay_on, | |
| 74 | + unsigned long *delay_off) | |
| 75 | +{ | |
| 76 | + del_timer_sync(&led_cdev->blink_timer); | |
| 77 | + | |
| 78 | + led_cdev->flags &= ~LED_BLINK_ONESHOT; | |
| 79 | + led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; | |
| 80 | + | |
| 81 | + led_blink_setup(led_cdev, delay_on, delay_off); | |
| 82 | +} | |
| 80 | 83 | EXPORT_SYMBOL(led_blink_set); |
| 81 | 84 | |
| 82 | −void led_brightness_set(struct led_classdev *led_cdev, | |
| 85 | +void led_blink_set_oneshot(struct led_classdev *led_cdev, | |
| 86 | + unsigned long *delay_on, | |
| 87 | + unsigned long *delay_off, | |
| 88 | + int invert) | |
| 89 | +{ | |
| 90 | + if ((led_cdev->flags & LED_BLINK_ONESHOT) && | |
| 91 | + timer_pending(&led_cdev->blink_timer)) | |
| 92 | + return; | |
| 93 | + | |
| 94 | + led_cdev->flags |= LED_BLINK_ONESHOT; | |
| 95 | + led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; | |
| 96 | + | |
| 97 | + if (invert) | |
| 98 | + led_cdev->flags |= LED_BLINK_INVERT; | |
| 99 | + else | |
| 100 | + led_cdev->flags &= ~LED_BLINK_INVERT; | |
| 101 | + | |
| 102 | + led_blink_setup(led_cdev, delay_on, delay_off); | |
| 103 | +} | |
| 104 | +EXPORT_SYMBOL(led_blink_set_oneshot); | |
| 105 | + | |
| 106 | +void led_set_brightness(struct led_classdev *led_cdev, | |
| 83 | 107 | enum led_brightness brightness) |
| 84 | 108 | { |
| 85 | − led_stop_software_blink(led_cdev); | |
| 86 | − led_cdev->brightness_set(led_cdev, brightness); | |
| 109 | + /* stop and clear soft-blink timer */ | |
| 110 | + del_timer_sync(&led_cdev->blink_timer); | |
| 111 | + led_cdev->blink_delay_on = 0; | |
| 112 | + led_cdev->blink_delay_off = 0; | |
| 113 | + | |
| 114 | + __led_set_brightness(led_cdev, brightness); | |
| 87 | 115 | } |
| 88 | −EXPORT_SYMBOL(led_brightness_set); | |
| 116 | +EXPORT_SYMBOL(led_set_brightness); | |
| @@ -99,7 +99,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, · 98 unmodified lines | ||
| 99 | 99 | EXPORT_SYMBOL_GPL(led_trigger_show); |
| 100 | 100 | |
| 101 | 101 | /* Caller must ensure led_cdev->trigger_lock held */ |
| 102 | −void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) | |
| 102 | +void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) | |
| 103 | 103 | { |
| 104 | 104 | unsigned long flags; |
| 105 | 105 | |
| @@ -112,15 +112,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) · 6 unmodified lines | ||
| 112 | 112 | if (led_cdev->trigger->deactivate) |
| 113 | 113 | led_cdev->trigger->deactivate(led_cdev); |
| 114 | 114 | led_cdev->trigger = NULL; |
| 115 | − led_brightness_set(led_cdev, LED_OFF); | |
| 115 | + led_set_brightness(led_cdev, LED_OFF); | |
| 116 | 116 | } |
| 117 | − if (trigger) { | |
| 118 | − write_lock_irqsave(&trigger->leddev_list_lock, flags); | |
| 119 | − list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); | |
| 120 | − write_unlock_irqrestore(&trigger->leddev_list_lock, flags); | |
| 121 | − led_cdev->trigger = trigger; | |
| 122 | − if (trigger->activate) | |
| 123 | − trigger->activate(led_cdev); | |
| 117 | + if (trig) { | |
| 118 | + write_lock_irqsave(&trig->leddev_list_lock, flags); | |
| 119 | + list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); | |
| 120 | + write_unlock_irqrestore(&trig->leddev_list_lock, flags); | |
| 121 | + led_cdev->trigger = trig; | |
| 122 | + if (trig->activate) | |
| 123 | + trig->activate(led_cdev); | |
| 124 | 124 | } |
| 125 | 125 | } |
| 126 | 126 | EXPORT_SYMBOL_GPL(led_trigger_set); |
| @@ -153,24 +153,24 @@ EXPORT_SYMBOL_GPL(led_trigger_set_default); · 26 unmodified lines | ||
| 153 | 153 | |
| 154 | 154 | /* LED Trigger Interface */ |
| 155 | 155 | |
| 156 | −int led_trigger_register(struct led_trigger *trigger) | |
| 156 | +int led_trigger_register(struct led_trigger *trig) | |
| 157 | 157 | { |
| 158 | 158 | struct led_classdev *led_cdev; |
| 159 | − struct led_trigger *trig; | |
| 159 | + struct led_trigger *_trig; | |
| 160 | 160 | |
| 161 | − rwlock_init(&trigger->leddev_list_lock); | |
| 162 | − INIT_LIST_HEAD(&trigger->led_cdevs); | |
| 161 | + rwlock_init(&trig->leddev_list_lock); | |
| 162 | + INIT_LIST_HEAD(&trig->led_cdevs); | |
| 163 | 163 | |
| 164 | 164 | down_write(&triggers_list_lock); |
| 165 | 165 | /* Make sure the trigger's name isn't already in use */ |
| 166 | − list_for_each_entry(trig, &trigger_list, next_trig) { | |
| 167 | − if (!strcmp(trig->name, trigger->name)) { | |
| 166 | + list_for_each_entry(_trig, &trigger_list, next_trig) { | |
| 167 | + if (!strcmp(_trig->name, trig->name)) { | |
| 168 | 168 | up_write(&triggers_list_lock); |
| 169 | 169 | return -EEXIST; |
| 170 | 170 | } |
| 171 | 171 | } |
| 172 | 172 | /* Add to the list of led triggers */ |
| 173 | − list_add_tail(&trigger->next_trig, &trigger_list); | |
| 173 | + list_add_tail(&trig->next_trig, &trigger_list); | |
| 174 | 174 | up_write(&triggers_list_lock); |
| 175 | 175 | |
| 176 | 176 | /* Register with any LEDs that have this as a default trigger */ |
| @@ -178,8 +178,8 @@ int led_trigger_register(struct led_trigger *trigger) · 1 unmodified line | ||
| 178 | 178 | list_for_each_entry(led_cdev, &leds_list, node) { |
| 179 | 179 | down_write(&led_cdev->trigger_lock); |
| 180 | 180 | if (!led_cdev->trigger && led_cdev->default_trigger && |
| 181 | − !strcmp(led_cdev->default_trigger, trigger->name)) | |
| 182 | − led_trigger_set(led_cdev, trigger); | |
| 181 | + !strcmp(led_cdev->default_trigger, trig->name)) | |
| 182 | + led_trigger_set(led_cdev, trig); | |
| 183 | 183 | up_write(&led_cdev->trigger_lock); |
| 184 | 184 | } |
| 185 | 185 | up_read(&leds_list_lock); |
| @@ -188,20 +188,20 @@ int led_trigger_register(struct led_trigger *trigger) · 2 unmodified lines | ||
| 188 | 188 | } |
| 189 | 189 | EXPORT_SYMBOL_GPL(led_trigger_register); |
| 190 | 190 | |
| 191 | −void led_trigger_unregister(struct led_trigger *trigger) | |
| 191 | +void led_trigger_unregister(struct led_trigger *trig) | |
| 192 | 192 | { |
| 193 | 193 | struct led_classdev *led_cdev; |
| 194 | 194 | |
| 195 | 195 | /* Remove from the list of led triggers */ |
| 196 | 196 | down_write(&triggers_list_lock); |
| 197 | − list_del(&trigger->next_trig); | |
| 197 | + list_del(&trig->next_trig); | |
| 198 | 198 | up_write(&triggers_list_lock); |
| 199 | 199 | |
| 200 | 200 | /* Remove anyone actively using this trigger */ |
| 201 | 201 | down_read(&leds_list_lock); |
| 202 | 202 | list_for_each_entry(led_cdev, &leds_list, node) { |
| 203 | 203 | down_write(&led_cdev->trigger_lock); |
| 204 | − if (led_cdev->trigger == trigger) | |
| 204 | + if (led_cdev->trigger == trig) | |
| 205 | 205 | led_trigger_set(led_cdev, NULL); |
| 206 | 206 | up_write(&led_cdev->trigger_lock); |
| 207 | 207 | } |
| @@ -211,58 +211,80 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister); · 3 unmodified lines | ||
| 211 | 211 | |
| 212 | 212 | /* Simple LED Tigger Interface */ |
| 213 | 213 | |
| 214 | −void led_trigger_event(struct led_trigger *trigger, | |
| 214 | +void led_trigger_event(struct led_trigger *trig, | |
| 215 | 215 | enum led_brightness brightness) |
| 216 | 216 | { |
| 217 | 217 | struct list_head *entry; |
| 218 | 218 | |
| 219 | − if (!trigger) | |
| 219 | + if (!trig) | |
| 220 | 220 | return; |
| 221 | 221 | |
| 222 | − read_lock(&trigger->leddev_list_lock); | |
| 223 | − list_for_each(entry, &trigger->led_cdevs) { | |
| 222 | + read_lock(&trig->leddev_list_lock); | |
| 223 | + list_for_each(entry, &trig->led_cdevs) { | |
| 224 | 224 | struct led_classdev *led_cdev; |
| 225 | 225 | |
| 226 | 226 | led_cdev = list_entry(entry, struct led_classdev, trig_list); |
| 227 | 227 | led_set_brightness(led_cdev, brightness); |
| 228 | 228 | } |
| 229 | − read_unlock(&trigger->leddev_list_lock); | |
| 229 | + read_unlock(&trig->leddev_list_lock); | |
| 230 | 230 | } |
| 231 | 231 | EXPORT_SYMBOL_GPL(led_trigger_event); |
| 232 | 232 | |
| 233 | −void led_trigger_blink(struct led_trigger *trigger, | |
| 234 | − unsigned long *delay_on, | |
| 235 | − unsigned long *delay_off) | |
| 233 | +static void led_trigger_blink_setup(struct led_trigger *trig, | |
| 234 | + unsigned long *delay_on, | |
| 235 | + unsigned long *delay_off, | |
| 236 | + int oneshot, | |
| 237 | + int invert) | |
| 236 | 238 | { |
| 237 | 239 | struct list_head *entry; |
| 238 | 240 | |
| 239 | − if (!trigger) | |
| 241 | + if (!trig) | |
| 240 | 242 | return; |
| 241 | 243 | |
| 242 | − read_lock(&trigger->leddev_list_lock); | |
| 243 | − list_for_each(entry, &trigger->led_cdevs) { | |
| 244 | + read_lock(&trig->leddev_list_lock); | |
| 245 | + list_for_each(entry, &trig->led_cdevs) { | |
| 244 | 246 | struct led_classdev *led_cdev; |
| 245 | 247 | |
| 246 | 248 | led_cdev = list_entry(entry, struct led_classdev, trig_list); |
| 247 | − led_blink_set(led_cdev, delay_on, delay_off); | |
| 249 | + if (oneshot) | |
| 250 | + led_blink_set_oneshot(led_cdev, delay_on, delay_off, | |
| 251 | + invert); | |
| 252 | + else | |
| 253 | + led_blink_set(led_cdev, delay_on, delay_off); | |
| 248 | 254 | } |
| 249 | − read_unlock(&trigger->leddev_list_lock); | |
| 255 | + read_unlock(&trig->leddev_list_lock); | |
| 256 | +} | |
| 257 | + | |
| 258 | +void led_trigger_blink(struct led_trigger *trig, | |
| 259 | + unsigned long *delay_on, | |
| 260 | + unsigned long *delay_off) | |
| 261 | +{ | |
| 262 | + led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); | |
| 250 | 263 | } |
| 251 | 264 | EXPORT_SYMBOL_GPL(led_trigger_blink); |
| 252 | 265 | |
| 266 | +void led_trigger_blink_oneshot(struct led_trigger *trig, | |
| 267 | + unsigned long *delay_on, | |
| 268 | + unsigned long *delay_off, | |
| 269 | + int invert) | |
| 270 | +{ | |
| 271 | + led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert); | |
| 272 | +} | |
| 273 | +EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot); | |
| 274 | + | |
| 253 | 275 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) |
| 254 | 276 | { |
| 255 | − struct led_trigger *trigger; | |
| 277 | + struct led_trigger *trig; | |
| 256 | 278 | int err; |
| 257 | 279 | |
| 258 | − trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | |
| 280 | + trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | |
| 259 | 281 | |
| 260 | − if (trigger) { | |
| 261 | − trigger->name = name; | |
| 262 | − err = led_trigger_register(trigger); | |
| 282 | + if (trig) { | |
| 283 | + trig->name = name; | |
| 284 | + err = led_trigger_register(trig); | |
| 263 | 285 | if (err < 0) { |
| 264 | − kfree(trigger); | |
| 265 | − trigger = NULL; | |
| 286 | + kfree(trig); | |
| 287 | + trig = NULL; | |
| 266 | 288 | printk(KERN_WARNING "LED trigger %s failed to register" |
| 267 | 289 | " (%d)\n", name, err); |
| 268 | 290 | } |
| @@ -270,15 +292,15 @@ void led_trigger_register_simple(const char *name, struct led_trigger **tp) · 1 unmodified line | ||
| 270 | 292 | printk(KERN_WARNING "LED trigger %s failed to register" |
| 271 | 293 | " (no memory)\n", name); |
| 272 | 294 | |
| 273 | − *tp = trigger; | |
| 295 | + *tp = trig; | |
| 274 | 296 | } |
| 275 | 297 | EXPORT_SYMBOL_GPL(led_trigger_register_simple); |
| 276 | 298 | |
| 277 | −void led_trigger_unregister_simple(struct led_trigger *trigger) | |
| 299 | +void led_trigger_unregister_simple(struct led_trigger *trig) | |
| 278 | 300 | { |
| 279 | − if (trigger) | |
| 280 | − led_trigger_unregister(trigger); | |
| 281 | − kfree(trigger); | |
| 301 | + if (trig) | |
| 302 | + led_trigger_unregister(trig); | |
| 303 | + kfree(trig); | |
| 282 | 304 | } |
| 283 | 305 | EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); |
| 284 | 306 | |
| @@ -209,7 +209,7 @@ static int pm860x_led_probe(struct platform_device *pdev) · 208 unmodified lines | ||
| 209 | 209 | return -EINVAL; |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | − data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); | |
| 212 | + data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_led), GFP_KERNEL); | |
| 213 | 213 | if (data == NULL) |
| 214 | 214 | return -ENOMEM; |
| 215 | 215 | strncpy(data->name, res->name, MFD_NAME_SIZE - 1); |
| @@ -220,7 +220,6 @@ static int pm860x_led_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 220 | 220 | data->port = pdata->flags; |
| 221 | 221 | if (data->port < 0) { |
| 222 | 222 | dev_err(&pdev->dev, "check device failed\n"); |
| 223 | − kfree(data); | |
| 224 | 223 | return -EINVAL; |
| 225 | 224 | } |
| 226 | 225 | |
| @@ -233,13 +232,10 @@ static int pm860x_led_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 233 | 232 | ret = led_classdev_register(chip->dev, &data->cdev); |
| 234 | 233 | if (ret < 0) { |
| 235 | 234 | dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); |
| 236 | − goto out; | |
| 235 | + return ret; | |
| 237 | 236 | } |
| 238 | 237 | pm860x_led_set(&data->cdev, 0); |
| 239 | 238 | return 0; |
| 240 | −out: | |
| 241 | − kfree(data); | |
| 242 | − return ret; | |
| 243 | 239 | } |
| 244 | 240 | |
| 245 | 241 | static int pm860x_led_remove(struct platform_device *pdev) |
| @@ -247,7 +243,6 @@ static int pm860x_led_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 247 | 243 | struct pm860x_led *data = platform_get_drvdata(pdev); |
| 248 | 244 | |
| 249 | 245 | led_classdev_unregister(&data->cdev); |
| 250 | − kfree(data); | |
| 251 | 246 | |
| 252 | 247 | return 0; |
| 253 | 248 | } |
| @@ -119,7 +119,8 @@ static int __devinit adp5520_led_probe(struct platform_device *pdev) · 118 unmodified lines | ||
| 119 | 119 | return -EFAULT; |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | − led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); | |
| 122 | + led = devm_kzalloc(&pdev->dev, sizeof(*led) * pdata->num_leds, | |
| 123 | + GFP_KERNEL); | |
| 123 | 124 | if (led == NULL) { |
| 124 | 125 | dev_err(&pdev->dev, "failed to alloc memory\n"); |
| 125 | 126 | return -ENOMEM; |
| @@ -129,7 +130,7 @@ static int __devinit adp5520_led_probe(struct platform_device *pdev) · 3 unmodified lines | ||
| 129 | 130 | |
| 130 | 131 | if (ret) { |
| 131 | 132 | dev_err(&pdev->dev, "failed to write\n"); |
| 132 | − goto err_free; | |
| 133 | + return ret; | |
| 133 | 134 | } |
| 134 | 135 | |
| 135 | 136 | for (i = 0; i < pdata->num_leds; ++i) { |
| @@ -179,8 +180,6 @@ err: · 43 unmodified lines | ||
| 179 | 180 | } |
| 180 | 181 | } |
| 181 | 182 | |
| 182 | −err_free: | |
| 183 | − kfree(led); | |
| 184 | 183 | return ret; |
| 185 | 184 | } |
| 186 | 185 | |
| @@ -200,7 +199,6 @@ static int __devexit adp5520_led_remove(struct platform_device *pdev) · 13 unmodified lines | ||
| 200 | 199 | cancel_work_sync(&led[i].work); |
| 201 | 200 | } |
| 202 | 201 | |
| 203 | − kfree(led); | |
| 204 | 202 | return 0; |
| 205 | 203 | } |
| 206 | 204 | |
| @@ -99,12 +99,13 @@ static int __devinit asic3_led_probe(struct platform_device *pdev) · 98 unmodified lines | ||
| 99 | 99 | |
| 100 | 100 | ret = mfd_cell_enable(pdev); |
| 101 | 101 | if (ret < 0) |
| 102 | − goto ret0; | |
| 102 | + return ret; | |
| 103 | 103 | |
| 104 | − led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); | |
| 104 | + led->cdev = devm_kzalloc(&pdev->dev, sizeof(struct led_classdev), | |
| 105 | + GFP_KERNEL); | |
| 105 | 106 | if (!led->cdev) { |
| 106 | 107 | ret = -ENOMEM; |
| 107 | − goto ret1; | |
| 108 | + goto out; | |
| 108 | 109 | } |
| 109 | 110 | |
| 110 | 111 | led->cdev->name = led->name; |
| @@ -115,15 +116,12 @@ static int __devinit asic3_led_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 115 | 116 | |
| 116 | 117 | ret = led_classdev_register(&pdev->dev, led->cdev); |
| 117 | 118 | if (ret < 0) |
| 118 | − goto ret2; | |
| 119 | + goto out; | |
| 119 | 120 | |
| 120 | 121 | return 0; |
| 121 | 122 | |
| 122 | −ret2: | |
| 123 | − kfree(led->cdev); | |
| 124 | −ret1: | |
| 123 | +out: | |
| 125 | 124 | (void) mfd_cell_disable(pdev); |
| 126 | −ret0: | |
| 127 | 125 | return ret; |
| 128 | 126 | } |
| 129 | 127 | |
| @@ -133,8 +131,6 @@ static int __devexit asic3_led_remove(struct platform_device *pdev) · 3 unmodified lines | ||
| 133 | 131 | |
| 134 | 132 | led_classdev_unregister(led->cdev); |
| 135 | 133 | |
| 136 | − kfree(led->cdev); | |
| 137 | − | |
| 138 | 134 | return mfd_cell_disable(pdev); |
| 139 | 135 | } |
| 140 | 136 | |
| @@ -46,7 +46,8 @@ static int __devinit pwmled_probe(struct platform_device *pdev) · 45 unmodified lines | ||
| 46 | 46 | if (!pdata || pdata->num_leds < 1) |
| 47 | 47 | return -ENODEV; |
| 48 | 48 | |
| 49 | − leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL); | |
| 49 | + leds = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*leds), | |
| 50 | + GFP_KERNEL); | |
| 50 | 51 | if (!leds) |
| 51 | 52 | return -ENOMEM; |
| 52 | 53 | |
| @@ -108,7 +109,6 @@ err: · 55 unmodified lines | ||
| 108 | 109 | pwm_channel_free(&leds[i].pwmc); |
| 109 | 110 | } |
| 110 | 111 | } |
| 111 | − kfree(leds); | |
| 112 | 112 | |
| 113 | 113 | return status; |
| 114 | 114 | } |
| @@ -129,7 +129,6 @@ static int __exit pwmled_remove(struct platform_device *pdev) · 14 unmodified lines | ||
| 129 | 129 | pwm_channel_free(&led->pwmc); |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | − kfree(leds); | |
| 133 | 132 | platform_set_drvdata(pdev, NULL); |
| 134 | 133 | return 0; |
| 135 | 134 | } |
| @@ -677,7 +677,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, · 676 unmodified lines | ||
| 677 | 677 | struct bd2802_led_platform_data *pdata; |
| 678 | 678 | int ret, i; |
| 679 | 679 | |
| 680 | − led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); | |
| 680 | + led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL); | |
| 681 | 681 | if (!led) { |
| 682 | 682 | dev_err(&client->dev, "failed to allocate driver data\n"); |
| 683 | 683 | return -ENOMEM; |
| @@ -697,7 +697,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, · 13 unmodified lines | ||
| 697 | 697 | ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00); |
| 698 | 698 | if (ret < 0) { |
| 699 | 699 | dev_err(&client->dev, "failed to detect device\n"); |
| 700 | − goto failed_free; | |
| 700 | + return ret; | |
| 701 | 701 | } else |
| 702 | 702 | dev_info(&client->dev, "return 0x%02x\n", ret); |
| 703 | 703 | |
| @@ -729,9 +729,6 @@ static int __devinit bd2802_probe(struct i2c_client *client, · 25 unmodified lines | ||
| 729 | 729 | failed_unregister_dev_file: |
| 730 | 730 | for (i--; i >= 0; i--) |
| 731 | 731 | device_remove_file(&led->client->dev, bd2802_attributes[i]); |
| 732 | −failed_free: | |
| 733 | − kfree(led); | |
| 734 | − | |
| 735 | 732 | return ret; |
| 736 | 733 | } |
| 737 | 734 | |
| @@ -746,7 +743,6 @@ static int __exit bd2802_remove(struct i2c_client *client) · 8 unmodified lines | ||
| 746 | 743 | bd2802_disable_adv_conf(led); |
| 747 | 744 | for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) |
| 748 | 745 | device_remove_file(&led->client->dev, bd2802_attributes[i]); |
| 749 | − kfree(led); | |
| 750 | 746 | |
| 751 | 747 | return 0; |
| 752 | 748 | } |
| @@ -0,0 +1,815 @@ | ||
| 1 | +/* | |
| 2 | + * leds-blinkm.c | |
| 3 | + * (c) Jan-Simon Möller (dl9pf@gmx.de) | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License as published by | |
| 7 | + * the Free Software Foundation; either version 2 of the License, or | |
| 8 | + * (at your option) any later version. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + * | |
| 15 | + * You should have received a copy of the GNU General Public License | |
| 16 | + * along with this program; if not, write to the Free Software | |
| 17 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#include <linux/module.h> | |
| 21 | +#include <linux/init.h> | |
| 22 | +#include <linux/slab.h> | |
| 23 | +#include <linux/jiffies.h> | |
| 24 | +#include <linux/i2c.h> | |
| 25 | +#include <linux/err.h> | |
| 26 | +#include <linux/mutex.h> | |
| 27 | +#include <linux/sysfs.h> | |
| 28 | +#include <linux/printk.h> | |
| 29 | +#include <linux/pm_runtime.h> | |
| 30 | +#include <linux/leds.h> | |
| 31 | +#include <linux/delay.h> | |
| 32 | + | |
| 33 | +/* Addresses to scan - BlinkM is on 0x09 by default*/ | |
| 34 | +static const unsigned short normal_i2c[] = { 0x09, I2C_CLIENT_END }; | |
| 35 | + | |
| 36 | +static int blinkm_transfer_hw(struct i2c_client *client, int cmd); | |
| 37 | +static int blinkm_test_run(struct i2c_client *client); | |
| 38 | + | |
| 39 | +struct blinkm_led { | |
| 40 | + struct i2c_client *i2c_client; | |
| 41 | + struct led_classdev led_cdev; | |
| 42 | + int id; | |
| 43 | + atomic_t active; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +struct blinkm_work { | |
| 47 | + struct blinkm_led *blinkm_led; | |
| 48 | + struct work_struct work; | |
| 49 | +}; | |
| 50 | + | |
| 51 | +#define cdev_to_blmled(c) container_of(c, struct blinkm_led, led_cdev) | |
| 52 | +#define work_to_blmwork(c) container_of(c, struct blinkm_work, work) | |
| 53 | + | |
| 54 | +struct blinkm_data { | |
| 55 | + struct i2c_client *i2c_client; | |
| 56 | + struct mutex update_lock; | |
| 57 | + /* used for led class interface */ | |
| 58 | + struct blinkm_led blinkm_leds[3]; | |
| 59 | + /* used for "blinkm" sysfs interface */ | |
| 60 | + u8 red; /* color red */ | |
| 61 | + u8 green; /* color green */ | |
| 62 | + u8 blue; /* color blue */ | |
| 63 | + /* next values to use for transfer */ | |
| 64 | + u8 next_red; /* color red */ | |
| 65 | + u8 next_green; /* color green */ | |
| 66 | + u8 next_blue; /* color blue */ | |
| 67 | + /* internal use */ | |
| 68 | + u8 args[7]; /* set of args for transmission */ | |
| 69 | + u8 i2c_addr; /* i2c addr */ | |
| 70 | + u8 fw_ver; /* firmware version */ | |
| 71 | + /* used, but not from userspace */ | |
| 72 | + u8 hue; /* HSB hue */ | |
| 73 | + u8 saturation; /* HSB saturation */ | |
| 74 | + u8 brightness; /* HSB brightness */ | |
| 75 | + u8 next_hue; /* HSB hue */ | |
| 76 | + u8 next_saturation; /* HSB saturation */ | |
| 77 | + u8 next_brightness; /* HSB brightness */ | |
| 78 | + /* currently unused / todo */ | |
| 79 | + u8 fade_speed; /* fade speed 1 - 255 */ | |
| 80 | + s8 time_adjust; /* time adjust -128 - 127 */ | |
| 81 | + u8 fade:1; /* fade on = 1, off = 0 */ | |
| 82 | + u8 rand:1; /* rand fade mode on = 1 */ | |
| 83 | + u8 script_id; /* script ID */ | |
| 84 | + u8 script_repeats; /* repeats of script */ | |
| 85 | + u8 script_startline; /* line to start */ | |
| 86 | +}; | |
| 87 | + | |
| 88 | +/* Colors */ | |
| 89 | +#define RED 0 | |
| 90 | +#define GREEN 1 | |
| 91 | +#define BLUE 2 | |
| 92 | + | |
| 93 | +/* mapping command names to cmd chars - see datasheet */ | |
| 94 | +#define BLM_GO_RGB 0 | |
| 95 | +#define BLM_FADE_RGB 1 | |
| 96 | +#define BLM_FADE_HSB 2 | |
| 97 | +#define BLM_FADE_RAND_RGB 3 | |
| 98 | +#define BLM_FADE_RAND_HSB 4 | |
| 99 | +#define BLM_PLAY_SCRIPT 5 | |
| 100 | +#define BLM_STOP_SCRIPT 6 | |
| 101 | +#define BLM_SET_FADE_SPEED 7 | |
| 102 | +#define BLM_SET_TIME_ADJ 8 | |
| 103 | +#define BLM_GET_CUR_RGB 9 | |
| 104 | +#define BLM_WRITE_SCRIPT_LINE 10 | |
| 105 | +#define BLM_READ_SCRIPT_LINE 11 | |
| 106 | +#define BLM_SET_SCRIPT_LR 12 /* Length & Repeats */ | |
| 107 | +#define BLM_SET_ADDR 13 | |
| 108 | +#define BLM_GET_ADDR 14 | |
| 109 | +#define BLM_GET_FW_VER 15 | |
| 110 | +#define BLM_SET_STARTUP_PARAM 16 | |
| 111 | + | |
| 112 | +/* BlinkM Commands | |
| 113 | + * as extracted out of the datasheet: | |
| 114 | + * | |
| 115 | + * cmdchar = command (ascii) | |
| 116 | + * cmdbyte = command in hex | |
| 117 | + * nr_args = number of arguments (to send) | |
| 118 | + * nr_ret = number of return values (to read) | |
| 119 | + * dir = direction (0 = read, 1 = write, 2 = both) | |
| 120 | + * | |
| 121 | + */ | |
| 122 | +static const struct { | |
| 123 | + char cmdchar; | |
| 124 | + u8 cmdbyte; | |
| 125 | + u8 nr_args; | |
| 126 | + u8 nr_ret; | |
| 127 | + u8 dir:2; | |
| 128 | +} blinkm_cmds[17] = { | |
| 129 | + /* cmdchar, cmdbyte, nr_args, nr_ret, dir */ | |
| 130 | + { 'n', 0x6e, 3, 0, 1}, | |
| 131 | + { 'c', 0x63, 3, 0, 1}, | |
| 132 | + { 'h', 0x68, 3, 0, 1}, | |
| 133 | + { 'C', 0x43, 3, 0, 1}, | |
| 134 | + { 'H', 0x48, 3, 0, 1}, | |
| 135 | + { 'p', 0x70, 3, 0, 1}, | |
| 136 | + { 'o', 0x6f, 0, 0, 1}, | |
| 137 | + { 'f', 0x66, 1, 0, 1}, | |
| 138 | + { 't', 0x74, 1, 0, 1}, | |
| 139 | + { 'g', 0x67, 0, 3, 0}, | |
| 140 | + { 'W', 0x57, 7, 0, 1}, | |
| 141 | + { 'R', 0x52, 2, 5, 2}, | |
| 142 | + { 'L', 0x4c, 3, 0, 1}, | |
| 143 | + { 'A', 0x41, 4, 0, 1}, | |
| 144 | + { 'a', 0x61, 0, 1, 0}, | |
| 145 | + { 'Z', 0x5a, 0, 1, 0}, | |
| 146 | + { 'B', 0x42, 5, 0, 1}, | |
| 147 | +}; | |
| 148 | + | |
| 149 | +static ssize_t show_color_common(struct device *dev, char *buf, int color) | |
| 150 | +{ | |
| 151 | + struct i2c_client *client; | |
| 152 | + struct blinkm_data *data; | |
| 153 | + int ret; | |
| 154 | + | |
| 155 | + client = to_i2c_client(dev); | |
| 156 | + data = i2c_get_clientdata(client); | |
| 157 | + | |
| 158 | + ret = blinkm_transfer_hw(client, BLM_GET_CUR_RGB); | |
| 159 | + if (ret < 0) | |
| 160 | + return ret; | |
| 161 | + switch (color) { | |
| 162 | + case RED: | |
| 163 | + return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red); | |
| 164 | + break; | |
| 165 | + case GREEN: | |
| 166 | + return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green); | |
| 167 | + break; | |
| 168 | + case BLUE: | |
| 169 | + return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue); | |
| 170 | + break; | |
| 171 | + default: | |
| 172 | + return -EINVAL; | |
| 173 | + } | |
| 174 | + return -EINVAL; | |
| 175 | +} | |
| 176 | + | |
| 177 | +static int store_color_common(struct device *dev, const char *buf, int color) | |
| 178 | +{ | |
| 179 | + struct i2c_client *client; | |
| 180 | + struct blinkm_data *data; | |
| 181 | + int ret; | |
| 182 | + u8 value; | |
| 183 | + | |
| 184 | + client = to_i2c_client(dev); | |
| 185 | + data = i2c_get_clientdata(client); | |
| 186 | + | |
| 187 | + ret = kstrtou8(buf, 10, &value); | |
| 188 | + if (ret < 0) { | |
| 189 | + dev_err(dev, "BlinkM: value too large!\n"); | |
| 190 | + return ret; | |
| 191 | + } | |
| 192 | + | |
| 193 | + switch (color) { | |
| 194 | + case RED: | |
| 195 | + data->next_red = value; | |
| 196 | + break; | |
| 197 | + case GREEN: | |
| 198 | + data->next_green = value; | |
| 199 | + break; | |
| 200 | + case BLUE: | |
| 201 | + data->next_blue = value; | |
| 202 | + break; | |
| 203 | + default: | |
| 204 | + return -EINVAL; | |
| 205 | + } | |
| 206 | + | |
| 207 | + dev_dbg(dev, "next_red = %d, next_green = %d, next_blue = %d\n", | |
| 208 | + data->next_red, data->next_green, data->next_blue); | |
| 209 | + | |
| 210 | + /* if mode ... */ | |
| 211 | + ret = blinkm_transfer_hw(client, BLM_GO_RGB); | |
| 212 | + if (ret < 0) { | |
| 213 | + dev_err(dev, "BlinkM: can't set RGB\n"); | |
| 214 | + return ret; | |
| 215 | + } | |
| 216 | + return 0; | |
| 217 | +} | |
| 218 | + | |
| 219 | +static ssize_t show_red(struct device *dev, struct device_attribute *attr, | |
| 220 | + char *buf) | |
| 221 | +{ | |
| 222 | + return show_color_common(dev, buf, RED); | |
| 223 | +} | |
| 224 | + | |
| 225 | +static ssize_t store_red(struct device *dev, struct device_attribute *attr, | |
| 226 | + const char *buf, size_t count) | |
| 227 | +{ | |
| 228 | + int ret; | |
| 229 | + | |
| 230 | + ret = store_color_common(dev, buf, RED); | |
| 231 | + if (ret < 0) | |
| 232 | + return ret; | |
| 233 | + return count; | |
| 234 | +} | |
| 235 | + | |
| 236 | +static DEVICE_ATTR(red, S_IRUGO | S_IWUSR, show_red, store_red); | |
| 237 | + | |
| 238 | +static ssize_t show_green(struct device *dev, struct device_attribute *attr, | |
| 239 | + char *buf) | |
| 240 | +{ | |
| 241 | + return show_color_common(dev, buf, GREEN); | |
| 242 | +} | |
| 243 | + | |
| 244 | +static ssize_t store_green(struct device *dev, struct device_attribute *attr, | |
| 245 | + const char *buf, size_t count) | |
| 246 | +{ | |
| 247 | + | |
| 248 | + int ret; | |
| 249 | + | |
| 250 | + ret = store_color_common(dev, buf, GREEN); | |
| 251 | + if (ret < 0) | |
| 252 | + return ret; | |
| 253 | + return count; | |
| 254 | +} | |
| 255 | + | |
| 256 | +static DEVICE_ATTR(green, S_IRUGO | S_IWUSR, show_green, store_green); | |
| 257 | + | |
| 258 | +static ssize_t show_blue(struct device *dev, struct device_attribute *attr, | |
| 259 | + char *buf) | |
| 260 | +{ | |
| 261 | + return show_color_common(dev, buf, BLUE); | |
| 262 | +} | |
| 263 | + | |
| 264 | +static ssize_t store_blue(struct device *dev, struct device_attribute *attr, | |
| 265 | + const char *buf, size_t count) | |
| 266 | +{ | |
| 267 | + int ret; | |
| 268 | + | |
| 269 | + ret = store_color_common(dev, buf, BLUE); | |
| 270 | + if (ret < 0) | |
| 271 | + return ret; | |
| 272 | + return count; | |
| 273 | +} | |
| 274 | + | |
| 275 | +static DEVICE_ATTR(blue, S_IRUGO | S_IWUSR, show_blue, store_blue); | |
| 276 | + | |
| 277 | +static ssize_t show_test(struct device *dev, struct device_attribute *attr, | |
| 278 | + char *buf) | |
| 279 | +{ | |
| 280 | + return scnprintf(buf, PAGE_SIZE, | |
| 281 | + "#Write into test to start test sequence!#\n"); | |
| 282 | +} | |
| 283 | + | |
| 284 | +static ssize_t store_test(struct device *dev, struct device_attribute *attr, | |
| 285 | + const char *buf, size_t count) | |
| 286 | +{ | |
| 287 | + | |
| 288 | + struct i2c_client *client; | |
| 289 | + int ret; | |
| 290 | + client = to_i2c_client(dev); | |
| 291 | + | |
| 292 | + /*test */ | |
| 293 | + ret = blinkm_test_run(client); | |
| 294 | + if (ret < 0) | |
| 295 | + return ret; | |
| 296 | + | |
| 297 | + return count; | |
| 298 | +} | |
| 299 | + | |
| 300 | +static DEVICE_ATTR(test, S_IRUGO | S_IWUSR, show_test, store_test); | |
| 301 | + | |
| 302 | +/* TODO: HSB, fade, timeadj, script ... */ | |
| 303 | + | |
| 304 | +static struct attribute *blinkm_attrs[] = { | |
| 305 | + &dev_attr_red.attr, | |
| 306 | + &dev_attr_green.attr, | |
| 307 | + &dev_attr_blue.attr, | |
| 308 | + &dev_attr_test.attr, | |
| 309 | + NULL, | |
| 310 | +}; | |
| 311 | + | |
| 312 | +static struct attribute_group blinkm_group = { | |
| 313 | + .name = "blinkm", | |
| 314 | + .attrs = blinkm_attrs, | |
| 315 | +}; | |
| 316 | + | |
| 317 | +static int blinkm_write(struct i2c_client *client, int cmd, u8 *arg) | |
| 318 | +{ | |
| 319 | + int result; | |
| 320 | + int i; | |
| 321 | + int arglen = blinkm_cmds[cmd].nr_args; | |
| 322 | + /* write out cmd to blinkm - always / default step */ | |
| 323 | + result = i2c_smbus_write_byte(client, blinkm_cmds[cmd].cmdbyte); | |
| 324 | + if (result < 0) | |
| 325 | + return result; | |
| 326 | + /* no args to write out */ | |
| 327 | + if (arglen == 0) | |
| 328 | + return 0; | |
| 329 | + | |
| 330 | + for (i = 0; i < arglen; i++) { | |
| 331 | + /* repeat for arglen */ | |
| 332 | + result = i2c_smbus_write_byte(client, arg[i]); | |
| 333 | + if (result < 0) | |
| 334 | + return result; | |
| 335 | + } | |
| 336 | + return 0; | |
| 337 | +} | |
| 338 | + | |
| 339 | +static int blinkm_read(struct i2c_client *client, int cmd, u8 *arg) | |
| 340 | +{ | |
| 341 | + int result; | |
| 342 | + int i; | |
| 343 | + int retlen = blinkm_cmds[cmd].nr_ret; | |
| 344 | + for (i = 0; i < retlen; i++) { | |
| 345 | + /* repeat for retlen */ | |
| 346 | + result = i2c_smbus_read_byte(client); | |
| 347 | + if (result < 0) | |
| 348 | + return result; | |
| 349 | + arg[i] = result; | |
| 350 | + } | |
| 351 | + | |
| 352 | + return 0; | |
| 353 | +} | |
| 354 | + | |
| 355 | +static int blinkm_transfer_hw(struct i2c_client *client, int cmd) | |
| 356 | +{ | |
| 357 | + /* the protocol is simple but non-standard: | |
| 358 | + * e.g. cmd 'g' (= 0x67) for "get device address" | |
| 359 | + * - which defaults to 0x09 - would be the sequence: | |
| 360 | + * a) write 0x67 to the device (byte write) | |
| 361 | + * b) read the value (0x09) back right after (byte read) | |
| 362 | + * | |
| 363 | + * Watch out for "unfinished" sequences (i.e. not enough reads | |
| 364 | + * or writes after a command. It will make the blinkM misbehave. | |
| 365 | + * Sequence is key here. | |
| 366 | + */ | |
| 367 | + | |
| 368 | + /* args / return are in private data struct */ | |
| 369 | + struct blinkm_data *data = i2c_get_clientdata(client); | |
| 370 | + | |
| 371 | + /* We start hardware transfers which are not to be | |
| 372 | + * mixed with other commands. Aquire a lock now. */ | |
| 373 | + if (mutex_lock_interruptible(&data->update_lock) < 0) | |
| 374 | + return -EAGAIN; | |
| 375 | + | |
| 376 | + /* switch cmd - usually write before reads */ | |
| 377 | + switch (cmd) { | |
| 378 | + case BLM_FADE_RAND_RGB: | |
| 379 | + case BLM_GO_RGB: | |
| 380 | + case BLM_FADE_RGB: | |
| 381 | + data->args[0] = data->next_red; | |
| 382 | + data->args[1] = data->next_green; | |
| 383 | + data->args[2] = data->next_blue; | |
| 384 | + blinkm_write(client, cmd, data->args); | |
| 385 | + data->red = data->args[0]; | |
| 386 | + data->green = data->args[1]; | |
| 387 | + data->blue = data->args[2]; | |
| 388 | + break; | |
| 389 | + case BLM_FADE_HSB: | |
| 390 | + case BLM_FADE_RAND_HSB: | |
| 391 | + data->args[0] = data->next_hue; | |
| 392 | + data->args[1] = data->next_saturation; | |
| 393 | + data->args[2] = data->next_brightness; | |
| 394 | + blinkm_write(client, cmd, data->args); | |
| 395 | + data->hue = data->next_hue; | |
| 396 | + data->saturation = data->next_saturation; | |
| 397 | + data->brightness = data->next_brightness; | |
| 398 | + break; | |
| 399 | + case BLM_PLAY_SCRIPT: | |
| 400 | + data->args[0] = data->script_id; | |
| 401 | + data->args[1] = data->script_repeats; | |
| 402 | + data->args[2] = data->script_startline; | |
| 403 | + blinkm_write(client, cmd, data->args); | |
| 404 | + break; | |
| 405 | + case BLM_STOP_SCRIPT: | |
| 406 | + blinkm_write(client, cmd, NULL); | |
| 407 | + break; | |
| 408 | + case BLM_GET_CUR_RGB: | |
| 409 | + data->args[0] = data->red; | |
| 410 | + data->args[1] = data->green; | |
| 411 | + data->args[2] = data->blue; | |
| 412 | + blinkm_write(client, cmd, NULL); | |
| 413 | + blinkm_read(client, cmd, data->args); | |
| 414 | + data->red = data->args[0]; | |
| 415 | + data->green = data->args[1]; | |
| 416 | + data->blue = data->args[2]; | |
| 417 | + break; | |
| 418 | + case BLM_GET_ADDR: | |
| 419 | + data->args[0] = data->i2c_addr; | |
| 420 | + blinkm_write(client, cmd, NULL); | |
| 421 | + blinkm_read(client, cmd, data->args); | |
| 422 | + data->i2c_addr = data->args[0]; | |
| 423 | + break; | |
| 424 | + case BLM_SET_TIME_ADJ: | |
| 425 | + case BLM_SET_FADE_SPEED: | |
| 426 | + case BLM_READ_SCRIPT_LINE: | |
| 427 | + case BLM_WRITE_SCRIPT_LINE: | |
| 428 | + case BLM_SET_SCRIPT_LR: | |
| 429 | + case BLM_SET_ADDR: | |
| 430 | + case BLM_GET_FW_VER: | |
| 431 | + case BLM_SET_STARTUP_PARAM: | |
| 432 | + dev_err(&client->dev, | |
| 433 | + "BlinkM: cmd %d not implemented yet.\n", cmd); | |
| 434 | + break; | |
| 435 | + default: | |
| 436 | + dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd); | |
| 437 | + mutex_unlock(&data->update_lock); | |
| 438 | + return -EINVAL; | |
| 439 | + } /* end switch(cmd) */ | |
| 440 | + | |
| 441 | + /* transfers done, unlock */ | |
| 442 | + mutex_unlock(&data->update_lock); | |
| 443 | + return 0; | |
| 444 | +} | |
| 445 | + | |
| 446 | +static void led_work(struct work_struct *work) | |
| 447 | +{ | |
| 448 | + int ret; | |
| 449 | + struct blinkm_led *led; | |
| 450 | + struct blinkm_data *data ; | |
| 451 | + struct blinkm_work *blm_work = work_to_blmwork(work); | |
| 452 | + | |
| 453 | + led = blm_work->blinkm_led; | |
| 454 | + data = i2c_get_clientdata(led->i2c_client); | |
| 455 | + ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB); | |
| 456 | + atomic_dec(&led->active); | |
| 457 | + dev_dbg(&led->i2c_client->dev, | |
| 458 | + "# DONE # next_red = %d, next_green = %d," | |
| 459 | + " next_blue = %d, active = %d\n", | |
| 460 | + data->next_red, data->next_green, | |
| 461 | + data->next_blue, atomic_read(&led->active)); | |
| 462 | + kfree(blm_work); | |
| 463 | +} | |
| 464 | + | |
| 465 | +static int blinkm_led_common_set(struct led_classdev *led_cdev, | |
| 466 | + enum led_brightness value, int color) | |
| 467 | +{ | |
| 468 | + /* led_brightness is 0, 127 or 255 - we just use it here as-is */ | |
| 469 | + struct blinkm_led *led = cdev_to_blmled(led_cdev); | |
| 470 | + struct blinkm_data *data = i2c_get_clientdata(led->i2c_client); | |
| 471 | + struct blinkm_work *bl_work; | |
| 472 | + | |
| 473 | + switch (color) { | |
| 474 | + case RED: | |
| 475 | + /* bail out if there's no change */ | |
| 476 | + if (data->next_red == (u8) value) | |
| 477 | + return 0; | |
| 478 | + /* we assume a quite fast sequence here ([off]->on->off) | |
| 479 | + * think of network led trigger - we cannot blink that fast, so | |
| 480 | + * in case we already have a off->on->off transition queued up, | |
| 481 | + * we refuse to queue up more. | |
| 482 | + * Revisit: fast-changing brightness. */ | |
| 483 | + if (atomic_read(&led->active) > 1) | |
| 484 | + return 0; | |
| 485 | + data->next_red = (u8) value; | |
| 486 | + break; | |
| 487 | + case GREEN: | |
| 488 | + /* bail out if there's no change */ | |
| 489 | + if (data->next_green == (u8) value) | |
| 490 | + return 0; | |
| 491 | + /* we assume a quite fast sequence here ([off]->on->off) | |
| 492 | + * Revisit: fast-changing brightness. */ | |
| 493 | + if (atomic_read(&led->active) > 1) | |
| 494 | + return 0; | |
| 495 | + data->next_green = (u8) value; | |
| 496 | + break; | |
| 497 | + case BLUE: | |
| 498 | + /* bail out if there's no change */ | |
| 499 | + if (data->next_blue == (u8) value) | |
| 500 | + return 0; | |
| 501 | + /* we assume a quite fast sequence here ([off]->on->off) | |
| 502 | + * Revisit: fast-changing brightness. */ | |
| 503 | + if (atomic_read(&led->active) > 1) | |
| 504 | + return 0; | |
| 505 | + data->next_blue = (u8) value; | |
| 506 | + break; | |
| 507 | + | |
| 508 | + default: | |
| 509 | + dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n"); | |
| 510 | + return -EINVAL; | |
| 511 | + } | |
| 512 | + | |
| 513 | + bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC); | |
| 514 | + if (!bl_work) | |
| 515 | + return -ENOMEM; | |
| 516 | + | |
| 517 | + atomic_inc(&led->active); | |
| 518 | + dev_dbg(&led->i2c_client->dev, | |
| 519 | + "#TO_SCHED# next_red = %d, next_green = %d," | |
| 520 | + " next_blue = %d, active = %d\n", | |
| 521 | + data->next_red, data->next_green, | |
| 522 | + data->next_blue, atomic_read(&led->active)); | |
| 523 | + | |
| 524 | + /* a fresh work _item_ for each change */ | |
| 525 | + bl_work->blinkm_led = led; | |
| 526 | + INIT_WORK(&bl_work->work, led_work); | |
| 527 | + /* queue work in own queue for easy sync on exit*/ | |
| 528 | + schedule_work(&bl_work->work); | |
| 529 | + | |
| 530 | + return 0; | |
| 531 | +} | |
| 532 | + | |
| 533 | +static void blinkm_led_red_set(struct led_classdev *led_cdev, | |
| 534 | + enum led_brightness value) | |
| 535 | +{ | |
| 536 | + blinkm_led_common_set(led_cdev, value, RED); | |
| 537 | +} | |
| 538 | + | |
| 539 | +static void blinkm_led_green_set(struct led_classdev *led_cdev, | |
| 540 | + enum led_brightness value) | |
| 541 | +{ | |
| 542 | + blinkm_led_common_set(led_cdev, value, GREEN); | |
| 543 | +} | |
| 544 | + | |
| 545 | +static void blinkm_led_blue_set(struct led_classdev *led_cdev, | |
| 546 | + enum led_brightness value) | |
| 547 | +{ | |
| 548 | + blinkm_led_common_set(led_cdev, value, BLUE); | |
| 549 | +} | |
| 550 | + | |
| 551 | +static void blinkm_init_hw(struct i2c_client *client) | |
| 552 | +{ | |
| 553 | + int ret; | |
| 554 | + ret = blinkm_transfer_hw(client, BLM_STOP_SCRIPT); | |
| 555 | + ret = blinkm_transfer_hw(client, BLM_GO_RGB); | |
| 556 | +} | |
| 557 | + | |
| 558 | +static int blinkm_test_run(struct i2c_client *client) | |
| 559 | +{ | |
| 560 | + int ret; | |
| 561 | + struct blinkm_data *data = i2c_get_clientdata(client); | |
| 562 | + | |
| 563 | + data->next_red = 0x01; | |
| 564 | + data->next_green = 0x05; | |
| 565 | + data->next_blue = 0x10; | |
| 566 | + ret = blinkm_transfer_hw(client, BLM_GO_RGB); | |
| 567 | + if (ret < 0) | |
| 568 | + return ret; | |
| 569 | + msleep(2000); | |
| 570 | + | |
| 571 | + data->next_red = 0x25; | |
| 572 | + data->next_green = 0x10; | |
| 573 | + data->next_blue = 0x31; | |
| 574 | + ret = blinkm_transfer_hw(client, BLM_FADE_RGB); | |
| 575 | + if (ret < 0) | |
| 576 | + return ret; | |
| 577 | + msleep(2000); | |
| 578 | + | |
| 579 | + data->next_hue = 0x50; | |
| 580 | + data->next_saturation = 0x10; | |
| 581 | + data->next_brightness = 0x20; | |
| 582 | + ret = blinkm_transfer_hw(client, BLM_FADE_HSB); | |
| 583 | + if (ret < 0) | |
| 584 | + return ret; | |
| 585 | + msleep(2000); | |
| 586 | + | |
| 587 | + return 0; | |
| 588 | +} | |
| 589 | + | |
| 590 | +/* Return 0 if detection is successful, -ENODEV otherwise */ | |
| 591 | +static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info) | |
| 592 | +{ | |
| 593 | + struct i2c_adapter *adapter = client->adapter; | |
| 594 | + int ret; | |
| 595 | + int count = 99; | |
| 596 | + u8 tmpargs[7]; | |
| 597 | + | |
| 598 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
| 599 | + | I2C_FUNC_SMBUS_WORD_DATA | |
| 600 | + | I2C_FUNC_SMBUS_WRITE_BYTE)) | |
| 601 | + return -ENODEV; | |
| 602 | + | |
| 603 | + /* Now, we do the remaining detection. Simple for now. */ | |
| 604 | + /* We might need more guards to protect other i2c slaves */ | |
| 605 | + | |
| 606 | + /* make sure the blinkM is balanced (read/writes) */ | |
| 607 | + while (count > 0) { | |
| 608 | + ret = blinkm_write(client, BLM_GET_ADDR, NULL); | |
| 609 | + usleep_range(5000, 10000); | |
| 610 | + ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); | |
| 611 | + usleep_range(5000, 10000); | |
| 612 | + if (tmpargs[0] == 0x09) | |
| 613 | + count = 0; | |
| 614 | + count--; | |
| 615 | + } | |
| 616 | + | |
| 617 | + /* Step 1: Read BlinkM address back - cmd_char 'a' */ | |
| 618 | + ret = blinkm_write(client, BLM_GET_ADDR, NULL); | |
| 619 | + if (ret < 0) | |
| 620 | + return ret; | |
| 621 | + usleep_range(20000, 30000); /* allow a small delay */ | |
| 622 | + ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); | |
| 623 | + if (ret < 0) | |
| 624 | + return ret; | |
| 625 | + | |
| 626 | + if (tmpargs[0] != 0x09) { | |
| 627 | + dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]); | |
| 628 | + return -ENODEV; | |
| 629 | + } | |
| 630 | + | |
| 631 | + strlcpy(info->type, "blinkm", I2C_NAME_SIZE); | |
| 632 | + return 0; | |
| 633 | +} | |
| 634 | + | |
| 635 | +static int __devinit blinkm_probe(struct i2c_client *client, | |
| 636 | + const struct i2c_device_id *id) | |
| 637 | +{ | |
| 638 | + struct blinkm_data *data; | |
| 639 | + struct blinkm_led *led[3]; | |
| 640 | + int err, i; | |
| 641 | + char blinkm_led_name[28]; | |
| 642 | + | |
| 643 | + data = devm_kzalloc(&client->dev, | |
| 644 | + sizeof(struct blinkm_data), GFP_KERNEL); | |
| 645 | + if (!data) { | |
| 646 | + err = -ENOMEM; | |
| 647 | + goto exit; | |
| 648 | + } | |
| 649 | + | |
| 650 | + data->i2c_addr = 0x09; | |
| 651 | + data->i2c_addr = 0x08; | |
| 652 | + /* i2c addr - use fake addr of 0x08 initially (real is 0x09) */ | |
| 653 | + data->fw_ver = 0xfe; | |
| 654 | + /* firmware version - use fake until we read real value | |
| 655 | + * (currently broken - BlinkM confused!) */ | |
| 656 | + data->script_id = 0x01; | |
| 657 | + data->i2c_client = client; | |
| 658 | + | |
| 659 | + i2c_set_clientdata(client, data); | |
| 660 | + mutex_init(&data->update_lock); | |
| 661 | + | |
| 662 | + /* Register sysfs hooks */ | |
| 663 | + err = sysfs_create_group(&client->dev.kobj, &blinkm_group); | |
| 664 | + if (err < 0) { | |
| 665 | + dev_err(&client->dev, "couldn't register sysfs group\n"); | |
| 666 | + goto exit; | |
| 667 | + } | |
| 668 | + | |
| 669 | + for (i = 0; i < 3; i++) { | |
| 670 | + /* RED = 0, GREEN = 1, BLUE = 2 */ | |
| 671 | + led[i] = &data->blinkm_leds[i]; | |
| 672 | + led[i]->i2c_client = client; | |
| 673 | + led[i]->id = i; | |
| 674 | + led[i]->led_cdev.max_brightness = 255; | |
| 675 | + led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME; | |
| 676 | + atomic_set(&led[i]->active, 0); | |
| 677 | + switch (i) { | |
| 678 | + case RED: | |
| 679 | + snprintf(blinkm_led_name, sizeof(blinkm_led_name), | |
| 680 | + "blinkm-%d-%d-red", | |
| 681 | + client->adapter->nr, | |
| 682 | + client->addr); | |
| 683 | + led[i]->led_cdev.name = blinkm_led_name; | |
| 684 | + led[i]->led_cdev.brightness_set = blinkm_led_red_set; | |
| 685 | + err = led_classdev_register(&client->dev, | |
| 686 | + &led[i]->led_cdev); | |
| 687 | + if (err < 0) { | |
| 688 | + dev_err(&client->dev, | |
| 689 | + "couldn't register LED %s\n", | |
| 690 | + led[i]->led_cdev.name); | |
| 691 | + goto failred; | |
| 692 | + } | |
| 693 | + break; | |
| 694 | + case GREEN: | |
| 695 | + snprintf(blinkm_led_name, sizeof(blinkm_led_name), | |
| 696 | + "blinkm-%d-%d-green", | |
| 697 | + client->adapter->nr, | |
| 698 | + client->addr); | |
| 699 | + led[i]->led_cdev.name = blinkm_led_name; | |
| 700 | + led[i]->led_cdev.brightness_set = blinkm_led_green_set; | |
| 701 | + err = led_classdev_register(&client->dev, | |
| 702 | + &led[i]->led_cdev); | |
| 703 | + if (err < 0) { | |
| 704 | + dev_err(&client->dev, | |
| 705 | + "couldn't register LED %s\n", | |
| 706 | + led[i]->led_cdev.name); | |
| 707 | + goto failgreen; | |
| 708 | + } | |
| 709 | + break; | |
| 710 | + case BLUE: | |
| 711 | + snprintf(blinkm_led_name, sizeof(blinkm_led_name), | |
| 712 | + "blinkm-%d-%d-blue", | |
| 713 | + client->adapter->nr, | |
| 714 | + client->addr); | |
| 715 | + led[i]->led_cdev.name = blinkm_led_name; | |
| 716 | + led[i]->led_cdev.brightness_set = blinkm_led_blue_set; | |
| 717 | + err = led_classdev_register(&client->dev, | |
| 718 | + &led[i]->led_cdev); | |
| 719 | + if (err < 0) { | |
| 720 | + dev_err(&client->dev, | |
| 721 | + "couldn't register LED %s\n", | |
| 722 | + led[i]->led_cdev.name); | |
| 723 | + goto failblue; | |
| 724 | + } | |
| 725 | + break; | |
| 726 | + } /* end switch */ | |
| 727 | + } /* end for */ | |
| 728 | + | |
| 729 | + /* Initialize the blinkm */ | |
| 730 | + blinkm_init_hw(client); | |
| 731 | + | |
| 732 | + return 0; | |
| 733 | + | |
| 734 | +failblue: | |
| 735 | + led_classdev_unregister(&led[GREEN]->led_cdev); | |
| 736 | + | |
| 737 | +failgreen: | |
| 738 | + led_classdev_unregister(&led[RED]->led_cdev); | |
| 739 | + | |
| 740 | +failred: | |
| 741 | + sysfs_remove_group(&client->dev.kobj, &blinkm_group); | |
| 742 | +exit: | |
| 743 | + return err; | |
| 744 | +} | |
| 745 | + | |
| 746 | +static int __devexit blinkm_remove(struct i2c_client *client) | |
| 747 | +{ | |
| 748 | + struct blinkm_data *data = i2c_get_clientdata(client); | |
| 749 | + int ret = 0; | |
| 750 | + int i; | |
| 751 | + | |
| 752 | + /* make sure no workqueue entries are pending */ | |
| 753 | + for (i = 0; i < 3; i++) { | |
| 754 | + flush_scheduled_work(); | |
| 755 | + led_classdev_unregister(&data->blinkm_leds[i].led_cdev); | |
| 756 | + } | |
| 757 | + | |
| 758 | + /* reset rgb */ | |
| 759 | + data->next_red = 0x00; | |
| 760 | + data->next_green = 0x00; | |
| 761 | + data->next_blue = 0x00; | |
| 762 | + ret = blinkm_transfer_hw(client, BLM_FADE_RGB); | |
| 763 | + if (ret < 0) | |
| 764 | + dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); | |
| 765 | + | |
| 766 | + /* reset hsb */ | |
| 767 | + data->next_hue = 0x00; | |
| 768 | + data->next_saturation = 0x00; | |
| 769 | + data->next_brightness = 0x00; | |
| 770 | + ret = blinkm_transfer_hw(client, BLM_FADE_HSB); | |
| 771 | + if (ret < 0) | |
| 772 | + dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); | |
| 773 | + | |
| 774 | + /* red fade to off */ | |
| 775 | + data->next_red = 0xff; | |
| 776 | + ret = blinkm_transfer_hw(client, BLM_GO_RGB); | |
| 777 | + if (ret < 0) | |
| 778 | + dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); | |
| 779 | + | |
| 780 | + /* off */ | |
| 781 | + data->next_red = 0x00; | |
| 782 | + ret = blinkm_transfer_hw(client, BLM_FADE_RGB); | |
| 783 | + if (ret < 0) | |
| 784 | + dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); | |
| 785 | + | |
| 786 | + sysfs_remove_group(&client->dev.kobj, &blinkm_group); | |
| 787 | + return 0; | |
| 788 | +} | |
| 789 | + | |
| 790 | +static const struct i2c_device_id blinkm_id[] = { | |
| 791 | + {"blinkm", 0}, | |
| 792 | + {} | |
| 793 | +}; | |
| 794 | + | |
| 795 | +MODULE_DEVICE_TABLE(i2c, blinkm_id); | |
| 796 | + | |
| 797 | + /* This is the driver that will be inserted */ | |
| 798 | +static struct i2c_driver blinkm_driver = { | |
| 799 | + .class = I2C_CLASS_HWMON, | |
| 800 | + .driver = { | |
| 801 | + .name = "blinkm", | |
| 802 | + }, | |
| 803 | + .probe = blinkm_probe, | |
| 804 | + .remove = __devexit_p(blinkm_remove), | |
| 805 | + .id_table = blinkm_id, | |
| 806 | + .detect = blinkm_detect, | |
| 807 | + .address_list = normal_i2c, | |
| 808 | +}; | |
| 809 | + | |
| 810 | +module_i2c_driver(blinkm_driver); | |
| 811 | + | |
| 812 | +MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>"); | |
| 813 | +MODULE_DESCRIPTION("BlinkM RGB LED driver"); | |
| 814 | +MODULE_LICENSE("GPL"); | |
| 815 | + | |
| @@ -108,7 +108,7 @@ static int __devinit da903x_led_probe(struct platform_device *pdev) · 107 unmodified lines | ||
| 108 | 108 | return -EINVAL; |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | − led = kzalloc(sizeof(struct da903x_led), GFP_KERNEL); | |
| 111 | + led = devm_kzalloc(&pdev->dev, sizeof(struct da903x_led), GFP_KERNEL); | |
| 112 | 112 | if (led == NULL) { |
| 113 | 113 | dev_err(&pdev->dev, "failed to alloc memory for LED%d\n", id); |
| 114 | 114 | return -ENOMEM; |
| @@ -129,15 +129,11 @@ static int __devinit da903x_led_probe(struct platform_device *pdev) · 14 unmodified lines | ||
| 129 | 129 | ret = led_classdev_register(led->master, &led->cdev); |
| 130 | 130 | if (ret) { |
| 131 | 131 | dev_err(&pdev->dev, "failed to register LED %d\n", id); |
| 132 | − goto err; | |
| 132 | + return ret; | |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | platform_set_drvdata(pdev, led); |
| 136 | 136 | return 0; |
| 137 | − | |
| 138 | −err: | |
| 139 | − kfree(led); | |
| 140 | − return ret; | |
| 141 | 137 | } |
| 142 | 138 | |
| 143 | 139 | static int __devexit da903x_led_remove(struct platform_device *pdev) |
| @@ -145,7 +141,6 @@ static int __devexit da903x_led_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 145 | 141 | struct da903x_led *led = platform_get_drvdata(pdev); |
| 146 | 142 | |
| 147 | 143 | led_classdev_unregister(&led->cdev); |
| 148 | − kfree(led); | |
| 149 | 144 | return 0; |
| 150 | 145 | } |
| 151 | 146 | |
| @@ -69,7 +69,7 @@ static int dac124s085_probe(struct spi_device *spi) · 68 unmodified lines | ||
| 69 | 69 | struct dac124s085_led *led; |
| 70 | 70 | int i, ret; |
| 71 | 71 | |
| 72 | − dac = kzalloc(sizeof(*dac), GFP_KERNEL); | |
| 72 | + dac = devm_kzalloc(&spi->dev, sizeof(*dac), GFP_KERNEL); | |
| 73 | 73 | if (!dac) |
| 74 | 74 | return -ENOMEM; |
| 75 | 75 | |
| @@ -102,7 +102,6 @@ eledcr: · 26 unmodified lines | ||
| 102 | 102 | led_classdev_unregister(&dac->leds[i].ldev); |
| 103 | 103 | |
| 104 | 104 | spi_set_drvdata(spi, NULL); |
| 105 | − kfree(dac); | |
| 106 | 105 | return ret; |
| 107 | 106 | } |
| 108 | 107 | |
| @@ -117,7 +116,6 @@ static int dac124s085_remove(struct spi_device *spi) · 8 unmodified lines | ||
| 117 | 116 | } |
| 118 | 117 | |
| 119 | 118 | spi_set_drvdata(spi, NULL); |
| 120 | − kfree(dac); | |
| 121 | 119 | |
| 122 | 120 | return 0; |
| 123 | 121 | } |
| @@ -178,7 +178,8 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev · 177 unmodified lines | ||
| 178 | 178 | if (!count) |
| 179 | 179 | return NULL; |
| 180 | 180 | |
| 181 | − priv = kzalloc(sizeof_gpio_leds_priv(count), GFP_KERNEL); | |
| 181 | + priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count), | |
| 182 | + GFP_KERNEL); | |
| 182 | 183 | if (!priv) |
| 183 | 184 | return NULL; |
| 184 | 185 | |
| @@ -215,7 +216,6 @@ static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_dev · 30 unmodified lines | ||
| 215 | 216 | err: |
| 216 | 217 | for (count = priv->num_leds - 2; count >= 0; count--) |
| 217 | 218 | delete_gpio_led(&priv->leds[count]); |
| 218 | − kfree(priv); | |
| 219 | 219 | return NULL; |
| 220 | 220 | } |
| 221 | 221 | |
| @@ -239,8 +239,9 @@ static int __devinit gpio_led_probe(struct platform_device *pdev) · 17 unmodified lines | ||
| 239 | 239 | int i, ret = 0; |
| 240 | 240 | |
| 241 | 241 | if (pdata && pdata->num_leds) { |
| 242 | − priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds), | |
| 243 | − GFP_KERNEL); | |
| 242 | + priv = devm_kzalloc(&pdev->dev, | |
| 243 | + sizeof_gpio_leds_priv(pdata->num_leds), | |
| 244 | + GFP_KERNEL); | |
| 244 | 245 | if (!priv) |
| 245 | 246 | return -ENOMEM; |
| 246 | 247 | |
| @@ -253,7 +254,6 @@ static int __devinit gpio_led_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 253 | 254 | /* On failure: unwind the led creations */ |
| 254 | 255 | for (i = i - 1; i >= 0; i--) |
| 255 | 256 | delete_gpio_led(&priv->leds[i]); |
| 256 | − kfree(priv); | |
| 257 | 257 | return ret; |
| 258 | 258 | } |
| 259 | 259 | } |
| @@ -277,7 +277,6 @@ static int __devexit gpio_led_remove(struct platform_device *pdev) · 17 unmodified lines | ||
| 277 | 277 | delete_gpio_led(&priv->leds[i]); |
| 278 | 278 | |
| 279 | 279 | dev_set_drvdata(&pdev->dev, NULL); |
| 280 | − kfree(priv); | |
| 281 | 280 | |
| 282 | 281 | return 0; |
| 283 | 282 | } |
| @@ -386,28 +386,24 @@ static int __devinit lm3530_probe(struct i2c_client *client, · 385 unmodified lines | ||
| 386 | 386 | |
| 387 | 387 | if (pdata == NULL) { |
| 388 | 388 | dev_err(&client->dev, "platform data required\n"); |
| 389 | − err = -ENODEV; | |
| 390 | − goto err_out; | |
| 389 | + return -ENODEV; | |
| 391 | 390 | } |
| 392 | 391 | |
| 393 | 392 | /* BL mode */ |
| 394 | 393 | if (pdata->mode > LM3530_BL_MODE_PWM) { |
| 395 | 394 | dev_err(&client->dev, "Illegal Mode request\n"); |
| 396 | − err = -EINVAL; | |
| 397 | − goto err_out; | |
| 395 | + return -EINVAL; | |
| 398 | 396 | } |
| 399 | 397 | |
| 400 | 398 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
| 401 | 399 | dev_err(&client->dev, "I2C_FUNC_I2C not supported\n"); |
| 402 | − err = -EIO; | |
| 403 | − goto err_out; | |
| 400 | + return -EIO; | |
| 404 | 401 | } |
| 405 | 402 | |
| 406 | − drvdata = kzalloc(sizeof(struct lm3530_data), GFP_KERNEL); | |
| 407 | − if (drvdata == NULL) { | |
| 408 | − err = -ENOMEM; | |
| 409 | − goto err_out; | |
| 410 | − } | |
| 403 | + drvdata = devm_kzalloc(&client->dev, sizeof(struct lm3530_data), | |
| 404 | + GFP_KERNEL); | |
| 405 | + if (drvdata == NULL) | |
| 406 | + return -ENOMEM; | |
| 411 | 407 | |
| 412 | 408 | drvdata->mode = pdata->mode; |
| 413 | 409 | drvdata->client = client; |
| @@ -425,7 +421,7 @@ static int __devinit lm3530_probe(struct i2c_client *client, · 11 unmodified lines | ||
| 425 | 421 | dev_err(&client->dev, "regulator get failed\n"); |
| 426 | 422 | err = PTR_ERR(drvdata->regulator); |
| 427 | 423 | drvdata->regulator = NULL; |
| 428 | − goto err_regulator_get; | |
| 424 | + return err; | |
| 429 | 425 | } |
| 430 | 426 | |
| 431 | 427 | if (drvdata->pdata->brt_val) { |
| @@ -458,9 +454,6 @@ err_create_file: · 26 unmodified lines | ||
| 458 | 454 | err_class_register: |
| 459 | 455 | err_reg_init: |
| 460 | 456 | regulator_put(drvdata->regulator); |
| 461 | −err_regulator_get: | |
| 462 | − kfree(drvdata); | |
| 463 | −err_out: | |
| 464 | 457 | return err; |
| 465 | 458 | } |
| 466 | 459 | |
| @@ -474,7 +467,6 @@ static int __devexit lm3530_remove(struct i2c_client *client) · 7 unmodified lines | ||
| 474 | 467 | regulator_disable(drvdata->regulator); |
| 475 | 468 | regulator_put(drvdata->regulator); |
| 476 | 469 | led_classdev_unregister(&drvdata->led_dev); |
| 477 | − kfree(drvdata); | |
| 478 | 470 | return 0; |
| 479 | 471 | } |
| 480 | 472 | |
| @@ -0,0 +1,512 @@ | ||
| 1 | +/* | |
| 2 | + * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03) | |
| 3 | + * Copyright (C) 2012 Texas Instruments | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License version 2 as | |
| 7 | + * published by the Free Software Foundation. | |
| 8 | + * | |
| 9 | + * Please refer Documentation/leds/leds-lm3556.txt file. | |
| 10 | + */ | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/delay.h> | |
| 13 | +#include <linux/i2c.h> | |
| 14 | +#include <linux/leds.h> | |
| 15 | +#include <linux/slab.h> | |
| 16 | +#include <linux/platform_device.h> | |
| 17 | +#include <linux/fs.h> | |
| 18 | +#include <linux/regmap.h> | |
| 19 | +#include <linux/platform_data/leds-lm3556.h> | |
| 20 | + | |
| 21 | +#define REG_FILT_TIME (0x0) | |
| 22 | +#define REG_IVFM_MODE (0x1) | |
| 23 | +#define REG_NTC (0x2) | |
| 24 | +#define REG_INDIC_TIME (0x3) | |
| 25 | +#define REG_INDIC_BLINK (0x4) | |
| 26 | +#define REG_INDIC_PERIOD (0x5) | |
| 27 | +#define REG_TORCH_TIME (0x6) | |
| 28 | +#define REG_CONF (0x7) | |
| 29 | +#define REG_FLASH (0x8) | |
| 30 | +#define REG_I_CTRL (0x9) | |
| 31 | +#define REG_ENABLE (0xA) | |
| 32 | +#define REG_FLAG (0xB) | |
| 33 | +#define REG_MAX (0xB) | |
| 34 | + | |
| 35 | +#define IVFM_FILTER_TIME_SHIFT (3) | |
| 36 | +#define UVLO_EN_SHIFT (7) | |
| 37 | +#define HYSTERSIS_SHIFT (5) | |
| 38 | +#define IVM_D_TH_SHIFT (2) | |
| 39 | +#define IVFM_ADJ_MODE_SHIFT (0) | |
| 40 | +#define NTC_EVENT_LVL_SHIFT (5) | |
| 41 | +#define NTC_TRIP_TH_SHIFT (2) | |
| 42 | +#define NTC_BIAS_I_LVL_SHIFT (0) | |
| 43 | +#define INDIC_RAMP_UP_TIME_SHIFT (3) | |
| 44 | +#define INDIC_RAMP_DN_TIME_SHIFT (0) | |
| 45 | +#define INDIC_N_BLANK_SHIFT (4) | |
| 46 | +#define INDIC_PULSE_TIME_SHIFT (0) | |
| 47 | +#define INDIC_N_PERIOD_SHIFT (0) | |
| 48 | +#define TORCH_RAMP_UP_TIME_SHIFT (3) | |
| 49 | +#define TORCH_RAMP_DN_TIME_SHIFT (0) | |
| 50 | +#define STROBE_USUAGE_SHIFT (7) | |
| 51 | +#define STROBE_PIN_POLARITY_SHIFT (6) | |
| 52 | +#define TORCH_PIN_POLARITY_SHIFT (5) | |
| 53 | +#define TX_PIN_POLARITY_SHIFT (4) | |
| 54 | +#define TX_EVENT_LVL_SHIFT (3) | |
| 55 | +#define IVFM_EN_SHIFT (2) | |
| 56 | +#define NTC_MODE_SHIFT (1) | |
| 57 | +#define INDIC_MODE_SHIFT (0) | |
| 58 | +#define INDUCTOR_I_LIMIT_SHIFT (6) | |
| 59 | +#define FLASH_RAMP_TIME_SHIFT (3) | |
| 60 | +#define FLASH_TOUT_TIME_SHIFT (0) | |
| 61 | +#define TORCH_I_SHIFT (4) | |
| 62 | +#define FLASH_I_SHIFT (0) | |
| 63 | +#define NTC_EN_SHIFT (7) | |
| 64 | +#define TX_PIN_EN_SHIFT (6) | |
| 65 | +#define STROBE_PIN_EN_SHIFT (5) | |
| 66 | +#define TORCH_PIN_EN_SHIFT (4) | |
| 67 | +#define PRECHG_MODE_EN_SHIFT (3) | |
| 68 | +#define PASS_MODE_ONLY_EN_SHIFT (2) | |
| 69 | +#define MODE_BITS_SHIFT (0) | |
| 70 | + | |
| 71 | +#define IVFM_FILTER_TIME_MASK (0x3) | |
| 72 | +#define UVLO_EN_MASK (0x1) | |
| 73 | +#define HYSTERSIS_MASK (0x3) | |
| 74 | +#define IVM_D_TH_MASK (0x7) | |
| 75 | +#define IVFM_ADJ_MODE_MASK (0x3) | |
| 76 | +#define NTC_EVENT_LVL_MASK (0x1) | |
| 77 | +#define NTC_TRIP_TH_MASK (0x7) | |
| 78 | +#define NTC_BIAS_I_LVL_MASK (0x3) | |
| 79 | +#define INDIC_RAMP_UP_TIME_MASK (0x7) | |
| 80 | +#define INDIC_RAMP_DN_TIME_MASK (0x7) | |
| 81 | +#define INDIC_N_BLANK_MASK (0x7) | |
| 82 | +#define INDIC_PULSE_TIME_MASK (0x7) | |
| 83 | +#define INDIC_N_PERIOD_MASK (0x7) | |
| 84 | +#define TORCH_RAMP_UP_TIME_MASK (0x7) | |
| 85 | +#define TORCH_RAMP_DN_TIME_MASK (0x7) | |
| 86 | +#define STROBE_USUAGE_MASK (0x1) | |
| 87 | +#define STROBE_PIN_POLARITY_MASK (0x1) | |
| 88 | +#define TORCH_PIN_POLARITY_MASK (0x1) | |
| 89 | +#define TX_PIN_POLARITY_MASK (0x1) | |
| 90 | +#define TX_EVENT_LVL_MASK (0x1) | |
| 91 | +#define IVFM_EN_MASK (0x1) | |
| 92 | +#define NTC_MODE_MASK (0x1) | |
| 93 | +#define INDIC_MODE_MASK (0x1) | |
| 94 | +#define INDUCTOR_I_LIMIT_MASK (0x3) | |
| 95 | +#define FLASH_RAMP_TIME_MASK (0x7) | |
| 96 | +#define FLASH_TOUT_TIME_MASK (0x7) | |
| 97 | +#define TORCH_I_MASK (0x7) | |
| 98 | +#define FLASH_I_MASK (0xF) | |
| 99 | +#define NTC_EN_MASK (0x1) | |
| 100 | +#define TX_PIN_EN_MASK (0x1) | |
| 101 | +#define STROBE_PIN_EN_MASK (0x1) | |
| 102 | +#define TORCH_PIN_EN_MASK (0x1) | |
| 103 | +#define PRECHG_MODE_EN_MASK (0x1) | |
| 104 | +#define PASS_MODE_ONLY_EN_MASK (0x1) | |
| 105 | +#define MODE_BITS_MASK (0x13) | |
| 106 | +#define EX_PIN_CONTROL_MASK (0xF1) | |
| 107 | +#define EX_PIN_ENABLE_MASK (0x70) | |
| 108 | + | |
| 109 | +enum lm3556_indic_pulse_time { | |
| 110 | + PULSE_TIME_0_MS = 0, | |
| 111 | + PULSE_TIME_32_MS, | |
| 112 | + PULSE_TIME_64_MS, | |
| 113 | + PULSE_TIME_92_MS, | |
| 114 | + PULSE_TIME_128_MS, | |
| 115 | + PULSE_TIME_160_MS, | |
| 116 | + PULSE_TIME_196_MS, | |
| 117 | + PULSE_TIME_224_MS, | |
| 118 | + PULSE_TIME_256_MS, | |
| 119 | + PULSE_TIME_288_MS, | |
| 120 | + PULSE_TIME_320_MS, | |
| 121 | + PULSE_TIME_352_MS, | |
| 122 | + PULSE_TIME_384_MS, | |
| 123 | + PULSE_TIME_416_MS, | |
| 124 | + PULSE_TIME_448_MS, | |
| 125 | + PULSE_TIME_480_MS, | |
| 126 | +}; | |
| 127 | + | |
| 128 | +enum lm3556_indic_n_blank { | |
| 129 | + INDIC_N_BLANK_0 = 0, | |
| 130 | + INDIC_N_BLANK_1, | |
| 131 | + INDIC_N_BLANK_2, | |
| 132 | + INDIC_N_BLANK_3, | |
| 133 | + INDIC_N_BLANK_4, | |
| 134 | + INDIC_N_BLANK_5, | |
| 135 | + INDIC_N_BLANK_6, | |
| 136 | + INDIC_N_BLANK_7, | |
| 137 | + INDIC_N_BLANK_8, | |
| 138 | + INDIC_N_BLANK_9, | |
| 139 | + INDIC_N_BLANK_10, | |
| 140 | + INDIC_N_BLANK_11, | |
| 141 | + INDIC_N_BLANK_12, | |
| 142 | + INDIC_N_BLANK_13, | |
| 143 | + INDIC_N_BLANK_14, | |
| 144 | + INDIC_N_BLANK_15, | |
| 145 | +}; | |
| 146 | + | |
| 147 | +enum lm3556_indic_period { | |
| 148 | + INDIC_PERIOD_0 = 0, | |
| 149 | + INDIC_PERIOD_1, | |
| 150 | + INDIC_PERIOD_2, | |
| 151 | + INDIC_PERIOD_3, | |
| 152 | + INDIC_PERIOD_4, | |
| 153 | + INDIC_PERIOD_5, | |
| 154 | + INDIC_PERIOD_6, | |
| 155 | + INDIC_PERIOD_7, | |
| 156 | +}; | |
| 157 | + | |
| 158 | +enum lm3556_mode { | |
| 159 | + MODES_STASNDBY = 0, | |
| 160 | + MODES_INDIC, | |
| 161 | + MODES_TORCH, | |
| 162 | + MODES_FLASH | |
| 163 | +}; | |
| 164 | + | |
| 165 | +#define INDIC_PATTERN_SIZE 4 | |
| 166 | + | |
| 167 | +struct indicator { | |
| 168 | + u8 blinking; | |
| 169 | + u8 period_cnt; | |
| 170 | +}; | |
| 171 | + | |
| 172 | +struct lm3556_chip_data { | |
| 173 | + struct device *dev; | |
| 174 | + | |
| 175 | + struct led_classdev cdev_flash; | |
| 176 | + struct led_classdev cdev_torch; | |
| 177 | + struct led_classdev cdev_indicator; | |
| 178 | + | |
| 179 | + struct lm3556_platform_data *pdata; | |
| 180 | + struct regmap *regmap; | |
| 181 | + struct mutex lock; | |
| 182 | + | |
| 183 | + unsigned int last_flag; | |
| 184 | +}; | |
| 185 | + | |
| 186 | +/* indicator pattern */ | |
| 187 | +static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = { | |
| 188 | + [0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT) | |
| 189 | + | PULSE_TIME_32_MS, INDIC_PERIOD_1}, | |
| 190 | + [1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT) | |
| 191 | + | PULSE_TIME_32_MS, INDIC_PERIOD_2}, | |
| 192 | + [2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT) | |
| 193 | + | PULSE_TIME_32_MS, INDIC_PERIOD_4}, | |
| 194 | + [3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT) | |
| 195 | + | PULSE_TIME_32_MS, INDIC_PERIOD_7}, | |
| 196 | +}; | |
| 197 | + | |
| 198 | +/* chip initialize */ | |
| 199 | +static int __devinit lm3556_chip_init(struct lm3556_chip_data *chip) | |
| 200 | +{ | |
| 201 | + unsigned int reg_val; | |
| 202 | + int ret; | |
| 203 | + struct lm3556_platform_data *pdata = chip->pdata; | |
| 204 | + | |
| 205 | + /* set config register */ | |
| 206 | + ret = regmap_read(chip->regmap, REG_CONF, ®_val); | |
| 207 | + if (ret < 0) { | |
| 208 | + dev_err(chip->dev, "Failed to read REG_CONF Register\n"); | |
| 209 | + goto out; | |
| 210 | + } | |
| 211 | + | |
| 212 | + reg_val &= (~EX_PIN_CONTROL_MASK); | |
| 213 | + reg_val |= ((pdata->torch_pin_polarity & 0x01) | |
| 214 | + << TORCH_PIN_POLARITY_SHIFT); | |
| 215 | + reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT); | |
| 216 | + reg_val |= ((pdata->strobe_pin_polarity & 0x01) | |
| 217 | + << STROBE_PIN_POLARITY_SHIFT); | |
| 218 | + reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT); | |
| 219 | + reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT); | |
| 220 | + | |
| 221 | + ret = regmap_write(chip->regmap, REG_CONF, reg_val); | |
| 222 | + if (ret < 0) { | |
| 223 | + dev_err(chip->dev, "Failed to write REG_CONF Regisgter\n"); | |
| 224 | + goto out; | |
| 225 | + } | |
| 226 | + | |
| 227 | + /* set enable register */ | |
| 228 | + ret = regmap_read(chip->regmap, REG_ENABLE, ®_val); | |
| 229 | + if (ret < 0) { | |
| 230 | + dev_err(chip->dev, "Failed to read REG_ENABLE Register\n"); | |
| 231 | + goto out; | |
| 232 | + } | |
| 233 | + | |
| 234 | + reg_val &= (~EX_PIN_ENABLE_MASK); | |
| 235 | + reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT); | |
| 236 | + reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT); | |
| 237 | + reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT); | |
| 238 | + | |
| 239 | + ret = regmap_write(chip->regmap, REG_ENABLE, reg_val); | |
| 240 | + if (ret < 0) { | |
| 241 | + dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n"); | |
| 242 | + goto out; | |
| 243 | + } | |
| 244 | + | |
| 245 | +out: | |
| 246 | + return ret; | |
| 247 | +} | |
| 248 | + | |
| 249 | +/* chip control */ | |
| 250 | +static int lm3556_control(struct lm3556_chip_data *chip, | |
| 251 | + u8 brightness, enum lm3556_mode opmode) | |
| 252 | +{ | |
| 253 | + int ret; | |
| 254 | + struct lm3556_platform_data *pdata = chip->pdata; | |
| 255 | + | |
| 256 | + ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag); | |
| 257 | + if (ret < 0) { | |
| 258 | + dev_err(chip->dev, "Failed to read REG_FLAG Register\n"); | |
| 259 | + goto out; | |
| 260 | + } | |
| 261 | + | |
| 262 | + if (chip->last_flag) | |
| 263 | + dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag); | |
| 264 | + | |
| 265 | + /* brightness 0 means off-state */ | |
| 266 | + if (!brightness) | |
| 267 | + opmode = MODES_STASNDBY; | |
| 268 | + | |
| 269 | + switch (opmode) { | |
| 270 | + case MODES_TORCH: | |
| 271 | + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, | |
| 272 | + TORCH_I_MASK << TORCH_I_SHIFT, | |
| 273 | + (brightness - 1) << TORCH_I_SHIFT); | |
| 274 | + | |
| 275 | + if (pdata->torch_pin_en) | |
| 276 | + opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT); | |
| 277 | + break; | |
| 278 | + | |
| 279 | + case MODES_FLASH: | |
| 280 | + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, | |
| 281 | + FLASH_I_MASK << FLASH_I_SHIFT, | |
| 282 | + (brightness - 1) << FLASH_I_SHIFT); | |
| 283 | + break; | |
| 284 | + | |
| 285 | + case MODES_INDIC: | |
| 286 | + ret = regmap_update_bits(chip->regmap, REG_I_CTRL, | |
| 287 | + TORCH_I_MASK << TORCH_I_SHIFT, | |
| 288 | + (brightness - 1) << TORCH_I_SHIFT); | |
| 289 | + break; | |
| 290 | + | |
| 291 | + case MODES_STASNDBY: | |
| 292 | + if (pdata->torch_pin_en) | |
| 293 | + opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT); | |
| 294 | + break; | |
| 295 | + | |
| 296 | + default: | |
| 297 | + return ret; | |
| 298 | + } | |
| 299 | + if (ret < 0) { | |
| 300 | + dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n"); | |
| 301 | + goto out; | |
| 302 | + } | |
| 303 | + ret = regmap_update_bits(chip->regmap, REG_ENABLE, | |
| 304 | + MODE_BITS_MASK << MODE_BITS_SHIFT, | |
| 305 | + opmode << MODE_BITS_SHIFT); | |
| 306 | + | |
| 307 | +out: | |
| 308 | + return ret; | |
| 309 | +} | |
| 310 | + | |
| 311 | +/* torch */ | |
| 312 | +static void lm3556_torch_brightness_set(struct led_classdev *cdev, | |
| 313 | + enum led_brightness brightness) | |
| 314 | +{ | |
| 315 | + struct lm3556_chip_data *chip = | |
| 316 | + container_of(cdev, struct lm3556_chip_data, cdev_torch); | |
| 317 | + | |
| 318 | + mutex_lock(&chip->lock); | |
| 319 | + lm3556_control(chip, brightness, MODES_TORCH); | |
| 320 | + mutex_unlock(&chip->lock); | |
| 321 | +} | |
| 322 | + | |
| 323 | +/* flash */ | |
| 324 | +static void lm3556_strobe_brightness_set(struct led_classdev *cdev, | |
| 325 | + enum led_brightness brightness) | |
| 326 | +{ | |
| 327 | + struct lm3556_chip_data *chip = | |
| 328 | + container_of(cdev, struct lm3556_chip_data, cdev_flash); | |
| 329 | + | |
| 330 | + mutex_lock(&chip->lock); | |
| 331 | + lm3556_control(chip, brightness, MODES_FLASH); | |
| 332 | + mutex_unlock(&chip->lock); | |
| 333 | +} | |
| 334 | + | |
| 335 | +/* indicator */ | |
| 336 | +static void lm3556_indicator_brightness_set(struct led_classdev *cdev, | |
| 337 | + enum led_brightness brightness) | |
| 338 | +{ | |
| 339 | + struct lm3556_chip_data *chip = | |
| 340 | + container_of(cdev, struct lm3556_chip_data, cdev_indicator); | |
| 341 | + | |
| 342 | + mutex_lock(&chip->lock); | |
| 343 | + lm3556_control(chip, brightness, MODES_INDIC); | |
| 344 | + mutex_unlock(&chip->lock); | |
| 345 | +} | |
| 346 | + | |
| 347 | +/* indicator pattern */ | |
| 348 | +static ssize_t lm3556_indicator_pattern_store(struct device *dev, | |
| 349 | + struct device_attribute *devAttr, | |
| 350 | + const char *buf, size_t size) | |
| 351 | +{ | |
| 352 | + ssize_t ret; | |
| 353 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 354 | + struct lm3556_chip_data *chip = | |
| 355 | + container_of(led_cdev, struct lm3556_chip_data, cdev_indicator); | |
| 356 | + unsigned int state; | |
| 357 | + | |
| 358 | + ret = kstrtouint(buf, 10, &state); | |
| 359 | + if (ret) | |
| 360 | + goto out; | |
| 361 | + if (state > INDIC_PATTERN_SIZE - 1) | |
| 362 | + state = INDIC_PATTERN_SIZE - 1; | |
| 363 | + | |
| 364 | + ret = regmap_write(chip->regmap, REG_INDIC_BLINK, | |
| 365 | + indicator_pattern[state].blinking); | |
| 366 | + if (ret < 0) { | |
| 367 | + dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n"); | |
| 368 | + goto out; | |
| 369 | + } | |
| 370 | + | |
| 371 | + ret = regmap_write(chip->regmap, REG_INDIC_PERIOD, | |
| 372 | + indicator_pattern[state].period_cnt); | |
| 373 | + if (ret < 0) { | |
| 374 | + dev_err(chip->dev, "Failed to write REG_ENABLE Regisgter\n"); | |
| 375 | + goto out; | |
| 376 | + } | |
| 377 | + | |
| 378 | + return size; | |
| 379 | +out: | |
| 380 | + dev_err(chip->dev, "Indicator pattern doesn't saved\n"); | |
| 381 | + return size; | |
| 382 | +} | |
| 383 | + | |
| 384 | +static DEVICE_ATTR(pattern, 0666, NULL, lm3556_indicator_pattern_store); | |
| 385 | + | |
| 386 | +static const struct regmap_config lm3556_regmap = { | |
| 387 | + .reg_bits = 8, | |
| 388 | + .val_bits = 8, | |
| 389 | + .max_register = REG_MAX, | |
| 390 | +}; | |
| 391 | + | |
| 392 | +/* module initialize */ | |
| 393 | +static int __devinit lm3556_probe(struct i2c_client *client, | |
| 394 | + const struct i2c_device_id *id) | |
| 395 | +{ | |
| 396 | + struct lm3556_platform_data *pdata = client->dev.platform_data; | |
| 397 | + struct lm3556_chip_data *chip; | |
| 398 | + | |
| 399 | + int err; | |
| 400 | + | |
| 401 | + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
| 402 | + dev_err(&client->dev, "i2c functionality check fail.\n"); | |
| 403 | + return -EOPNOTSUPP; | |
| 404 | + } | |
| 405 | + | |
| 406 | + if (pdata == NULL) { | |
| 407 | + dev_err(&client->dev, "Needs Platform Data.\n"); | |
| 408 | + return -ENODATA; | |
| 409 | + } | |
| 410 | + | |
| 411 | + chip = | |
| 412 | + devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data), | |
| 413 | + GFP_KERNEL); | |
| 414 | + if (!chip) | |
| 415 | + return -ENOMEM; | |
| 416 | + | |
| 417 | + chip->dev = &client->dev; | |
| 418 | + chip->pdata = pdata; | |
| 419 | + | |
| 420 | + chip->regmap = devm_regmap_init_i2c(client, &lm3556_regmap); | |
| 421 | + if (IS_ERR(chip->regmap)) { | |
| 422 | + err = PTR_ERR(chip->regmap); | |
| 423 | + dev_err(&client->dev, "Failed to allocate register map: %d\n", | |
| 424 | + err); | |
| 425 | + return err; | |
| 426 | + } | |
| 427 | + | |
| 428 | + mutex_init(&chip->lock); | |
| 429 | + i2c_set_clientdata(client, chip); | |
| 430 | + | |
| 431 | + err = lm3556_chip_init(chip); | |
| 432 | + if (err < 0) | |
| 433 | + goto err_out; | |
| 434 | + | |
| 435 | + /* flash */ | |
| 436 | + chip->cdev_flash.name = "flash"; | |
| 437 | + chip->cdev_flash.max_brightness = 16; | |
| 438 | + chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set; | |
| 439 | + err = led_classdev_register((struct device *) | |
| 440 | + &client->dev, &chip->cdev_flash); | |
| 441 | + if (err < 0) | |
| 442 | + goto err_out; | |
| 443 | + /* torch */ | |
| 444 | + chip->cdev_torch.name = "torch"; | |
| 445 | + chip->cdev_torch.max_brightness = 8; | |
| 446 | + chip->cdev_torch.brightness_set = lm3556_torch_brightness_set; | |
| 447 | + err = led_classdev_register((struct device *) | |
| 448 | + &client->dev, &chip->cdev_torch); | |
| 449 | + if (err < 0) | |
| 450 | + goto err_create_torch_file; | |
| 451 | + /* indicator */ | |
| 452 | + chip->cdev_indicator.name = "indicator"; | |
| 453 | + chip->cdev_indicator.max_brightness = 8; | |
| 454 | + chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set; | |
| 455 | + err = led_classdev_register((struct device *) | |
| 456 | + &client->dev, &chip->cdev_indicator); | |
| 457 | + if (err < 0) | |
| 458 | + goto err_create_indicator_file; | |
| 459 | + | |
| 460 | + err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern); | |
| 461 | + if (err < 0) | |
| 462 | + goto err_create_pattern_file; | |
| 463 | + | |
| 464 | + dev_info(&client->dev, "LM3556 is initialized\n"); | |
| 465 | + return 0; | |
| 466 | + | |
| 467 | +err_create_pattern_file: | |
| 468 | + led_classdev_unregister(&chip->cdev_indicator); | |
| 469 | +err_create_indicator_file: | |
| 470 | + led_classdev_unregister(&chip->cdev_torch); | |
| 471 | +err_create_torch_file: | |
| 472 | + led_classdev_unregister(&chip->cdev_flash); | |
| 473 | +err_out: | |
| 474 | + return err; | |
| 475 | +} | |
| 476 | + | |
| 477 | +static int __devexit lm3556_remove(struct i2c_client *client) | |
| 478 | +{ | |
| 479 | + struct lm3556_chip_data *chip = i2c_get_clientdata(client); | |
| 480 | + | |
| 481 | + device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern); | |
| 482 | + led_classdev_unregister(&chip->cdev_indicator); | |
| 483 | + led_classdev_unregister(&chip->cdev_torch); | |
| 484 | + led_classdev_unregister(&chip->cdev_flash); | |
| 485 | + regmap_write(chip->regmap, REG_ENABLE, 0); | |
| 486 | + return 0; | |
| 487 | +} | |
| 488 | + | |
| 489 | +static const struct i2c_device_id lm3556_id[] = { | |
| 490 | + {LM3556_NAME, 0}, | |
| 491 | + {} | |
| 492 | +}; | |
| 493 | + | |
| 494 | +MODULE_DEVICE_TABLE(i2c, lm3556_id); | |
| 495 | + | |
| 496 | +static struct i2c_driver lm3556_i2c_driver = { | |
| 497 | + .driver = { | |
| 498 | + .name = LM3556_NAME, | |
| 499 | + .owner = THIS_MODULE, | |
| 500 | + .pm = NULL, | |
| 501 | + }, | |
| 502 | + .probe = lm3556_probe, | |
| 503 | + .remove = __devexit_p(lm3556_remove), | |
| 504 | + .id_table = lm3556_id, | |
| 505 | +}; | |
| 506 | + | |
| 507 | +module_i2c_driver(lm3556_i2c_driver); | |
| 508 | + | |
| 509 | +MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556"); | |
| 510 | +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); | |
| 511 | +MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); | |
| 512 | +MODULE_LICENSE("GPL v2"); | |
| @@ -393,7 +393,8 @@ static int __devinit lp3944_probe(struct i2c_client *client, · 392 unmodified lines | ||
| 393 | 393 | return -ENODEV; |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | − data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL); | |
| 396 | + data = devm_kzalloc(&client->dev, sizeof(struct lp3944_data), | |
| 397 | + GFP_KERNEL); | |
| 397 | 398 | if (!data) |
| 398 | 399 | return -ENOMEM; |
| 399 | 400 | |
| @@ -403,10 +404,8 @@ static int __devinit lp3944_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 403 | 404 | mutex_init(&data->lock); |
| 404 | 405 | |
| 405 | 406 | err = lp3944_configure(client, data, lp3944_pdata); |
| 406 | − if (err < 0) { | |
| 407 | − kfree(data); | |
| 407 | + if (err < 0) | |
| 408 | 408 | return err; |
| 409 | − } | |
| 410 | 409 | |
| 411 | 410 | dev_info(&client->dev, "lp3944 enabled\n"); |
| 412 | 411 | return 0; |
| @@ -431,8 +430,6 @@ static int __devexit lp3944_remove(struct i2c_client *client) · 18 unmodified lines | ||
| 431 | 430 | break; |
| 432 | 431 | } |
| 433 | 432 | |
| 434 | − kfree(data); | |
| 435 | − | |
| 436 | 433 | return 0; |
| 437 | 434 | } |
| 438 | 435 | |
| @@ -744,7 +744,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 743 unmodified lines | ||
| 744 | 744 | int ret, i, led; |
| 745 | 745 | u8 buf; |
| 746 | 746 | |
| 747 | − chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
| 747 | + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); | |
| 748 | 748 | if (!chip) |
| 749 | 749 | return -ENOMEM; |
| 750 | 750 | |
| @@ -755,8 +755,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 755 | 755 | |
| 756 | 756 | if (!pdata) { |
| 757 | 757 | dev_err(&client->dev, "no platform data\n"); |
| 758 | − ret = -EINVAL; | |
| 759 | − goto fail1; | |
| 758 | + return -EINVAL; | |
| 760 | 759 | } |
| 761 | 760 | |
| 762 | 761 | mutex_init(&chip->lock); |
| @@ -766,7 +765,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 766 | 765 | if (pdata->setup_resources) { |
| 767 | 766 | ret = pdata->setup_resources(); |
| 768 | 767 | if (ret < 0) |
| 769 | − goto fail1; | |
| 768 | + return ret; | |
| 770 | 769 | } |
| 771 | 770 | |
| 772 | 771 | if (pdata->enable) { |
| @@ -807,7 +806,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 34 unmodified lines | ||
| 807 | 806 | ret = lp5521_configure(client); |
| 808 | 807 | if (ret < 0) { |
| 809 | 808 | dev_err(&client->dev, "error configuring chip\n"); |
| 810 | − goto fail2; | |
| 809 | + goto fail1; | |
| 811 | 810 | } |
| 812 | 811 | |
| 813 | 812 | /* Initialize leds */ |
| @@ -822,7 +821,7 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 8 unmodified lines | ||
| 822 | 821 | ret = lp5521_init_led(&chip->leds[led], client, i, pdata); |
| 823 | 822 | if (ret) { |
| 824 | 823 | dev_err(&client->dev, "error initializing leds\n"); |
| 825 | − goto fail3; | |
| 824 | + goto fail2; | |
| 826 | 825 | } |
| 827 | 826 | chip->num_leds++; |
| 828 | 827 | |
| @@ -840,21 +839,19 @@ static int __devinit lp5521_probe(struct i2c_client *client, · 11 unmodified lines | ||
| 840 | 839 | ret = lp5521_register_sysfs(client); |
| 841 | 840 | if (ret) { |
| 842 | 841 | dev_err(&client->dev, "registering sysfs failed\n"); |
| 843 | − goto fail3; | |
| 842 | + goto fail2; | |
| 844 | 843 | } |
| 845 | 844 | return ret; |
| 846 | −fail3: | |
| 845 | +fail2: | |
| 847 | 846 | for (i = 0; i < chip->num_leds; i++) { |
| 848 | 847 | led_classdev_unregister(&chip->leds[i].cdev); |
| 849 | 848 | cancel_work_sync(&chip->leds[i].brightness_work); |
| 850 | 849 | } |
| 851 | −fail2: | |
| 850 | +fail1: | |
| 852 | 851 | if (pdata->enable) |
| 853 | 852 | pdata->enable(0); |
| 854 | 853 | if (pdata->release_resources) |
| 855 | 854 | pdata->release_resources(); |
| 856 | −fail1: | |
| 857 | − kfree(chip); | |
| 858 | 855 | return ret; |
| 859 | 856 | } |
| 860 | 857 | |
| @@ -875,7 +872,6 @@ static int __devexit lp5521_remove(struct i2c_client *client) · 14 unmodified lines | ||
| 875 | 872 | chip->pdata->enable(0); |
| 876 | 873 | if (chip->pdata->release_resources) |
| 877 | 874 | chip->pdata->release_resources(); |
| 878 | − kfree(chip); | |
| 879 | 875 | return 0; |
| 880 | 876 | } |
| 881 | 877 | |
| @@ -877,7 +877,7 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 876 unmodified lines | ||
| 877 | 877 | struct lp5523_platform_data *pdata; |
| 878 | 878 | int ret, i, led; |
| 879 | 879 | |
| 880 | − chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
| 880 | + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); | |
| 881 | 881 | if (!chip) |
| 882 | 882 | return -ENOMEM; |
| 883 | 883 | |
| @@ -888,8 +888,7 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 888 | 888 | |
| 889 | 889 | if (!pdata) { |
| 890 | 890 | dev_err(&client->dev, "no platform data\n"); |
| 891 | − ret = -EINVAL; | |
| 892 | − goto fail1; | |
| 891 | + return -EINVAL; | |
| 893 | 892 | } |
| 894 | 893 | |
| 895 | 894 | mutex_init(&chip->lock); |
| @@ -899,7 +898,7 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 899 | 898 | if (pdata->setup_resources) { |
| 900 | 899 | ret = pdata->setup_resources(); |
| 901 | 900 | if (ret < 0) |
| 902 | − goto fail1; | |
| 901 | + return ret; | |
| 903 | 902 | } |
| 904 | 903 | |
| 905 | 904 | if (pdata->enable) { |
| @@ -916,7 +915,7 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 10 unmodified lines | ||
| 916 | 915 | */ |
| 917 | 916 | ret = lp5523_detect(client); |
| 918 | 917 | if (ret) |
| 919 | − goto fail2; | |
| 918 | + goto fail1; | |
| 920 | 919 | |
| 921 | 920 | dev_info(&client->dev, "LP5523 Programmable led chip found\n"); |
| 922 | 921 | |
| @@ -925,13 +924,13 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 925 | 924 | ret = lp5523_init_engine(&chip->engines[i], i + 1); |
| 926 | 925 | if (ret) { |
| 927 | 926 | dev_err(&client->dev, "error initializing engine\n"); |
| 928 | − goto fail2; | |
| 927 | + goto fail1; | |
| 929 | 928 | } |
| 930 | 929 | } |
| 931 | 930 | ret = lp5523_configure(client); |
| 932 | 931 | if (ret < 0) { |
| 933 | 932 | dev_err(&client->dev, "error configuring chip\n"); |
| 934 | − goto fail2; | |
| 933 | + goto fail1; | |
| 935 | 934 | } |
| 936 | 935 | |
| 937 | 936 | /* Initialize leds */ |
| @@ -943,10 +942,13 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 5 unmodified lines | ||
| 943 | 942 | if (pdata->led_config[i].led_current == 0) |
| 944 | 943 | continue; |
| 945 | 944 | |
| 945 | + INIT_WORK(&chip->leds[led].brightness_work, | |
| 946 | + lp5523_led_brightness_work); | |
| 947 | + | |
| 946 | 948 | ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata); |
| 947 | 949 | if (ret) { |
| 948 | 950 | dev_err(&client->dev, "error initializing leds\n"); |
| 949 | − goto fail3; | |
| 951 | + goto fail2; | |
| 950 | 952 | } |
| 951 | 953 | chip->num_leds++; |
| 952 | 954 | |
| @@ -956,30 +958,25 @@ static int __devinit lp5523_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 956 | 958 | LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr, |
| 957 | 959 | chip->leds[led].led_current); |
| 958 | 960 | |
| 959 | − INIT_WORK(&(chip->leds[led].brightness_work), | |
| 960 | − lp5523_led_brightness_work); | |
| 961 | − | |
| 962 | 961 | led++; |
| 963 | 962 | } |
| 964 | 963 | |
| 965 | 964 | ret = lp5523_register_sysfs(client); |
| 966 | 965 | if (ret) { |
| 967 | 966 | dev_err(&client->dev, "registering sysfs failed\n"); |
| 968 | − goto fail3; | |
| 967 | + goto fail2; | |
| 969 | 968 | } |
| 970 | 969 | return ret; |
| 971 | −fail3: | |
| 970 | +fail2: | |
| 972 | 971 | for (i = 0; i < chip->num_leds; i++) { |
| 973 | 972 | led_classdev_unregister(&chip->leds[i].cdev); |
| 974 | 973 | cancel_work_sync(&chip->leds[i].brightness_work); |
| 975 | 974 | } |
| 976 | −fail2: | |
| 975 | +fail1: | |
| 977 | 976 | if (pdata->enable) |
| 978 | 977 | pdata->enable(0); |
| 979 | 978 | if (pdata->release_resources) |
| 980 | 979 | pdata->release_resources(); |
| 981 | −fail1: | |
| 982 | − kfree(chip); | |
| 983 | 980 | return ret; |
| 984 | 981 | } |
| 985 | 982 | |
| @@ -999,7 +996,6 @@ static int lp5523_remove(struct i2c_client *client) · 13 unmodified lines | ||
| 999 | 996 | chip->pdata->enable(0); |
| 1000 | 997 | if (chip->pdata->release_resources) |
| 1001 | 998 | chip->pdata->release_resources(); |
| 1002 | − kfree(chip); | |
| 1003 | 999 | return 0; |
| 1004 | 1000 | } |
| 1005 | 1001 | |
| @@ -0,0 +1,193 @@ | ||
| 1 | +/* | |
| 2 | + * TI LP8788 MFD - keyled driver | |
| 3 | + * | |
| 4 | + * Copyright 2012 Texas Instruments | |
| 5 | + * | |
| 6 | + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + * | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/slab.h> | |
| 16 | +#include <linux/err.h> | |
| 17 | +#include <linux/platform_device.h> | |
| 18 | +#include <linux/leds.h> | |
| 19 | +#include <linux/mutex.h> | |
| 20 | +#include <linux/mfd/lp8788.h> | |
| 21 | +#include <linux/mfd/lp8788-isink.h> | |
| 22 | + | |
| 23 | +#define MAX_BRIGHTNESS LP8788_ISINK_MAX_PWM | |
| 24 | +#define DEFAULT_LED_NAME "keyboard-backlight" | |
| 25 | + | |
| 26 | +struct lp8788_led { | |
| 27 | + struct lp8788 *lp; | |
| 28 | + struct mutex lock; | |
| 29 | + struct work_struct work; | |
| 30 | + struct led_classdev led_dev; | |
| 31 | + enum lp8788_isink_number isink_num; | |
| 32 | + enum led_brightness brightness; | |
| 33 | + int on; | |
| 34 | +}; | |
| 35 | + | |
| 36 | +struct lp8788_led_config { | |
| 37 | + enum lp8788_isink_scale scale; | |
| 38 | + enum lp8788_isink_number num; | |
| 39 | + int iout; | |
| 40 | +}; | |
| 41 | + | |
| 42 | +static struct lp8788_led_config default_led_config = { | |
| 43 | + .scale = LP8788_ISINK_SCALE_100mA, | |
| 44 | + .num = LP8788_ISINK_3, | |
| 45 | + .iout = 0, | |
| 46 | +}; | |
| 47 | + | |
| 48 | +static int lp8788_led_init_device(struct lp8788_led *led, | |
| 49 | + struct lp8788_led_platform_data *pdata) | |
| 50 | +{ | |
| 51 | + struct lp8788_led_config *cfg = &default_led_config; | |
| 52 | + u8 addr, mask, val; | |
| 53 | + int ret; | |
| 54 | + | |
| 55 | + if (pdata) { | |
| 56 | + cfg->scale = pdata->scale; | |
| 57 | + cfg->num = pdata->num; | |
| 58 | + cfg->iout = pdata->iout_code; | |
| 59 | + } | |
| 60 | + | |
| 61 | + led->isink_num = cfg->num; | |
| 62 | + | |
| 63 | + /* scale configuration */ | |
| 64 | + addr = LP8788_ISINK_CTRL; | |
| 65 | + mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET); | |
| 66 | + val = cfg->scale << cfg->num; | |
| 67 | + ret = lp8788_update_bits(led->lp, addr, mask, val); | |
| 68 | + if (ret) | |
| 69 | + return ret; | |
| 70 | + | |
| 71 | + /* current configuration */ | |
| 72 | + addr = lp8788_iout_addr[cfg->num]; | |
| 73 | + mask = lp8788_iout_mask[cfg->num]; | |
| 74 | + val = cfg->iout; | |
| 75 | + | |
| 76 | + return lp8788_update_bits(led->lp, addr, mask, val); | |
| 77 | +} | |
| 78 | + | |
| 79 | +static void lp8788_led_enable(struct lp8788_led *led, | |
| 80 | + enum lp8788_isink_number num, int on) | |
| 81 | +{ | |
| 82 | + u8 mask = 1 << num; | |
| 83 | + u8 val = on << num; | |
| 84 | + | |
| 85 | + if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val)) | |
| 86 | + return; | |
| 87 | + | |
| 88 | + led->on = on; | |
| 89 | +} | |
| 90 | + | |
| 91 | +static void lp8788_led_work(struct work_struct *work) | |
| 92 | +{ | |
| 93 | + struct lp8788_led *led = container_of(work, struct lp8788_led, work); | |
| 94 | + enum lp8788_isink_number num = led->isink_num; | |
| 95 | + int enable; | |
| 96 | + u8 val = led->brightness; | |
| 97 | + | |
| 98 | + mutex_lock(&led->lock); | |
| 99 | + | |
| 100 | + switch (num) { | |
| 101 | + case LP8788_ISINK_1: | |
| 102 | + case LP8788_ISINK_2: | |
| 103 | + case LP8788_ISINK_3: | |
| 104 | + lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val); | |
| 105 | + break; | |
| 106 | + default: | |
| 107 | + mutex_unlock(&led->lock); | |
| 108 | + return; | |
| 109 | + } | |
| 110 | + | |
| 111 | + enable = (val > 0) ? 1 : 0; | |
| 112 | + if (enable != led->on) | |
| 113 | + lp8788_led_enable(led, num, enable); | |
| 114 | + | |
| 115 | + mutex_unlock(&led->lock); | |
| 116 | +} | |
| 117 | + | |
| 118 | +static void lp8788_brightness_set(struct led_classdev *led_cdev, | |
| 119 | + enum led_brightness brt_val) | |
| 120 | +{ | |
| 121 | + struct lp8788_led *led = | |
| 122 | + container_of(led_cdev, struct lp8788_led, led_dev); | |
| 123 | + | |
| 124 | + led->brightness = brt_val; | |
| 125 | + schedule_work(&led->work); | |
| 126 | +} | |
| 127 | + | |
| 128 | +static __devinit int lp8788_led_probe(struct platform_device *pdev) | |
| 129 | +{ | |
| 130 | + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); | |
| 131 | + struct lp8788_led_platform_data *led_pdata; | |
| 132 | + struct lp8788_led *led; | |
| 133 | + int ret; | |
| 134 | + | |
| 135 | + led = devm_kzalloc(lp->dev, sizeof(struct lp8788_led), GFP_KERNEL); | |
| 136 | + if (!led) | |
| 137 | + return -ENOMEM; | |
| 138 | + | |
| 139 | + led->lp = lp; | |
| 140 | + led->led_dev.max_brightness = MAX_BRIGHTNESS; | |
| 141 | + led->led_dev.brightness_set = lp8788_brightness_set; | |
| 142 | + | |
| 143 | + led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL; | |
| 144 | + | |
| 145 | + if (!led_pdata || !led_pdata->name) | |
| 146 | + led->led_dev.name = DEFAULT_LED_NAME; | |
| 147 | + else | |
| 148 | + led->led_dev.name = led_pdata->name; | |
| 149 | + | |
| 150 | + mutex_init(&led->lock); | |
| 151 | + INIT_WORK(&led->work, lp8788_led_work); | |
| 152 | + | |
| 153 | + platform_set_drvdata(pdev, led); | |
| 154 | + | |
| 155 | + ret = lp8788_led_init_device(led, led_pdata); | |
| 156 | + if (ret) { | |
| 157 | + dev_err(lp->dev, "led init device err: %d\n", ret); | |
| 158 | + return ret; | |
| 159 | + } | |
| 160 | + | |
| 161 | + ret = led_classdev_register(lp->dev, &led->led_dev); | |
| 162 | + if (ret) { | |
| 163 | + dev_err(lp->dev, "led register err: %d\n", ret); | |
| 164 | + return ret; | |
| 165 | + } | |
| 166 | + | |
| 167 | + return 0; | |
| 168 | +} | |
| 169 | + | |
| 170 | +static int __devexit lp8788_led_remove(struct platform_device *pdev) | |
| 171 | +{ | |
| 172 | + struct lp8788_led *led = platform_get_drvdata(pdev); | |
| 173 | + | |
| 174 | + led_classdev_unregister(&led->led_dev); | |
| 175 | + flush_work_sync(&led->work); | |
| 176 | + | |
| 177 | + return 0; | |
| 178 | +} | |
| 179 | + | |
| 180 | +static struct platform_driver lp8788_led_driver = { | |
| 181 | + .probe = lp8788_led_probe, | |
| 182 | + .remove = __devexit_p(lp8788_led_remove), | |
| 183 | + .driver = { | |
| 184 | + .name = LP8788_DEV_KEYLED, | |
| 185 | + .owner = THIS_MODULE, | |
| 186 | + }, | |
| 187 | +}; | |
| 188 | +module_platform_driver(lp8788_led_driver); | |
| 189 | + | |
| 190 | +MODULE_DESCRIPTION("Texas Instruments LP8788 Keyboard LED Driver"); | |
| 191 | +MODULE_AUTHOR("Milo Kim"); | |
| 192 | +MODULE_LICENSE("GPL"); | |
| 193 | +MODULE_ALIAS("platform:lp8788-keyled"); | |
| @@ -149,8 +149,9 @@ static int __devinit lt3593_led_probe(struct platform_device *pdev) · 148 unmodified lines | ||
| 149 | 149 | if (!pdata) |
| 150 | 150 | return -EBUSY; |
| 151 | 151 | |
| 152 | − leds_data = kzalloc(sizeof(struct lt3593_led_data) * pdata->num_leds, | |
| 153 | − GFP_KERNEL); | |
| 152 | + leds_data = devm_kzalloc(&pdev->dev, | |
| 153 | + sizeof(struct lt3593_led_data) * pdata->num_leds, | |
| 154 | + GFP_KERNEL); | |
| 154 | 155 | if (!leds_data) |
| 155 | 156 | return -ENOMEM; |
| 156 | 157 | |
| @@ -169,8 +170,6 @@ err: · 12 unmodified lines | ||
| 169 | 170 | for (i = i - 1; i >= 0; i--) |
| 170 | 171 | delete_lt3593_led(&leds_data[i]); |
| 171 | 172 | |
| 172 | − kfree(leds_data); | |
| 173 | − | |
| 174 | 173 | return ret; |
| 175 | 174 | } |
| 176 | 175 | |
| @@ -185,8 +184,6 @@ static int __devexit lt3593_led_remove(struct platform_device *pdev) · 8 unmodified lines | ||
| 185 | 184 | for (i = 0; i < pdata->num_leds; i++) |
| 186 | 185 | delete_lt3593_led(&leds_data[i]); |
| 187 | 186 | |
| 188 | − kfree(leds_data); | |
| 189 | − | |
| 190 | 187 | return 0; |
| 191 | 188 | } |
| 192 | 189 | |
| @@ -49,71 +49,37 @@ struct max8997_led { · 48 unmodified lines | ||
| 49 | 49 | struct mutex mutex; |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | −static void max8997_led_clear_mode(struct max8997_led *led, | |
| 53 | − enum max8997_led_mode mode) | |
| 54 | −{ | |
| 55 | − struct i2c_client *client = led->iodev->i2c; | |
| 56 | − u8 val = 0, mask = 0; | |
| 57 | − int ret; | |
| 58 | − | |
| 59 | − switch (mode) { | |
| 60 | − case MAX8997_FLASH_MODE: | |
| 61 | − mask = led->id ? | |
| 62 | − MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; | |
| 63 | − break; | |
| 64 | − case MAX8997_MOVIE_MODE: | |
| 65 | − mask = led->id ? | |
| 66 | − MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; | |
| 67 | − break; | |
| 68 | − case MAX8997_FLASH_PIN_CONTROL_MODE: | |
| 69 | − mask = led->id ? | |
| 70 | − MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; | |
| 71 | − break; | |
| 72 | − case MAX8997_MOVIE_PIN_CONTROL_MODE: | |
| 73 | − mask = led->id ? | |
| 74 | − MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; | |
| 75 | − break; | |
| 76 | − default: | |
| 77 | − break; | |
| 78 | − } | |
| 79 | − | |
| 80 | − if (mask) { | |
| 81 | − ret = max8997_update_reg(client, | |
| 82 | − MAX8997_REG_LEN_CNTL, val, mask); | |
| 83 | − if (ret) | |
| 84 | − dev_err(led->iodev->dev, | |
| 85 | − "failed to update register(%d)\n", ret); | |
| 86 | − } | |
| 87 | −} | |
| 88 | − | |
| 89 | 52 | static void max8997_led_set_mode(struct max8997_led *led, |
| 90 | 53 | enum max8997_led_mode mode) |
| 91 | 54 | { |
| 92 | 55 | int ret; |
| 93 | 56 | struct i2c_client *client = led->iodev->i2c; |
| 94 | − u8 mask = 0; | |
| 95 | − | |
| 96 | − /* First, clear the previous mode */ | |
| 97 | − max8997_led_clear_mode(led, led->led_mode); | |
| 57 | + u8 mask = 0, val; | |
| 98 | 58 | |
| 99 | 59 | switch (mode) { |
| 100 | 60 | case MAX8997_FLASH_MODE: |
| 101 | − mask = led->id ? | |
| 61 | + mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK; | |
| 62 | + val = led->id ? | |
| 102 | 63 | MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; |
| 103 | 64 | led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; |
| 104 | 65 | break; |
| 105 | 66 | case MAX8997_MOVIE_MODE: |
| 106 | − mask = led->id ? | |
| 67 | + mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK; | |
| 68 | + val = led->id ? | |
| 107 | 69 | MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; |
| 108 | 70 | led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; |
| 109 | 71 | break; |
| 110 | 72 | case MAX8997_FLASH_PIN_CONTROL_MODE: |
| 111 | − mask = led->id ? | |
| 73 | + mask = MAX8997_LED1_FLASH_PIN_MASK | | |
| 74 | + MAX8997_LED0_FLASH_PIN_MASK; | |
| 75 | + val = led->id ? | |
| 112 | 76 | MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; |
| 113 | 77 | led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; |
| 114 | 78 | break; |
| 115 | 79 | case MAX8997_MOVIE_PIN_CONTROL_MODE: |
| 116 | − mask = led->id ? | |
| 80 | + mask = MAX8997_LED1_MOVIE_PIN_MASK | | |
| 81 | + MAX8997_LED0_MOVIE_PIN_MASK; | |
| 82 | + val = led->id ? | |
| 117 | 83 | MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; |
| 118 | 84 | led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; |
| 119 | 85 | break; |
| @@ -123,8 +89,8 @@ static void max8997_led_set_mode(struct max8997_led *led, · 3 unmodified lines | ||
| 123 | 89 | } |
| 124 | 90 | |
| 125 | 91 | if (mask) { |
| 126 | − ret = max8997_update_reg(client, | |
| 127 | − MAX8997_REG_LEN_CNTL, mask, mask); | |
| 92 | + ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val, | |
| 93 | + mask); | |
| 128 | 94 | if (ret) |
| 129 | 95 | dev_err(led->iodev->dev, |
| 130 | 96 | "failed to update register(%d)\n", ret); |
| @@ -276,11 +242,9 @@ static int __devinit max8997_led_probe(struct platform_device *pdev) · 145 unmodified lines | ||
| 276 | 242 | return -ENODEV; |
| 277 | 243 | } |
| 278 | 244 | |
| 279 | − led = kzalloc(sizeof(*led), GFP_KERNEL); | |
| 280 | − if (led == NULL) { | |
| 281 | − ret = -ENOMEM; | |
| 282 | − goto err_mem; | |
| 283 | − } | |
| 245 | + led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); | |
| 246 | + if (led == NULL) | |
| 247 | + return -ENOMEM; | |
| 284 | 248 | |
| 285 | 249 | led->id = pdev->id; |
| 286 | 250 | snprintf(name, sizeof(name), "max8997-led%d", pdev->id); |
| @@ -315,23 +279,17 @@ static int __devinit max8997_led_probe(struct platform_device *pdev) · 28 unmodified lines | ||
| 315 | 279 | |
| 316 | 280 | ret = led_classdev_register(&pdev->dev, &led->cdev); |
| 317 | 281 | if (ret < 0) |
| 318 | − goto err_led; | |
| 282 | + return ret; | |
| 319 | 283 | |
| 320 | 284 | ret = device_create_file(led->cdev.dev, &dev_attr_mode); |
| 321 | 285 | if (ret != 0) { |
| 322 | 286 | dev_err(&pdev->dev, |
| 323 | 287 | "failed to create file: %d\n", ret); |
| 324 | − goto err_file; | |
| 288 | + led_classdev_unregister(&led->cdev); | |
| 289 | + return ret; | |
| 325 | 290 | } |
| 326 | 291 | |
| 327 | 292 | return 0; |
| 328 | − | |
| 329 | −err_file: | |
| 330 | − led_classdev_unregister(&led->cdev); | |
| 331 | −err_led: | |
| 332 | − kfree(led); | |
| 333 | −err_mem: | |
| 334 | − return ret; | |
| 335 | 293 | } |
| 336 | 294 | |
| 337 | 295 | static int __devexit max8997_led_remove(struct platform_device *pdev) |
| @@ -340,7 +298,6 @@ static int __devexit max8997_led_remove(struct platform_device *pdev) · 2 unmodified lines | ||
| 340 | 298 | |
| 341 | 299 | device_remove_file(led->cdev.dev, &dev_attr_mode); |
| 342 | 300 | led_classdev_unregister(&led->cdev); |
| 343 | − kfree(led); | |
| 344 | 301 | |
| 345 | 302 | return 0; |
| 346 | 303 | } |
| @@ -354,17 +311,7 @@ static struct platform_driver max8997_led_driver = { · 7 unmodified lines | ||
| 354 | 311 | .remove = __devexit_p(max8997_led_remove), |
| 355 | 312 | }; |
| 356 | 313 | |
| 357 | −static int __init max8997_led_init(void) | |
| 358 | −{ | |
| 359 | − return platform_driver_register(&max8997_led_driver); | |
| 360 | −} | |
| 361 | −module_init(max8997_led_init); | |
| 362 | − | |
| 363 | −static void __exit max8997_led_exit(void) | |
| 364 | −{ | |
| 365 | − platform_driver_unregister(&max8997_led_driver); | |
| 366 | −} | |
| 367 | −module_exit(max8997_led_exit); | |
| 314 | +module_platform_driver(max8997_led_driver); | |
| 368 | 315 | |
| 369 | 316 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); |
| 370 | 317 | MODULE_DESCRIPTION("MAX8997 LED driver"); |
| @@ -280,7 +280,8 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev) · 279 unmodified lines | ||
| 280 | 280 | return -EINVAL; |
| 281 | 281 | } |
| 282 | 282 | |
| 283 | − led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL); | |
| 283 | + led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led), | |
| 284 | + GFP_KERNEL); | |
| 284 | 285 | if (led == NULL) { |
| 285 | 286 | dev_err(&pdev->dev, "failed to alloc memory\n"); |
| 286 | 287 | return -ENOMEM; |
| @@ -289,7 +290,7 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 289 | 290 | ret = mc13783_leds_prepare(pdev); |
| 290 | 291 | if (ret) { |
| 291 | 292 | dev_err(&pdev->dev, "unable to init led driver\n"); |
| 292 | − goto err_free; | |
| 293 | + return ret; | |
| 293 | 294 | } |
| 294 | 295 | |
| 295 | 296 | for (i = 0; i < pdata->num_leds; i++) { |
| @@ -344,8 +345,6 @@ err_register: · 48 unmodified lines | ||
| 344 | 345 | cancel_work_sync(&led[i].work); |
| 345 | 346 | } |
| 346 | 347 | |
| 347 | −err_free: | |
| 348 | − kfree(led); | |
| 349 | 348 | return ret; |
| 350 | 349 | } |
| 351 | 350 | |
| @@ -372,7 +371,7 @@ static int __devexit mc13783_led_remove(struct platform_device *pdev) · 20 unmodified lines | ||
| 372 | 371 | |
| 373 | 372 | mc13xxx_unlock(dev); |
| 374 | 373 | |
| 375 | − kfree(led); | |
| 374 | + platform_set_drvdata(pdev, NULL); | |
| 376 | 375 | return 0; |
| 377 | 376 | } |
| 378 | 377 | |
| @@ -362,14 +362,14 @@ static int __devinit netxbig_led_probe(struct platform_device *pdev) · 361 unmodified lines | ||
| 362 | 362 | if (!pdata) |
| 363 | 363 | return -EINVAL; |
| 364 | 364 | |
| 365 | − leds_data = kzalloc(sizeof(struct netxbig_led_data) * pdata->num_leds, | |
| 366 | − GFP_KERNEL); | |
| 365 | + leds_data = devm_kzalloc(&pdev->dev, | |
| 366 | + sizeof(struct netxbig_led_data) * pdata->num_leds, GFP_KERNEL); | |
| 367 | 367 | if (!leds_data) |
| 368 | 368 | return -ENOMEM; |
| 369 | 369 | |
| 370 | 370 | ret = gpio_ext_init(pdata->gpio_ext); |
| 371 | 371 | if (ret < 0) |
| 372 | − goto err_free_data; | |
| 372 | + return ret; | |
| 373 | 373 | |
| 374 | 374 | for (i = 0; i < pdata->num_leds; i++) { |
| 375 | 375 | ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]); |
| @@ -386,9 +386,6 @@ err_free_leds: · 10 unmodified lines | ||
| 386 | 386 | delete_netxbig_led(&leds_data[i]); |
| 387 | 387 | |
| 388 | 388 | gpio_ext_free(pdata->gpio_ext); |
| 389 | −err_free_data: | |
| 390 | − kfree(leds_data); | |
| 391 | − | |
| 392 | 389 | return ret; |
| 393 | 390 | } |
| 394 | 391 | |
| @@ -404,7 +401,6 @@ static int __devexit netxbig_led_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 404 | 401 | delete_netxbig_led(&leds_data[i]); |
| 405 | 402 | |
| 406 | 403 | gpio_ext_free(pdata->gpio_ext); |
| 407 | − kfree(leds_data); | |
| 408 | 404 | |
| 409 | 405 | return 0; |
| 410 | 406 | } |
| @@ -273,29 +273,23 @@ static int __devinit ns2_led_probe(struct platform_device *pdev) · 272 unmodified lines | ||
| 273 | 273 | if (!pdata) |
| 274 | 274 | return -EINVAL; |
| 275 | 275 | |
| 276 | − leds_data = kzalloc(sizeof(struct ns2_led_data) * | |
| 276 | + leds_data = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_data) * | |
| 277 | 277 | pdata->num_leds, GFP_KERNEL); |
| 278 | 278 | if (!leds_data) |
| 279 | 279 | return -ENOMEM; |
| 280 | 280 | |
| 281 | 281 | for (i = 0; i < pdata->num_leds; i++) { |
| 282 | 282 | ret = create_ns2_led(pdev, &leds_data[i], &pdata->leds[i]); |
| 283 | − if (ret < 0) | |
| 284 | − goto err; | |
| 285 | − | |
| 283 | + if (ret < 0) { | |
| 284 | + for (i = i - 1; i >= 0; i--) | |
| 285 | + delete_ns2_led(&leds_data[i]); | |
| 286 | + return ret; | |
| 287 | + } | |
| 286 | 288 | } |
| 287 | 289 | |
| 288 | 290 | platform_set_drvdata(pdev, leds_data); |
| 289 | 291 | |
| 290 | 292 | return 0; |
| 291 | − | |
| 292 | −err: | |
| 293 | − for (i = i - 1; i >= 0; i--) | |
| 294 | − delete_ns2_led(&leds_data[i]); | |
| 295 | − | |
| 296 | − kfree(leds_data); | |
| 297 | − | |
| 298 | − return ret; | |
| 299 | 293 | } |
| 300 | 294 | |
| 301 | 295 | static int __devexit ns2_led_remove(struct platform_device *pdev) |
| @@ -309,7 +303,6 @@ static int __devexit ns2_led_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 309 | 303 | for (i = 0; i < pdata->num_leds; i++) |
| 310 | 304 | delete_ns2_led(&leds_data[i]); |
| 311 | 305 | |
| 312 | − kfree(leds_data); | |
| 313 | 306 | platform_set_drvdata(pdev, NULL); |
| 314 | 307 | |
| 315 | 308 | return 0; |
| @@ -449,7 +449,6 @@ static int pca9532_probe(struct i2c_client *client, · 448 unmodified lines | ||
| 449 | 449 | { |
| 450 | 450 | struct pca9532_data *data = i2c_get_clientdata(client); |
| 451 | 451 | struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data; |
| 452 | − int err; | |
| 453 | 452 | |
| 454 | 453 | if (!pca9532_pdata) |
| 455 | 454 | return -EIO; |
| @@ -458,7 +457,7 @@ static int pca9532_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 458 | 457 | I2C_FUNC_SMBUS_BYTE_DATA)) |
| 459 | 458 | return -EIO; |
| 460 | 459 | |
| 461 | − data = kzalloc(sizeof(*data), GFP_KERNEL); | |
| 460 | + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); | |
| 462 | 461 | if (!data) |
| 463 | 462 | return -ENOMEM; |
| 464 | 463 | |
| @@ -469,11 +468,7 @@ static int pca9532_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 469 | 468 | data->client = client; |
| 470 | 469 | mutex_init(&data->update_lock); |
| 471 | 470 | |
| 472 | − err = pca9532_configure(client, data, pca9532_pdata); | |
| 473 | − if (err) | |
| 474 | − kfree(data); | |
| 475 | − | |
| 476 | − return err; | |
| 471 | + return pca9532_configure(client, data, pca9532_pdata); | |
| 477 | 472 | } |
| 478 | 473 | |
| 479 | 474 | static int pca9532_remove(struct i2c_client *client) |
| @@ -485,7 +480,6 @@ static int pca9532_remove(struct i2c_client *client) · 5 unmodified lines | ||
| 485 | 480 | if (err) |
| 486 | 481 | return err; |
| 487 | 482 | |
| 488 | − kfree(data); | |
| 489 | 483 | return 0; |
| 490 | 484 | } |
| 491 | 485 | |
| @@ -293,15 +293,14 @@ static int __devinit pca955x_probe(struct i2c_client *client, · 292 unmodified lines | ||
| 293 | 293 | } |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | − pca955x = kzalloc(sizeof(*pca955x), GFP_KERNEL); | |
| 296 | + pca955x = devm_kzalloc(&client->dev, sizeof(*pca955x), GFP_KERNEL); | |
| 297 | 297 | if (!pca955x) |
| 298 | 298 | return -ENOMEM; |
| 299 | 299 | |
| 300 | − pca955x->leds = kzalloc(sizeof(*pca955x_led) * chip->bits, GFP_KERNEL); | |
| 301 | − if (!pca955x->leds) { | |
| 302 | − err = -ENOMEM; | |
| 303 | − goto exit_nomem; | |
| 304 | − } | |
| 300 | + pca955x->leds = devm_kzalloc(&client->dev, | |
| 301 | + sizeof(*pca955x_led) * chip->bits, GFP_KERNEL); | |
| 302 | + if (!pca955x->leds) | |
| 303 | + return -ENOMEM; | |
| 305 | 304 | |
| 306 | 305 | i2c_set_clientdata(client, pca955x); |
| 307 | 306 | |
| @@ -361,10 +360,6 @@ exit: · 53 unmodified lines | ||
| 361 | 360 | cancel_work_sync(&pca955x->leds[i].work); |
| 362 | 361 | } |
| 363 | 362 | |
| 364 | − kfree(pca955x->leds); | |
| 365 | −exit_nomem: | |
| 366 | − kfree(pca955x); | |
| 367 | − | |
| 368 | 363 | return err; |
| 369 | 364 | } |
| 370 | 365 | |
| @@ -378,9 +373,6 @@ static int __devexit pca955x_remove(struct i2c_client *client) · 7 unmodified lines | ||
| 378 | 373 | cancel_work_sync(&pca955x->leds[i].work); |
| 379 | 374 | } |
| 380 | 375 | |
| 381 | − kfree(pca955x->leds); | |
| 382 | − kfree(pca955x); | |
| 383 | − | |
| 384 | 376 | return 0; |
| 385 | 377 | } |
| 386 | 378 | |
| @@ -108,7 +108,7 @@ static int __devinit pca9633_probe(struct i2c_client *client, · 107 unmodified lines | ||
| 108 | 108 | } |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | − pca9633 = kcalloc(4, sizeof(*pca9633), GFP_KERNEL); | |
| 111 | + pca9633 = devm_kzalloc(&client->dev, 4 * sizeof(*pca9633), GFP_KERNEL); | |
| 112 | 112 | if (!pca9633) |
| 113 | 113 | return -ENOMEM; |
| 114 | 114 | |
| @@ -156,8 +156,6 @@ exit: · 41 unmodified lines | ||
| 156 | 156 | cancel_work_sync(&pca9633[i].work); |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | − kfree(pca9633); | |
| 160 | − | |
| 161 | 159 | return err; |
| 162 | 160 | } |
| 163 | 161 | |
| @@ -171,8 +169,6 @@ static int __devexit pca9633_remove(struct i2c_client *client) · 7 unmodified lines | ||
| 171 | 169 | cancel_work_sync(&pca9633[i].work); |
| 172 | 170 | } |
| 173 | 171 | |
| 174 | − kfree(pca9633); | |
| 175 | − | |
| 176 | 172 | return 0; |
| 177 | 173 | } |
| 178 | 174 | |
| @@ -57,7 +57,8 @@ static int led_pwm_probe(struct platform_device *pdev) · 56 unmodified lines | ||
| 57 | 57 | if (!pdata) |
| 58 | 58 | return -EBUSY; |
| 59 | 59 | |
| 60 | − leds_data = kzalloc(sizeof(struct led_pwm_data) * pdata->num_leds, | |
| 60 | + leds_data = devm_kzalloc(&pdev->dev, | |
| 61 | + sizeof(struct led_pwm_data) * pdata->num_leds, | |
| 61 | 62 | GFP_KERNEL); |
| 62 | 63 | if (!leds_data) |
| 63 | 64 | return -ENOMEM; |
| @@ -103,8 +104,6 @@ err: · 39 unmodified lines | ||
| 103 | 104 | } |
| 104 | 105 | } |
| 105 | 106 | |
| 106 | − kfree(leds_data); | |
| 107 | − | |
| 108 | 107 | return ret; |
| 109 | 108 | } |
| 110 | 109 | |
| @@ -121,8 +120,6 @@ static int __devexit led_pwm_remove(struct platform_device *pdev) · 10 unmodified lines | ||
| 121 | 120 | pwm_free(leds_data[i].pwm); |
| 122 | 121 | } |
| 123 | 122 | |
| 124 | − kfree(leds_data); | |
| 125 | − | |
| 126 | 123 | return 0; |
| 127 | 124 | } |
| 128 | 125 | |
| @@ -158,7 +158,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev) · 157 unmodified lines | ||
| 158 | 158 | return PTR_ERR(vcc); |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | − led = kzalloc(sizeof(*led), GFP_KERNEL); | |
| 161 | + led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); | |
| 162 | 162 | if (led == NULL) { |
| 163 | 163 | ret = -ENOMEM; |
| 164 | 164 | goto err_vcc; |
| @@ -169,7 +169,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 169 | 169 | dev_err(&pdev->dev, "Invalid default brightness %d\n", |
| 170 | 170 | pdata->brightness); |
| 171 | 171 | ret = -EINVAL; |
| 172 | − goto err_led; | |
| 172 | + goto err_vcc; | |
| 173 | 173 | } |
| 174 | 174 | led->value = pdata->brightness; |
| 175 | 175 | |
| @@ -190,7 +190,7 @@ static int __devinit regulator_led_probe(struct platform_device *pdev) · 14 unmodified lines | ||
| 190 | 190 | ret = led_classdev_register(&pdev->dev, &led->cdev); |
| 191 | 191 | if (ret < 0) { |
| 192 | 192 | cancel_work_sync(&led->work); |
| 193 | − goto err_led; | |
| 193 | + goto err_vcc; | |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | 196 | /* to expose the default value to userspace */ |
| @@ -201,8 +201,6 @@ static int __devinit regulator_led_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 201 | 201 | |
| 202 | 202 | return 0; |
| 203 | 203 | |
| 204 | −err_led: | |
| 205 | − kfree(led); | |
| 206 | 204 | err_vcc: |
| 207 | 205 | regulator_put(vcc); |
| 208 | 206 | return ret; |
| @@ -216,7 +214,6 @@ static int __devexit regulator_led_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 216 | 214 | cancel_work_sync(&led->work); |
| 217 | 215 | regulator_led_disable(led); |
| 218 | 216 | regulator_put(led->vcc); |
| 219 | − kfree(led); | |
| 220 | 217 | return 0; |
| 221 | 218 | } |
| 222 | 219 | |
| @@ -243,31 +243,30 @@ static int __devinit r_tpu_probe(struct platform_device *pdev) · 242 unmodified lines | ||
| 243 | 243 | struct led_renesas_tpu_config *cfg = pdev->dev.platform_data; |
| 244 | 244 | struct r_tpu_priv *p; |
| 245 | 245 | struct resource *res; |
| 246 | − int ret = -ENXIO; | |
| 246 | + int ret; | |
| 247 | 247 | |
| 248 | 248 | if (!cfg) { |
| 249 | 249 | dev_err(&pdev->dev, "missing platform data\n"); |
| 250 | 250 | goto err0; |
| 251 | 251 | } |
| 252 | 252 | |
| 253 | − p = kzalloc(sizeof(*p), GFP_KERNEL); | |
| 253 | + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | |
| 254 | 254 | if (p == NULL) { |
| 255 | 255 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
| 256 | − ret = -ENOMEM; | |
| 257 | − goto err0; | |
| 256 | + return -ENOMEM; | |
| 258 | 257 | } |
| 259 | 258 | |
| 260 | 259 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 261 | 260 | if (!res) { |
| 262 | 261 | dev_err(&pdev->dev, "failed to get I/O memory\n"); |
| 263 | − goto err1; | |
| 262 | + return -ENXIO; | |
| 264 | 263 | } |
| 265 | 264 | |
| 266 | 265 | /* map memory, let mapbase point to our channel */ |
| 267 | 266 | p->mapbase = ioremap_nocache(res->start, resource_size(res)); |
| 268 | 267 | if (p->mapbase == NULL) { |
| 269 | 268 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); |
| 270 | − goto err1; | |
| 269 | + return -ENXIO; | |
| 271 | 270 | } |
| 272 | 271 | |
| 273 | 272 | /* get hold of clock */ |
| @@ -275,7 +274,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 275 | 274 | if (IS_ERR(p->clk)) { |
| 276 | 275 | dev_err(&pdev->dev, "cannot get clock\n"); |
| 277 | 276 | ret = PTR_ERR(p->clk); |
| 278 | − goto err2; | |
| 277 | + goto err0; | |
| 279 | 278 | } |
| 280 | 279 | |
| 281 | 280 | p->pdev = pdev; |
| @@ -294,7 +293,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 294 | 293 | p->ldev.flags |= LED_CORE_SUSPENDRESUME; |
| 295 | 294 | ret = led_classdev_register(&pdev->dev, &p->ldev); |
| 296 | 295 | if (ret < 0) |
| 297 | − goto err3; | |
| 296 | + goto err1; | |
| 298 | 297 | |
| 299 | 298 | /* max_brightness may be updated by the LED core code */ |
| 300 | 299 | p->min_rate = p->ldev.max_brightness * p->refresh_rate; |
| @@ -302,14 +301,11 @@ static int __devinit r_tpu_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 302 | 301 | pm_runtime_enable(&pdev->dev); |
| 303 | 302 | return 0; |
| 304 | 303 | |
| 305 | − err3: | |
| 304 | + err1: | |
| 306 | 305 | r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF); |
| 307 | 306 | clk_put(p->clk); |
| 308 | − err2: | |
| 309 | − iounmap(p->mapbase); | |
| 310 | − err1: | |
| 311 | − kfree(p); | |
| 312 | 307 | err0: |
| 308 | + iounmap(p->mapbase); | |
| 313 | 309 | return ret; |
| 314 | 310 | } |
| 315 | 311 | |
| @@ -327,7 +323,6 @@ static int __devexit r_tpu_remove(struct platform_device *pdev) · 11 unmodified lines | ||
| 327 | 323 | clk_put(p->clk); |
| 328 | 324 | |
| 329 | 325 | iounmap(p->mapbase); |
| 330 | − kfree(p); | |
| 331 | 326 | return 0; |
| 332 | 327 | } |
| 333 | 328 | |
| @@ -45,17 +45,19 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev, · 44 unmodified lines | ||
| 45 | 45 | { |
| 46 | 46 | struct s3c24xx_gpio_led *led = to_gpio(led_cdev); |
| 47 | 47 | struct s3c24xx_led_platdata *pd = led->pdata; |
| 48 | + int state = (value ? 1 : 0) ^ (pd->flags & S3C24XX_LEDF_ACTLOW); | |
| 48 | 49 | |
| 49 | 50 | /* there will be a short delay between setting the output and |
| 50 | 51 | * going from output to input when using tristate. */ |
| 51 | 52 | |
| 52 | − s3c2410_gpio_setpin(pd->gpio, (value ? 1 : 0) ^ | |
| 53 | − (pd->flags & S3C24XX_LEDF_ACTLOW)); | |
| 54 | − | |
| 55 | − if (pd->flags & S3C24XX_LEDF_TRISTATE) | |
| 56 | − s3c2410_gpio_cfgpin(pd->gpio, | |
| 57 | − value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT); | |
| 53 | + gpio_set_value(pd->gpio, state); | |
| 58 | 54 | |
| 55 | + if (pd->flags & S3C24XX_LEDF_TRISTATE) { | |
| 56 | + if (value) | |
| 57 | + gpio_direction_output(pd->gpio, state); | |
| 58 | + else | |
| 59 | + gpio_direction_input(pd->gpio); | |
| 60 | + } | |
| 59 | 61 | } |
| 60 | 62 | |
| 61 | 63 | static int s3c24xx_led_remove(struct platform_device *dev) |
| @@ -63,7 +65,6 @@ static int s3c24xx_led_remove(struct platform_device *dev) · 1 unmodified line | ||
| 63 | 65 | struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); |
| 64 | 66 | |
| 65 | 67 | led_classdev_unregister(&led->cdev); |
| 66 | − kfree(led); | |
| 67 | 68 | |
| 68 | 69 | return 0; |
| 69 | 70 | } |
| @@ -74,7 +75,8 @@ static int s3c24xx_led_probe(struct platform_device *dev) · 4 unmodified lines | ||
| 74 | 75 | struct s3c24xx_gpio_led *led; |
| 75 | 76 | int ret; |
| 76 | 77 | |
| 77 | − led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL); | |
| 78 | + led = devm_kzalloc(&dev->dev, sizeof(struct s3c24xx_gpio_led), | |
| 79 | + GFP_KERNEL); | |
| 78 | 80 | if (led == NULL) { |
| 79 | 81 | dev_err(&dev->dev, "No memory for device\n"); |
| 80 | 82 | return -ENOMEM; |
| @@ -89,27 +91,27 @@ static int s3c24xx_led_probe(struct platform_device *dev) · 8 unmodified lines | ||
| 89 | 91 | |
| 90 | 92 | led->pdata = pdata; |
| 91 | 93 | |
| 94 | + ret = devm_gpio_request(&dev->dev, pdata->gpio, "S3C24XX_LED"); | |
| 95 | + if (ret < 0) | |
| 96 | + return ret; | |
| 97 | + | |
| 92 | 98 | /* no point in having a pull-up if we are always driving */ |
| 93 | 99 | |
| 94 | − if (pdata->flags & S3C24XX_LEDF_TRISTATE) { | |
| 95 | − s3c2410_gpio_setpin(pdata->gpio, 0); | |
| 96 | − s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_INPUT); | |
| 97 | − } else { | |
| 98 | − s3c2410_gpio_pullup(pdata->gpio, 0); | |
| 99 | − s3c2410_gpio_setpin(pdata->gpio, 0); | |
| 100 | − s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_OUTPUT); | |
| 101 | − } | |
| 100 | + s3c_gpio_setpull(pdata->gpio, S3C_GPIO_PULL_NONE); | |
| 101 | + | |
| 102 | + if (pdata->flags & S3C24XX_LEDF_TRISTATE) | |
| 103 | + gpio_direction_input(pdata->gpio); | |
| 104 | + else | |
| 105 | + gpio_direction_output(pdata->gpio, | |
| 106 | + pdata->flags & S3C24XX_LEDF_ACTLOW ? 1 : 0); | |
| 102 | 107 | |
| 103 | 108 | /* register our new led device */ |
| 104 | 109 | |
| 105 | 110 | ret = led_classdev_register(&dev->dev, &led->cdev); |
| 106 | − if (ret < 0) { | |
| 111 | + if (ret < 0) | |
| 107 | 112 | dev_err(&dev->dev, "led_classdev_register failed\n"); |
| 108 | − kfree(led); | |
| 109 | − return ret; | |
| 110 | − } | |
| 111 | 113 | |
| 112 | − return 0; | |
| 114 | + return ret; | |
| 113 | 115 | } |
| 114 | 116 | |
| 115 | 117 | static struct platform_driver s3c24xx_led_driver = { |
| @@ -132,15 +132,13 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, · 131 unmodified lines | ||
| 132 | 132 | if (pdev->num_resources != 1) { |
| 133 | 133 | printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n", |
| 134 | 134 | pdev->num_resources); |
| 135 | − err = -EINVAL; | |
| 136 | − goto out; | |
| 135 | + return -EINVAL; | |
| 137 | 136 | } |
| 138 | 137 | |
| 139 | − p = kzalloc(sizeof(*p), GFP_KERNEL); | |
| 138 | + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | |
| 140 | 139 | if (!p) { |
| 141 | 140 | printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n"); |
| 142 | − err = -ENOMEM; | |
| 143 | − goto out; | |
| 141 | + return -ENOMEM; | |
| 144 | 142 | } |
| 145 | 143 | |
| 146 | 144 | for (i = 0; i < NUM_LEDS_PER_BOARD; i++) { |
| @@ -156,20 +154,15 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, · 9 unmodified lines | ||
| 156 | 154 | if (err) { |
| 157 | 155 | printk(KERN_ERR PFX "Could not register %s LED\n", |
| 158 | 156 | lp->name); |
| 159 | − goto out_unregister_led_cdevs; | |
| 157 | + for (i--; i >= 0; i--) | |
| 158 | + led_classdev_unregister(&p->leds[i].led_cdev); | |
| 159 | + return err; | |
| 160 | 160 | } |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | dev_set_drvdata(&pdev->dev, p); |
| 164 | 164 | |
| 165 | 165 | return 0; |
| 166 | − | |
| 167 | −out_unregister_led_cdevs: | |
| 168 | − for (i--; i >= 0; i--) | |
| 169 | − led_classdev_unregister(&p->leds[i].led_cdev); | |
| 170 | − kfree(p); | |
| 171 | −out: | |
| 172 | − return err; | |
| 173 | 166 | } |
| 174 | 167 | |
| 175 | 168 | static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) |
| @@ -180,8 +173,6 @@ static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) · 4 unmodified lines | ||
| 180 | 173 | for (i = 0; i < NUM_LEDS_PER_BOARD; i++) |
| 181 | 174 | led_classdev_unregister(&p->leds[i].led_cdev); |
| 182 | 175 | |
| 183 | − kfree(p); | |
| 184 | − | |
| 185 | 176 | return 0; |
| 186 | 177 | } |
| 187 | 178 | |
| @@ -687,7 +687,7 @@ static int __devinit tca6507_probe(struct i2c_client *client, · 686 unmodified lines | ||
| 687 | 687 | NUM_LEDS); |
| 688 | 688 | return -ENODEV; |
| 689 | 689 | } |
| 690 | − tca = kzalloc(sizeof(*tca), GFP_KERNEL); | |
| 690 | + tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); | |
| 691 | 691 | if (!tca) |
| 692 | 692 | return -ENOMEM; |
| 693 | 693 | |
| @@ -727,7 +727,6 @@ exit: · 33 unmodified lines | ||
| 727 | 727 | if (tca->leds[i].led_cdev.name) |
| 728 | 728 | led_classdev_unregister(&tca->leds[i].led_cdev); |
| 729 | 729 | } |
| 730 | − kfree(tca); | |
| 731 | 730 | return err; |
| 732 | 731 | } |
| 733 | 732 | |
| @@ -743,7 +742,6 @@ static int __devexit tca6507_remove(struct i2c_client *client) · 9 unmodified lines | ||
| 743 | 742 | } |
| 744 | 743 | tca6507_remove_gpio(tca); |
| 745 | 744 | cancel_work_sync(&tca->work); |
| 746 | − kfree(tca); | |
| 747 | 745 | |
| 748 | 746 | return 0; |
| 749 | 747 | } |
| @@ -758,18 +756,7 @@ static struct i2c_driver tca6507_driver = { · 8 unmodified lines | ||
| 758 | 756 | .id_table = tca6507_id, |
| 759 | 757 | }; |
| 760 | 758 | |
| 761 | −static int __init tca6507_leds_init(void) | |
| 762 | −{ | |
| 763 | − return i2c_add_driver(&tca6507_driver); | |
| 764 | −} | |
| 765 | − | |
| 766 | −static void __exit tca6507_leds_exit(void) | |
| 767 | −{ | |
| 768 | − i2c_del_driver(&tca6507_driver); | |
| 769 | −} | |
| 770 | − | |
| 771 | −module_init(tca6507_leds_init); | |
| 772 | −module_exit(tca6507_leds_exit); | |
| 759 | +module_i2c_driver(tca6507_driver); | |
| 773 | 760 | |
| 774 | 761 | MODULE_AUTHOR("NeilBrown <neilb@suse.de>"); |
| 775 | 762 | MODULE_DESCRIPTION("TCA6507 LED/GPO driver"); |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/rwsem.h> |
| 18 | 18 | #include <linux/leds.h> |
| 19 | 19 | |
| 20 | −static inline void led_set_brightness(struct led_classdev *led_cdev, | |
| 20 | +static inline void __led_set_brightness(struct led_classdev *led_cdev, | |
| 21 | 21 | enum led_brightness value) |
| 22 | 22 | { |
| 23 | 23 | if (value > led_cdev->max_brightness) |
| @@ -46,9 +46,9 @@ static int fb_notifier_callback(struct notifier_block *p, · 45 unmodified lines | ||
| 46 | 46 | |
| 47 | 47 | if ((n->old_status == UNBLANK) ^ n->invert) { |
| 48 | 48 | n->brightness = led->brightness; |
| 49 | − led_set_brightness(led, LED_OFF); | |
| 49 | + __led_set_brightness(led, LED_OFF); | |
| 50 | 50 | } else { |
| 51 | − led_set_brightness(led, n->brightness); | |
| 51 | + __led_set_brightness(led, n->brightness); | |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | n->old_status = new_status; |
| @@ -87,9 +87,9 @@ static ssize_t bl_trig_invert_store(struct device *dev, · 32 unmodified lines | ||
| 87 | 87 | |
| 88 | 88 | /* After inverting, we need to update the LED. */ |
| 89 | 89 | if ((n->old_status == BLANK) ^ n->invert) |
| 90 | − led_set_brightness(led, LED_OFF); | |
| 90 | + __led_set_brightness(led, LED_OFF); | |
| 91 | 91 | else |
| 92 | − led_set_brightness(led, n->brightness); | |
| 92 | + __led_set_brightness(led, n->brightness); | |
| 93 | 93 | |
| 94 | 94 | return num; |
| 95 | 95 | } |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | static void defon_trig_activate(struct led_classdev *led_cdev) |
| 21 | 21 | { |
| 22 | − led_set_brightness(led_cdev, led_cdev->max_brightness); | |
| 22 | + __led_set_brightness(led_cdev, led_cdev->max_brightness); | |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | static struct led_trigger defon_led_trigger = { |
| @@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work) · 53 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | if (tmp) { |
| 56 | 56 | if (gpio_data->desired_brightness) |
| 57 | − led_set_brightness(gpio_data->led, | |
| 57 | + __led_set_brightness(gpio_data->led, | |
| 58 | 58 | gpio_data->desired_brightness); |
| 59 | 59 | else |
| 60 | − led_set_brightness(gpio_data->led, LED_FULL); | |
| 60 | + __led_set_brightness(gpio_data->led, LED_FULL); | |
| 61 | 61 | } else { |
| 62 | − led_set_brightness(gpio_data->led, LED_OFF); | |
| 62 | + __led_set_brightness(gpio_data->led, LED_OFF); | |
| 63 | 63 | } |
| 64 | 64 | } |
| 65 | 65 | |
| @@ -74,7 +74,7 @@ static void led_heartbeat_function(unsigned long data) · 73 unmodified lines | ||
| 74 | 74 | break; |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | − led_set_brightness(led_cdev, brightness); | |
| 77 | + __led_set_brightness(led_cdev, brightness); | |
| 78 | 78 | mod_timer(&heartbeat_data->timer, jiffies + delay); |
| 79 | 79 | } |
| 80 | 80 | |
| @@ -12,39 +12,22 @@ · 11 unmodified lines | ||
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | 14 | #include <linux/module.h> |
| 15 | −#include <linux/jiffies.h> | |
| 16 | 15 | #include <linux/kernel.h> |
| 17 | 16 | #include <linux/init.h> |
| 18 | −#include <linux/timer.h> | |
| 19 | 17 | #include <linux/leds.h> |
| 20 | 18 | |
| 21 | −static void ledtrig_ide_timerfunc(unsigned long data); | |
| 19 | +#define BLINK_DELAY 30 | |
| 22 | 20 | |
| 23 | 21 | DEFINE_LED_TRIGGER(ledtrig_ide); |
| 24 | −static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0); | |
| 25 | −static int ide_activity; | |
| 26 | −static int ide_lastactivity; | |
| 22 | +static unsigned long ide_blink_delay = BLINK_DELAY; | |
| 27 | 23 | |
| 28 | 24 | void ledtrig_ide_activity(void) |
| 29 | 25 | { |
| 30 | − ide_activity++; | |
| 31 | − if (!timer_pending(&ledtrig_ide_timer)) | |
| 32 | − mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); | |
| 26 | + led_trigger_blink_oneshot(ledtrig_ide, | |
| 27 | + &ide_blink_delay, &ide_blink_delay, 0); | |
| 33 | 28 | } |
| 34 | 29 | EXPORT_SYMBOL(ledtrig_ide_activity); |
| 35 | 30 | |
| 36 | −static void ledtrig_ide_timerfunc(unsigned long data) | |
| 37 | −{ | |
| 38 | − if (ide_lastactivity != ide_activity) { | |
| 39 | − ide_lastactivity = ide_activity; | |
| 40 | − /* INT_MAX will set each LED to its maximum brightness */ | |
| 41 | − led_trigger_event(ledtrig_ide, INT_MAX); | |
| 42 | − mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); | |
| 43 | − } else { | |
| 44 | − led_trigger_event(ledtrig_ide, LED_OFF); | |
| 45 | − } | |
| 46 | −} | |
| 47 | − | |
| 48 | 31 | static int __init ledtrig_ide_init(void) |
| 49 | 32 | { |
| 50 | 33 | led_trigger_register_simple("ide-disk", &ledtrig_ide); |
| @@ -0,0 +1,204 @@ | ||
| 1 | +/* | |
| 2 | + * One-shot LED Trigger | |
| 3 | + * | |
| 4 | + * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com> | |
| 5 | + * | |
| 6 | + * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + * | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/kernel.h> | |
| 16 | +#include <linux/init.h> | |
| 17 | +#include <linux/device.h> | |
| 18 | +#include <linux/ctype.h> | |
| 19 | +#include <linux/slab.h> | |
| 20 | +#include <linux/leds.h> | |
| 21 | +#include "leds.h" | |
| 22 | + | |
| 23 | +#define DEFAULT_DELAY 100 | |
| 24 | + | |
| 25 | +struct oneshot_trig_data { | |
| 26 | + unsigned int invert; | |
| 27 | +}; | |
| 28 | + | |
| 29 | +static ssize_t led_shot(struct device *dev, | |
| 30 | + struct device_attribute *attr, const char *buf, size_t size) | |
| 31 | +{ | |
| 32 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 33 | + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; | |
| 34 | + | |
| 35 | + led_blink_set_oneshot(led_cdev, | |
| 36 | + &led_cdev->blink_delay_on, &led_cdev->blink_delay_off, | |
| 37 | + oneshot_data->invert); | |
| 38 | + | |
| 39 | + /* content is ignored */ | |
| 40 | + return size; | |
| 41 | +} | |
| 42 | +static ssize_t led_invert_show(struct device *dev, | |
| 43 | + struct device_attribute *attr, char *buf) | |
| 44 | +{ | |
| 45 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 46 | + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; | |
| 47 | + | |
| 48 | + return sprintf(buf, "%u\n", oneshot_data->invert); | |
| 49 | +} | |
| 50 | + | |
| 51 | +static ssize_t led_invert_store(struct device *dev, | |
| 52 | + struct device_attribute *attr, const char *buf, size_t size) | |
| 53 | +{ | |
| 54 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 55 | + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; | |
| 56 | + unsigned long state; | |
| 57 | + int ret; | |
| 58 | + | |
| 59 | + ret = kstrtoul(buf, 0, &state); | |
| 60 | + if (ret) | |
| 61 | + return ret; | |
| 62 | + | |
| 63 | + oneshot_data->invert = !!state; | |
| 64 | + | |
| 65 | + if (oneshot_data->invert) | |
| 66 | + __led_set_brightness(led_cdev, LED_FULL); | |
| 67 | + else | |
| 68 | + __led_set_brightness(led_cdev, LED_OFF); | |
| 69 | + | |
| 70 | + return size; | |
| 71 | +} | |
| 72 | + | |
| 73 | +static ssize_t led_delay_on_show(struct device *dev, | |
| 74 | + struct device_attribute *attr, char *buf) | |
| 75 | +{ | |
| 76 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 77 | + | |
| 78 | + return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); | |
| 79 | +} | |
| 80 | + | |
| 81 | +static ssize_t led_delay_on_store(struct device *dev, | |
| 82 | + struct device_attribute *attr, const char *buf, size_t size) | |
| 83 | +{ | |
| 84 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 85 | + unsigned long state; | |
| 86 | + int ret; | |
| 87 | + | |
| 88 | + ret = kstrtoul(buf, 0, &state); | |
| 89 | + if (ret) | |
| 90 | + return ret; | |
| 91 | + | |
| 92 | + led_cdev->blink_delay_on = state; | |
| 93 | + | |
| 94 | + return size; | |
| 95 | +} | |
| 96 | +static ssize_t led_delay_off_show(struct device *dev, | |
| 97 | + struct device_attribute *attr, char *buf) | |
| 98 | +{ | |
| 99 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 100 | + | |
| 101 | + return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); | |
| 102 | +} | |
| 103 | + | |
| 104 | +static ssize_t led_delay_off_store(struct device *dev, | |
| 105 | + struct device_attribute *attr, const char *buf, size_t size) | |
| 106 | +{ | |
| 107 | + struct led_classdev *led_cdev = dev_get_drvdata(dev); | |
| 108 | + unsigned long state; | |
| 109 | + int ret; | |
| 110 | + | |
| 111 | + ret = kstrtoul(buf, 0, &state); | |
| 112 | + if (ret) | |
| 113 | + return ret; | |
| 114 | + | |
| 115 | + led_cdev->blink_delay_off = state; | |
| 116 | + | |
| 117 | + return size; | |
| 118 | +} | |
| 119 | + | |
| 120 | +static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); | |
| 121 | +static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); | |
| 122 | +static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store); | |
| 123 | +static DEVICE_ATTR(shot, 0200, NULL, led_shot); | |
| 124 | + | |
| 125 | +static void oneshot_trig_activate(struct led_classdev *led_cdev) | |
| 126 | +{ | |
| 127 | + struct oneshot_trig_data *oneshot_data; | |
| 128 | + int rc; | |
| 129 | + | |
| 130 | + oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL); | |
| 131 | + if (!oneshot_data) | |
| 132 | + return; | |
| 133 | + | |
| 134 | + led_cdev->trigger_data = oneshot_data; | |
| 135 | + | |
| 136 | + rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); | |
| 137 | + if (rc) | |
| 138 | + goto err_out_trig_data; | |
| 139 | + rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); | |
| 140 | + if (rc) | |
| 141 | + goto err_out_delayon; | |
| 142 | + rc = device_create_file(led_cdev->dev, &dev_attr_invert); | |
| 143 | + if (rc) | |
| 144 | + goto err_out_delayoff; | |
| 145 | + rc = device_create_file(led_cdev->dev, &dev_attr_shot); | |
| 146 | + if (rc) | |
| 147 | + goto err_out_invert; | |
| 148 | + | |
| 149 | + led_cdev->blink_delay_on = DEFAULT_DELAY; | |
| 150 | + led_cdev->blink_delay_off = DEFAULT_DELAY; | |
| 151 | + | |
| 152 | + led_cdev->activated = true; | |
| 153 | + | |
| 154 | + return; | |
| 155 | + | |
| 156 | +err_out_invert: | |
| 157 | + device_remove_file(led_cdev->dev, &dev_attr_invert); | |
| 158 | +err_out_delayoff: | |
| 159 | + device_remove_file(led_cdev->dev, &dev_attr_delay_off); | |
| 160 | +err_out_delayon: | |
| 161 | + device_remove_file(led_cdev->dev, &dev_attr_delay_on); | |
| 162 | +err_out_trig_data: | |
| 163 | + kfree(led_cdev->trigger_data); | |
| 164 | +} | |
| 165 | + | |
| 166 | +static void oneshot_trig_deactivate(struct led_classdev *led_cdev) | |
| 167 | +{ | |
| 168 | + struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data; | |
| 169 | + | |
| 170 | + if (led_cdev->activated) { | |
| 171 | + device_remove_file(led_cdev->dev, &dev_attr_delay_on); | |
| 172 | + device_remove_file(led_cdev->dev, &dev_attr_delay_off); | |
| 173 | + device_remove_file(led_cdev->dev, &dev_attr_invert); | |
| 174 | + device_remove_file(led_cdev->dev, &dev_attr_shot); | |
| 175 | + kfree(oneshot_data); | |
| 176 | + led_cdev->activated = false; | |
| 177 | + } | |
| 178 | + | |
| 179 | + /* Stop blinking */ | |
| 180 | + led_set_brightness(led_cdev, LED_OFF); | |
| 181 | +} | |
| 182 | + | |
| 183 | +static struct led_trigger oneshot_led_trigger = { | |
| 184 | + .name = "oneshot", | |
| 185 | + .activate = oneshot_trig_activate, | |
| 186 | + .deactivate = oneshot_trig_deactivate, | |
| 187 | +}; | |
| 188 | + | |
| 189 | +static int __init oneshot_trig_init(void) | |
| 190 | +{ | |
| 191 | + return led_trigger_register(&oneshot_led_trigger); | |
| 192 | +} | |
| 193 | + | |
| 194 | +static void __exit oneshot_trig_exit(void) | |
| 195 | +{ | |
| 196 | + led_trigger_unregister(&oneshot_led_trigger); | |
| 197 | +} | |
| 198 | + | |
| 199 | +module_init(oneshot_trig_init); | |
| 200 | +module_exit(oneshot_trig_exit); | |
| 201 | + | |
| 202 | +MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>"); | |
| 203 | +MODULE_DESCRIPTION("One-shot LED trigger"); | |
| 204 | +MODULE_LICENSE("GPL"); | |
| @@ -104,7 +104,7 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev) · 103 unmodified lines | ||
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | /* Stop blinking */ |
| 107 | − led_brightness_set(led_cdev, LED_OFF); | |
| 107 | + led_set_brightness(led_cdev, LED_OFF); | |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | 110 | static struct led_trigger timer_led_trigger = { |
| @@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data) · 40 unmodified lines | ||
| 41 | 41 | struct transient_trig_data *transient_data = led_cdev->trigger_data; |
| 42 | 42 | |
| 43 | 43 | transient_data->activate = 0; |
| 44 | − led_set_brightness(led_cdev, transient_data->restore_state); | |
| 44 | + __led_set_brightness(led_cdev, transient_data->restore_state); | |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | static ssize_t transient_activate_show(struct device *dev, |
| @@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev, · 24 unmodified lines | ||
| 72 | 72 | if (state == 0 && transient_data->activate == 1) { |
| 73 | 73 | del_timer(&transient_data->timer); |
| 74 | 74 | transient_data->activate = state; |
| 75 | − led_set_brightness(led_cdev, transient_data->restore_state); | |
| 75 | + __led_set_brightness(led_cdev, transient_data->restore_state); | |
| 76 | 76 | return size; |
| 77 | 77 | } |
| 78 | 78 | |
| @@ -80,7 +80,7 @@ static ssize_t transient_activate_store(struct device *dev, · 1 unmodified line | ||
| 80 | 80 | if (state == 1 && transient_data->activate == 0 && |
| 81 | 81 | transient_data->duration != 0) { |
| 82 | 82 | transient_data->activate = state; |
| 83 | − led_set_brightness(led_cdev, transient_data->state); | |
| 83 | + __led_set_brightness(led_cdev, transient_data->state); | |
| 84 | 84 | transient_data->restore_state = |
| 85 | 85 | (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL; |
| 86 | 86 | mod_timer(&transient_data->timer, |
| @@ -203,7 +203,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev) · 116 unmodified lines | ||
| 203 | 203 | |
| 204 | 204 | if (led_cdev->activated) { |
| 205 | 205 | del_timer_sync(&transient_data->timer); |
| 206 | − led_set_brightness(led_cdev, transient_data->restore_state); | |
| 206 | + __led_set_brightness(led_cdev, transient_data->restore_state); | |
| 207 | 207 | device_remove_file(led_cdev->dev, &dev_attr_activate); |
| 208 | 208 | device_remove_file(led_cdev->dev, &dev_attr_duration); |
| 209 | 209 | device_remove_file(led_cdev->dev, &dev_attr_state); |
| @@ -38,6 +38,9 @@ struct led_classdev { · 37 unmodified lines | ||
| 38 | 38 | #define LED_SUSPENDED (1 << 0) |
| 39 | 39 | /* Upper 16 bits reflect control information */ |
| 40 | 40 | #define LED_CORE_SUSPENDRESUME (1 << 16) |
| 41 | +#define LED_BLINK_ONESHOT (1 << 17) | |
| 42 | +#define LED_BLINK_ONESHOT_STOP (1 << 18) | |
| 43 | +#define LED_BLINK_INVERT (1 << 19) | |
| 41 | 44 | |
| 42 | 45 | /* Set LED brightness level */ |
| 43 | 46 | /* Must not sleep, use a workqueue if needed */ |
| @@ -103,7 +106,25 @@ extern void led_blink_set(struct led_classdev *led_cdev, · 59 unmodified lines | ||
| 103 | 106 | unsigned long *delay_on, |
| 104 | 107 | unsigned long *delay_off); |
| 105 | 108 | /** |
| 106 | − * led_brightness_set - set LED brightness | |
| 109 | + * led_blink_set_oneshot - do a oneshot software blink | |
| 110 | + * @led_cdev: the LED to start blinking | |
| 111 | + * @delay_on: the time it should be on (in ms) | |
| 112 | + * @delay_off: the time it should ble off (in ms) | |
| 113 | + * @invert: blink off, then on, leaving the led on | |
| 114 | + * | |
| 115 | + * This function makes the LED blink one time for delay_on + | |
| 116 | + * delay_off time, ignoring the request if another one-shot | |
| 117 | + * blink is already in progress. | |
| 118 | + * | |
| 119 | + * If invert is set, led blinks for delay_off first, then for | |
| 120 | + * delay_on and leave the led on after the on-off cycle. | |
| 121 | + */ | |
| 122 | +extern void led_blink_set_oneshot(struct led_classdev *led_cdev, | |
| 123 | + unsigned long *delay_on, | |
| 124 | + unsigned long *delay_off, | |
| 125 | + int invert); | |
| 126 | +/** | |
| 127 | + * led_set_brightness - set LED brightness | |
| 107 | 128 | * @led_cdev: the LED to set |
| 108 | 129 | * @brightness: the brightness to set it to |
| 109 | 130 | * |
| @@ -111,7 +132,7 @@ extern void led_blink_set(struct led_classdev *led_cdev, · 1 unmodified line | ||
| 111 | 132 | * software blink timer that implements blinking when the |
| 112 | 133 | * hardware doesn't. |
| 113 | 134 | */ |
| 114 | −extern void led_brightness_set(struct led_classdev *led_cdev, | |
| 135 | +extern void led_set_brightness(struct led_classdev *led_cdev, | |
| 115 | 136 | enum led_brightness brightness); |
| 116 | 137 | |
| 117 | 138 | /* |
| @@ -150,6 +171,10 @@ extern void led_trigger_event(struct led_trigger *trigger, · 32 unmodified lines | ||
| 150 | 171 | extern void led_trigger_blink(struct led_trigger *trigger, |
| 151 | 172 | unsigned long *delay_on, |
| 152 | 173 | unsigned long *delay_off); |
| 174 | +extern void led_trigger_blink_oneshot(struct led_trigger *trigger, | |
| 175 | + unsigned long *delay_on, | |
| 176 | + unsigned long *delay_off, | |
| 177 | + int invert); | |
| 153 | 178 | |
| 154 | 179 | #else |
| 155 | 180 | |
| @@ -0,0 +1,50 @@ | ||
| 1 | +/* | |
| 2 | + * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03) | |
| 3 | + * Copyright (C) 2012 Texas Instruments | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License version 2 as | |
| 7 | + * published by the Free Software Foundation. | |
| 8 | + * | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef __LINUX_LM3556_H | |
| 12 | +#define __LINUX_LM3556_H | |
| 13 | + | |
| 14 | +#define LM3556_NAME "leds-lm3556" | |
| 15 | + | |
| 16 | +enum lm3556_pin_polarity { | |
| 17 | + PIN_LOW_ACTIVE = 0, | |
| 18 | + PIN_HIGH_ACTIVE, | |
| 19 | +}; | |
| 20 | + | |
| 21 | +enum lm3556_pin_enable { | |
| 22 | + PIN_DISABLED = 0, | |
| 23 | + PIN_ENABLED, | |
| 24 | +}; | |
| 25 | + | |
| 26 | +enum lm3556_strobe_usuage { | |
| 27 | + STROBE_EDGE_DETECT = 0, | |
| 28 | + STROBE_LEVEL_DETECT, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +enum lm3556_indic_mode { | |
| 32 | + INDIC_MODE_INTERNAL = 0, | |
| 33 | + INDIC_MODE_EXTERNAL, | |
| 34 | +}; | |
| 35 | + | |
| 36 | +struct lm3556_platform_data { | |
| 37 | + enum lm3556_pin_enable torch_pin_en; | |
| 38 | + enum lm3556_pin_polarity torch_pin_polarity; | |
| 39 | + | |
| 40 | + enum lm3556_strobe_usuage strobe_usuage; | |
| 41 | + enum lm3556_pin_enable strobe_pin_en; | |
| 42 | + enum lm3556_pin_polarity strobe_pin_polarity; | |
| 43 | + | |
| 44 | + enum lm3556_pin_enable tx_pin_en; | |
| 45 | + enum lm3556_pin_polarity tx_pin_polarity; | |
| 46 | + | |
| 47 | + enum lm3556_indic_mode indicator_mode; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +#endif /* __LINUX_LM3556_H */ | |
| @@ -276,7 +276,7 @@ static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) · 275 unmodified lines | ||
| 276 | 276 | |
| 277 | 277 | read_lock(&tpt_trig->trig.leddev_list_lock); |
| 278 | 278 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) |
| 279 | − led_brightness_set(led_cdev, LED_OFF); | |
| 279 | + led_set_brightness(led_cdev, LED_OFF); | |
| 280 | 280 | read_unlock(&tpt_trig->trig.leddev_list_lock); |
| 281 | 281 | } |
| 282 | 282 | |