Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds

Pull LED subsystem updates from Bryan Wu:
"In this cycle, we finished to merge patches for LED Flash class
driver.

Other than that we have some bug fixes and new drivers for LED
controllers"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds: (33 commits)
leds:lp55xx: fix firmware loading error
leds: fix max77693-led build errors
leds: fix aat1290 build errors
leds: aat1290: pass flags parameter to devm_gpiod_get
leds: ktd2692: pass flags parameter to devm_gpiod_get
drivers/leds: don't use module_init in non-modular leds-cobalt-raq.c
leds: aat1290: add support for V4L2 Flash sub-device
DT: aat1290: Document handling external strobe sources
leds: max77693: add support for V4L2 Flash sub-device
media: Add registration helpers for V4L2 flash sub-devices
v4l: async: Add a pointer to of_node to struct v4l2_subdev, match it
Documentation: leds: Add description of v4l2-flash sub-device
leds: add BCM6358 LED driver
leds: add DT binding for BCM6358 LED controller
leds: fix brightness changing when software blinking is active
Documentation: leds-lp5523: describe master fader attributes
leds: lp5523: add master_fader support
leds: leds-gpio: Allow compile test if !GPIOLIB
leds: leds-gpio: Add missing #include <linux/of.h>
gpiolib: Add missing dummies for the unified device properties interface
...

+4939 -58
+73
Documentation/devicetree/bindings/leds/leds-aat1290.txt
··· 1 + * Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs 2 + 3 + The device is controlled through two pins: FL_EN and EN_SET. The pins when, 4 + asserted high, enable flash strobe and movie mode (max 1/2 of flash current) 5 + respectively. In order to add a capability of selecting the strobe signal source 6 + (e.g. CPU or camera sensor) there is an additional switch required, independent 7 + of the flash chip. The switch is controlled with pin control. 8 + 9 + Required properties: 10 + 11 + - compatible : Must be "skyworks,aat1290". 12 + - flen-gpios : Must be device tree identifier of the flash device FL_EN pin. 13 + - enset-gpios : Must be device tree identifier of the flash device EN_SET pin. 14 + 15 + Optional properties: 16 + - pinctrl-names : Must contain entries: "default", "host", "isp". Entries 17 + "default" and "host" must refer to the same pin configuration 18 + node, which sets the host as a strobe signal provider. Entry 19 + "isp" must refer to the pin configuration node, which sets the 20 + ISP as a strobe signal provider. 21 + 22 + A discrete LED element connected to the device must be represented by a child 23 + node - see Documentation/devicetree/bindings/leds/common.txt. 24 + 25 + Required properties of the LED child node: 26 + - led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt 27 + - flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt 28 + Maximum flash LED supply current can be calculated using 29 + following formula: I = 1A * 162kohm / Rset. 30 + - flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt 31 + Maximum flash timeout can be calculated using following 32 + formula: T = 8.82 * 10^9 * Ct. 33 + 34 + Optional properties of the LED child node: 35 + - label : see Documentation/devicetree/bindings/leds/common.txt 36 + 37 + Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with 38 + a switch that allows for routing strobe signal either from the host or from 39 + the camera sensor): 40 + 41 + #include "exynos4412.dtsi" 42 + 43 + aat1290 { 44 + compatible = "skyworks,aat1290"; 45 + flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>; 46 + enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>; 47 + 48 + pinctrl-names = "default", "host", "isp"; 49 + pinctrl-0 = <&camera_flash_host>; 50 + pinctrl-1 = <&camera_flash_host>; 51 + pinctrl-2 = <&camera_flash_isp>; 52 + 53 + camera_flash: flash-led { 54 + label = "aat1290-flash"; 55 + led-max-microamp = <520833>; 56 + flash-max-microamp = <1012500>; 57 + flash-timeout-us = <1940000>; 58 + }; 59 + }; 60 + 61 + &pinctrl_0 { 62 + camera_flash_host: camera-flash-host { 63 + samsung,pins = "gpj1-0"; 64 + samsung,pin-function = <1>; 65 + samsung,pin-val = <0>; 66 + }; 67 + 68 + camera_flash_isp: camera-flash-isp { 69 + samsung,pins = "gpj1-0"; 70 + samsung,pin-function = <1>; 71 + samsung,pin-val = <1>; 72 + }; 73 + };
+309
Documentation/devicetree/bindings/leds/leds-bcm6328.txt
··· 1 + LEDs connected to Broadcom BCM6328 controller 2 + 3 + This controller is present on BCM6318, BCM6328, BCM6362 and BCM63268. 4 + In these SoCs it's possible to control LEDs both as GPIOs or by hardware. 5 + However, on some devices there are Serial LEDs (LEDs connected to a 74x164 6 + controller), which can either be controlled by software (exporting the 74x164 7 + as spi-gpio. See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or 8 + by hardware using this driver. 9 + Some of these Serial LEDs are hardware controlled (e.g. ethernet LEDs) and 10 + exporting the 74x164 as spi-gpio prevents those LEDs to be hardware 11 + controlled, so the only chance to keep them working is by using this driver. 12 + 13 + BCM6328 LED controller has a HWDIS register, which controls whether a LED 14 + should be controlled by a hardware signal instead of the MODE register value, 15 + with 0 meaning hardware control enabled and 1 hardware control disabled. This 16 + is usually 1:1 for hardware to LED signals, but through the activity/link 17 + registers you have some limited control over rerouting the LEDs (as 18 + explained later in brcm,link-signal-sources). Even if a LED is hardware 19 + controlled you are still able to make it blink or light it up if it isn't, 20 + but you can't turn it off if the hardware decides to light it up. For this 21 + reason, hardware controlled LEDs aren't registered as LED class devices. 22 + 23 + Required properties: 24 + - compatible : should be "brcm,bcm6328-leds". 25 + - #address-cells : must be 1. 26 + - #size-cells : must be 0. 27 + - reg : BCM6328 LED controller address and size. 28 + 29 + Optional properties: 30 + - brcm,serial-leds : Boolean, enables Serial LEDs. 31 + Default : false 32 + 33 + Each LED is represented as a sub-node of the brcm,bcm6328-leds device. 34 + 35 + LED sub-node required properties: 36 + - reg : LED pin number (only LEDs 0 to 23 are valid). 37 + 38 + LED sub-node optional properties: 39 + a) Optional properties for sub-nodes related to software controlled LEDs: 40 + - label : see Documentation/devicetree/bindings/leds/common.txt 41 + - active-low : Boolean, makes LED active low. 42 + Default : false 43 + - default-state : see 44 + Documentation/devicetree/bindings/leds/leds-gpio.txt 45 + - linux,default-trigger : see 46 + Documentation/devicetree/bindings/leds/common.txt 47 + 48 + b) Optional properties for sub-nodes related to hardware controlled LEDs: 49 + - brcm,hardware-controlled : Boolean, makes this LED hardware controlled. 50 + Default : false 51 + - brcm,link-signal-sources : An array of hardware link 52 + signal sources. Up to four link hardware signals can get muxed into 53 + these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may 54 + be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs 55 + 4 to 7. A signal can be muxed to more than one LED, and one LED can 56 + have more than one source signal. 57 + - brcm,activity-signal-sources : An array of hardware activity 58 + signal sources. Up to four activity hardware signals can get muxed into 59 + these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may 60 + be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs 61 + 4 to 7. A signal can be muxed to more than one LED, and one LED can 62 + have more than one source signal. 63 + 64 + Examples: 65 + Scenario 1 : BCM6328 with 4 EPHY LEDs 66 + leds0: led-controller@10000800 { 67 + compatible = "brcm,bcm6328-leds"; 68 + #address-cells = <1>; 69 + #size-cells = <0>; 70 + reg = <0x10000800 0x24>; 71 + 72 + alarm_red@2 { 73 + reg = <2>; 74 + active-low; 75 + label = "red:alarm"; 76 + }; 77 + inet_green@3 { 78 + reg = <3>; 79 + active-low; 80 + label = "green:inet"; 81 + }; 82 + power_green@4 { 83 + reg = <4>; 84 + active-low; 85 + label = "green:power"; 86 + default-state = "on"; 87 + }; 88 + ephy0_spd@17 { 89 + reg = <17>; 90 + brcm,hardware-controlled; 91 + }; 92 + ephy1_spd@18 { 93 + reg = <18>; 94 + brcm,hardware-controlled; 95 + }; 96 + ephy2_spd@19 { 97 + reg = <19>; 98 + brcm,hardware-controlled; 99 + }; 100 + ephy3_spd@20 { 101 + reg = <20>; 102 + brcm,hardware-controlled; 103 + }; 104 + }; 105 + 106 + Scenario 2 : BCM63268 with Serial/GPHY0 LEDs 107 + leds0: led-controller@10001900 { 108 + compatible = "brcm,bcm6328-leds"; 109 + #address-cells = <1>; 110 + #size-cells = <0>; 111 + reg = <0x10001900 0x24>; 112 + brcm,serial-leds; 113 + 114 + gphy0_spd0@0 { 115 + reg = <0>; 116 + brcm,hardware-controlled; 117 + brcm,link-signal-sources = <0>; 118 + }; 119 + gphy0_spd1@1 { 120 + reg = <1>; 121 + brcm,hardware-controlled; 122 + brcm,link-signal-sources = <1>; 123 + }; 124 + inet_red@2 { 125 + reg = <2>; 126 + active-low; 127 + label = "red:inet"; 128 + }; 129 + dsl_green@3 { 130 + reg = <3>; 131 + active-low; 132 + label = "green:dsl"; 133 + }; 134 + usb_green@4 { 135 + reg = <4>; 136 + active-low; 137 + label = "green:usb"; 138 + }; 139 + wps_green@7 { 140 + reg = <7>; 141 + active-low; 142 + label = "green:wps"; 143 + }; 144 + inet_green@8 { 145 + reg = <8>; 146 + active-low; 147 + label = "green:inet"; 148 + }; 149 + ephy0_act@9 { 150 + reg = <9>; 151 + brcm,hardware-controlled; 152 + }; 153 + ephy1_act@10 { 154 + reg = <10>; 155 + brcm,hardware-controlled; 156 + }; 157 + ephy2_act@11 { 158 + reg = <11>; 159 + brcm,hardware-controlled; 160 + }; 161 + gphy0_act@12 { 162 + reg = <12>; 163 + brcm,hardware-controlled; 164 + }; 165 + ephy0_spd@13 { 166 + reg = <13>; 167 + brcm,hardware-controlled; 168 + }; 169 + ephy1_spd@14 { 170 + reg = <14>; 171 + brcm,hardware-controlled; 172 + }; 173 + ephy2_spd@15 { 174 + reg = <15>; 175 + brcm,hardware-controlled; 176 + }; 177 + power_green@20 { 178 + reg = <20>; 179 + active-low; 180 + label = "green:power"; 181 + default-state = "on"; 182 + }; 183 + }; 184 + 185 + Scenario 3 : BCM6362 with 1 LED for each EPHY 186 + leds0: led-controller@10001900 { 187 + compatible = "brcm,bcm6328-leds"; 188 + #address-cells = <1>; 189 + #size-cells = <0>; 190 + reg = <0x10001900 0x24>; 191 + 192 + usb@0 { 193 + reg = <0>; 194 + brcm,hardware-controlled; 195 + brcm,link-signal-sources = <0>; 196 + brcm,activity-signal-sources = <0>; 197 + /* USB link/activity routed to USB LED */ 198 + }; 199 + inet@1 { 200 + reg = <1>; 201 + brcm,hardware-controlled; 202 + brcm,activity-signal-sources = <1>; 203 + /* INET activity routed to INET LED */ 204 + }; 205 + ephy0@4 { 206 + reg = <4>; 207 + brcm,hardware-controlled; 208 + brcm,link-signal-sources = <4>; 209 + /* EPHY0 link routed to EPHY0 LED */ 210 + }; 211 + ephy1@5 { 212 + reg = <5>; 213 + brcm,hardware-controlled; 214 + brcm,link-signal-sources = <5>; 215 + /* EPHY1 link routed to EPHY1 LED */ 216 + }; 217 + ephy2@6 { 218 + reg = <6>; 219 + brcm,hardware-controlled; 220 + brcm,link-signal-sources = <6>; 221 + /* EPHY2 link routed to EPHY2 LED */ 222 + }; 223 + ephy3@7 { 224 + reg = <7>; 225 + brcm,hardware-controlled; 226 + brcm,link-signal-sources = <7>; 227 + /* EPHY3 link routed to EPHY3 LED */ 228 + }; 229 + power_green@20 { 230 + reg = <20>; 231 + active-low; 232 + label = "green:power"; 233 + default-state = "on"; 234 + }; 235 + }; 236 + 237 + Scenario 4 : BCM6362 with 1 LED for all EPHYs 238 + leds0: led-controller@10001900 { 239 + compatible = "brcm,bcm6328-leds"; 240 + #address-cells = <1>; 241 + #size-cells = <0>; 242 + reg = <0x10001900 0x24>; 243 + 244 + usb@0 { 245 + reg = <0>; 246 + brcm,hardware-controlled; 247 + brcm,link-signal-sources = <0 1>; 248 + brcm,activity-signal-sources = <0 1>; 249 + /* USB/INET link/activity routed to USB LED */ 250 + }; 251 + ephy@4 { 252 + reg = <4>; 253 + brcm,hardware-controlled; 254 + brcm,link-signal-sources = <4 5 6 7>; 255 + /* EPHY0/1/2/3 link routed to EPHY0 LED */ 256 + }; 257 + power_green@20 { 258 + reg = <20>; 259 + active-low; 260 + label = "green:power"; 261 + default-state = "on"; 262 + }; 263 + }; 264 + 265 + Scenario 5 : BCM6362 with EPHY LEDs swapped 266 + leds0: led-controller@10001900 { 267 + compatible = "brcm,bcm6328-leds"; 268 + #address-cells = <1>; 269 + #size-cells = <0>; 270 + reg = <0x10001900 0x24>; 271 + 272 + usb@0 { 273 + reg = <0>; 274 + brcm,hardware-controlled; 275 + brcm,link-signal-sources = <0>; 276 + brcm,activity-signal-sources = <0 1>; 277 + /* USB link/act and INET act routed to USB LED */ 278 + }; 279 + ephy0@4 { 280 + reg = <4>; 281 + brcm,hardware-controlled; 282 + brcm,link-signal-sources = <7>; 283 + /* EPHY3 link routed to EPHY0 LED */ 284 + }; 285 + ephy1@5 { 286 + reg = <5>; 287 + brcm,hardware-controlled; 288 + brcm,link-signal-sources = <6>; 289 + /* EPHY2 link routed to EPHY1 LED */ 290 + }; 291 + ephy2@6 { 292 + reg = <6>; 293 + brcm,hardware-controlled; 294 + brcm,link-signal-sources = <5>; 295 + /* EPHY1 link routed to EPHY2 LED */ 296 + }; 297 + ephy3@7 { 298 + reg = <7>; 299 + brcm,hardware-controlled; 300 + brcm,link-signal-sources = <4>; 301 + /* EPHY0 link routed to EPHY3 LED */ 302 + }; 303 + power_green@20 { 304 + reg = <20>; 305 + active-low; 306 + label = "green:power"; 307 + default-state = "on"; 308 + }; 309 + };
+145
Documentation/devicetree/bindings/leds/leds-bcm6358.txt
··· 1 + LEDs connected to Broadcom BCM6358 controller 2 + 3 + This controller is present on BCM6358 and BCM6368. 4 + In these SoCs there are Serial LEDs (LEDs connected to a 74x164 controller), 5 + which can either be controlled by software (exporting the 74x164 as spi-gpio. 6 + See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or 7 + by hardware using this driver. 8 + 9 + Required properties: 10 + - compatible : should be "brcm,bcm6358-leds". 11 + - #address-cells : must be 1. 12 + - #size-cells : must be 0. 13 + - reg : BCM6358 LED controller address and size. 14 + 15 + Optional properties: 16 + - brcm,clk-div : SCK signal divider. Possible values are 1, 2, 4 and 8. 17 + Default : 1 18 + - brcm,clk-dat-low : Boolean, makes clock and data signals active low. 19 + Default : false 20 + 21 + Each LED is represented as a sub-node of the brcm,bcm6358-leds device. 22 + 23 + LED sub-node required properties: 24 + - reg : LED pin number (only LEDs 0 to 31 are valid). 25 + 26 + LED sub-node optional properties: 27 + - label : see Documentation/devicetree/bindings/leds/common.txt 28 + - active-low : Boolean, makes LED active low. 29 + Default : false 30 + - default-state : see 31 + Documentation/devicetree/bindings/leds/leds-gpio.txt 32 + - linux,default-trigger : see 33 + Documentation/devicetree/bindings/leds/common.txt 34 + 35 + Examples: 36 + Scenario 1 : BCM6358 37 + leds0: led-controller@fffe00d0 { 38 + compatible = "brcm,bcm6358-leds"; 39 + #address-cells = <1>; 40 + #size-cells = <0>; 41 + reg = <0xfffe00d0 0x8>; 42 + 43 + alarm_white { 44 + reg = <0>; 45 + active-low; 46 + label = "white:alarm"; 47 + }; 48 + tv_white { 49 + reg = <2>; 50 + active-low; 51 + label = "white:tv"; 52 + }; 53 + tel_white { 54 + reg = <3>; 55 + active-low; 56 + label = "white:tel"; 57 + }; 58 + adsl_white { 59 + reg = <4>; 60 + active-low; 61 + label = "white:adsl"; 62 + }; 63 + }; 64 + 65 + Scenario 2 : BCM6368 66 + leds0: led-controller@100000d0 { 67 + compatible = "brcm,bcm6358-leds"; 68 + #address-cells = <1>; 69 + #size-cells = <0>; 70 + reg = <0x100000d0 0x8>; 71 + brcm,pol-low; 72 + brcm,clk-div = <4>; 73 + 74 + power_red { 75 + reg = <0>; 76 + active-low; 77 + label = "red:power"; 78 + }; 79 + power_green { 80 + reg = <1>; 81 + active-low; 82 + label = "green:power"; 83 + default-state = "on"; 84 + }; 85 + power_blue { 86 + reg = <2>; 87 + label = "blue:power"; 88 + }; 89 + broadband_red { 90 + reg = <3>; 91 + active-low; 92 + label = "red:broadband"; 93 + }; 94 + broadband_green { 95 + reg = <4>; 96 + label = "green:broadband"; 97 + }; 98 + broadband_blue { 99 + reg = <5>; 100 + active-low; 101 + label = "blue:broadband"; 102 + }; 103 + wireless_red { 104 + reg = <6>; 105 + active-low; 106 + label = "red:wireless"; 107 + }; 108 + wireless_green { 109 + reg = <7>; 110 + active-low; 111 + label = "green:wireless"; 112 + }; 113 + wireless_blue { 114 + reg = <8>; 115 + label = "blue:wireless"; 116 + }; 117 + phone_red { 118 + reg = <9>; 119 + active-low; 120 + label = "red:phone"; 121 + }; 122 + phone_green { 123 + reg = <10>; 124 + active-low; 125 + label = "green:phone"; 126 + }; 127 + phone_blue { 128 + reg = <11>; 129 + label = "blue:phone"; 130 + }; 131 + upgrading_red { 132 + reg = <12>; 133 + active-low; 134 + label = "red:upgrading"; 135 + }; 136 + upgrading_green { 137 + reg = <13>; 138 + active-low; 139 + label = "green:upgrading"; 140 + }; 141 + upgrading_blue { 142 + reg = <14>; 143 + label = "blue:upgrading"; 144 + }; 145 + };
+50
Documentation/devicetree/bindings/leds/leds-ktd2692.txt
··· 1 + * Kinetic Technologies - KTD2692 Flash LED Driver 2 + 3 + KTD2692 is the ideal power solution for high-power flash LEDs. 4 + It uses ExpressWire single-wire programming for maximum flexibility. 5 + 6 + The ExpressWire interface through CTRL pin can control LED on/off and 7 + enable/disable the IC, Movie(max 1/3 of Flash current) / Flash mode current, 8 + Flash timeout, LVP(low voltage protection). 9 + 10 + Also, When the AUX pin is pulled high while CTRL pin is high, 11 + LED current will be ramped up to the flash-mode current level. 12 + 13 + Required properties: 14 + - compatible : Should be "kinetic,ktd2692". 15 + - ctrl-gpios : Specifier of the GPIO connected to CTRL pin. 16 + - aux-gpios : Specifier of the GPIO connected to AUX pin. 17 + 18 + Optional properties: 19 + - vin-supply : "vin" LED supply (2.7V to 5.5V). 20 + See Documentation/devicetree/bindings/regulator/regulator.txt 21 + 22 + A discrete LED element connected to the device must be represented by a child 23 + node - See Documentation/devicetree/bindings/leds/common.txt 24 + 25 + Required properties for flash LED child nodes: 26 + See Documentation/devicetree/bindings/leds/common.txt 27 + - led-max-microamp : Minimum Threshold for Timer protection 28 + is defined internally (Maximum 300mA). 29 + - flash-max-microamp : Flash LED maximum current 30 + Formula : I(mA) = 15000 / Rset. 31 + - flash-max-timeout-us : Flash LED maximum timeout. 32 + 33 + Optional properties for flash LED child nodes: 34 + - label : See Documentation/devicetree/bindings/leds/common.txt 35 + 36 + Example: 37 + 38 + ktd2692 { 39 + compatible = "kinetic,ktd2692"; 40 + ctrl-gpios = <&gpc0 1 0>; 41 + aux-gpios = <&gpc0 2 0>; 42 + vin-supply = <&vbat>; 43 + 44 + flash-led { 45 + label = "ktd2692-flash"; 46 + led-max-microamp = <300000>; 47 + flash-max-microamp = <1500000>; 48 + flash-max-timeout-us = <1835000>; 49 + }; 50 + };
+40
Documentation/devicetree/bindings/leds/leds-tlc591xx.txt
··· 1 + LEDs connected to tlc59116 or tlc59108 2 + 3 + Required properties 4 + - compatible: should be "ti,tlc59116" or "ti,tlc59108" 5 + - #address-cells: must be 1 6 + - #size-cells: must be 0 7 + - reg: typically 0x68 8 + 9 + Each led is represented as a sub-node of the ti,tlc59116. 10 + See Documentation/devicetree/bindings/leds/common.txt 11 + 12 + LED sub-node properties: 13 + - reg: number of LED line, 0 to 15 or 0 to 7 14 + - label: (optional) name of LED 15 + - linux,default-trigger : (optional) 16 + 17 + Examples: 18 + 19 + tlc59116@68 { 20 + #address-cells = <1>; 21 + #size-cells = <0>; 22 + compatible = "ti,tlc59116"; 23 + reg = <0x68>; 24 + 25 + wan@0 { 26 + label = "wrt1900ac:amber:wan"; 27 + reg = <0x0>; 28 + }; 29 + 30 + 2g@2 { 31 + label = "wrt1900ac:white:2g"; 32 + reg = <0x2>; 33 + }; 34 + 35 + alive@9 { 36 + label = "wrt1900ac:green:alive"; 37 + reg = <0x9>; 38 + linux,default_trigger = "heartbeat"; 39 + }; 40 + };
+1
Documentation/devicetree/bindings/vendor-prefixes.txt
··· 114 114 isil Intersil 115 115 karo Ka-Ro electronics GmbH 116 116 keymile Keymile GmbH 117 + kinetic Kinetic Technologies 117 118 lacie LaCie 118 119 lantiq Lantiq Semiconductor 119 120 lenovo Lenovo Group Ltd.
+51
Documentation/leds/leds-class-flash.txt
··· 20 20 - max_flash_timeout 21 21 - flash_strobe 22 22 - flash_fault 23 + 24 + 25 + V4L2 flash wrapper for flash LEDs 26 + ================================= 27 + 28 + A LED subsystem driver can be controlled also from the level of VideoForLinux2 29 + subsystem. In order to enable this CONFIG_V4L2_FLASH_LED_CLASS symbol has to 30 + be defined in the kernel config. 31 + 32 + The driver must call the v4l2_flash_init function to get registered in the 33 + V4L2 subsystem. The function takes six arguments: 34 + - dev : flash device, e.g. an I2C device 35 + - of_node : of_node of the LED, may be NULL if the same as device's 36 + - fled_cdev : LED flash class device to wrap 37 + - iled_cdev : LED flash class device representing indicator LED associated with 38 + fled_cdev, may be NULL 39 + - ops : V4L2 specific ops 40 + * external_strobe_set - defines the source of the flash LED strobe - 41 + V4L2_CID_FLASH_STROBE control or external source, typically 42 + a sensor, which makes it possible to synchronise the flash 43 + strobe start with exposure start, 44 + * intensity_to_led_brightness and led_brightness_to_intensity - perform 45 + enum led_brightness <-> V4L2 intensity conversion in a device 46 + specific manner - they can be used for devices with non-linear 47 + LED current scale. 48 + - config : configuration for V4L2 Flash sub-device 49 + * dev_name - the name of the media entity, unique in the system, 50 + * flash_faults - bitmask of flash faults that the LED flash class 51 + device can report; corresponding LED_FAULT* bit definitions are 52 + available in <linux/led-class-flash.h>, 53 + * torch_intensity - constraints for the LED in TORCH mode 54 + in microamperes, 55 + * indicator_intensity - constraints for the indicator LED 56 + in microamperes, 57 + * has_external_strobe - determines whether the flash strobe source 58 + can be switched to external, 59 + 60 + On remove the v4l2_flash_release function has to be called, which takes one 61 + argument - struct v4l2_flash pointer returned previously by v4l2_flash_init. 62 + This function can be safely called with NULL or error pointer argument. 63 + 64 + Please refer to drivers/leds/leds-max77693.c for an exemplary usage of the 65 + v4l2 flash wrapper. 66 + 67 + Once the V4L2 sub-device is registered by the driver which created the Media 68 + controller device, the sub-device node acts just as a node of a native V4L2 69 + flash API device would. The calls are simply routed to the LED flash API. 70 + 71 + Opening the V4L2 flash sub-device makes the LED subsystem sysfs interface 72 + unavailable. The interface is re-enabled after the V4L2 flash sub-device 73 + is closed.
+30
Documentation/leds/leds-lp5523.txt
··· 49 49 2) Firmware interface - LP55xx common interface 50 50 For the details, please refer to 'firmware' section in leds-lp55xx.txt 51 51 52 + LP5523 has three master faders. If a channel is mapped to one of 53 + the master faders, its output is dimmed based on the value of the master 54 + fader. 55 + 56 + For example, 57 + 58 + echo "123000123" > master_fader_leds 59 + 60 + creates the following channel-fader mappings: 61 + 62 + channel 0,6 to master_fader1 63 + channel 1,7 to master_fader2 64 + channel 2,8 to master_fader3 65 + 66 + Then, to have 25% of the original output on channel 0,6: 67 + 68 + echo 64 > master_fader1 69 + 70 + To have 0% of the original output (i.e. no output) channel 1,7: 71 + 72 + echo 0 > master_fader2 73 + 74 + To have 100% of the original output (i.e. no dimming) on channel 2,8: 75 + 76 + echo 255 > master_fader3 77 + 78 + To clear all master fader controls: 79 + 80 + echo "000000000" > master_fader_leds 81 + 52 82 Selftest uses always the current from the platform data. 53 83 54 84 Each channel contains led current settings.
+56 -1
drivers/leds/Kconfig
··· 39 39 This option enables support for on-chip LED drivers found on Marvell 40 40 Semiconductor 88PM8606 PMIC. 41 41 42 + config LEDS_AAT1290 43 + tristate "LED support for the AAT1290" 44 + depends on LEDS_CLASS_FLASH 45 + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS 46 + depends on GPIOLIB 47 + depends on OF 48 + depends on PINCTRL 49 + help 50 + This option enables support for the LEDs on the AAT1290. 51 + 52 + config LEDS_BCM6328 53 + tristate "LED Support for Broadcom BCM6328" 54 + depends on LEDS_CLASS 55 + depends on OF 56 + help 57 + This option enables support for LEDs connected to the BCM6328 58 + LED HW controller accessed via MMIO registers. 59 + 60 + config LEDS_BCM6358 61 + tristate "LED Support for Broadcom BCM6358" 62 + depends on LEDS_CLASS 63 + depends on OF 64 + help 65 + This option enables support for LEDs connected to the BCM6358 66 + LED HW controller accessed via MMIO registers. 67 + 42 68 config LEDS_LM3530 43 69 tristate "LCD Backlight driver for LM3530" 44 70 depends on LEDS_CLASS ··· 205 179 config LEDS_GPIO 206 180 tristate "LED Support for GPIO connected LEDs" 207 181 depends on LEDS_CLASS 208 - depends on GPIOLIB 182 + depends on GPIOLIB || COMPILE_TEST 209 183 help 210 184 This option enables support for the LEDs connected to GPIO 211 185 outputs. To be useful the particular board must have LEDs ··· 229 203 tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" 230 204 depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501 231 205 select FW_LOADER 206 + select FW_LOADER_USER_HELPER_FALLBACK 232 207 help 233 208 This option supports common operations for LP5521/5523/55231/5562/8501 234 209 devices. ··· 491 464 LED driver chips accessed via the I2C bus. 492 465 Driver support brightness control and hardware-assisted blinking. 493 466 467 + config LEDS_TLC591XX 468 + tristate "LED driver for TLC59108 and TLC59116 controllers" 469 + depends on LEDS_CLASS && I2C 470 + select REGMAP_I2C 471 + help 472 + This option enables support for Texas Instruments TLC59108 473 + and TLC59116 LED controllers. 474 + 475 + config LEDS_MAX77693 476 + tristate "LED support for MAX77693 Flash" 477 + depends on LEDS_CLASS_FLASH 478 + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS 479 + depends on MFD_MAX77693 480 + depends on OF 481 + help 482 + This option enables support for the flash part of the MAX77693 483 + multifunction device. It has build in control for two leds in flash 484 + and torch mode. 485 + 494 486 config LEDS_MAX8997 495 487 tristate "LED support for MAX8997 PMIC" 496 488 depends on LEDS_CLASS && MFD_MAX8997 ··· 540 494 541 495 This driver can also be built as a module. If so the module 542 496 will be called leds-menf21bmc. 497 + 498 + config LEDS_KTD2692 499 + tristate "LED support for KTD2692 flash LED controller" 500 + depends on LEDS_CLASS_FLASH && GPIOLIB && OF 501 + help 502 + This option enables support for KTD2692 LED flash connected 503 + through ExpressWire interface. 504 + 505 + Say Y to enable this driver. 543 506 544 507 comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" 545 508
+6
drivers/leds/Makefile
··· 7 7 8 8 # LED Platform Drivers 9 9 obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o 10 + obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o 11 + obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o 12 + obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o 10 13 obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o 11 14 obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 12 15 obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o ··· 34 31 obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o 35 32 obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o 36 33 obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o 34 + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o 37 35 obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o 38 36 obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o 39 37 obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o ··· 56 52 obj-$(CONFIG_LEDS_NS2) += leds-ns2.o 57 53 obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o 58 54 obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o 55 + obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o 59 56 obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o 60 57 obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o 61 58 obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o ··· 64 59 obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o 65 60 obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o 66 61 obj-$(CONFIG_LEDS_PM8941_WLED) += leds-pm8941-wled.o 62 + obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o 67 63 68 64 # LED SPI Drivers 69 65 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
+5
drivers/leds/led-class.c
··· 121 121 brightness = led_get_brightness(led_cdev); 122 122 if (!brightness) { 123 123 /* Time to switch the LED on. */ 124 + if (led_cdev->delayed_set_value) { 125 + led_cdev->blink_brightness = 126 + led_cdev->delayed_set_value; 127 + led_cdev->delayed_set_value = 0; 128 + } 124 129 brightness = led_cdev->blink_brightness; 125 130 delay = led_cdev->blink_delay_on; 126 131 } else {
+3 -2
drivers/leds/led-core.c
··· 119 119 { 120 120 int ret = 0; 121 121 122 - /* delay brightness setting if need to stop soft-blink timer */ 122 + /* delay brightness if soft-blink is active */ 123 123 if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { 124 124 led_cdev->delayed_set_value = brightness; 125 - schedule_work(&led_cdev->set_brightness_work); 125 + if (brightness == LED_OFF) 126 + schedule_work(&led_cdev->set_brightness_work); 126 127 return; 127 128 } 128 129
+576
drivers/leds/leds-aat1290.c
··· 1 + /* 2 + * LED Flash class driver for the AAT1290 3 + * 1.5A Step-Up Current Regulator for Flash LEDs 4 + * 5 + * Copyright (C) 2015, Samsung Electronics Co., Ltd. 6 + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/delay.h> 14 + #include <linux/gpio/consumer.h> 15 + #include <linux/led-class-flash.h> 16 + #include <linux/leds.h> 17 + #include <linux/module.h> 18 + #include <linux/mutex.h> 19 + #include <linux/of.h> 20 + #include <linux/pinctrl/consumer.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/slab.h> 23 + #include <linux/workqueue.h> 24 + #include <media/v4l2-flash-led-class.h> 25 + 26 + #define AAT1290_MOVIE_MODE_CURRENT_ADDR 17 27 + #define AAT1290_MAX_MM_CURR_PERCENT_0 16 28 + #define AAT1290_MAX_MM_CURR_PERCENT_100 1 29 + 30 + #define AAT1290_FLASH_SAFETY_TIMER_ADDR 18 31 + 32 + #define AAT1290_MOVIE_MODE_CONFIG_ADDR 19 33 + #define AAT1290_MOVIE_MODE_OFF 1 34 + #define AAT1290_MOVIE_MODE_ON 3 35 + 36 + #define AAT1290_MM_CURRENT_RATIO_ADDR 20 37 + #define AAT1290_MM_TO_FL_1_92 1 38 + 39 + #define AAT1290_MM_TO_FL_RATIO 1000 / 1920 40 + #define AAT1290_MAX_MM_CURRENT(fl_max) (fl_max * AAT1290_MM_TO_FL_RATIO) 41 + 42 + #define AAT1290_LATCH_TIME_MIN_US 500 43 + #define AAT1290_LATCH_TIME_MAX_US 1000 44 + #define AAT1290_EN_SET_TICK_TIME_US 1 45 + #define AAT1290_FLEN_OFF_DELAY_TIME_US 10 46 + #define AAT1290_FLASH_TM_NUM_LEVELS 16 47 + #define AAT1290_MM_CURRENT_SCALE_SIZE 15 48 + 49 + 50 + struct aat1290_led_config_data { 51 + /* maximum LED current in movie mode */ 52 + u32 max_mm_current; 53 + /* maximum LED current in flash mode */ 54 + u32 max_flash_current; 55 + /* maximum flash timeout */ 56 + u32 max_flash_tm; 57 + /* external strobe capability */ 58 + bool has_external_strobe; 59 + /* max LED brightness level */ 60 + enum led_brightness max_brightness; 61 + }; 62 + 63 + struct aat1290_led { 64 + /* platform device data */ 65 + struct platform_device *pdev; 66 + /* secures access to the device */ 67 + struct mutex lock; 68 + 69 + /* corresponding LED Flash class device */ 70 + struct led_classdev_flash fled_cdev; 71 + /* V4L2 Flash device */ 72 + struct v4l2_flash *v4l2_flash; 73 + 74 + /* FLEN pin */ 75 + struct gpio_desc *gpio_fl_en; 76 + /* EN|SET pin */ 77 + struct gpio_desc *gpio_en_set; 78 + /* movie mode current scale */ 79 + int *mm_current_scale; 80 + /* device mode */ 81 + bool movie_mode; 82 + 83 + /* brightness cache */ 84 + unsigned int torch_brightness; 85 + /* assures led-triggers compatibility */ 86 + struct work_struct work_brightness_set; 87 + }; 88 + 89 + static struct aat1290_led *fled_cdev_to_led( 90 + struct led_classdev_flash *fled_cdev) 91 + { 92 + return container_of(fled_cdev, struct aat1290_led, fled_cdev); 93 + } 94 + 95 + static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value) 96 + { 97 + int i; 98 + 99 + gpiod_direction_output(led->gpio_fl_en, 0); 100 + gpiod_direction_output(led->gpio_en_set, 0); 101 + 102 + udelay(AAT1290_FLEN_OFF_DELAY_TIME_US); 103 + 104 + /* write address */ 105 + for (i = 0; i < addr; ++i) { 106 + udelay(AAT1290_EN_SET_TICK_TIME_US); 107 + gpiod_direction_output(led->gpio_en_set, 0); 108 + udelay(AAT1290_EN_SET_TICK_TIME_US); 109 + gpiod_direction_output(led->gpio_en_set, 1); 110 + } 111 + 112 + usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US); 113 + 114 + /* write data */ 115 + for (i = 0; i < value; ++i) { 116 + udelay(AAT1290_EN_SET_TICK_TIME_US); 117 + gpiod_direction_output(led->gpio_en_set, 0); 118 + udelay(AAT1290_EN_SET_TICK_TIME_US); 119 + gpiod_direction_output(led->gpio_en_set, 1); 120 + } 121 + 122 + usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US); 123 + } 124 + 125 + static void aat1290_set_flash_safety_timer(struct aat1290_led *led, 126 + unsigned int micro_sec) 127 + { 128 + struct led_classdev_flash *fled_cdev = &led->fled_cdev; 129 + struct led_flash_setting *flash_tm = &fled_cdev->timeout; 130 + int flash_tm_reg = AAT1290_FLASH_TM_NUM_LEVELS - 131 + (micro_sec / flash_tm->step) + 1; 132 + 133 + aat1290_as2cwire_write(led, AAT1290_FLASH_SAFETY_TIMER_ADDR, 134 + flash_tm_reg); 135 + } 136 + 137 + static void aat1290_brightness_set(struct aat1290_led *led, 138 + enum led_brightness brightness) 139 + { 140 + mutex_lock(&led->lock); 141 + 142 + if (brightness == 0) { 143 + gpiod_direction_output(led->gpio_fl_en, 0); 144 + gpiod_direction_output(led->gpio_en_set, 0); 145 + led->movie_mode = false; 146 + } else { 147 + if (!led->movie_mode) { 148 + aat1290_as2cwire_write(led, 149 + AAT1290_MM_CURRENT_RATIO_ADDR, 150 + AAT1290_MM_TO_FL_1_92); 151 + led->movie_mode = true; 152 + } 153 + 154 + aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CURRENT_ADDR, 155 + AAT1290_MAX_MM_CURR_PERCENT_0 - brightness); 156 + aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CONFIG_ADDR, 157 + AAT1290_MOVIE_MODE_ON); 158 + } 159 + 160 + mutex_unlock(&led->lock); 161 + } 162 + 163 + /* LED subsystem callbacks */ 164 + 165 + static void aat1290_brightness_set_work(struct work_struct *work) 166 + { 167 + struct aat1290_led *led = 168 + container_of(work, struct aat1290_led, work_brightness_set); 169 + 170 + aat1290_brightness_set(led, led->torch_brightness); 171 + } 172 + 173 + static void aat1290_led_brightness_set(struct led_classdev *led_cdev, 174 + enum led_brightness brightness) 175 + { 176 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 177 + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); 178 + 179 + led->torch_brightness = brightness; 180 + schedule_work(&led->work_brightness_set); 181 + } 182 + 183 + static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev, 184 + enum led_brightness brightness) 185 + { 186 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 187 + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); 188 + 189 + aat1290_brightness_set(led, brightness); 190 + 191 + return 0; 192 + } 193 + 194 + static int aat1290_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, 195 + bool state) 196 + 197 + { 198 + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); 199 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 200 + struct led_flash_setting *timeout = &fled_cdev->timeout; 201 + 202 + mutex_lock(&led->lock); 203 + 204 + if (state) { 205 + aat1290_set_flash_safety_timer(led, timeout->val); 206 + gpiod_direction_output(led->gpio_fl_en, 1); 207 + } else { 208 + gpiod_direction_output(led->gpio_fl_en, 0); 209 + gpiod_direction_output(led->gpio_en_set, 0); 210 + } 211 + 212 + /* 213 + * To reenter movie mode after a flash event the part must be cycled 214 + * off and back on to reset the movie mode and reprogrammed via the 215 + * AS2Cwire. Therefore the brightness and movie_mode properties needs 216 + * to be updated here to reflect the actual state. 217 + */ 218 + led_cdev->brightness = 0; 219 + led->movie_mode = false; 220 + 221 + mutex_unlock(&led->lock); 222 + 223 + return 0; 224 + } 225 + 226 + static int aat1290_led_flash_timeout_set(struct led_classdev_flash *fled_cdev, 227 + u32 timeout) 228 + { 229 + /* 230 + * Don't do anything - flash timeout is cached in the led-class-flash 231 + * core and will be applied in the strobe_set op, as writing the 232 + * safety timer register spuriously turns the torch mode on. 233 + */ 234 + 235 + return 0; 236 + } 237 + 238 + static int aat1290_led_parse_dt(struct aat1290_led *led, 239 + struct aat1290_led_config_data *cfg, 240 + struct device_node **sub_node) 241 + { 242 + struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; 243 + struct device *dev = &led->pdev->dev; 244 + struct device_node *child_node; 245 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 246 + struct pinctrl *pinctrl; 247 + #endif 248 + int ret = 0; 249 + 250 + led->gpio_fl_en = devm_gpiod_get(dev, "flen", GPIOD_ASIS); 251 + if (IS_ERR(led->gpio_fl_en)) { 252 + ret = PTR_ERR(led->gpio_fl_en); 253 + dev_err(dev, "Unable to claim gpio \"flen\".\n"); 254 + return ret; 255 + } 256 + 257 + led->gpio_en_set = devm_gpiod_get(dev, "enset", GPIOD_ASIS); 258 + if (IS_ERR(led->gpio_en_set)) { 259 + ret = PTR_ERR(led->gpio_en_set); 260 + dev_err(dev, "Unable to claim gpio \"enset\".\n"); 261 + return ret; 262 + } 263 + 264 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 265 + pinctrl = devm_pinctrl_get_select_default(&led->pdev->dev); 266 + if (IS_ERR(pinctrl)) { 267 + cfg->has_external_strobe = false; 268 + dev_info(dev, 269 + "No support for external strobe detected.\n"); 270 + } else { 271 + cfg->has_external_strobe = true; 272 + } 273 + #endif 274 + 275 + child_node = of_get_next_available_child(dev->of_node, NULL); 276 + if (!child_node) { 277 + dev_err(dev, "No DT child node found for connected LED.\n"); 278 + return -EINVAL; 279 + } 280 + 281 + led_cdev->name = of_get_property(child_node, "label", NULL) ? : 282 + child_node->name; 283 + 284 + ret = of_property_read_u32(child_node, "led-max-microamp", 285 + &cfg->max_mm_current); 286 + /* 287 + * led-max-microamp will default to 1/20 of flash-max-microamp 288 + * in case it is missing. 289 + */ 290 + if (ret < 0) 291 + dev_warn(dev, 292 + "led-max-microamp DT property missing\n"); 293 + 294 + ret = of_property_read_u32(child_node, "flash-max-microamp", 295 + &cfg->max_flash_current); 296 + if (ret < 0) { 297 + dev_err(dev, 298 + "flash-max-microamp DT property missing\n"); 299 + return ret; 300 + } 301 + 302 + ret = of_property_read_u32(child_node, "flash-max-timeout-us", 303 + &cfg->max_flash_tm); 304 + if (ret < 0) { 305 + dev_err(dev, 306 + "flash-max-timeout-us DT property missing\n"); 307 + return ret; 308 + } 309 + 310 + of_node_put(child_node); 311 + 312 + *sub_node = child_node; 313 + 314 + return ret; 315 + } 316 + 317 + static void aat1290_led_validate_mm_current(struct aat1290_led *led, 318 + struct aat1290_led_config_data *cfg) 319 + { 320 + int i, b = 0, e = AAT1290_MM_CURRENT_SCALE_SIZE; 321 + 322 + while (e - b > 1) { 323 + i = b + (e - b) / 2; 324 + if (cfg->max_mm_current < led->mm_current_scale[i]) 325 + e = i; 326 + else 327 + b = i; 328 + } 329 + 330 + cfg->max_mm_current = led->mm_current_scale[b]; 331 + cfg->max_brightness = b + 1; 332 + } 333 + 334 + int init_mm_current_scale(struct aat1290_led *led, 335 + struct aat1290_led_config_data *cfg) 336 + { 337 + int max_mm_current_percent[] = { 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, 338 + 63, 71, 79, 89, 100 }; 339 + int i, max_mm_current = 340 + AAT1290_MAX_MM_CURRENT(cfg->max_flash_current); 341 + 342 + led->mm_current_scale = devm_kzalloc(&led->pdev->dev, 343 + sizeof(max_mm_current_percent), 344 + GFP_KERNEL); 345 + if (!led->mm_current_scale) 346 + return -ENOMEM; 347 + 348 + for (i = 0; i < AAT1290_MM_CURRENT_SCALE_SIZE; ++i) 349 + led->mm_current_scale[i] = max_mm_current * 350 + max_mm_current_percent[i] / 100; 351 + 352 + return 0; 353 + } 354 + 355 + static int aat1290_led_get_configuration(struct aat1290_led *led, 356 + struct aat1290_led_config_data *cfg, 357 + struct device_node **sub_node) 358 + { 359 + int ret; 360 + 361 + ret = aat1290_led_parse_dt(led, cfg, sub_node); 362 + if (ret < 0) 363 + return ret; 364 + /* 365 + * Init non-linear movie mode current scale basing 366 + * on the max flash current from led configuration. 367 + */ 368 + ret = init_mm_current_scale(led, cfg); 369 + if (ret < 0) 370 + return ret; 371 + 372 + aat1290_led_validate_mm_current(led, cfg); 373 + 374 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 375 + #else 376 + devm_kfree(&led->pdev->dev, led->mm_current_scale); 377 + #endif 378 + 379 + return 0; 380 + } 381 + 382 + static void aat1290_init_flash_timeout(struct aat1290_led *led, 383 + struct aat1290_led_config_data *cfg) 384 + { 385 + struct led_classdev_flash *fled_cdev = &led->fled_cdev; 386 + struct led_flash_setting *setting; 387 + 388 + /* Init flash timeout setting */ 389 + setting = &fled_cdev->timeout; 390 + setting->min = cfg->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS; 391 + setting->max = cfg->max_flash_tm; 392 + setting->step = setting->min; 393 + setting->val = setting->max; 394 + } 395 + 396 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 397 + static enum led_brightness aat1290_intensity_to_brightness( 398 + struct v4l2_flash *v4l2_flash, 399 + s32 intensity) 400 + { 401 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 402 + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); 403 + int i; 404 + 405 + for (i = AAT1290_MM_CURRENT_SCALE_SIZE - 1; i >= 0; --i) 406 + if (intensity >= led->mm_current_scale[i]) 407 + return i + 1; 408 + 409 + return 1; 410 + } 411 + 412 + static s32 aat1290_brightness_to_intensity(struct v4l2_flash *v4l2_flash, 413 + enum led_brightness brightness) 414 + { 415 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 416 + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); 417 + 418 + return led->mm_current_scale[brightness - 1]; 419 + } 420 + 421 + static int aat1290_led_external_strobe_set(struct v4l2_flash *v4l2_flash, 422 + bool enable) 423 + { 424 + struct aat1290_led *led = fled_cdev_to_led(v4l2_flash->fled_cdev); 425 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 426 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 427 + struct pinctrl *pinctrl; 428 + 429 + gpiod_direction_output(led->gpio_fl_en, 0); 430 + gpiod_direction_output(led->gpio_en_set, 0); 431 + 432 + led->movie_mode = false; 433 + led_cdev->brightness = 0; 434 + 435 + pinctrl = devm_pinctrl_get_select(&led->pdev->dev, 436 + enable ? "isp" : "host"); 437 + if (IS_ERR(pinctrl)) { 438 + dev_warn(&led->pdev->dev, "Unable to switch strobe source.\n"); 439 + return PTR_ERR(pinctrl); 440 + } 441 + 442 + return 0; 443 + } 444 + 445 + static void aat1290_init_v4l2_flash_config(struct aat1290_led *led, 446 + struct aat1290_led_config_data *led_cfg, 447 + struct v4l2_flash_config *v4l2_sd_cfg) 448 + { 449 + struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; 450 + struct led_flash_setting *s; 451 + 452 + strlcpy(v4l2_sd_cfg->dev_name, led_cdev->name, 453 + sizeof(v4l2_sd_cfg->dev_name)); 454 + 455 + s = &v4l2_sd_cfg->torch_intensity; 456 + s->min = led->mm_current_scale[0]; 457 + s->max = led_cfg->max_mm_current; 458 + s->step = 1; 459 + s->val = s->max; 460 + 461 + v4l2_sd_cfg->has_external_strobe = led_cfg->has_external_strobe; 462 + } 463 + 464 + static const struct v4l2_flash_ops v4l2_flash_ops = { 465 + .external_strobe_set = aat1290_led_external_strobe_set, 466 + .intensity_to_led_brightness = aat1290_intensity_to_brightness, 467 + .led_brightness_to_intensity = aat1290_brightness_to_intensity, 468 + }; 469 + #else 470 + static inline void aat1290_init_v4l2_flash_config(struct aat1290_led *led, 471 + struct aat1290_led_config_data *led_cfg, 472 + struct v4l2_flash_config *v4l2_sd_cfg) 473 + { 474 + } 475 + static const struct v4l2_flash_ops v4l2_flash_ops; 476 + #endif 477 + 478 + static const struct led_flash_ops flash_ops = { 479 + .strobe_set = aat1290_led_flash_strobe_set, 480 + .timeout_set = aat1290_led_flash_timeout_set, 481 + }; 482 + 483 + static int aat1290_led_probe(struct platform_device *pdev) 484 + { 485 + struct device *dev = &pdev->dev; 486 + struct device_node *sub_node = NULL; 487 + struct aat1290_led *led; 488 + struct led_classdev *led_cdev; 489 + struct led_classdev_flash *fled_cdev; 490 + struct aat1290_led_config_data led_cfg = {}; 491 + struct v4l2_flash_config v4l2_sd_cfg = {}; 492 + int ret; 493 + 494 + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); 495 + if (!led) 496 + return -ENOMEM; 497 + 498 + led->pdev = pdev; 499 + platform_set_drvdata(pdev, led); 500 + 501 + fled_cdev = &led->fled_cdev; 502 + fled_cdev->ops = &flash_ops; 503 + led_cdev = &fled_cdev->led_cdev; 504 + 505 + ret = aat1290_led_get_configuration(led, &led_cfg, &sub_node); 506 + if (ret < 0) 507 + return ret; 508 + 509 + mutex_init(&led->lock); 510 + 511 + /* Initialize LED Flash class device */ 512 + led_cdev->brightness_set = aat1290_led_brightness_set; 513 + led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync; 514 + led_cdev->max_brightness = led_cfg.max_brightness; 515 + led_cdev->flags |= LED_DEV_CAP_FLASH; 516 + INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work); 517 + 518 + aat1290_init_flash_timeout(led, &led_cfg); 519 + 520 + /* Register LED Flash class device */ 521 + ret = led_classdev_flash_register(&pdev->dev, fled_cdev); 522 + if (ret < 0) 523 + goto err_flash_register; 524 + 525 + aat1290_init_v4l2_flash_config(led, &led_cfg, &v4l2_sd_cfg); 526 + 527 + /* Create V4L2 Flash subdev. */ 528 + led->v4l2_flash = v4l2_flash_init(dev, sub_node, fled_cdev, NULL, 529 + &v4l2_flash_ops, &v4l2_sd_cfg); 530 + if (IS_ERR(led->v4l2_flash)) { 531 + ret = PTR_ERR(led->v4l2_flash); 532 + goto error_v4l2_flash_init; 533 + } 534 + 535 + return 0; 536 + 537 + error_v4l2_flash_init: 538 + led_classdev_flash_unregister(fled_cdev); 539 + err_flash_register: 540 + mutex_destroy(&led->lock); 541 + 542 + return ret; 543 + } 544 + 545 + static int aat1290_led_remove(struct platform_device *pdev) 546 + { 547 + struct aat1290_led *led = platform_get_drvdata(pdev); 548 + 549 + v4l2_flash_release(led->v4l2_flash); 550 + led_classdev_flash_unregister(&led->fled_cdev); 551 + cancel_work_sync(&led->work_brightness_set); 552 + 553 + mutex_destroy(&led->lock); 554 + 555 + return 0; 556 + } 557 + 558 + static const struct of_device_id aat1290_led_dt_match[] = { 559 + { .compatible = "skyworks,aat1290" }, 560 + {}, 561 + }; 562 + 563 + static struct platform_driver aat1290_led_driver = { 564 + .probe = aat1290_led_probe, 565 + .remove = aat1290_led_remove, 566 + .driver = { 567 + .name = "aat1290", 568 + .of_match_table = aat1290_led_dt_match, 569 + }, 570 + }; 571 + 572 + module_platform_driver(aat1290_led_driver); 573 + 574 + MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); 575 + MODULE_DESCRIPTION("Skyworks Current Regulator for Flash LEDs"); 576 + MODULE_LICENSE("GPL v2");
+413
drivers/leds/leds-bcm6328.c
··· 1 + /* 2 + * Driver for BCM6328 memory-mapped LEDs, based on leds-syscon.c 3 + * 4 + * Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com> 5 + * Copyright 2015 Jonas Gorski <jogo@openwrt.org> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2 of the License, or (at your 10 + * option) any later version. 11 + */ 12 + #include <linux/io.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/spinlock.h> 18 + 19 + #define BCM6328_REG_INIT 0x00 20 + #define BCM6328_REG_MODE_HI 0x04 21 + #define BCM6328_REG_MODE_LO 0x08 22 + #define BCM6328_REG_HWDIS 0x0c 23 + #define BCM6328_REG_STROBE 0x10 24 + #define BCM6328_REG_LNKACTSEL_HI 0x14 25 + #define BCM6328_REG_LNKACTSEL_LO 0x18 26 + #define BCM6328_REG_RBACK 0x1c 27 + #define BCM6328_REG_SERMUX 0x20 28 + 29 + #define BCM6328_LED_MAX_COUNT 24 30 + #define BCM6328_LED_DEF_DELAY 500 31 + #define BCM6328_LED_INTERVAL_MS 20 32 + 33 + #define BCM6328_LED_INTV_MASK 0x3f 34 + #define BCM6328_LED_FAST_INTV_SHIFT 6 35 + #define BCM6328_LED_FAST_INTV_MASK (BCM6328_LED_INTV_MASK << \ 36 + BCM6328_LED_FAST_INTV_SHIFT) 37 + #define BCM6328_SERIAL_LED_EN BIT(12) 38 + #define BCM6328_SERIAL_LED_MUX BIT(13) 39 + #define BCM6328_SERIAL_LED_CLK_NPOL BIT(14) 40 + #define BCM6328_SERIAL_LED_DATA_PPOL BIT(15) 41 + #define BCM6328_SERIAL_LED_SHIFT_DIR BIT(16) 42 + #define BCM6328_LED_SHIFT_TEST BIT(30) 43 + #define BCM6328_LED_TEST BIT(31) 44 + 45 + #define BCM6328_LED_MODE_MASK 3 46 + #define BCM6328_LED_MODE_OFF 0 47 + #define BCM6328_LED_MODE_FAST 1 48 + #define BCM6328_LED_MODE_BLINK 2 49 + #define BCM6328_LED_MODE_ON 3 50 + #define BCM6328_LED_SHIFT(X) ((X) << 1) 51 + 52 + /** 53 + * struct bcm6328_led - state container for bcm6328 based LEDs 54 + * @cdev: LED class device for this LED 55 + * @mem: memory resource 56 + * @lock: memory lock 57 + * @pin: LED pin number 58 + * @blink_leds: blinking LEDs 59 + * @blink_delay: blinking delay 60 + * @active_low: LED is active low 61 + */ 62 + struct bcm6328_led { 63 + struct led_classdev cdev; 64 + void __iomem *mem; 65 + spinlock_t *lock; 66 + unsigned long pin; 67 + unsigned long *blink_leds; 68 + unsigned long *blink_delay; 69 + bool active_low; 70 + }; 71 + 72 + static void bcm6328_led_write(void __iomem *reg, unsigned long data) 73 + { 74 + iowrite32be(data, reg); 75 + } 76 + 77 + static unsigned long bcm6328_led_read(void __iomem *reg) 78 + { 79 + return ioread32be(reg); 80 + } 81 + 82 + /** 83 + * LEDMode 64 bits / 24 LEDs 84 + * bits [31:0] -> LEDs 8-23 85 + * bits [47:32] -> LEDs 0-7 86 + * bits [63:48] -> unused 87 + */ 88 + static unsigned long bcm6328_pin2shift(unsigned long pin) 89 + { 90 + if (pin < 8) 91 + return pin + 16; /* LEDs 0-7 (bits 47:32) */ 92 + else 93 + return pin - 8; /* LEDs 8-23 (bits 31:0) */ 94 + } 95 + 96 + static void bcm6328_led_mode(struct bcm6328_led *led, unsigned long value) 97 + { 98 + void __iomem *mode; 99 + unsigned long val, shift; 100 + 101 + shift = bcm6328_pin2shift(led->pin); 102 + if (shift / 16) 103 + mode = led->mem + BCM6328_REG_MODE_HI; 104 + else 105 + mode = led->mem + BCM6328_REG_MODE_LO; 106 + 107 + val = bcm6328_led_read(mode); 108 + val &= ~(BCM6328_LED_MODE_MASK << BCM6328_LED_SHIFT(shift % 16)); 109 + val |= (value << BCM6328_LED_SHIFT(shift % 16)); 110 + bcm6328_led_write(mode, val); 111 + } 112 + 113 + static void bcm6328_led_set(struct led_classdev *led_cdev, 114 + enum led_brightness value) 115 + { 116 + struct bcm6328_led *led = 117 + container_of(led_cdev, struct bcm6328_led, cdev); 118 + unsigned long flags; 119 + 120 + spin_lock_irqsave(led->lock, flags); 121 + *(led->blink_leds) &= ~BIT(led->pin); 122 + if ((led->active_low && value == LED_OFF) || 123 + (!led->active_low && value != LED_OFF)) 124 + bcm6328_led_mode(led, BCM6328_LED_MODE_OFF); 125 + else 126 + bcm6328_led_mode(led, BCM6328_LED_MODE_ON); 127 + spin_unlock_irqrestore(led->lock, flags); 128 + } 129 + 130 + static int bcm6328_blink_set(struct led_classdev *led_cdev, 131 + unsigned long *delay_on, unsigned long *delay_off) 132 + { 133 + struct bcm6328_led *led = 134 + container_of(led_cdev, struct bcm6328_led, cdev); 135 + unsigned long delay, flags; 136 + 137 + if (!*delay_on) 138 + *delay_on = BCM6328_LED_DEF_DELAY; 139 + if (!*delay_off) 140 + *delay_off = BCM6328_LED_DEF_DELAY; 141 + 142 + if (*delay_on != *delay_off) { 143 + dev_dbg(led_cdev->dev, 144 + "fallback to soft blinking (delay_on != delay_off)\n"); 145 + return -EINVAL; 146 + } 147 + 148 + delay = *delay_on / BCM6328_LED_INTERVAL_MS; 149 + if (delay == 0) 150 + delay = 1; 151 + else if (delay > BCM6328_LED_INTV_MASK) { 152 + dev_dbg(led_cdev->dev, 153 + "fallback to soft blinking (delay > %ums)\n", 154 + BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS); 155 + return -EINVAL; 156 + } 157 + 158 + spin_lock_irqsave(led->lock, flags); 159 + if (*(led->blink_leds) == 0 || 160 + *(led->blink_leds) == BIT(led->pin) || 161 + *(led->blink_delay) == delay) { 162 + unsigned long val; 163 + 164 + *(led->blink_leds) |= BIT(led->pin); 165 + *(led->blink_delay) = delay; 166 + 167 + val = bcm6328_led_read(led->mem + BCM6328_REG_INIT); 168 + val &= ~BCM6328_LED_FAST_INTV_MASK; 169 + val |= (delay << BCM6328_LED_FAST_INTV_SHIFT); 170 + bcm6328_led_write(led->mem + BCM6328_REG_INIT, val); 171 + 172 + bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK); 173 + 174 + spin_unlock_irqrestore(led->lock, flags); 175 + } else { 176 + spin_unlock_irqrestore(led->lock, flags); 177 + dev_dbg(led_cdev->dev, 178 + "fallback to soft blinking (delay already set)\n"); 179 + return -EINVAL; 180 + } 181 + 182 + return 0; 183 + } 184 + 185 + static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg, 186 + void __iomem *mem, spinlock_t *lock) 187 + { 188 + int i, cnt; 189 + unsigned long flags, val; 190 + 191 + spin_lock_irqsave(lock, flags); 192 + val = bcm6328_led_read(mem + BCM6328_REG_HWDIS); 193 + val &= ~BIT(reg); 194 + bcm6328_led_write(mem + BCM6328_REG_HWDIS, val); 195 + spin_unlock_irqrestore(lock, flags); 196 + 197 + /* Only LEDs 0-7 can be activity/link controlled */ 198 + if (reg >= 8) 199 + return 0; 200 + 201 + cnt = of_property_count_elems_of_size(nc, "brcm,link-signal-sources", 202 + sizeof(u32)); 203 + for (i = 0; i < cnt; i++) { 204 + u32 sel; 205 + void __iomem *addr; 206 + 207 + if (reg < 4) 208 + addr = mem + BCM6328_REG_LNKACTSEL_LO; 209 + else 210 + addr = mem + BCM6328_REG_LNKACTSEL_HI; 211 + 212 + of_property_read_u32_index(nc, "brcm,link-signal-sources", i, 213 + &sel); 214 + 215 + if (reg / 4 != sel / 4) { 216 + dev_warn(dev, "invalid link signal source\n"); 217 + continue; 218 + } 219 + 220 + spin_lock_irqsave(lock, flags); 221 + val = bcm6328_led_read(addr); 222 + val |= (BIT(reg) << (((sel % 4) * 4) + 16)); 223 + bcm6328_led_write(addr, val); 224 + spin_unlock_irqrestore(lock, flags); 225 + } 226 + 227 + cnt = of_property_count_elems_of_size(nc, 228 + "brcm,activity-signal-sources", 229 + sizeof(u32)); 230 + for (i = 0; i < cnt; i++) { 231 + u32 sel; 232 + void __iomem *addr; 233 + 234 + if (reg < 4) 235 + addr = mem + BCM6328_REG_LNKACTSEL_LO; 236 + else 237 + addr = mem + BCM6328_REG_LNKACTSEL_HI; 238 + 239 + of_property_read_u32_index(nc, "brcm,activity-signal-sources", 240 + i, &sel); 241 + 242 + if (reg / 4 != sel / 4) { 243 + dev_warn(dev, "invalid activity signal source\n"); 244 + continue; 245 + } 246 + 247 + spin_lock_irqsave(lock, flags); 248 + val = bcm6328_led_read(addr); 249 + val |= (BIT(reg) << ((sel % 4) * 4)); 250 + bcm6328_led_write(addr, val); 251 + spin_unlock_irqrestore(lock, flags); 252 + } 253 + 254 + return 0; 255 + } 256 + 257 + static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, 258 + void __iomem *mem, spinlock_t *lock, 259 + unsigned long *blink_leds, unsigned long *blink_delay) 260 + { 261 + struct bcm6328_led *led; 262 + unsigned long flags; 263 + const char *state; 264 + int rc; 265 + 266 + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); 267 + if (!led) 268 + return -ENOMEM; 269 + 270 + led->pin = reg; 271 + led->mem = mem; 272 + led->lock = lock; 273 + led->blink_leds = blink_leds; 274 + led->blink_delay = blink_delay; 275 + 276 + if (of_property_read_bool(nc, "active-low")) 277 + led->active_low = true; 278 + 279 + led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name; 280 + led->cdev.default_trigger = of_get_property(nc, 281 + "linux,default-trigger", 282 + NULL); 283 + 284 + if (!of_property_read_string(nc, "default-state", &state)) { 285 + spin_lock_irqsave(lock, flags); 286 + if (!strcmp(state, "on")) { 287 + led->cdev.brightness = LED_FULL; 288 + bcm6328_led_mode(led, BCM6328_LED_MODE_ON); 289 + } else if (!strcmp(state, "keep")) { 290 + void __iomem *mode; 291 + unsigned long val, shift; 292 + 293 + shift = bcm6328_pin2shift(led->pin); 294 + if (shift / 16) 295 + mode = mem + BCM6328_REG_MODE_HI; 296 + else 297 + mode = mem + BCM6328_REG_MODE_LO; 298 + 299 + val = bcm6328_led_read(mode) >> (shift % 16); 300 + val &= BCM6328_LED_MODE_MASK; 301 + if (val == BCM6328_LED_MODE_ON) 302 + led->cdev.brightness = LED_FULL; 303 + else { 304 + led->cdev.brightness = LED_OFF; 305 + bcm6328_led_mode(led, BCM6328_LED_MODE_OFF); 306 + } 307 + } else { 308 + led->cdev.brightness = LED_OFF; 309 + bcm6328_led_mode(led, BCM6328_LED_MODE_OFF); 310 + } 311 + spin_unlock_irqrestore(lock, flags); 312 + } 313 + 314 + led->cdev.brightness_set = bcm6328_led_set; 315 + led->cdev.blink_set = bcm6328_blink_set; 316 + 317 + rc = led_classdev_register(dev, &led->cdev); 318 + if (rc < 0) 319 + return rc; 320 + 321 + dev_dbg(dev, "registered LED %s\n", led->cdev.name); 322 + 323 + return 0; 324 + } 325 + 326 + static int bcm6328_leds_probe(struct platform_device *pdev) 327 + { 328 + struct device *dev = &pdev->dev; 329 + struct device_node *np = pdev->dev.of_node; 330 + struct device_node *child; 331 + struct resource *mem_r; 332 + void __iomem *mem; 333 + spinlock_t *lock; 334 + unsigned long val, *blink_leds, *blink_delay; 335 + 336 + mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 337 + if (!mem_r) 338 + return -EINVAL; 339 + 340 + mem = devm_ioremap_resource(dev, mem_r); 341 + if (IS_ERR(mem)) 342 + return PTR_ERR(mem); 343 + 344 + lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL); 345 + if (!lock) 346 + return -ENOMEM; 347 + 348 + blink_leds = devm_kzalloc(dev, sizeof(*blink_leds), GFP_KERNEL); 349 + if (!blink_leds) 350 + return -ENOMEM; 351 + 352 + blink_delay = devm_kzalloc(dev, sizeof(*blink_delay), GFP_KERNEL); 353 + if (!blink_delay) 354 + return -ENOMEM; 355 + 356 + spin_lock_init(lock); 357 + 358 + bcm6328_led_write(mem + BCM6328_REG_HWDIS, ~0); 359 + bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_HI, 0); 360 + bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0); 361 + 362 + val = bcm6328_led_read(mem + BCM6328_REG_INIT); 363 + val &= ~BCM6328_SERIAL_LED_EN; 364 + if (of_property_read_bool(np, "brcm,serial-leds")) 365 + val |= BCM6328_SERIAL_LED_EN; 366 + bcm6328_led_write(mem + BCM6328_REG_INIT, val); 367 + 368 + for_each_available_child_of_node(np, child) { 369 + int rc; 370 + u32 reg; 371 + 372 + if (of_property_read_u32(child, "reg", &reg)) 373 + continue; 374 + 375 + if (reg >= BCM6328_LED_MAX_COUNT) { 376 + dev_err(dev, "invalid LED (>= %d)\n", 377 + BCM6328_LED_MAX_COUNT); 378 + continue; 379 + } 380 + 381 + if (of_property_read_bool(child, "brcm,hardware-controlled")) 382 + rc = bcm6328_hwled(dev, child, reg, mem, lock); 383 + else 384 + rc = bcm6328_led(dev, child, reg, mem, lock, 385 + blink_leds, blink_delay); 386 + 387 + if (rc < 0) 388 + return rc; 389 + } 390 + 391 + return 0; 392 + } 393 + 394 + static const struct of_device_id bcm6328_leds_of_match[] = { 395 + { .compatible = "brcm,bcm6328-leds", }, 396 + { }, 397 + }; 398 + 399 + static struct platform_driver bcm6328_leds_driver = { 400 + .probe = bcm6328_leds_probe, 401 + .driver = { 402 + .name = "leds-bcm6328", 403 + .of_match_table = bcm6328_leds_of_match, 404 + }, 405 + }; 406 + 407 + module_platform_driver(bcm6328_leds_driver); 408 + 409 + MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>"); 410 + MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 411 + MODULE_DESCRIPTION("LED driver for BCM6328 controllers"); 412 + MODULE_LICENSE("GPL v2"); 413 + MODULE_ALIAS("platform:leds-bcm6328");
+243
drivers/leds/leds-bcm6358.c
··· 1 + /* 2 + * Driver for BCM6358 memory-mapped LEDs, based on leds-syscon.c 3 + * 4 + * Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License as published by the 8 + * Free Software Foundation; either version 2 of the License, or (at your 9 + * option) any later version. 10 + */ 11 + #include <linux/delay.h> 12 + #include <linux/io.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/spinlock.h> 18 + 19 + #define BCM6358_REG_MODE 0x0 20 + #define BCM6358_REG_CTRL 0x4 21 + 22 + #define BCM6358_SLED_CLKDIV_MASK 3 23 + #define BCM6358_SLED_CLKDIV_1 0 24 + #define BCM6358_SLED_CLKDIV_2 1 25 + #define BCM6358_SLED_CLKDIV_4 2 26 + #define BCM6358_SLED_CLKDIV_8 3 27 + 28 + #define BCM6358_SLED_POLARITY BIT(2) 29 + #define BCM6358_SLED_BUSY BIT(3) 30 + 31 + #define BCM6358_SLED_MAX_COUNT 32 32 + #define BCM6358_SLED_WAIT 100 33 + 34 + /** 35 + * struct bcm6358_led - state container for bcm6358 based LEDs 36 + * @cdev: LED class device for this LED 37 + * @mem: memory resource 38 + * @lock: memory lock 39 + * @pin: LED pin number 40 + * @active_low: LED is active low 41 + */ 42 + struct bcm6358_led { 43 + struct led_classdev cdev; 44 + void __iomem *mem; 45 + spinlock_t *lock; 46 + unsigned long pin; 47 + bool active_low; 48 + }; 49 + 50 + static void bcm6358_led_write(void __iomem *reg, unsigned long data) 51 + { 52 + iowrite32be(data, reg); 53 + } 54 + 55 + static unsigned long bcm6358_led_read(void __iomem *reg) 56 + { 57 + return ioread32be(reg); 58 + } 59 + 60 + static unsigned long bcm6358_led_busy(void __iomem *mem) 61 + { 62 + unsigned long val; 63 + 64 + while ((val = bcm6358_led_read(mem + BCM6358_REG_CTRL)) & 65 + BCM6358_SLED_BUSY) 66 + udelay(BCM6358_SLED_WAIT); 67 + 68 + return val; 69 + } 70 + 71 + static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value) 72 + { 73 + unsigned long val; 74 + 75 + bcm6358_led_busy(led->mem); 76 + 77 + val = bcm6358_led_read(led->mem + BCM6358_REG_MODE); 78 + if ((led->active_low && value == LED_OFF) || 79 + (!led->active_low && value != LED_OFF)) 80 + val |= BIT(led->pin); 81 + else 82 + val &= ~(BIT(led->pin)); 83 + bcm6358_led_write(led->mem + BCM6358_REG_MODE, val); 84 + } 85 + 86 + static void bcm6358_led_set(struct led_classdev *led_cdev, 87 + enum led_brightness value) 88 + { 89 + struct bcm6358_led *led = 90 + container_of(led_cdev, struct bcm6358_led, cdev); 91 + unsigned long flags; 92 + 93 + spin_lock_irqsave(led->lock, flags); 94 + bcm6358_led_mode(led, value); 95 + spin_unlock_irqrestore(led->lock, flags); 96 + } 97 + 98 + static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, 99 + void __iomem *mem, spinlock_t *lock) 100 + { 101 + struct bcm6358_led *led; 102 + unsigned long flags; 103 + const char *state; 104 + int rc; 105 + 106 + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); 107 + if (!led) 108 + return -ENOMEM; 109 + 110 + led->pin = reg; 111 + led->mem = mem; 112 + led->lock = lock; 113 + 114 + if (of_property_read_bool(nc, "active-low")) 115 + led->active_low = true; 116 + 117 + led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name; 118 + led->cdev.default_trigger = of_get_property(nc, 119 + "linux,default-trigger", 120 + NULL); 121 + 122 + spin_lock_irqsave(lock, flags); 123 + if (!of_property_read_string(nc, "default-state", &state)) { 124 + if (!strcmp(state, "on")) { 125 + led->cdev.brightness = LED_FULL; 126 + } else if (!strcmp(state, "keep")) { 127 + unsigned long val; 128 + 129 + bcm6358_led_busy(led->mem); 130 + 131 + val = bcm6358_led_read(led->mem + BCM6358_REG_MODE); 132 + val &= BIT(led->pin); 133 + if ((led->active_low && !val) || 134 + (!led->active_low && val)) 135 + led->cdev.brightness = LED_FULL; 136 + else 137 + led->cdev.brightness = LED_OFF; 138 + } else { 139 + led->cdev.brightness = LED_OFF; 140 + } 141 + } else { 142 + led->cdev.brightness = LED_OFF; 143 + } 144 + bcm6358_led_mode(led, led->cdev.brightness); 145 + spin_unlock_irqrestore(lock, flags); 146 + 147 + led->cdev.brightness_set = bcm6358_led_set; 148 + 149 + rc = led_classdev_register(dev, &led->cdev); 150 + if (rc < 0) 151 + return rc; 152 + 153 + dev_dbg(dev, "registered LED %s\n", led->cdev.name); 154 + 155 + return 0; 156 + } 157 + 158 + static int bcm6358_leds_probe(struct platform_device *pdev) 159 + { 160 + struct device *dev = &pdev->dev; 161 + struct device_node *np = pdev->dev.of_node; 162 + struct device_node *child; 163 + struct resource *mem_r; 164 + void __iomem *mem; 165 + spinlock_t *lock; /* memory lock */ 166 + unsigned long val; 167 + u32 clk_div; 168 + 169 + mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 170 + if (!mem_r) 171 + return -EINVAL; 172 + 173 + mem = devm_ioremap_resource(dev, mem_r); 174 + if (IS_ERR(mem)) 175 + return PTR_ERR(mem); 176 + 177 + lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL); 178 + if (!lock) 179 + return -ENOMEM; 180 + 181 + spin_lock_init(lock); 182 + 183 + val = bcm6358_led_busy(mem); 184 + val &= ~(BCM6358_SLED_POLARITY | BCM6358_SLED_CLKDIV_MASK); 185 + if (of_property_read_bool(np, "brcm,clk-dat-low")) 186 + val |= BCM6358_SLED_POLARITY; 187 + of_property_read_u32(np, "brcm,clk-div", &clk_div); 188 + switch (clk_div) { 189 + case 8: 190 + val |= BCM6358_SLED_CLKDIV_8; 191 + break; 192 + case 4: 193 + val |= BCM6358_SLED_CLKDIV_4; 194 + break; 195 + case 2: 196 + val |= BCM6358_SLED_CLKDIV_2; 197 + break; 198 + default: 199 + val |= BCM6358_SLED_CLKDIV_1; 200 + break; 201 + } 202 + bcm6358_led_write(mem + BCM6358_REG_CTRL, val); 203 + 204 + for_each_available_child_of_node(np, child) { 205 + int rc; 206 + u32 reg; 207 + 208 + if (of_property_read_u32(child, "reg", &reg)) 209 + continue; 210 + 211 + if (reg >= BCM6358_SLED_MAX_COUNT) { 212 + dev_err(dev, "invalid LED (%u >= %d)\n", reg, 213 + BCM6358_SLED_MAX_COUNT); 214 + continue; 215 + } 216 + 217 + rc = bcm6358_led(dev, child, reg, mem, lock); 218 + if (rc < 0) 219 + return rc; 220 + } 221 + 222 + return 0; 223 + } 224 + 225 + static const struct of_device_id bcm6358_leds_of_match[] = { 226 + { .compatible = "brcm,bcm6358-leds", }, 227 + { }, 228 + }; 229 + 230 + static struct platform_driver bcm6358_leds_driver = { 231 + .probe = bcm6358_leds_probe, 232 + .driver = { 233 + .name = "leds-bcm6358", 234 + .of_match_table = bcm6358_leds_of_match, 235 + }, 236 + }; 237 + 238 + module_platform_driver(bcm6358_leds_driver); 239 + 240 + MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>"); 241 + MODULE_DESCRIPTION("LED driver for BCM6358 controllers"); 242 + MODULE_LICENSE("GPL v2"); 243 + MODULE_ALIAS("platform:leds-bcm6358");
+1 -14
drivers/leds/leds-cobalt-raq.c
··· 108 108 return retval; 109 109 } 110 110 111 - static int cobalt_raq_led_remove(struct platform_device *pdev) 112 - { 113 - led_classdev_unregister(&raq_power_off_led); 114 - led_classdev_unregister(&raq_web_led); 115 - 116 - if (led_port) 117 - led_port = NULL; 118 - 119 - return 0; 120 - } 121 - 122 111 static struct platform_driver cobalt_raq_led_driver = { 123 112 .probe = cobalt_raq_led_probe, 124 - .remove = cobalt_raq_led_remove, 125 113 .driver = { 126 114 .name = "cobalt-raq-leds", 127 115 }, ··· 119 131 { 120 132 return platform_driver_register(&cobalt_raq_led_driver); 121 133 } 122 - 123 - module_init(cobalt_raq_led_init); 134 + device_initcall(cobalt_raq_led_init);
+8 -4
drivers/leds/leds-gpio.c
··· 16 16 #include <linux/kernel.h> 17 17 #include <linux/leds.h> 18 18 #include <linux/module.h> 19 + #include <linux/of.h> 19 20 #include <linux/platform_device.h> 20 21 #include <linux/property.h> 21 22 #include <linux/slab.h> ··· 199 198 } else { 200 199 if (IS_ENABLED(CONFIG_OF) && !led.name && np) 201 200 led.name = np->name; 202 - if (!led.name) 203 - return ERR_PTR(-EINVAL); 201 + if (!led.name) { 202 + ret = -EINVAL; 203 + goto err; 204 + } 204 205 } 205 206 fwnode_property_read_string(child, "linux,default-trigger", 206 207 &led.default_trigger); ··· 220 217 if (fwnode_property_present(child, "retain-state-suspended")) 221 218 led.retain_state_suspended = 1; 222 219 223 - ret = create_gpio_led(&led, &priv->leds[priv->num_leds++], 220 + ret = create_gpio_led(&led, &priv->leds[priv->num_leds], 224 221 dev, NULL); 225 222 if (ret < 0) { 226 223 fwnode_handle_put(child); 227 224 goto err; 228 225 } 226 + priv->num_leds++; 229 227 } 230 228 231 229 return priv; 232 230 233 231 err: 234 - for (count = priv->num_leds - 2; count >= 0; count--) 232 + for (count = priv->num_leds - 1; count >= 0; count--) 235 233 delete_gpio_led(&priv->leds[count]); 236 234 return ERR_PTR(ret); 237 235 }
+443
drivers/leds/leds-ktd2692.c
··· 1 + /* 2 + * LED driver : leds-ktd2692.c 3 + * 4 + * Copyright (C) 2015 Samsung Electronics 5 + * Ingi Kim <ingi2.kim@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/delay.h> 13 + #include <linux/err.h> 14 + #include <linux/gpio/consumer.h> 15 + #include <linux/led-class-flash.h> 16 + #include <linux/module.h> 17 + #include <linux/mutex.h> 18 + #include <linux/of.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/regulator/consumer.h> 21 + #include <linux/workqueue.h> 22 + 23 + /* Value related the movie mode */ 24 + #define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16 25 + #define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3) 26 + #define KTD2962_MM_MIN_CURR_THRESHOLD_SCALE 8 27 + 28 + /* Value related the flash mode */ 29 + #define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8 30 + #define KTD2692_FLASH_MODE_TIMEOUT_DISABLE 0 31 + #define KTD2692_FLASH_MODE_CURR_PERCENT(x) (((x) * 16) / 100) 32 + 33 + /* Macro for getting offset of flash timeout */ 34 + #define GET_TIMEOUT_OFFSET(timeout, step) ((timeout) / (step)) 35 + 36 + /* Base register address */ 37 + #define KTD2692_REG_LVP_BASE 0x00 38 + #define KTD2692_REG_FLASH_TIMEOUT_BASE 0x20 39 + #define KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE 0x40 40 + #define KTD2692_REG_MOVIE_CURRENT_BASE 0x60 41 + #define KTD2692_REG_FLASH_CURRENT_BASE 0x80 42 + #define KTD2692_REG_MODE_BASE 0xA0 43 + 44 + /* Set bit coding time for expresswire interface */ 45 + #define KTD2692_TIME_RESET_US 700 46 + #define KTD2692_TIME_DATA_START_TIME_US 10 47 + #define KTD2692_TIME_HIGH_END_OF_DATA_US 350 48 + #define KTD2692_TIME_LOW_END_OF_DATA_US 10 49 + #define KTD2692_TIME_SHORT_BITSET_US 4 50 + #define KTD2692_TIME_LONG_BITSET_US 12 51 + 52 + /* KTD2692 default length of name */ 53 + #define KTD2692_NAME_LENGTH 20 54 + 55 + enum ktd2692_bitset { 56 + KTD2692_LOW = 0, 57 + KTD2692_HIGH, 58 + }; 59 + 60 + /* Movie / Flash Mode Control */ 61 + enum ktd2692_led_mode { 62 + KTD2692_MODE_DISABLE = 0, /* default */ 63 + KTD2692_MODE_MOVIE, 64 + KTD2692_MODE_FLASH, 65 + }; 66 + 67 + struct ktd2692_led_config_data { 68 + /* maximum LED current in movie mode */ 69 + u32 movie_max_microamp; 70 + /* maximum LED current in flash mode */ 71 + u32 flash_max_microamp; 72 + /* maximum flash timeout */ 73 + u32 flash_max_timeout; 74 + /* max LED brightness level */ 75 + enum led_brightness max_brightness; 76 + }; 77 + 78 + struct ktd2692_context { 79 + /* Related LED Flash class device */ 80 + struct led_classdev_flash fled_cdev; 81 + 82 + /* secures access to the device */ 83 + struct mutex lock; 84 + struct regulator *regulator; 85 + struct work_struct work_brightness_set; 86 + 87 + struct gpio_desc *aux_gpio; 88 + struct gpio_desc *ctrl_gpio; 89 + 90 + enum ktd2692_led_mode mode; 91 + enum led_brightness torch_brightness; 92 + }; 93 + 94 + static struct ktd2692_context *fled_cdev_to_led( 95 + struct led_classdev_flash *fled_cdev) 96 + { 97 + return container_of(fled_cdev, struct ktd2692_context, fled_cdev); 98 + } 99 + 100 + static void ktd2692_expresswire_start(struct ktd2692_context *led) 101 + { 102 + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); 103 + udelay(KTD2692_TIME_DATA_START_TIME_US); 104 + } 105 + 106 + static void ktd2692_expresswire_reset(struct ktd2692_context *led) 107 + { 108 + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); 109 + udelay(KTD2692_TIME_RESET_US); 110 + } 111 + 112 + static void ktd2692_expresswire_end(struct ktd2692_context *led) 113 + { 114 + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); 115 + udelay(KTD2692_TIME_LOW_END_OF_DATA_US); 116 + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); 117 + udelay(KTD2692_TIME_HIGH_END_OF_DATA_US); 118 + } 119 + 120 + static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit) 121 + { 122 + /* 123 + * The Low Bit(0) and High Bit(1) is based on a time detection 124 + * algorithm between time low and time high 125 + * Time_(L_LB) : Low time of the Low Bit(0) 126 + * Time_(H_LB) : High time of the LOW Bit(0) 127 + * Time_(L_HB) : Low time of the High Bit(1) 128 + * Time_(H_HB) : High time of the High Bit(1) 129 + * 130 + * It can be simplified to: 131 + * Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB) 132 + * High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB) 133 + * HIGH ___ ____ _.. _________ ___ 134 + * |_________| |_.. |____| |__| 135 + * LOW <L_LB> <H_LB> <L_HB> <H_HB> 136 + * [ Low Bit (0) ] [ High Bit(1) ] 137 + */ 138 + if (bit) { 139 + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); 140 + udelay(KTD2692_TIME_SHORT_BITSET_US); 141 + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); 142 + udelay(KTD2692_TIME_LONG_BITSET_US); 143 + } else { 144 + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); 145 + udelay(KTD2692_TIME_LONG_BITSET_US); 146 + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); 147 + udelay(KTD2692_TIME_SHORT_BITSET_US); 148 + } 149 + } 150 + 151 + static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value) 152 + { 153 + int i; 154 + 155 + ktd2692_expresswire_start(led); 156 + for (i = 7; i >= 0; i--) 157 + ktd2692_expresswire_set_bit(led, value & BIT(i)); 158 + ktd2692_expresswire_end(led); 159 + } 160 + 161 + static void ktd2692_brightness_set(struct ktd2692_context *led, 162 + enum led_brightness brightness) 163 + { 164 + mutex_lock(&led->lock); 165 + 166 + if (brightness == LED_OFF) { 167 + led->mode = KTD2692_MODE_DISABLE; 168 + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); 169 + } else { 170 + ktd2692_expresswire_write(led, brightness | 171 + KTD2692_REG_MOVIE_CURRENT_BASE); 172 + led->mode = KTD2692_MODE_MOVIE; 173 + } 174 + 175 + ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE); 176 + mutex_unlock(&led->lock); 177 + } 178 + 179 + static void ktd2692_brightness_set_work(struct work_struct *work) 180 + { 181 + struct ktd2692_context *led = 182 + container_of(work, struct ktd2692_context, work_brightness_set); 183 + 184 + ktd2692_brightness_set(led, led->torch_brightness); 185 + } 186 + 187 + static void ktd2692_led_brightness_set(struct led_classdev *led_cdev, 188 + enum led_brightness brightness) 189 + { 190 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 191 + struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 192 + 193 + led->torch_brightness = brightness; 194 + schedule_work(&led->work_brightness_set); 195 + } 196 + 197 + static int ktd2692_led_brightness_set_sync(struct led_classdev *led_cdev, 198 + enum led_brightness brightness) 199 + { 200 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 201 + struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 202 + 203 + ktd2692_brightness_set(led, brightness); 204 + 205 + return 0; 206 + } 207 + 208 + static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, 209 + bool state) 210 + { 211 + struct ktd2692_context *led = fled_cdev_to_led(fled_cdev); 212 + struct led_flash_setting *timeout = &fled_cdev->timeout; 213 + u32 flash_tm_reg; 214 + 215 + mutex_lock(&led->lock); 216 + 217 + if (state) { 218 + flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step); 219 + ktd2692_expresswire_write(led, flash_tm_reg 220 + | KTD2692_REG_FLASH_TIMEOUT_BASE); 221 + 222 + led->mode = KTD2692_MODE_FLASH; 223 + gpiod_direction_output(led->aux_gpio, KTD2692_HIGH); 224 + } else { 225 + led->mode = KTD2692_MODE_DISABLE; 226 + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); 227 + } 228 + 229 + ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE); 230 + 231 + fled_cdev->led_cdev.brightness = LED_OFF; 232 + led->mode = KTD2692_MODE_DISABLE; 233 + 234 + mutex_unlock(&led->lock); 235 + 236 + return 0; 237 + } 238 + 239 + static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev, 240 + u32 timeout) 241 + { 242 + return 0; 243 + } 244 + 245 + static void ktd2692_init_movie_current_max(struct ktd2692_led_config_data *cfg) 246 + { 247 + u32 offset, step; 248 + u32 movie_current_microamp; 249 + 250 + offset = KTD2692_MOVIE_MODE_CURRENT_LEVELS; 251 + step = KTD2692_MM_TO_FL_RATIO(cfg->flash_max_microamp) 252 + / KTD2692_MOVIE_MODE_CURRENT_LEVELS; 253 + 254 + do { 255 + movie_current_microamp = step * offset; 256 + offset--; 257 + } while ((movie_current_microamp > cfg->movie_max_microamp) && 258 + (offset > 0)); 259 + 260 + cfg->max_brightness = offset; 261 + } 262 + 263 + static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev, 264 + struct ktd2692_led_config_data *cfg) 265 + { 266 + struct led_flash_setting *setting; 267 + 268 + setting = &fled_cdev->timeout; 269 + setting->min = KTD2692_FLASH_MODE_TIMEOUT_DISABLE; 270 + setting->max = cfg->flash_max_timeout; 271 + setting->step = cfg->flash_max_timeout 272 + / (KTD2692_FLASH_MODE_TIMEOUT_LEVELS - 1); 273 + setting->val = cfg->flash_max_timeout; 274 + } 275 + 276 + static void ktd2692_setup(struct ktd2692_context *led) 277 + { 278 + led->mode = KTD2692_MODE_DISABLE; 279 + ktd2692_expresswire_reset(led); 280 + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); 281 + 282 + ktd2692_expresswire_write(led, (KTD2962_MM_MIN_CURR_THRESHOLD_SCALE - 1) 283 + | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE); 284 + ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45) 285 + | KTD2692_REG_FLASH_CURRENT_BASE); 286 + } 287 + 288 + static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, 289 + struct ktd2692_led_config_data *cfg) 290 + { 291 + struct device_node *np = dev->of_node; 292 + struct device_node *child_node; 293 + int ret; 294 + 295 + if (!dev->of_node) 296 + return -ENXIO; 297 + 298 + led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); 299 + if (IS_ERR(led->ctrl_gpio)) { 300 + ret = PTR_ERR(led->ctrl_gpio); 301 + dev_err(dev, "cannot get ctrl-gpios %d\n", ret); 302 + return ret; 303 + } 304 + 305 + led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS); 306 + if (IS_ERR(led->aux_gpio)) { 307 + ret = PTR_ERR(led->aux_gpio); 308 + dev_err(dev, "cannot get aux-gpios %d\n", ret); 309 + return ret; 310 + } 311 + 312 + led->regulator = devm_regulator_get(dev, "vin"); 313 + if (IS_ERR(led->regulator)) 314 + led->regulator = NULL; 315 + 316 + if (led->regulator) { 317 + ret = regulator_enable(led->regulator); 318 + if (ret) 319 + dev_err(dev, "Failed to enable supply: %d\n", ret); 320 + } 321 + 322 + child_node = of_get_next_available_child(np, NULL); 323 + if (!child_node) { 324 + dev_err(dev, "No DT child node found for connected LED.\n"); 325 + return -EINVAL; 326 + } 327 + 328 + led->fled_cdev.led_cdev.name = 329 + of_get_property(child_node, "label", NULL) ? : child_node->name; 330 + 331 + ret = of_property_read_u32(child_node, "led-max-microamp", 332 + &cfg->movie_max_microamp); 333 + if (ret) { 334 + dev_err(dev, "failed to parse led-max-microamp\n"); 335 + return ret; 336 + } 337 + 338 + ret = of_property_read_u32(child_node, "flash-max-microamp", 339 + &cfg->flash_max_microamp); 340 + if (ret) { 341 + dev_err(dev, "failed to parse flash-max-microamp\n"); 342 + return ret; 343 + } 344 + 345 + ret = of_property_read_u32(child_node, "flash-max-timeout-us", 346 + &cfg->flash_max_timeout); 347 + if (ret) 348 + dev_err(dev, "failed to parse flash-max-timeout-us\n"); 349 + 350 + of_node_put(child_node); 351 + return ret; 352 + } 353 + 354 + static const struct led_flash_ops flash_ops = { 355 + .strobe_set = ktd2692_led_flash_strobe_set, 356 + .timeout_set = ktd2692_led_flash_timeout_set, 357 + }; 358 + 359 + static int ktd2692_probe(struct platform_device *pdev) 360 + { 361 + struct ktd2692_context *led; 362 + struct led_classdev *led_cdev; 363 + struct led_classdev_flash *fled_cdev; 364 + struct ktd2692_led_config_data led_cfg; 365 + int ret; 366 + 367 + led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); 368 + if (!led) 369 + return -ENOMEM; 370 + 371 + fled_cdev = &led->fled_cdev; 372 + led_cdev = &fled_cdev->led_cdev; 373 + 374 + ret = ktd2692_parse_dt(led, &pdev->dev, &led_cfg); 375 + if (ret) 376 + return ret; 377 + 378 + ktd2692_init_flash_timeout(fled_cdev, &led_cfg); 379 + ktd2692_init_movie_current_max(&led_cfg); 380 + 381 + fled_cdev->ops = &flash_ops; 382 + 383 + led_cdev->max_brightness = led_cfg.max_brightness; 384 + led_cdev->brightness_set = ktd2692_led_brightness_set; 385 + led_cdev->brightness_set_sync = ktd2692_led_brightness_set_sync; 386 + led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH; 387 + 388 + mutex_init(&led->lock); 389 + INIT_WORK(&led->work_brightness_set, ktd2692_brightness_set_work); 390 + 391 + platform_set_drvdata(pdev, led); 392 + 393 + ret = led_classdev_flash_register(&pdev->dev, fled_cdev); 394 + if (ret) { 395 + dev_err(&pdev->dev, "can't register LED %s\n", led_cdev->name); 396 + mutex_destroy(&led->lock); 397 + return ret; 398 + } 399 + 400 + ktd2692_setup(led); 401 + 402 + return 0; 403 + } 404 + 405 + static int ktd2692_remove(struct platform_device *pdev) 406 + { 407 + struct ktd2692_context *led = platform_get_drvdata(pdev); 408 + int ret; 409 + 410 + led_classdev_flash_unregister(&led->fled_cdev); 411 + cancel_work_sync(&led->work_brightness_set); 412 + 413 + if (led->regulator) { 414 + ret = regulator_disable(led->regulator); 415 + if (ret) 416 + dev_err(&pdev->dev, 417 + "Failed to disable supply: %d\n", ret); 418 + } 419 + 420 + mutex_destroy(&led->lock); 421 + 422 + return 0; 423 + } 424 + 425 + static const struct of_device_id ktd2692_match[] = { 426 + { .compatible = "kinetic,ktd2692", }, 427 + { /* sentinel */ }, 428 + }; 429 + 430 + static struct platform_driver ktd2692_driver = { 431 + .driver = { 432 + .name = "ktd2692", 433 + .of_match_table = ktd2692_match, 434 + }, 435 + .probe = ktd2692_probe, 436 + .remove = ktd2692_remove, 437 + }; 438 + 439 + module_platform_driver(ktd2692_driver); 440 + 441 + MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>"); 442 + MODULE_DESCRIPTION("Kinetic KTD2692 LED driver"); 443 + MODULE_LICENSE("GPL v2");
+148
drivers/leds/leds-lp5523.c
··· 50 50 #define LP5523_REG_OP_MODE 0x01 51 51 #define LP5523_REG_ENABLE_LEDS_MSB 0x04 52 52 #define LP5523_REG_ENABLE_LEDS_LSB 0x05 53 + #define LP5523_REG_LED_CTRL_BASE 0x06 53 54 #define LP5523_REG_LED_PWM_BASE 0x16 54 55 #define LP5523_REG_LED_CURRENT_BASE 0x26 55 56 #define LP5523_REG_CONFIG 0x36 ··· 58 57 #define LP5523_REG_RESET 0x3D 59 58 #define LP5523_REG_LED_TEST_CTRL 0x41 60 59 #define LP5523_REG_LED_TEST_ADC 0x42 60 + #define LP5523_REG_MASTER_FADER_BASE 0x48 61 61 #define LP5523_REG_CH1_PROG_START 0x4C 62 62 #define LP5523_REG_CH2_PROG_START 0x4D 63 63 #define LP5523_REG_CH3_PROG_START 0x4E ··· 79 77 #define LP5523_ADC_SHORTCIRC_LIM 80 80 78 #define LP5523_EXT_CLK_USED 0x08 81 79 #define LP5523_ENG_STATUS_MASK 0x07 80 + 81 + #define LP5523_FADER_MAPPING_MASK 0xC0 82 + #define LP5523_FADER_MAPPING_SHIFT 6 82 83 83 84 /* Memory Page Selection */ 84 85 #define LP5523_PAGE_ENG1 0 ··· 671 666 return pos; 672 667 } 673 668 669 + #define show_fader(nr) \ 670 + static ssize_t show_master_fader##nr(struct device *dev, \ 671 + struct device_attribute *attr, \ 672 + char *buf) \ 673 + { \ 674 + return show_master_fader(dev, attr, buf, nr); \ 675 + } 676 + 677 + #define store_fader(nr) \ 678 + static ssize_t store_master_fader##nr(struct device *dev, \ 679 + struct device_attribute *attr, \ 680 + const char *buf, size_t len) \ 681 + { \ 682 + return store_master_fader(dev, attr, buf, len, nr); \ 683 + } 684 + 685 + static ssize_t show_master_fader(struct device *dev, 686 + struct device_attribute *attr, 687 + char *buf, int nr) 688 + { 689 + struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); 690 + struct lp55xx_chip *chip = led->chip; 691 + int ret; 692 + u8 val; 693 + 694 + mutex_lock(&chip->lock); 695 + ret = lp55xx_read(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, &val); 696 + mutex_unlock(&chip->lock); 697 + 698 + if (ret == 0) 699 + ret = sprintf(buf, "%u\n", val); 700 + 701 + return ret; 702 + } 703 + show_fader(1) 704 + show_fader(2) 705 + show_fader(3) 706 + 707 + static ssize_t store_master_fader(struct device *dev, 708 + struct device_attribute *attr, 709 + const char *buf, size_t len, int nr) 710 + { 711 + struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); 712 + struct lp55xx_chip *chip = led->chip; 713 + int ret; 714 + unsigned long val; 715 + 716 + if (kstrtoul(buf, 0, &val)) 717 + return -EINVAL; 718 + 719 + if (val > 0xff) 720 + return -EINVAL; 721 + 722 + mutex_lock(&chip->lock); 723 + ret = lp55xx_write(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, 724 + (u8)val); 725 + mutex_unlock(&chip->lock); 726 + 727 + if (ret == 0) 728 + ret = len; 729 + 730 + return ret; 731 + } 732 + store_fader(1) 733 + store_fader(2) 734 + store_fader(3) 735 + 736 + static ssize_t show_master_fader_leds(struct device *dev, 737 + struct device_attribute *attr, 738 + char *buf) 739 + { 740 + struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); 741 + struct lp55xx_chip *chip = led->chip; 742 + int i, ret, pos = 0; 743 + u8 val; 744 + 745 + mutex_lock(&chip->lock); 746 + 747 + for (i = 0; i < LP5523_MAX_LEDS; i++) { 748 + ret = lp55xx_read(chip, LP5523_REG_LED_CTRL_BASE + i, &val); 749 + if (ret) 750 + goto leave; 751 + 752 + val = (val & LP5523_FADER_MAPPING_MASK) 753 + >> LP5523_FADER_MAPPING_SHIFT; 754 + if (val > 3) { 755 + ret = -EINVAL; 756 + goto leave; 757 + } 758 + buf[pos++] = val + '0'; 759 + } 760 + buf[pos++] = '\n'; 761 + ret = pos; 762 + leave: 763 + mutex_unlock(&chip->lock); 764 + return ret; 765 + } 766 + 767 + static ssize_t store_master_fader_leds(struct device *dev, 768 + struct device_attribute *attr, 769 + const char *buf, size_t len) 770 + { 771 + struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); 772 + struct lp55xx_chip *chip = led->chip; 773 + int i, n, ret; 774 + u8 val; 775 + 776 + n = min_t(int, len, LP5523_MAX_LEDS); 777 + 778 + mutex_lock(&chip->lock); 779 + 780 + for (i = 0; i < n; i++) { 781 + if (buf[i] >= '0' && buf[i] <= '3') { 782 + val = (buf[i] - '0') << LP5523_FADER_MAPPING_SHIFT; 783 + ret = lp55xx_update_bits(chip, 784 + LP5523_REG_LED_CTRL_BASE + i, 785 + LP5523_FADER_MAPPING_MASK, 786 + val); 787 + if (ret) 788 + goto leave; 789 + } else { 790 + ret = -EINVAL; 791 + goto leave; 792 + } 793 + } 794 + ret = len; 795 + leave: 796 + mutex_unlock(&chip->lock); 797 + return ret; 798 + } 799 + 674 800 static void lp5523_led_brightness_work(struct work_struct *work) 675 801 { 676 802 struct lp55xx_led *led = container_of(work, struct lp55xx_led, ··· 824 688 static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load); 825 689 static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load); 826 690 static LP55XX_DEV_ATTR_RO(selftest, lp5523_selftest); 691 + static LP55XX_DEV_ATTR_RW(master_fader1, show_master_fader1, 692 + store_master_fader1); 693 + static LP55XX_DEV_ATTR_RW(master_fader2, show_master_fader2, 694 + store_master_fader2); 695 + static LP55XX_DEV_ATTR_RW(master_fader3, show_master_fader3, 696 + store_master_fader3); 697 + static LP55XX_DEV_ATTR_RW(master_fader_leds, show_master_fader_leds, 698 + store_master_fader_leds); 827 699 828 700 static struct attribute *lp5523_attributes[] = { 829 701 &dev_attr_engine1_mode.attr, ··· 844 700 &dev_attr_engine2_leds.attr, 845 701 &dev_attr_engine3_leds.attr, 846 702 &dev_attr_selftest.attr, 703 + &dev_attr_master_fader1.attr, 704 + &dev_attr_master_fader2.attr, 705 + &dev_attr_master_fader3.attr, 706 + &dev_attr_master_fader_leds.attr, 847 707 NULL, 848 708 }; 849 709
+1 -1
drivers/leds/leds-lp55xx-common.c
··· 223 223 const char *name = chip->cl->name; 224 224 struct device *dev = &chip->cl->dev; 225 225 226 - return request_firmware_nowait(THIS_MODULE, true, name, dev, 226 + return request_firmware_nowait(THIS_MODULE, false, name, dev, 227 227 GFP_KERNEL, chip, lp55xx_firmware_loaded); 228 228 } 229 229
+1097
drivers/leds/leds-max77693.c
··· 1 + /* 2 + * LED Flash class driver for the flash cell of max77693 mfd. 3 + * 4 + * Copyright (C) 2015, Samsung Electronics Co., Ltd. 5 + * 6 + * Authors: Jacek Anaszewski <j.anaszewski@samsung.com> 7 + * Andrzej Hajda <a.hajda@samsung.com> 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * version 2 as published by the Free Software Foundation. 12 + */ 13 + 14 + #include <linux/led-class-flash.h> 15 + #include <linux/mfd/max77693.h> 16 + #include <linux/mfd/max77693-private.h> 17 + #include <linux/module.h> 18 + #include <linux/mutex.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/regmap.h> 21 + #include <linux/slab.h> 22 + #include <linux/workqueue.h> 23 + #include <media/v4l2-flash-led-class.h> 24 + 25 + #define MODE_OFF 0 26 + #define MODE_FLASH(a) (1 << (a)) 27 + #define MODE_TORCH(a) (1 << (2 + (a))) 28 + #define MODE_FLASH_EXTERNAL(a) (1 << (4 + (a))) 29 + 30 + #define MODE_FLASH_MASK (MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \ 31 + MODE_FLASH_EXTERNAL(FLED1) | \ 32 + MODE_FLASH_EXTERNAL(FLED2)) 33 + #define MODE_TORCH_MASK (MODE_TORCH(FLED1) | MODE_TORCH(FLED2)) 34 + 35 + #define FLED1_IOUT (1 << 0) 36 + #define FLED2_IOUT (1 << 1) 37 + 38 + enum max77693_fled { 39 + FLED1, 40 + FLED2, 41 + }; 42 + 43 + enum max77693_led_mode { 44 + FLASH, 45 + TORCH, 46 + }; 47 + 48 + struct max77693_led_config_data { 49 + const char *label[2]; 50 + u32 iout_torch_max[2]; 51 + u32 iout_flash_max[2]; 52 + u32 flash_timeout_max[2]; 53 + u32 num_leds; 54 + u32 boost_mode; 55 + u32 boost_vout; 56 + u32 low_vsys; 57 + }; 58 + 59 + struct max77693_sub_led { 60 + /* corresponding FLED output identifier */ 61 + int fled_id; 62 + /* corresponding LED Flash class device */ 63 + struct led_classdev_flash fled_cdev; 64 + /* assures led-triggers compatibility */ 65 + struct work_struct work_brightness_set; 66 + /* V4L2 Flash device */ 67 + struct v4l2_flash *v4l2_flash; 68 + 69 + /* brightness cache */ 70 + unsigned int torch_brightness; 71 + /* flash timeout cache */ 72 + unsigned int flash_timeout; 73 + /* flash faults that may have occurred */ 74 + u32 flash_faults; 75 + }; 76 + 77 + struct max77693_led_device { 78 + /* parent mfd regmap */ 79 + struct regmap *regmap; 80 + /* platform device data */ 81 + struct platform_device *pdev; 82 + /* secures access to the device */ 83 + struct mutex lock; 84 + 85 + /* sub led data */ 86 + struct max77693_sub_led sub_leds[2]; 87 + 88 + /* maximum torch current values for FLED outputs */ 89 + u32 iout_torch_max[2]; 90 + /* maximum flash current values for FLED outputs */ 91 + u32 iout_flash_max[2]; 92 + 93 + /* current flash timeout cache */ 94 + unsigned int current_flash_timeout; 95 + /* ITORCH register cache */ 96 + u8 torch_iout_reg; 97 + /* mode of fled outputs */ 98 + unsigned int mode_flags; 99 + /* recently strobed fled */ 100 + int strobing_sub_led_id; 101 + /* bitmask of FLED outputs use state (bit 0. - FLED1, bit 1. - FLED2) */ 102 + u8 fled_mask; 103 + /* FLED modes that can be set */ 104 + u8 allowed_modes; 105 + 106 + /* arrangement of current outputs */ 107 + bool iout_joint; 108 + }; 109 + 110 + static u8 max77693_led_iout_to_reg(u32 ua) 111 + { 112 + if (ua < FLASH_IOUT_MIN) 113 + ua = FLASH_IOUT_MIN; 114 + return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP; 115 + } 116 + 117 + static u8 max77693_flash_timeout_to_reg(u32 us) 118 + { 119 + return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP; 120 + } 121 + 122 + static inline struct max77693_sub_led *flcdev_to_sub_led( 123 + struct led_classdev_flash *fled_cdev) 124 + { 125 + return container_of(fled_cdev, struct max77693_sub_led, fled_cdev); 126 + } 127 + 128 + static inline struct max77693_led_device *sub_led_to_led( 129 + struct max77693_sub_led *sub_led) 130 + { 131 + return container_of(sub_led, struct max77693_led_device, 132 + sub_leds[sub_led->fled_id]); 133 + } 134 + 135 + static inline u8 max77693_led_vsys_to_reg(u32 mv) 136 + { 137 + return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2; 138 + } 139 + 140 + static inline u8 max77693_led_vout_to_reg(u32 mv) 141 + { 142 + return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN; 143 + } 144 + 145 + static inline bool max77693_fled_used(struct max77693_led_device *led, 146 + int fled_id) 147 + { 148 + u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT; 149 + 150 + return led->fled_mask & fled_bit; 151 + } 152 + 153 + static int max77693_set_mode_reg(struct max77693_led_device *led, u8 mode) 154 + { 155 + struct regmap *rmap = led->regmap; 156 + int ret, v = 0, i; 157 + 158 + for (i = FLED1; i <= FLED2; ++i) { 159 + if (mode & MODE_TORCH(i)) 160 + v |= FLASH_EN_ON << TORCH_EN_SHIFT(i); 161 + 162 + if (mode & MODE_FLASH(i)) { 163 + v |= FLASH_EN_ON << FLASH_EN_SHIFT(i); 164 + } else if (mode & MODE_FLASH_EXTERNAL(i)) { 165 + v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i); 166 + /* 167 + * Enable hw triggering also for torch mode, as some 168 + * camera sensors use torch led to fathom ambient light 169 + * conditions before strobing the flash. 170 + */ 171 + v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i); 172 + } 173 + } 174 + 175 + /* Reset the register only prior setting flash modes */ 176 + if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) { 177 + ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0); 178 + if (ret < 0) 179 + return ret; 180 + } 181 + 182 + return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v); 183 + } 184 + 185 + static int max77693_add_mode(struct max77693_led_device *led, u8 mode) 186 + { 187 + u8 new_mode_flags; 188 + int i, ret; 189 + 190 + if (led->iout_joint) 191 + /* Span the mode on FLED2 for joint iouts case */ 192 + mode |= (mode << 1); 193 + 194 + /* 195 + * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device. 196 + * Corresponding register bit fields interfere with SW triggered modes, 197 + * thus clear them to ensure proper device configuration. 198 + */ 199 + for (i = FLED1; i <= FLED2; ++i) 200 + if (mode & MODE_FLASH_EXTERNAL(i)) 201 + led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i)); 202 + 203 + new_mode_flags = mode | led->mode_flags; 204 + new_mode_flags &= led->allowed_modes; 205 + 206 + if (new_mode_flags ^ led->mode_flags) 207 + led->mode_flags = new_mode_flags; 208 + else 209 + return 0; 210 + 211 + ret = max77693_set_mode_reg(led, led->mode_flags); 212 + if (ret < 0) 213 + return ret; 214 + 215 + /* 216 + * Clear flash mode flag after setting the mode to avoid spurious flash 217 + * strobing on each subsequent torch mode setting. 218 + */ 219 + if (mode & MODE_FLASH_MASK) 220 + led->mode_flags &= ~mode; 221 + 222 + return ret; 223 + } 224 + 225 + static int max77693_clear_mode(struct max77693_led_device *led, 226 + u8 mode) 227 + { 228 + if (led->iout_joint) 229 + /* Clear mode also on FLED2 for joint iouts case */ 230 + mode |= (mode << 1); 231 + 232 + led->mode_flags &= ~mode; 233 + 234 + return max77693_set_mode_reg(led, led->mode_flags); 235 + } 236 + 237 + static void max77693_add_allowed_modes(struct max77693_led_device *led, 238 + int fled_id, enum max77693_led_mode mode) 239 + { 240 + if (mode == FLASH) 241 + led->allowed_modes |= (MODE_FLASH(fled_id) | 242 + MODE_FLASH_EXTERNAL(fled_id)); 243 + else 244 + led->allowed_modes |= MODE_TORCH(fled_id); 245 + } 246 + 247 + static void max77693_distribute_currents(struct max77693_led_device *led, 248 + int fled_id, enum max77693_led_mode mode, 249 + u32 micro_amp, u32 iout_max[2], u32 iout[2]) 250 + { 251 + if (!led->iout_joint) { 252 + iout[fled_id] = micro_amp; 253 + max77693_add_allowed_modes(led, fled_id, mode); 254 + return; 255 + } 256 + 257 + iout[FLED1] = min(micro_amp, iout_max[FLED1]); 258 + iout[FLED2] = micro_amp - iout[FLED1]; 259 + 260 + if (mode == FLASH) 261 + led->allowed_modes &= ~MODE_FLASH_MASK; 262 + else 263 + led->allowed_modes &= ~MODE_TORCH_MASK; 264 + 265 + max77693_add_allowed_modes(led, FLED1, mode); 266 + 267 + if (iout[FLED2]) 268 + max77693_add_allowed_modes(led, FLED2, mode); 269 + } 270 + 271 + static int max77693_set_torch_current(struct max77693_led_device *led, 272 + int fled_id, u32 micro_amp) 273 + { 274 + struct regmap *rmap = led->regmap; 275 + u8 iout1_reg = 0, iout2_reg = 0; 276 + u32 iout[2]; 277 + 278 + max77693_distribute_currents(led, fled_id, TORCH, micro_amp, 279 + led->iout_torch_max, iout); 280 + 281 + if (fled_id == FLED1 || led->iout_joint) { 282 + iout1_reg = max77693_led_iout_to_reg(iout[FLED1]); 283 + led->torch_iout_reg &= TORCH_IOUT_MASK(TORCH_IOUT2_SHIFT); 284 + } 285 + if (fled_id == FLED2 || led->iout_joint) { 286 + iout2_reg = max77693_led_iout_to_reg(iout[FLED2]); 287 + led->torch_iout_reg &= TORCH_IOUT_MASK(TORCH_IOUT1_SHIFT); 288 + } 289 + 290 + led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) | 291 + (iout2_reg << TORCH_IOUT2_SHIFT)); 292 + 293 + return regmap_write(rmap, MAX77693_LED_REG_ITORCH, 294 + led->torch_iout_reg); 295 + } 296 + 297 + static int max77693_set_flash_current(struct max77693_led_device *led, 298 + int fled_id, 299 + u32 micro_amp) 300 + { 301 + struct regmap *rmap = led->regmap; 302 + u8 iout1_reg, iout2_reg; 303 + u32 iout[2]; 304 + int ret = -EINVAL; 305 + 306 + max77693_distribute_currents(led, fled_id, FLASH, micro_amp, 307 + led->iout_flash_max, iout); 308 + 309 + if (fled_id == FLED1 || led->iout_joint) { 310 + iout1_reg = max77693_led_iout_to_reg(iout[FLED1]); 311 + ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1, 312 + iout1_reg); 313 + if (ret < 0) 314 + return ret; 315 + } 316 + if (fled_id == FLED2 || led->iout_joint) { 317 + iout2_reg = max77693_led_iout_to_reg(iout[FLED2]); 318 + ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2, 319 + iout2_reg); 320 + } 321 + 322 + return ret; 323 + } 324 + 325 + static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec) 326 + { 327 + struct regmap *rmap = led->regmap; 328 + u8 v; 329 + int ret; 330 + 331 + v = max77693_flash_timeout_to_reg(microsec) | FLASH_TMR_LEVEL; 332 + 333 + ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v); 334 + if (ret < 0) 335 + return ret; 336 + 337 + led->current_flash_timeout = microsec; 338 + 339 + return 0; 340 + } 341 + 342 + static int max77693_get_strobe_status(struct max77693_led_device *led, 343 + bool *state) 344 + { 345 + struct regmap *rmap = led->regmap; 346 + unsigned int v; 347 + int ret; 348 + 349 + ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v); 350 + if (ret < 0) 351 + return ret; 352 + 353 + *state = v & FLASH_STATUS_FLASH_ON; 354 + 355 + return ret; 356 + } 357 + 358 + static int max77693_get_flash_faults(struct max77693_sub_led *sub_led) 359 + { 360 + struct max77693_led_device *led = sub_led_to_led(sub_led); 361 + struct regmap *rmap = led->regmap; 362 + unsigned int v; 363 + u8 fault_open_mask, fault_short_mask; 364 + int ret; 365 + 366 + sub_led->flash_faults = 0; 367 + 368 + if (led->iout_joint) { 369 + fault_open_mask = FLASH_INT_FLED1_OPEN | FLASH_INT_FLED2_OPEN; 370 + fault_short_mask = FLASH_INT_FLED1_SHORT | 371 + FLASH_INT_FLED2_SHORT; 372 + } else { 373 + fault_open_mask = (sub_led->fled_id == FLED1) ? 374 + FLASH_INT_FLED1_OPEN : 375 + FLASH_INT_FLED2_OPEN; 376 + fault_short_mask = (sub_led->fled_id == FLED1) ? 377 + FLASH_INT_FLED1_SHORT : 378 + FLASH_INT_FLED2_SHORT; 379 + } 380 + 381 + ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, &v); 382 + if (ret < 0) 383 + return ret; 384 + 385 + if (v & fault_open_mask) 386 + sub_led->flash_faults |= LED_FAULT_OVER_VOLTAGE; 387 + if (v & fault_short_mask) 388 + sub_led->flash_faults |= LED_FAULT_SHORT_CIRCUIT; 389 + if (v & FLASH_INT_OVER_CURRENT) 390 + sub_led->flash_faults |= LED_FAULT_OVER_CURRENT; 391 + 392 + return 0; 393 + } 394 + 395 + static int max77693_setup(struct max77693_led_device *led, 396 + struct max77693_led_config_data *led_cfg) 397 + { 398 + struct regmap *rmap = led->regmap; 399 + int i, first_led, last_led, ret; 400 + u32 max_flash_curr[2]; 401 + u8 v; 402 + 403 + /* 404 + * Initialize only flash current. Torch current doesn't 405 + * require initialization as ITORCH register is written with 406 + * new value each time brightness_set op is called. 407 + */ 408 + if (led->iout_joint) { 409 + first_led = FLED1; 410 + last_led = FLED1; 411 + max_flash_curr[FLED1] = led_cfg->iout_flash_max[FLED1] + 412 + led_cfg->iout_flash_max[FLED2]; 413 + } else { 414 + first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2; 415 + last_led = max77693_fled_used(led, FLED2) ? FLED2 : FLED1; 416 + max_flash_curr[FLED1] = led_cfg->iout_flash_max[FLED1]; 417 + max_flash_curr[FLED2] = led_cfg->iout_flash_max[FLED2]; 418 + } 419 + 420 + for (i = first_led; i <= last_led; ++i) { 421 + ret = max77693_set_flash_current(led, i, 422 + max_flash_curr[i]); 423 + if (ret < 0) 424 + return ret; 425 + } 426 + 427 + v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL; 428 + ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v); 429 + if (ret < 0) 430 + return ret; 431 + 432 + if (led_cfg->low_vsys > 0) 433 + v = max77693_led_vsys_to_reg(led_cfg->low_vsys) | 434 + MAX_FLASH1_MAX_FL_EN; 435 + else 436 + v = 0; 437 + 438 + ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v); 439 + if (ret < 0) 440 + return ret; 441 + ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0); 442 + if (ret < 0) 443 + return ret; 444 + 445 + if (led_cfg->boost_mode == MAX77693_LED_BOOST_FIXED) 446 + v = FLASH_BOOST_FIXED; 447 + else 448 + v = led_cfg->boost_mode | led_cfg->boost_mode << 1; 449 + 450 + if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2)) 451 + v |= FLASH_BOOST_LEDNUM_2; 452 + 453 + ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v); 454 + if (ret < 0) 455 + return ret; 456 + 457 + v = max77693_led_vout_to_reg(led_cfg->boost_vout); 458 + ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v); 459 + if (ret < 0) 460 + return ret; 461 + 462 + return max77693_set_mode_reg(led, MODE_OFF); 463 + } 464 + 465 + static int __max77693_led_brightness_set(struct max77693_led_device *led, 466 + int fled_id, enum led_brightness value) 467 + { 468 + int ret; 469 + 470 + mutex_lock(&led->lock); 471 + 472 + if (value == 0) { 473 + ret = max77693_clear_mode(led, MODE_TORCH(fled_id)); 474 + if (ret < 0) 475 + dev_dbg(&led->pdev->dev, 476 + "Failed to clear torch mode (%d)\n", 477 + ret); 478 + goto unlock; 479 + } 480 + 481 + ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP); 482 + if (ret < 0) { 483 + dev_dbg(&led->pdev->dev, 484 + "Failed to set torch current (%d)\n", 485 + ret); 486 + goto unlock; 487 + } 488 + 489 + ret = max77693_add_mode(led, MODE_TORCH(fled_id)); 490 + if (ret < 0) 491 + dev_dbg(&led->pdev->dev, 492 + "Failed to set torch mode (%d)\n", 493 + ret); 494 + unlock: 495 + mutex_unlock(&led->lock); 496 + return ret; 497 + } 498 + 499 + static void max77693_led_brightness_set_work( 500 + struct work_struct *work) 501 + { 502 + struct max77693_sub_led *sub_led = 503 + container_of(work, struct max77693_sub_led, 504 + work_brightness_set); 505 + struct max77693_led_device *led = sub_led_to_led(sub_led); 506 + 507 + __max77693_led_brightness_set(led, sub_led->fled_id, 508 + sub_led->torch_brightness); 509 + } 510 + 511 + /* LED subsystem callbacks */ 512 + 513 + static int max77693_led_brightness_set_sync( 514 + struct led_classdev *led_cdev, 515 + enum led_brightness value) 516 + { 517 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 518 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 519 + struct max77693_led_device *led = sub_led_to_led(sub_led); 520 + 521 + return __max77693_led_brightness_set(led, sub_led->fled_id, value); 522 + } 523 + 524 + static void max77693_led_brightness_set( 525 + struct led_classdev *led_cdev, 526 + enum led_brightness value) 527 + { 528 + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 529 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 530 + 531 + sub_led->torch_brightness = value; 532 + schedule_work(&sub_led->work_brightness_set); 533 + } 534 + 535 + static int max77693_led_flash_brightness_set( 536 + struct led_classdev_flash *fled_cdev, 537 + u32 brightness) 538 + { 539 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 540 + struct max77693_led_device *led = sub_led_to_led(sub_led); 541 + int ret; 542 + 543 + mutex_lock(&led->lock); 544 + ret = max77693_set_flash_current(led, sub_led->fled_id, brightness); 545 + mutex_unlock(&led->lock); 546 + 547 + return ret; 548 + } 549 + 550 + static int max77693_led_flash_strobe_set( 551 + struct led_classdev_flash *fled_cdev, 552 + bool state) 553 + { 554 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 555 + struct max77693_led_device *led = sub_led_to_led(sub_led); 556 + int fled_id = sub_led->fled_id; 557 + int ret; 558 + 559 + mutex_lock(&led->lock); 560 + 561 + if (!state) { 562 + ret = max77693_clear_mode(led, MODE_FLASH(fled_id)); 563 + goto unlock; 564 + } 565 + 566 + if (sub_led->flash_timeout != led->current_flash_timeout) { 567 + ret = max77693_set_timeout(led, sub_led->flash_timeout); 568 + if (ret < 0) 569 + goto unlock; 570 + } 571 + 572 + led->strobing_sub_led_id = fled_id; 573 + 574 + ret = max77693_add_mode(led, MODE_FLASH(fled_id)); 575 + if (ret < 0) 576 + goto unlock; 577 + 578 + ret = max77693_get_flash_faults(sub_led); 579 + 580 + unlock: 581 + mutex_unlock(&led->lock); 582 + return ret; 583 + } 584 + 585 + static int max77693_led_flash_fault_get( 586 + struct led_classdev_flash *fled_cdev, 587 + u32 *fault) 588 + { 589 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 590 + 591 + *fault = sub_led->flash_faults; 592 + 593 + return 0; 594 + } 595 + 596 + static int max77693_led_flash_strobe_get( 597 + struct led_classdev_flash *fled_cdev, 598 + bool *state) 599 + { 600 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 601 + struct max77693_led_device *led = sub_led_to_led(sub_led); 602 + int ret; 603 + 604 + if (!state) 605 + return -EINVAL; 606 + 607 + mutex_lock(&led->lock); 608 + 609 + ret = max77693_get_strobe_status(led, state); 610 + 611 + *state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id)); 612 + 613 + mutex_unlock(&led->lock); 614 + 615 + return ret; 616 + } 617 + 618 + static int max77693_led_flash_timeout_set( 619 + struct led_classdev_flash *fled_cdev, 620 + u32 timeout) 621 + { 622 + struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev); 623 + struct max77693_led_device *led = sub_led_to_led(sub_led); 624 + 625 + mutex_lock(&led->lock); 626 + sub_led->flash_timeout = timeout; 627 + mutex_unlock(&led->lock); 628 + 629 + return 0; 630 + } 631 + 632 + static int max77693_led_parse_dt(struct max77693_led_device *led, 633 + struct max77693_led_config_data *cfg, 634 + struct device_node **sub_nodes) 635 + { 636 + struct device *dev = &led->pdev->dev; 637 + struct max77693_sub_led *sub_leds = led->sub_leds; 638 + struct device_node *node = dev->of_node, *child_node; 639 + struct property *prop; 640 + u32 led_sources[2]; 641 + int i, ret, fled_id; 642 + 643 + of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode); 644 + of_property_read_u32(node, "maxim,boost-mvout", &cfg->boost_vout); 645 + of_property_read_u32(node, "maxim,mvsys-min", &cfg->low_vsys); 646 + 647 + for_each_available_child_of_node(node, child_node) { 648 + prop = of_find_property(child_node, "led-sources", NULL); 649 + if (prop) { 650 + const __be32 *srcs = NULL; 651 + 652 + for (i = 0; i < ARRAY_SIZE(led_sources); ++i) { 653 + srcs = of_prop_next_u32(prop, srcs, 654 + &led_sources[i]); 655 + if (!srcs) 656 + break; 657 + } 658 + } else { 659 + dev_err(dev, 660 + "led-sources DT property missing\n"); 661 + of_node_put(child_node); 662 + return -EINVAL; 663 + } 664 + 665 + if (i == 2) { 666 + fled_id = FLED1; 667 + led->fled_mask = FLED1_IOUT | FLED2_IOUT; 668 + } else if (led_sources[0] == FLED1) { 669 + fled_id = FLED1; 670 + led->fled_mask |= FLED1_IOUT; 671 + } else if (led_sources[0] == FLED2) { 672 + fled_id = FLED2; 673 + led->fled_mask |= FLED2_IOUT; 674 + } else { 675 + dev_err(dev, 676 + "Wrong led-sources DT property value.\n"); 677 + of_node_put(child_node); 678 + return -EINVAL; 679 + } 680 + 681 + if (sub_nodes[fled_id]) { 682 + dev_err(dev, 683 + "Conflicting \"led-sources\" DT properties\n"); 684 + return -EINVAL; 685 + } 686 + 687 + sub_nodes[fled_id] = child_node; 688 + sub_leds[fled_id].fled_id = fled_id; 689 + 690 + cfg->label[fled_id] = 691 + of_get_property(child_node, "label", NULL) ? : 692 + child_node->name; 693 + 694 + ret = of_property_read_u32(child_node, "led-max-microamp", 695 + &cfg->iout_torch_max[fled_id]); 696 + if (ret < 0) { 697 + cfg->iout_torch_max[fled_id] = TORCH_IOUT_MIN; 698 + dev_warn(dev, "led-max-microamp DT property missing\n"); 699 + } 700 + 701 + ret = of_property_read_u32(child_node, "flash-max-microamp", 702 + &cfg->iout_flash_max[fled_id]); 703 + if (ret < 0) { 704 + cfg->iout_flash_max[fled_id] = FLASH_IOUT_MIN; 705 + dev_warn(dev, 706 + "flash-max-microamp DT property missing\n"); 707 + } 708 + 709 + ret = of_property_read_u32(child_node, "flash-max-timeout-us", 710 + &cfg->flash_timeout_max[fled_id]); 711 + if (ret < 0) { 712 + cfg->flash_timeout_max[fled_id] = FLASH_TIMEOUT_MIN; 713 + dev_warn(dev, 714 + "flash-max-timeout-us DT property missing\n"); 715 + } 716 + 717 + if (++cfg->num_leds == 2 || 718 + (max77693_fled_used(led, FLED1) && 719 + max77693_fled_used(led, FLED2))) { 720 + of_node_put(child_node); 721 + break; 722 + } 723 + } 724 + 725 + if (cfg->num_leds == 0) { 726 + dev_err(dev, "No DT child node found for connected LED(s).\n"); 727 + return -EINVAL; 728 + } 729 + 730 + return 0; 731 + } 732 + 733 + static void clamp_align(u32 *v, u32 min, u32 max, u32 step) 734 + { 735 + *v = clamp_val(*v, min, max); 736 + if (step > 1) 737 + *v = (*v - min) / step * step + min; 738 + } 739 + 740 + static void max77693_align_iout_current(struct max77693_led_device *led, 741 + u32 *iout, u32 min, u32 max, u32 step) 742 + { 743 + int i; 744 + 745 + if (led->iout_joint) { 746 + if (iout[FLED1] > min) { 747 + iout[FLED1] /= 2; 748 + iout[FLED2] = iout[FLED1]; 749 + } else { 750 + iout[FLED1] = min; 751 + iout[FLED2] = 0; 752 + return; 753 + } 754 + } 755 + 756 + for (i = FLED1; i <= FLED2; ++i) 757 + if (max77693_fled_used(led, i)) 758 + clamp_align(&iout[i], min, max, step); 759 + else 760 + iout[i] = 0; 761 + } 762 + 763 + static void max77693_led_validate_configuration(struct max77693_led_device *led, 764 + struct max77693_led_config_data *cfg) 765 + { 766 + u32 flash_iout_max = cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS : 767 + FLASH_IOUT_MAX_1LED; 768 + int i; 769 + 770 + if (cfg->num_leds == 1 && 771 + max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2)) 772 + led->iout_joint = true; 773 + 774 + cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE, 775 + MAX77693_LED_BOOST_FIXED); 776 + 777 + /* Boost must be enabled if both current outputs are used */ 778 + if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint) 779 + cfg->boost_mode = MAX77693_LED_BOOST_FIXED; 780 + 781 + max77693_align_iout_current(led, cfg->iout_torch_max, 782 + TORCH_IOUT_MIN, TORCH_IOUT_MAX, TORCH_IOUT_STEP); 783 + 784 + max77693_align_iout_current(led, cfg->iout_flash_max, 785 + FLASH_IOUT_MIN, flash_iout_max, FLASH_IOUT_STEP); 786 + 787 + for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout_max); ++i) 788 + clamp_align(&cfg->flash_timeout_max[i], FLASH_TIMEOUT_MIN, 789 + FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP); 790 + 791 + clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX, 792 + FLASH_VOUT_STEP); 793 + 794 + if (cfg->low_vsys) 795 + clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN, 796 + MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP); 797 + } 798 + 799 + static int max77693_led_get_configuration(struct max77693_led_device *led, 800 + struct max77693_led_config_data *cfg, 801 + struct device_node **sub_nodes) 802 + { 803 + int ret; 804 + 805 + ret = max77693_led_parse_dt(led, cfg, sub_nodes); 806 + if (ret < 0) 807 + return ret; 808 + 809 + max77693_led_validate_configuration(led, cfg); 810 + 811 + memcpy(led->iout_torch_max, cfg->iout_torch_max, 812 + sizeof(led->iout_torch_max)); 813 + memcpy(led->iout_flash_max, cfg->iout_flash_max, 814 + sizeof(led->iout_flash_max)); 815 + 816 + return 0; 817 + } 818 + 819 + static const struct led_flash_ops flash_ops = { 820 + .flash_brightness_set = max77693_led_flash_brightness_set, 821 + .strobe_set = max77693_led_flash_strobe_set, 822 + .strobe_get = max77693_led_flash_strobe_get, 823 + .timeout_set = max77693_led_flash_timeout_set, 824 + .fault_get = max77693_led_flash_fault_get, 825 + }; 826 + 827 + static void max77693_init_flash_settings(struct max77693_sub_led *sub_led, 828 + struct max77693_led_config_data *led_cfg) 829 + { 830 + struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev; 831 + struct max77693_led_device *led = sub_led_to_led(sub_led); 832 + int fled_id = sub_led->fled_id; 833 + struct led_flash_setting *setting; 834 + 835 + /* Init flash intensity setting */ 836 + setting = &fled_cdev->brightness; 837 + setting->min = FLASH_IOUT_MIN; 838 + setting->max = led->iout_joint ? 839 + led_cfg->iout_flash_max[FLED1] + 840 + led_cfg->iout_flash_max[FLED2] : 841 + led_cfg->iout_flash_max[fled_id]; 842 + setting->step = FLASH_IOUT_STEP; 843 + setting->val = setting->max; 844 + 845 + /* Init flash timeout setting */ 846 + setting = &fled_cdev->timeout; 847 + setting->min = FLASH_TIMEOUT_MIN; 848 + setting->max = led_cfg->flash_timeout_max[fled_id]; 849 + setting->step = FLASH_TIMEOUT_STEP; 850 + setting->val = setting->max; 851 + } 852 + 853 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 854 + 855 + static int max77693_led_external_strobe_set( 856 + struct v4l2_flash *v4l2_flash, 857 + bool enable) 858 + { 859 + struct max77693_sub_led *sub_led = 860 + flcdev_to_sub_led(v4l2_flash->fled_cdev); 861 + struct max77693_led_device *led = sub_led_to_led(sub_led); 862 + int fled_id = sub_led->fled_id; 863 + int ret; 864 + 865 + mutex_lock(&led->lock); 866 + 867 + if (enable) 868 + ret = max77693_add_mode(led, MODE_FLASH_EXTERNAL(fled_id)); 869 + else 870 + ret = max77693_clear_mode(led, MODE_FLASH_EXTERNAL(fled_id)); 871 + 872 + mutex_unlock(&led->lock); 873 + 874 + return ret; 875 + } 876 + 877 + static void max77693_init_v4l2_flash_config(struct max77693_sub_led *sub_led, 878 + struct max77693_led_config_data *led_cfg, 879 + struct v4l2_flash_config *v4l2_sd_cfg) 880 + { 881 + struct max77693_led_device *led = sub_led_to_led(sub_led); 882 + struct device *dev = &led->pdev->dev; 883 + struct max77693_dev *iodev = dev_get_drvdata(dev->parent); 884 + struct i2c_client *i2c = iodev->i2c; 885 + struct led_flash_setting *s; 886 + 887 + snprintf(v4l2_sd_cfg->dev_name, sizeof(v4l2_sd_cfg->dev_name), 888 + "%s %d-%04x", sub_led->fled_cdev.led_cdev.name, 889 + i2c_adapter_id(i2c->adapter), i2c->addr); 890 + 891 + s = &v4l2_sd_cfg->torch_intensity; 892 + s->min = TORCH_IOUT_MIN; 893 + s->max = sub_led->fled_cdev.led_cdev.max_brightness * TORCH_IOUT_STEP; 894 + s->step = TORCH_IOUT_STEP; 895 + s->val = s->max; 896 + 897 + /* Init flash faults config */ 898 + v4l2_sd_cfg->flash_faults = LED_FAULT_OVER_VOLTAGE | 899 + LED_FAULT_SHORT_CIRCUIT | 900 + LED_FAULT_OVER_CURRENT; 901 + 902 + v4l2_sd_cfg->has_external_strobe = true; 903 + } 904 + 905 + static const struct v4l2_flash_ops v4l2_flash_ops = { 906 + .external_strobe_set = max77693_led_external_strobe_set, 907 + }; 908 + #else 909 + static inline void max77693_init_v4l2_flash_config( 910 + struct max77693_sub_led *sub_led, 911 + struct max77693_led_config_data *led_cfg, 912 + struct v4l2_flash_config *v4l2_sd_cfg) 913 + { 914 + } 915 + static const struct v4l2_flash_ops v4l2_flash_ops; 916 + #endif 917 + 918 + static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led, 919 + struct max77693_led_config_data *led_cfg) 920 + { 921 + struct max77693_led_device *led = sub_led_to_led(sub_led); 922 + int fled_id = sub_led->fled_id; 923 + struct led_classdev_flash *fled_cdev; 924 + struct led_classdev *led_cdev; 925 + 926 + /* Initialize LED Flash class device */ 927 + fled_cdev = &sub_led->fled_cdev; 928 + fled_cdev->ops = &flash_ops; 929 + led_cdev = &fled_cdev->led_cdev; 930 + 931 + led_cdev->name = led_cfg->label[fled_id]; 932 + 933 + led_cdev->brightness_set = max77693_led_brightness_set; 934 + led_cdev->brightness_set_sync = max77693_led_brightness_set_sync; 935 + led_cdev->max_brightness = (led->iout_joint ? 936 + led_cfg->iout_torch_max[FLED1] + 937 + led_cfg->iout_torch_max[FLED2] : 938 + led_cfg->iout_torch_max[fled_id]) / 939 + TORCH_IOUT_STEP; 940 + led_cdev->flags |= LED_DEV_CAP_FLASH; 941 + INIT_WORK(&sub_led->work_brightness_set, 942 + max77693_led_brightness_set_work); 943 + 944 + max77693_init_flash_settings(sub_led, led_cfg); 945 + 946 + /* Init flash timeout cache */ 947 + sub_led->flash_timeout = fled_cdev->timeout.val; 948 + } 949 + 950 + static int max77693_register_led(struct max77693_sub_led *sub_led, 951 + struct max77693_led_config_data *led_cfg, 952 + struct device_node *sub_node) 953 + { 954 + struct max77693_led_device *led = sub_led_to_led(sub_led); 955 + struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev; 956 + struct device *dev = &led->pdev->dev; 957 + struct v4l2_flash_config v4l2_sd_cfg = {}; 958 + int ret; 959 + 960 + /* Register in the LED subsystem */ 961 + ret = led_classdev_flash_register(dev, fled_cdev); 962 + if (ret < 0) 963 + return ret; 964 + 965 + max77693_init_v4l2_flash_config(sub_led, led_cfg, &v4l2_sd_cfg); 966 + 967 + /* Register in the V4L2 subsystem. */ 968 + sub_led->v4l2_flash = v4l2_flash_init(dev, sub_node, fled_cdev, NULL, 969 + &v4l2_flash_ops, &v4l2_sd_cfg); 970 + if (IS_ERR(sub_led->v4l2_flash)) { 971 + ret = PTR_ERR(sub_led->v4l2_flash); 972 + goto err_v4l2_flash_init; 973 + } 974 + 975 + return 0; 976 + 977 + err_v4l2_flash_init: 978 + led_classdev_flash_unregister(fled_cdev); 979 + return ret; 980 + } 981 + 982 + static int max77693_led_probe(struct platform_device *pdev) 983 + { 984 + struct device *dev = &pdev->dev; 985 + struct max77693_dev *iodev = dev_get_drvdata(dev->parent); 986 + struct max77693_led_device *led; 987 + struct max77693_sub_led *sub_leds; 988 + struct device_node *sub_nodes[2] = {}; 989 + struct max77693_led_config_data led_cfg = {}; 990 + int init_fled_cdev[2], i, ret; 991 + 992 + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); 993 + if (!led) 994 + return -ENOMEM; 995 + 996 + led->pdev = pdev; 997 + led->regmap = iodev->regmap; 998 + led->allowed_modes = MODE_FLASH_MASK; 999 + sub_leds = led->sub_leds; 1000 + 1001 + platform_set_drvdata(pdev, led); 1002 + ret = max77693_led_get_configuration(led, &led_cfg, sub_nodes); 1003 + if (ret < 0) 1004 + return ret; 1005 + 1006 + ret = max77693_setup(led, &led_cfg); 1007 + if (ret < 0) 1008 + return ret; 1009 + 1010 + mutex_init(&led->lock); 1011 + 1012 + init_fled_cdev[FLED1] = 1013 + led->iout_joint || max77693_fled_used(led, FLED1); 1014 + init_fled_cdev[FLED2] = 1015 + !led->iout_joint && max77693_fled_used(led, FLED2); 1016 + 1017 + for (i = FLED1; i <= FLED2; ++i) { 1018 + if (!init_fled_cdev[i]) 1019 + continue; 1020 + 1021 + /* Initialize LED Flash class device */ 1022 + max77693_init_fled_cdev(&sub_leds[i], &led_cfg); 1023 + 1024 + /* 1025 + * Register LED Flash class device and corresponding 1026 + * V4L2 Flash device. 1027 + */ 1028 + ret = max77693_register_led(&sub_leds[i], &led_cfg, 1029 + sub_nodes[i]); 1030 + if (ret < 0) { 1031 + /* 1032 + * At this moment FLED1 might have been already 1033 + * registered and it needs to be released. 1034 + */ 1035 + if (i == FLED2) 1036 + goto err_register_led2; 1037 + else 1038 + goto err_register_led1; 1039 + } 1040 + } 1041 + 1042 + return 0; 1043 + 1044 + err_register_led2: 1045 + /* It is possible than only FLED2 was to be registered */ 1046 + if (!init_fled_cdev[FLED1]) 1047 + goto err_register_led1; 1048 + v4l2_flash_release(sub_leds[FLED1].v4l2_flash); 1049 + led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev); 1050 + err_register_led1: 1051 + mutex_destroy(&led->lock); 1052 + 1053 + return ret; 1054 + } 1055 + 1056 + static int max77693_led_remove(struct platform_device *pdev) 1057 + { 1058 + struct max77693_led_device *led = platform_get_drvdata(pdev); 1059 + struct max77693_sub_led *sub_leds = led->sub_leds; 1060 + 1061 + if (led->iout_joint || max77693_fled_used(led, FLED1)) { 1062 + v4l2_flash_release(sub_leds[FLED1].v4l2_flash); 1063 + led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev); 1064 + cancel_work_sync(&sub_leds[FLED1].work_brightness_set); 1065 + } 1066 + 1067 + if (!led->iout_joint && max77693_fled_used(led, FLED2)) { 1068 + v4l2_flash_release(sub_leds[FLED2].v4l2_flash); 1069 + led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev); 1070 + cancel_work_sync(&sub_leds[FLED2].work_brightness_set); 1071 + } 1072 + 1073 + mutex_destroy(&led->lock); 1074 + 1075 + return 0; 1076 + } 1077 + 1078 + static const struct of_device_id max77693_led_dt_match[] = { 1079 + { .compatible = "maxim,max77693-led" }, 1080 + {}, 1081 + }; 1082 + 1083 + static struct platform_driver max77693_led_driver = { 1084 + .probe = max77693_led_probe, 1085 + .remove = max77693_led_remove, 1086 + .driver = { 1087 + .name = "max77693-led", 1088 + .of_match_table = max77693_led_dt_match, 1089 + }, 1090 + }; 1091 + 1092 + module_platform_driver(max77693_led_driver); 1093 + 1094 + MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); 1095 + MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); 1096 + MODULE_DESCRIPTION("Maxim MAX77693 led flash driver"); 1097 + MODULE_LICENSE("GPL v2");
+300
drivers/leds/leds-tlc591xx.c
··· 1 + /* 2 + * Copyright 2014 Belkin Inc. 3 + * Copyright 2015 Andrew Lunn <andrew@lunn.ch> 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; version 2 of the License. 8 + */ 9 + 10 + #include <linux/i2c.h> 11 + #include <linux/leds.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_device.h> 15 + #include <linux/regmap.h> 16 + #include <linux/slab.h> 17 + #include <linux/workqueue.h> 18 + 19 + #define TLC591XX_MAX_LEDS 16 20 + 21 + #define TLC591XX_REG_MODE1 0x00 22 + #define MODE1_RESPON_ADDR_MASK 0xF0 23 + #define MODE1_NORMAL_MODE (0 << 4) 24 + #define MODE1_SPEED_MODE (1 << 4) 25 + 26 + #define TLC591XX_REG_MODE2 0x01 27 + #define MODE2_DIM (0 << 5) 28 + #define MODE2_BLINK (1 << 5) 29 + #define MODE2_OCH_STOP (0 << 3) 30 + #define MODE2_OCH_ACK (1 << 3) 31 + 32 + #define TLC591XX_REG_PWM(x) (0x02 + (x)) 33 + 34 + #define TLC591XX_REG_GRPPWM 0x12 35 + #define TLC591XX_REG_GRPFREQ 0x13 36 + 37 + /* LED Driver Output State, determine the source that drives LED outputs */ 38 + #define LEDOUT_OFF 0x0 /* Output LOW */ 39 + #define LEDOUT_ON 0x1 /* Output HI-Z */ 40 + #define LEDOUT_DIM 0x2 /* Dimming */ 41 + #define LEDOUT_BLINK 0x3 /* Blinking */ 42 + #define LEDOUT_MASK 0x3 43 + 44 + #define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev) 45 + #define work_to_led(work) container_of(work, struct tlc591xx_led, work) 46 + 47 + struct tlc591xx_led { 48 + bool active; 49 + unsigned int led_no; 50 + struct led_classdev ldev; 51 + struct work_struct work; 52 + struct tlc591xx_priv *priv; 53 + }; 54 + 55 + struct tlc591xx_priv { 56 + struct tlc591xx_led leds[TLC591XX_MAX_LEDS]; 57 + struct regmap *regmap; 58 + unsigned int reg_ledout_offset; 59 + }; 60 + 61 + struct tlc591xx { 62 + unsigned int max_leds; 63 + unsigned int reg_ledout_offset; 64 + }; 65 + 66 + static const struct tlc591xx tlc59116 = { 67 + .max_leds = 16, 68 + .reg_ledout_offset = 0x14, 69 + }; 70 + 71 + static const struct tlc591xx tlc59108 = { 72 + .max_leds = 8, 73 + .reg_ledout_offset = 0x0c, 74 + }; 75 + 76 + static int 77 + tlc591xx_set_mode(struct regmap *regmap, u8 mode) 78 + { 79 + int err; 80 + u8 val; 81 + 82 + err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE); 83 + if (err) 84 + return err; 85 + 86 + val = MODE2_OCH_STOP | mode; 87 + 88 + return regmap_write(regmap, TLC591XX_REG_MODE2, val); 89 + } 90 + 91 + static int 92 + tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led, 93 + u8 val) 94 + { 95 + unsigned int i = (led->led_no % 4) * 2; 96 + unsigned int mask = LEDOUT_MASK << i; 97 + unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2); 98 + 99 + val = val << i; 100 + 101 + return regmap_update_bits(priv->regmap, addr, mask, val); 102 + } 103 + 104 + static int 105 + tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led, 106 + u8 brightness) 107 + { 108 + u8 pwm = TLC591XX_REG_PWM(led->led_no); 109 + 110 + return regmap_write(priv->regmap, pwm, brightness); 111 + } 112 + 113 + static void 114 + tlc591xx_led_work(struct work_struct *work) 115 + { 116 + struct tlc591xx_led *led = work_to_led(work); 117 + struct tlc591xx_priv *priv = led->priv; 118 + enum led_brightness brightness = led->ldev.brightness; 119 + int err; 120 + 121 + switch (brightness) { 122 + case 0: 123 + err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF); 124 + break; 125 + case LED_FULL: 126 + err = tlc591xx_set_ledout(priv, led, LEDOUT_ON); 127 + break; 128 + default: 129 + err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM); 130 + if (!err) 131 + err = tlc591xx_set_pwm(priv, led, brightness); 132 + } 133 + 134 + if (err) 135 + dev_err(led->ldev.dev, "Failed setting brightness\n"); 136 + } 137 + 138 + static void 139 + tlc591xx_brightness_set(struct led_classdev *led_cdev, 140 + enum led_brightness brightness) 141 + { 142 + struct tlc591xx_led *led = ldev_to_led(led_cdev); 143 + 144 + led->ldev.brightness = brightness; 145 + schedule_work(&led->work); 146 + } 147 + 148 + static void 149 + tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j) 150 + { 151 + int i = j; 152 + 153 + while (--i >= 0) { 154 + if (priv->leds[i].active) { 155 + led_classdev_unregister(&priv->leds[i].ldev); 156 + cancel_work_sync(&priv->leds[i].work); 157 + } 158 + } 159 + } 160 + 161 + static int 162 + tlc591xx_configure(struct device *dev, 163 + struct tlc591xx_priv *priv, 164 + const struct tlc591xx *tlc591xx) 165 + { 166 + unsigned int i; 167 + int err = 0; 168 + 169 + tlc591xx_set_mode(priv->regmap, MODE2_DIM); 170 + for (i = 0; i < TLC591XX_MAX_LEDS; i++) { 171 + struct tlc591xx_led *led = &priv->leds[i]; 172 + 173 + if (!led->active) 174 + continue; 175 + 176 + led->priv = priv; 177 + led->led_no = i; 178 + led->ldev.brightness_set = tlc591xx_brightness_set; 179 + led->ldev.max_brightness = LED_FULL; 180 + INIT_WORK(&led->work, tlc591xx_led_work); 181 + err = led_classdev_register(dev, &led->ldev); 182 + if (err < 0) { 183 + dev_err(dev, "couldn't register LED %s\n", 184 + led->ldev.name); 185 + goto exit; 186 + } 187 + } 188 + 189 + return 0; 190 + 191 + exit: 192 + tlc591xx_destroy_devices(priv, i); 193 + return err; 194 + } 195 + 196 + static const struct regmap_config tlc591xx_regmap = { 197 + .reg_bits = 8, 198 + .val_bits = 8, 199 + .max_register = 0x1e, 200 + }; 201 + 202 + static const struct of_device_id of_tlc591xx_leds_match[] = { 203 + { .compatible = "ti,tlc59116", 204 + .data = &tlc59116 }, 205 + { .compatible = "ti,tlc59108", 206 + .data = &tlc59108 }, 207 + {}, 208 + }; 209 + MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match); 210 + 211 + static int 212 + tlc591xx_probe(struct i2c_client *client, 213 + const struct i2c_device_id *id) 214 + { 215 + struct device_node *np = client->dev.of_node, *child; 216 + struct device *dev = &client->dev; 217 + const struct of_device_id *match; 218 + const struct tlc591xx *tlc591xx; 219 + struct tlc591xx_priv *priv; 220 + int err, count, reg; 221 + 222 + match = of_match_device(of_tlc591xx_leds_match, dev); 223 + if (!match) 224 + return -ENODEV; 225 + 226 + tlc591xx = match->data; 227 + if (!np) 228 + return -ENODEV; 229 + 230 + count = of_get_child_count(np); 231 + if (!count || count > tlc591xx->max_leds) 232 + return -EINVAL; 233 + 234 + if (!i2c_check_functionality(client->adapter, 235 + I2C_FUNC_SMBUS_BYTE_DATA)) 236 + return -EIO; 237 + 238 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 239 + if (!priv) 240 + return -ENOMEM; 241 + 242 + priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap); 243 + if (IS_ERR(priv->regmap)) { 244 + err = PTR_ERR(priv->regmap); 245 + dev_err(dev, "Failed to allocate register map: %d\n", err); 246 + return err; 247 + } 248 + priv->reg_ledout_offset = tlc591xx->reg_ledout_offset; 249 + 250 + i2c_set_clientdata(client, priv); 251 + 252 + for_each_child_of_node(np, child) { 253 + err = of_property_read_u32(child, "reg", &reg); 254 + if (err) 255 + return err; 256 + if (reg < 0 || reg >= tlc591xx->max_leds) 257 + return -EINVAL; 258 + if (priv->leds[reg].active) 259 + return -EINVAL; 260 + priv->leds[reg].active = true; 261 + priv->leds[reg].ldev.name = 262 + of_get_property(child, "label", NULL) ? : child->name; 263 + priv->leds[reg].ldev.default_trigger = 264 + of_get_property(child, "linux,default-trigger", NULL); 265 + } 266 + return tlc591xx_configure(dev, priv, tlc591xx); 267 + } 268 + 269 + static int 270 + tlc591xx_remove(struct i2c_client *client) 271 + { 272 + struct tlc591xx_priv *priv = i2c_get_clientdata(client); 273 + 274 + tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS); 275 + 276 + return 0; 277 + } 278 + 279 + static const struct i2c_device_id tlc591xx_id[] = { 280 + { "tlc59116" }, 281 + { "tlc59108" }, 282 + {}, 283 + }; 284 + MODULE_DEVICE_TABLE(i2c, tlc591xx_id); 285 + 286 + static struct i2c_driver tlc591xx_driver = { 287 + .driver = { 288 + .name = "tlc591xx", 289 + .of_match_table = of_match_ptr(of_tlc591xx_leds_match), 290 + }, 291 + .probe = tlc591xx_probe, 292 + .remove = tlc591xx_remove, 293 + .id_table = tlc591xx_id, 294 + }; 295 + 296 + module_i2c_driver(tlc591xx_driver); 297 + 298 + MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 299 + MODULE_LICENSE("GPL"); 300 + MODULE_DESCRIPTION("TLC591XX LED driver");
-24
drivers/leds/leds.h
··· 13 13 #ifndef __LEDS_H_INCLUDED 14 14 #define __LEDS_H_INCLUDED 15 15 16 - #include <linux/device.h> 17 16 #include <linux/rwsem.h> 18 17 #include <linux/leds.h> 19 18 ··· 48 49 49 50 extern struct rw_semaphore leds_list_lock; 50 51 extern struct list_head leds_list; 51 - 52 - #ifdef CONFIG_LEDS_TRIGGERS 53 - void led_trigger_set_default(struct led_classdev *led_cdev); 54 - void led_trigger_set(struct led_classdev *led_cdev, 55 - struct led_trigger *trigger); 56 - void led_trigger_remove(struct led_classdev *led_cdev); 57 - 58 - static inline void *led_get_trigger_data(struct led_classdev *led_cdev) 59 - { 60 - return led_cdev->trigger_data; 61 - } 62 - 63 - #else 64 - #define led_trigger_set_default(x) do {} while (0) 65 - #define led_trigger_set(x, y) do {} while (0) 66 - #define led_trigger_remove(x) do {} while (0) 67 - #define led_get_trigger_data(x) (NULL) 68 - #endif 69 - 70 - ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, 71 - const char *buf, size_t count); 72 - ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, 73 - char *buf); 74 52 75 53 #endif /* __LEDS_H_INCLUDED */
+11
drivers/media/v4l2-core/Kconfig
··· 44 44 tristate 45 45 depends on VIDEOBUF2_CORE 46 46 47 + # Used by LED subsystem flash drivers 48 + config V4L2_FLASH_LED_CLASS 49 + tristate "V4L2 flash API for LED flash class devices" 50 + depends on VIDEO_V4L2_SUBDEV_API 51 + depends on LEDS_CLASS_FLASH 52 + ---help--- 53 + Say Y here to enable V4L2 flash API support for LED flash 54 + class drivers. 55 + 56 + When in doubt, say N. 57 + 47 58 # Used by drivers that need Videobuf modules 48 59 config VIDEOBUF_GEN 49 60 tristate
+2
drivers/media/v4l2-core/Makefile
··· 22 22 23 23 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o 24 24 25 + obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o 26 + 25 27 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o 26 28 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o 27 29 obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
+27 -12
drivers/media/v4l2-core/v4l2-async.c
··· 22 22 #include <media/v4l2-device.h> 23 23 #include <media/v4l2-subdev.h> 24 24 25 - static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd) 25 + static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) 26 26 { 27 27 #if IS_ENABLED(CONFIG_I2C) 28 - struct i2c_client *client = i2c_verify_client(dev); 28 + struct i2c_client *client = i2c_verify_client(sd->dev); 29 29 return client && 30 30 asd->match.i2c.adapter_id == client->adapter->nr && 31 31 asd->match.i2c.address == client->addr; ··· 34 34 #endif 35 35 } 36 36 37 - static bool match_devname(struct device *dev, struct v4l2_async_subdev *asd) 37 + static bool match_devname(struct v4l2_subdev *sd, 38 + struct v4l2_async_subdev *asd) 38 39 { 39 - return !strcmp(asd->match.device_name.name, dev_name(dev)); 40 + return !strcmp(asd->match.device_name.name, dev_name(sd->dev)); 40 41 } 41 42 42 - static bool match_of(struct device *dev, struct v4l2_async_subdev *asd) 43 + static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) 43 44 { 44 - return dev->of_node == asd->match.of.node; 45 + return sd->of_node == asd->match.of.node; 46 + } 47 + 48 + static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) 49 + { 50 + if (!asd->match.custom.match) 51 + /* Match always */ 52 + return true; 53 + 54 + return asd->match.custom.match(sd->dev, asd); 45 55 } 46 56 47 57 static LIST_HEAD(subdev_list); ··· 61 51 static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier, 62 52 struct v4l2_subdev *sd) 63 53 { 54 + bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *); 64 55 struct v4l2_async_subdev *asd; 65 - bool (*match)(struct device *, struct v4l2_async_subdev *); 66 56 67 57 list_for_each_entry(asd, &notifier->waiting, list) { 68 58 /* bus_type has been verified valid before */ 69 59 switch (asd->match_type) { 70 60 case V4L2_ASYNC_MATCH_CUSTOM: 71 - match = asd->match.custom.match; 72 - if (!match) 73 - /* Match always */ 74 - return asd; 61 + match = match_custom; 75 62 break; 76 63 case V4L2_ASYNC_MATCH_DEVNAME: 77 64 match = match_devname; ··· 86 79 } 87 80 88 81 /* match cannot be NULL here */ 89 - if (match(sd->dev, asd)) 82 + if (match(sd, asd)) 90 83 return asd; 91 84 } 92 85 ··· 272 265 int v4l2_async_register_subdev(struct v4l2_subdev *sd) 273 266 { 274 267 struct v4l2_async_notifier *notifier; 268 + 269 + /* 270 + * No reference taken. The reference is held by the device 271 + * (struct v4l2_subdev.dev), and async sub-device does not 272 + * exist independently of the device at any point of time. 273 + */ 274 + if (!sd->of_node && sd->dev) 275 + sd->of_node = sd->dev->of_node; 275 276 276 277 mutex_lock(&list_lock); 277 278
+710
drivers/media/v4l2-core/v4l2-flash-led-class.c
··· 1 + /* 2 + * V4L2 flash LED sub-device registration helpers. 3 + * 4 + * Copyright (C) 2015 Samsung Electronics Co., Ltd 5 + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/led-class-flash.h> 13 + #include <linux/module.h> 14 + #include <linux/mutex.h> 15 + #include <linux/of.h> 16 + #include <linux/slab.h> 17 + #include <linux/types.h> 18 + #include <media/v4l2-flash-led-class.h> 19 + 20 + #define has_flash_op(v4l2_flash, op) \ 21 + (v4l2_flash && v4l2_flash->ops->op) 22 + 23 + #define call_flash_op(v4l2_flash, op, arg) \ 24 + (has_flash_op(v4l2_flash, op) ? \ 25 + v4l2_flash->ops->op(v4l2_flash, arg) : \ 26 + -EINVAL) 27 + 28 + enum ctrl_init_data_id { 29 + LED_MODE, 30 + TORCH_INTENSITY, 31 + FLASH_INTENSITY, 32 + INDICATOR_INTENSITY, 33 + FLASH_TIMEOUT, 34 + STROBE_SOURCE, 35 + /* 36 + * Only above values are applicable to 37 + * the 'ctrls' array in the struct v4l2_flash. 38 + */ 39 + FLASH_STROBE, 40 + STROBE_STOP, 41 + STROBE_STATUS, 42 + FLASH_FAULT, 43 + NUM_FLASH_CTRLS, 44 + }; 45 + 46 + static enum led_brightness __intensity_to_led_brightness( 47 + struct v4l2_ctrl *ctrl, s32 intensity) 48 + { 49 + intensity -= ctrl->minimum; 50 + intensity /= (u32) ctrl->step; 51 + 52 + /* 53 + * Indicator LEDs, unlike torch LEDs, are turned on/off basing on 54 + * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only. 55 + * Therefore it must be possible to set it to 0 level which in 56 + * the LED subsystem reflects LED_OFF state. 57 + */ 58 + if (ctrl->minimum) 59 + ++intensity; 60 + 61 + return intensity; 62 + } 63 + 64 + static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl, 65 + enum led_brightness brightness) 66 + { 67 + /* 68 + * Indicator LEDs, unlike torch LEDs, are turned on/off basing on 69 + * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only. 70 + * Do not decrement brightness read from the LED subsystem for 71 + * indicator LED as it may equal 0. For torch LEDs this function 72 + * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the 73 + * brightness read is guaranteed to be greater than 0. In the mode 74 + * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used. 75 + */ 76 + if (ctrl->id != V4L2_CID_FLASH_INDICATOR_INTENSITY) 77 + --brightness; 78 + 79 + return (brightness * ctrl->step) + ctrl->minimum; 80 + } 81 + 82 + static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, 83 + struct v4l2_ctrl *ctrl) 84 + { 85 + struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; 86 + enum led_brightness brightness; 87 + 88 + if (has_flash_op(v4l2_flash, intensity_to_led_brightness)) 89 + brightness = call_flash_op(v4l2_flash, 90 + intensity_to_led_brightness, 91 + ctrl->val); 92 + else 93 + brightness = __intensity_to_led_brightness(ctrl, ctrl->val); 94 + /* 95 + * In case a LED Flash class driver provides ops for custom 96 + * brightness <-> intensity conversion, it also must have defined 97 + * related v4l2 control step == 1. In such a case a backward conversion 98 + * from led brightness to v4l2 intensity is required to find out the 99 + * the aligned intensity value. 100 + */ 101 + if (has_flash_op(v4l2_flash, led_brightness_to_intensity)) 102 + ctrl->val = call_flash_op(v4l2_flash, 103 + led_brightness_to_intensity, 104 + brightness); 105 + 106 + if (ctrl == ctrls[TORCH_INTENSITY]) { 107 + if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) 108 + return; 109 + 110 + led_set_brightness(&v4l2_flash->fled_cdev->led_cdev, 111 + brightness); 112 + } else { 113 + led_set_brightness(&v4l2_flash->iled_cdev->led_cdev, 114 + brightness); 115 + } 116 + } 117 + 118 + static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, 119 + struct v4l2_ctrl *ctrl) 120 + { 121 + struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; 122 + struct led_classdev *led_cdev; 123 + int ret; 124 + 125 + if (ctrl == ctrls[TORCH_INTENSITY]) { 126 + /* 127 + * Update torch brightness only if in TORCH_MODE. In other modes 128 + * torch led is turned off, which would spuriously inform the 129 + * user space that V4L2_CID_FLASH_TORCH_INTENSITY control value 130 + * has changed to 0. 131 + */ 132 + if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) 133 + return 0; 134 + led_cdev = &v4l2_flash->fled_cdev->led_cdev; 135 + } else { 136 + led_cdev = &v4l2_flash->iled_cdev->led_cdev; 137 + } 138 + 139 + ret = led_update_brightness(led_cdev); 140 + if (ret < 0) 141 + return ret; 142 + 143 + if (has_flash_op(v4l2_flash, led_brightness_to_intensity)) 144 + ctrl->val = call_flash_op(v4l2_flash, 145 + led_brightness_to_intensity, 146 + led_cdev->brightness); 147 + else 148 + ctrl->val = __led_brightness_to_intensity(ctrl, 149 + led_cdev->brightness); 150 + 151 + return 0; 152 + } 153 + 154 + static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c) 155 + { 156 + struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c); 157 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 158 + bool is_strobing; 159 + int ret; 160 + 161 + switch (c->id) { 162 + case V4L2_CID_FLASH_TORCH_INTENSITY: 163 + case V4L2_CID_FLASH_INDICATOR_INTENSITY: 164 + return v4l2_flash_update_led_brightness(v4l2_flash, c); 165 + case V4L2_CID_FLASH_INTENSITY: 166 + ret = led_update_flash_brightness(fled_cdev); 167 + if (ret < 0) 168 + return ret; 169 + /* 170 + * No conversion is needed as LED Flash class also uses 171 + * microamperes for flash intensity units. 172 + */ 173 + c->val = fled_cdev->brightness.val; 174 + return 0; 175 + case V4L2_CID_FLASH_STROBE_STATUS: 176 + ret = led_get_flash_strobe(fled_cdev, &is_strobing); 177 + if (ret < 0) 178 + return ret; 179 + c->val = is_strobing; 180 + return 0; 181 + case V4L2_CID_FLASH_FAULT: 182 + /* LED faults map directly to V4L2 flash faults */ 183 + return led_get_flash_fault(fled_cdev, &c->val); 184 + default: 185 + return -EINVAL; 186 + } 187 + } 188 + 189 + static bool __software_strobe_mode_inactive(struct v4l2_ctrl **ctrls) 190 + { 191 + return ((ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH) || 192 + (ctrls[STROBE_SOURCE] && (ctrls[STROBE_SOURCE]->val != 193 + V4L2_FLASH_STROBE_SOURCE_SOFTWARE))); 194 + } 195 + 196 + static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) 197 + { 198 + struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c); 199 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 200 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 201 + struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; 202 + bool external_strobe; 203 + int ret = 0; 204 + 205 + switch (c->id) { 206 + case V4L2_CID_FLASH_LED_MODE: 207 + switch (c->val) { 208 + case V4L2_FLASH_LED_MODE_NONE: 209 + led_set_brightness(led_cdev, LED_OFF); 210 + return led_set_flash_strobe(fled_cdev, false); 211 + case V4L2_FLASH_LED_MODE_FLASH: 212 + /* Turn the torch LED off */ 213 + led_set_brightness(led_cdev, LED_OFF); 214 + if (ctrls[STROBE_SOURCE]) { 215 + external_strobe = (ctrls[STROBE_SOURCE]->val == 216 + V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 217 + 218 + ret = call_flash_op(v4l2_flash, 219 + external_strobe_set, 220 + external_strobe); 221 + } 222 + return ret; 223 + case V4L2_FLASH_LED_MODE_TORCH: 224 + if (ctrls[STROBE_SOURCE]) { 225 + ret = call_flash_op(v4l2_flash, 226 + external_strobe_set, 227 + false); 228 + if (ret < 0) 229 + return ret; 230 + } 231 + /* Stop flash strobing */ 232 + ret = led_set_flash_strobe(fled_cdev, false); 233 + if (ret < 0) 234 + return ret; 235 + 236 + v4l2_flash_set_led_brightness(v4l2_flash, 237 + ctrls[TORCH_INTENSITY]); 238 + return 0; 239 + } 240 + break; 241 + case V4L2_CID_FLASH_STROBE_SOURCE: 242 + external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 243 + /* 244 + * For some hardware arrangements setting strobe source may 245 + * affect torch mode. Therefore, if not in the flash mode, 246 + * cache only this setting. It will be applied upon switching 247 + * to flash mode. 248 + */ 249 + if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH) 250 + return 0; 251 + 252 + return call_flash_op(v4l2_flash, external_strobe_set, 253 + external_strobe); 254 + case V4L2_CID_FLASH_STROBE: 255 + if (__software_strobe_mode_inactive(ctrls)) 256 + return -EBUSY; 257 + return led_set_flash_strobe(fled_cdev, true); 258 + case V4L2_CID_FLASH_STROBE_STOP: 259 + if (__software_strobe_mode_inactive(ctrls)) 260 + return -EBUSY; 261 + return led_set_flash_strobe(fled_cdev, false); 262 + case V4L2_CID_FLASH_TIMEOUT: 263 + /* 264 + * No conversion is needed as LED Flash class also uses 265 + * microseconds for flash timeout units. 266 + */ 267 + return led_set_flash_timeout(fled_cdev, c->val); 268 + case V4L2_CID_FLASH_INTENSITY: 269 + /* 270 + * No conversion is needed as LED Flash class also uses 271 + * microamperes for flash intensity units. 272 + */ 273 + return led_set_flash_brightness(fled_cdev, c->val); 274 + case V4L2_CID_FLASH_TORCH_INTENSITY: 275 + case V4L2_CID_FLASH_INDICATOR_INTENSITY: 276 + v4l2_flash_set_led_brightness(v4l2_flash, c); 277 + return 0; 278 + } 279 + 280 + return -EINVAL; 281 + } 282 + 283 + static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = { 284 + .g_volatile_ctrl = v4l2_flash_g_volatile_ctrl, 285 + .s_ctrl = v4l2_flash_s_ctrl, 286 + }; 287 + 288 + static void __lfs_to_v4l2_ctrl_config(struct led_flash_setting *s, 289 + struct v4l2_ctrl_config *c) 290 + { 291 + c->min = s->min; 292 + c->max = s->max; 293 + c->step = s->step; 294 + c->def = s->val; 295 + } 296 + 297 + static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, 298 + struct v4l2_flash_config *flash_cfg, 299 + struct v4l2_flash_ctrl_data *ctrl_init_data) 300 + { 301 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 302 + const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops; 303 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 304 + struct v4l2_ctrl_config *ctrl_cfg; 305 + u32 mask; 306 + 307 + /* Init FLASH_FAULT ctrl data */ 308 + if (flash_cfg->flash_faults) { 309 + ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT; 310 + ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config; 311 + ctrl_cfg->id = V4L2_CID_FLASH_FAULT; 312 + ctrl_cfg->max = flash_cfg->flash_faults; 313 + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 314 + V4L2_CTRL_FLAG_READ_ONLY; 315 + } 316 + 317 + /* Init FLASH_LED_MODE ctrl data */ 318 + mask = 1 << V4L2_FLASH_LED_MODE_NONE | 319 + 1 << V4L2_FLASH_LED_MODE_TORCH; 320 + if (led_cdev->flags & LED_DEV_CAP_FLASH) 321 + mask |= 1 << V4L2_FLASH_LED_MODE_FLASH; 322 + 323 + ctrl_init_data[LED_MODE].cid = V4L2_CID_FLASH_LED_MODE; 324 + ctrl_cfg = &ctrl_init_data[LED_MODE].config; 325 + ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE; 326 + ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH; 327 + ctrl_cfg->menu_skip_mask = ~mask; 328 + ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE; 329 + ctrl_cfg->flags = 0; 330 + 331 + /* Init TORCH_INTENSITY ctrl data */ 332 + ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY; 333 + ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config; 334 + __lfs_to_v4l2_ctrl_config(&flash_cfg->torch_intensity, ctrl_cfg); 335 + ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY; 336 + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 337 + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 338 + 339 + /* Init INDICATOR_INTENSITY ctrl data */ 340 + if (v4l2_flash->iled_cdev) { 341 + ctrl_init_data[INDICATOR_INTENSITY].cid = 342 + V4L2_CID_FLASH_INDICATOR_INTENSITY; 343 + ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config; 344 + __lfs_to_v4l2_ctrl_config(&flash_cfg->indicator_intensity, 345 + ctrl_cfg); 346 + ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY; 347 + ctrl_cfg->min = 0; 348 + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 349 + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 350 + } 351 + 352 + if (!(led_cdev->flags & LED_DEV_CAP_FLASH)) 353 + return; 354 + 355 + /* Init FLASH_STROBE ctrl data */ 356 + ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE; 357 + ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config; 358 + ctrl_cfg->id = V4L2_CID_FLASH_STROBE; 359 + 360 + /* Init STROBE_STOP ctrl data */ 361 + ctrl_init_data[STROBE_STOP].cid = V4L2_CID_FLASH_STROBE_STOP; 362 + ctrl_cfg = &ctrl_init_data[STROBE_STOP].config; 363 + ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP; 364 + 365 + /* Init FLASH_STROBE_SOURCE ctrl data */ 366 + if (flash_cfg->has_external_strobe) { 367 + mask = (1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE) | 368 + (1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL); 369 + ctrl_init_data[STROBE_SOURCE].cid = 370 + V4L2_CID_FLASH_STROBE_SOURCE; 371 + ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config; 372 + ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE; 373 + ctrl_cfg->max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; 374 + ctrl_cfg->menu_skip_mask = ~mask; 375 + ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; 376 + } 377 + 378 + /* Init STROBE_STATUS ctrl data */ 379 + if (fled_cdev_ops->strobe_get) { 380 + ctrl_init_data[STROBE_STATUS].cid = 381 + V4L2_CID_FLASH_STROBE_STATUS; 382 + ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config; 383 + ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS; 384 + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 385 + V4L2_CTRL_FLAG_READ_ONLY; 386 + } 387 + 388 + /* Init FLASH_TIMEOUT ctrl data */ 389 + if (fled_cdev_ops->timeout_set) { 390 + ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT; 391 + ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config; 392 + __lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg); 393 + ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT; 394 + } 395 + 396 + /* Init FLASH_INTENSITY ctrl data */ 397 + if (fled_cdev_ops->flash_brightness_set) { 398 + ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY; 399 + ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config; 400 + __lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg); 401 + ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY; 402 + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | 403 + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; 404 + } 405 + } 406 + 407 + static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash, 408 + struct v4l2_flash_config *flash_cfg) 409 + 410 + { 411 + struct v4l2_flash_ctrl_data *ctrl_init_data; 412 + struct v4l2_ctrl *ctrl; 413 + struct v4l2_ctrl_config *ctrl_cfg; 414 + int i, ret, num_ctrls = 0; 415 + 416 + v4l2_flash->ctrls = devm_kzalloc(v4l2_flash->sd.dev, 417 + sizeof(*v4l2_flash->ctrls) * 418 + (STROBE_SOURCE + 1), GFP_KERNEL); 419 + if (!v4l2_flash->ctrls) 420 + return -ENOMEM; 421 + 422 + /* allocate memory dynamically so as not to exceed stack frame size */ 423 + ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data), 424 + GFP_KERNEL); 425 + if (!ctrl_init_data) 426 + return -ENOMEM; 427 + 428 + __fill_ctrl_init_data(v4l2_flash, flash_cfg, ctrl_init_data); 429 + 430 + for (i = 0; i < NUM_FLASH_CTRLS; ++i) 431 + if (ctrl_init_data[i].cid) 432 + ++num_ctrls; 433 + 434 + v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls); 435 + 436 + for (i = 0; i < NUM_FLASH_CTRLS; ++i) { 437 + ctrl_cfg = &ctrl_init_data[i].config; 438 + if (!ctrl_init_data[i].cid) 439 + continue; 440 + 441 + if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE || 442 + ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE) 443 + ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl, 444 + &v4l2_flash_ctrl_ops, 445 + ctrl_cfg->id, 446 + ctrl_cfg->max, 447 + ctrl_cfg->menu_skip_mask, 448 + ctrl_cfg->def); 449 + else 450 + ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, 451 + &v4l2_flash_ctrl_ops, 452 + ctrl_cfg->id, 453 + ctrl_cfg->min, 454 + ctrl_cfg->max, 455 + ctrl_cfg->step, 456 + ctrl_cfg->def); 457 + 458 + if (ctrl) 459 + ctrl->flags |= ctrl_cfg->flags; 460 + 461 + if (i <= STROBE_SOURCE) 462 + v4l2_flash->ctrls[i] = ctrl; 463 + } 464 + 465 + kfree(ctrl_init_data); 466 + 467 + if (v4l2_flash->hdl.error) { 468 + ret = v4l2_flash->hdl.error; 469 + goto error_free_handler; 470 + } 471 + 472 + v4l2_ctrl_handler_setup(&v4l2_flash->hdl); 473 + 474 + v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl; 475 + 476 + return 0; 477 + 478 + error_free_handler: 479 + v4l2_ctrl_handler_free(&v4l2_flash->hdl); 480 + return ret; 481 + } 482 + 483 + static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) 484 + { 485 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 486 + struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; 487 + int ret = 0; 488 + 489 + v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]); 490 + 491 + if (ctrls[INDICATOR_INTENSITY]) 492 + v4l2_flash_set_led_brightness(v4l2_flash, 493 + ctrls[INDICATOR_INTENSITY]); 494 + 495 + if (ctrls[FLASH_TIMEOUT]) { 496 + ret = led_set_flash_timeout(fled_cdev, 497 + ctrls[FLASH_TIMEOUT]->val); 498 + if (ret < 0) 499 + return ret; 500 + } 501 + 502 + if (ctrls[FLASH_INTENSITY]) { 503 + ret = led_set_flash_brightness(fled_cdev, 504 + ctrls[FLASH_INTENSITY]->val); 505 + if (ret < 0) 506 + return ret; 507 + } 508 + 509 + /* 510 + * For some hardware arrangements setting strobe source may affect 511 + * torch mode. Synchronize strobe source setting only if not in torch 512 + * mode. For torch mode case it will get synchronized upon switching 513 + * to flash mode. 514 + */ 515 + if (ctrls[STROBE_SOURCE] && 516 + ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) 517 + ret = call_flash_op(v4l2_flash, external_strobe_set, 518 + ctrls[STROBE_SOURCE]->val); 519 + 520 + return ret; 521 + } 522 + 523 + /* 524 + * V4L2 subdev internal operations 525 + */ 526 + 527 + static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 528 + { 529 + struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 530 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 531 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 532 + struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; 533 + struct led_classdev *led_cdev_ind = NULL; 534 + int ret = 0; 535 + 536 + if (!v4l2_fh_is_singular(&fh->vfh)) 537 + return 0; 538 + 539 + mutex_lock(&led_cdev->led_access); 540 + 541 + led_sysfs_disable(led_cdev); 542 + led_trigger_remove(led_cdev); 543 + 544 + mutex_unlock(&led_cdev->led_access); 545 + 546 + if (iled_cdev) { 547 + led_cdev_ind = &iled_cdev->led_cdev; 548 + 549 + mutex_lock(&led_cdev_ind->led_access); 550 + 551 + led_sysfs_disable(led_cdev_ind); 552 + led_trigger_remove(led_cdev_ind); 553 + 554 + mutex_unlock(&led_cdev_ind->led_access); 555 + } 556 + 557 + ret = __sync_device_with_v4l2_controls(v4l2_flash); 558 + if (ret < 0) 559 + goto out_sync_device; 560 + 561 + return 0; 562 + out_sync_device: 563 + mutex_lock(&led_cdev->led_access); 564 + led_sysfs_enable(led_cdev); 565 + mutex_unlock(&led_cdev->led_access); 566 + 567 + if (led_cdev_ind) { 568 + mutex_lock(&led_cdev_ind->led_access); 569 + led_sysfs_enable(led_cdev_ind); 570 + mutex_unlock(&led_cdev_ind->led_access); 571 + } 572 + 573 + return ret; 574 + } 575 + 576 + static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 577 + { 578 + struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); 579 + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; 580 + struct led_classdev *led_cdev = &fled_cdev->led_cdev; 581 + struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; 582 + int ret = 0; 583 + 584 + if (!v4l2_fh_is_singular(&fh->vfh)) 585 + return 0; 586 + 587 + mutex_lock(&led_cdev->led_access); 588 + 589 + if (v4l2_flash->ctrls[STROBE_SOURCE]) 590 + ret = v4l2_ctrl_s_ctrl(v4l2_flash->ctrls[STROBE_SOURCE], 591 + V4L2_FLASH_STROBE_SOURCE_SOFTWARE); 592 + led_sysfs_enable(led_cdev); 593 + 594 + mutex_unlock(&led_cdev->led_access); 595 + 596 + if (iled_cdev) { 597 + struct led_classdev *led_cdev_ind = &iled_cdev->led_cdev; 598 + 599 + mutex_lock(&led_cdev_ind->led_access); 600 + led_sysfs_enable(led_cdev_ind); 601 + mutex_unlock(&led_cdev_ind->led_access); 602 + } 603 + 604 + return ret; 605 + } 606 + 607 + static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = { 608 + .open = v4l2_flash_open, 609 + .close = v4l2_flash_close, 610 + }; 611 + 612 + static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = { 613 + .queryctrl = v4l2_subdev_queryctrl, 614 + .querymenu = v4l2_subdev_querymenu, 615 + }; 616 + 617 + static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = { 618 + .core = &v4l2_flash_core_ops, 619 + }; 620 + 621 + struct v4l2_flash *v4l2_flash_init( 622 + struct device *dev, struct device_node *of_node, 623 + struct led_classdev_flash *fled_cdev, 624 + struct led_classdev_flash *iled_cdev, 625 + const struct v4l2_flash_ops *ops, 626 + struct v4l2_flash_config *config) 627 + { 628 + struct v4l2_flash *v4l2_flash; 629 + struct led_classdev *led_cdev; 630 + struct v4l2_subdev *sd; 631 + int ret; 632 + 633 + if (!fled_cdev || !ops || !config) 634 + return ERR_PTR(-EINVAL); 635 + 636 + led_cdev = &fled_cdev->led_cdev; 637 + 638 + v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash), 639 + GFP_KERNEL); 640 + if (!v4l2_flash) 641 + return ERR_PTR(-ENOMEM); 642 + 643 + sd = &v4l2_flash->sd; 644 + v4l2_flash->fled_cdev = fled_cdev; 645 + v4l2_flash->iled_cdev = iled_cdev; 646 + v4l2_flash->ops = ops; 647 + sd->dev = dev; 648 + sd->of_node = of_node; 649 + v4l2_subdev_init(sd, &v4l2_flash_subdev_ops); 650 + sd->internal_ops = &v4l2_flash_subdev_internal_ops; 651 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 652 + strlcpy(sd->name, config->dev_name, sizeof(sd->name)); 653 + 654 + ret = media_entity_init(&sd->entity, 0, NULL, 0); 655 + if (ret < 0) 656 + return ERR_PTR(ret); 657 + 658 + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; 659 + 660 + ret = v4l2_flash_init_controls(v4l2_flash, config); 661 + if (ret < 0) 662 + goto err_init_controls; 663 + 664 + if (sd->of_node) 665 + of_node_get(sd->of_node); 666 + else 667 + of_node_get(led_cdev->dev->of_node); 668 + 669 + ret = v4l2_async_register_subdev(sd); 670 + if (ret < 0) 671 + goto err_async_register_sd; 672 + 673 + return v4l2_flash; 674 + 675 + err_async_register_sd: 676 + of_node_put(led_cdev->dev->of_node); 677 + v4l2_ctrl_handler_free(sd->ctrl_handler); 678 + err_init_controls: 679 + media_entity_cleanup(&sd->entity); 680 + 681 + return ERR_PTR(ret); 682 + } 683 + EXPORT_SYMBOL_GPL(v4l2_flash_init); 684 + 685 + void v4l2_flash_release(struct v4l2_flash *v4l2_flash) 686 + { 687 + struct v4l2_subdev *sd; 688 + struct led_classdev *led_cdev; 689 + 690 + if (IS_ERR_OR_NULL(v4l2_flash)) 691 + return; 692 + 693 + sd = &v4l2_flash->sd; 694 + led_cdev = &v4l2_flash->fled_cdev->led_cdev; 695 + 696 + v4l2_async_unregister_subdev(sd); 697 + 698 + if (sd->of_node) 699 + of_node_put(sd->of_node); 700 + else 701 + of_node_put(led_cdev->dev->of_node); 702 + 703 + v4l2_ctrl_handler_free(sd->ctrl_handler); 704 + media_entity_cleanup(&sd->entity); 705 + } 706 + EXPORT_SYMBOL_GPL(v4l2_flash_release); 707 + 708 + MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); 709 + MODULE_DESCRIPTION("V4L2 Flash sub-device helpers"); 710 + MODULE_LICENSE("GPL v2");
+15
include/linux/gpio/consumer.h
··· 407 407 return -EINVAL; 408 408 } 409 409 410 + /* Child properties interface */ 411 + struct fwnode_handle; 412 + 413 + static inline struct gpio_desc *fwnode_get_named_gpiod( 414 + struct fwnode_handle *fwnode, const char *propname) 415 + { 416 + return ERR_PTR(-ENOSYS); 417 + } 418 + 419 + static inline struct gpio_desc *devm_get_gpiod_from_child( 420 + struct device *dev, const char *con_id, struct fwnode_handle *child) 421 + { 422 + return ERR_PTR(-ENOSYS); 423 + } 424 + 410 425 #endif /* CONFIG_GPIOLIB */ 411 426 412 427 /*
+25
include/linux/leds.h
··· 12 12 #ifndef __LINUX_LEDS_H_INCLUDED 13 13 #define __LINUX_LEDS_H_INCLUDED 14 14 15 + #include <linux/device.h> 15 16 #include <linux/list.h> 16 17 #include <linux/mutex.h> 17 18 #include <linux/rwsem.h> ··· 223 222 struct list_head next_trig; 224 223 }; 225 224 225 + ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, 226 + const char *buf, size_t count); 227 + ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, 228 + char *buf); 229 + 226 230 /* Registration functions for complex triggers */ 227 231 extern int led_trigger_register(struct led_trigger *trigger); 228 232 extern void led_trigger_unregister(struct led_trigger *trigger); ··· 244 238 unsigned long *delay_on, 245 239 unsigned long *delay_off, 246 240 int invert); 241 + extern void led_trigger_set_default(struct led_classdev *led_cdev); 242 + extern void led_trigger_set(struct led_classdev *led_cdev, 243 + struct led_trigger *trigger); 244 + extern void led_trigger_remove(struct led_classdev *led_cdev); 245 + 246 + static inline void *led_get_trigger_data(struct led_classdev *led_cdev) 247 + { 248 + return led_cdev->trigger_data; 249 + } 250 + 247 251 /** 248 252 * led_trigger_rename_static - rename a trigger 249 253 * @name: the new trigger name ··· 283 267 static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} 284 268 static inline void led_trigger_event(struct led_trigger *trigger, 285 269 enum led_brightness event) {} 270 + static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} 271 + static inline void led_trigger_set(struct led_classdev *led_cdev, 272 + struct led_trigger *trigger) {} 273 + static inline void led_trigger_remove(struct led_classdev *led_cdev) {} 274 + static inline void *led_get_trigger_data(struct led_classdev *led_cdev) 275 + { 276 + return NULL; 277 + } 278 + 286 279 #endif /* CONFIG_LEDS_TRIGGERS */ 287 280 288 281 /* Trigger specific functions */
+148
include/media/v4l2-flash-led-class.h
··· 1 + /* 2 + * V4L2 flash LED sub-device registration helpers. 3 + * 4 + * Copyright (C) 2015 Samsung Electronics Co., Ltd 5 + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #ifndef _V4L2_FLASH_H 13 + #define _V4L2_FLASH_H 14 + 15 + #include <media/v4l2-ctrls.h> 16 + #include <media/v4l2-subdev.h> 17 + 18 + struct led_classdev_flash; 19 + struct led_classdev; 20 + struct v4l2_flash; 21 + enum led_brightness; 22 + 23 + /* 24 + * struct v4l2_flash_ctrl_data - flash control initialization data, filled 25 + * basing on the features declared by the LED flash 26 + * class driver in the v4l2_flash_config 27 + * @config: initialization data for a control 28 + * @cid: contains v4l2 flash control id if the config 29 + * field was initialized, 0 otherwise 30 + */ 31 + struct v4l2_flash_ctrl_data { 32 + struct v4l2_ctrl_config config; 33 + u32 cid; 34 + }; 35 + 36 + struct v4l2_flash_ops { 37 + /* setup strobing the flash by hardware pin state assertion */ 38 + int (*external_strobe_set)(struct v4l2_flash *v4l2_flash, 39 + bool enable); 40 + /* convert intensity to brightness in a device specific manner */ 41 + enum led_brightness (*intensity_to_led_brightness) 42 + (struct v4l2_flash *v4l2_flash, s32 intensity); 43 + /* convert brightness to intensity in a device specific manner */ 44 + s32 (*led_brightness_to_intensity) 45 + (struct v4l2_flash *v4l2_flash, enum led_brightness); 46 + }; 47 + 48 + /** 49 + * struct v4l2_flash_config - V4L2 Flash sub-device initialization data 50 + * @dev_name: the name of the media entity, 51 + unique in the system 52 + * @torch_intensity: constraints for the LED in torch mode 53 + * @indicator_intensity: constraints for the indicator LED 54 + * @flash_faults: bitmask of flash faults that the LED flash class 55 + device can report; corresponding LED_FAULT* bit 56 + definitions are available in the header file 57 + <linux/led-class-flash.h> 58 + * @has_external_strobe: external strobe capability 59 + */ 60 + struct v4l2_flash_config { 61 + char dev_name[32]; 62 + struct led_flash_setting torch_intensity; 63 + struct led_flash_setting indicator_intensity; 64 + u32 flash_faults; 65 + unsigned int has_external_strobe:1; 66 + }; 67 + 68 + /** 69 + * struct v4l2_flash - Flash sub-device context 70 + * @fled_cdev: LED flash class device controlled by this sub-device 71 + * @iled_cdev: LED class device representing indicator LED associated 72 + * with the LED flash class device 73 + * @ops: V4L2 specific flash ops 74 + * @sd: V4L2 sub-device 75 + * @hdl: flash controls handler 76 + * @ctrls: array of pointers to controls, whose values define 77 + * the sub-device state 78 + */ 79 + struct v4l2_flash { 80 + struct led_classdev_flash *fled_cdev; 81 + struct led_classdev_flash *iled_cdev; 82 + const struct v4l2_flash_ops *ops; 83 + 84 + struct v4l2_subdev sd; 85 + struct v4l2_ctrl_handler hdl; 86 + struct v4l2_ctrl **ctrls; 87 + }; 88 + 89 + static inline struct v4l2_flash *v4l2_subdev_to_v4l2_flash( 90 + struct v4l2_subdev *sd) 91 + { 92 + return container_of(sd, struct v4l2_flash, sd); 93 + } 94 + 95 + static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c) 96 + { 97 + return container_of(c->handler, struct v4l2_flash, hdl); 98 + } 99 + 100 + #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 101 + /** 102 + * v4l2_flash_init - initialize V4L2 flash led sub-device 103 + * @dev: flash device, e.g. an I2C device 104 + * @of_node: of_node of the LED, may be NULL if the same as device's 105 + * @fled_cdev: LED flash class device to wrap 106 + * @iled_cdev: LED flash class device representing indicator LED associated 107 + * with fled_cdev, may be NULL 108 + * @flash_ops: V4L2 Flash device ops 109 + * @config: initialization data for V4L2 Flash sub-device 110 + * 111 + * Create V4L2 Flash sub-device wrapping given LED subsystem device. 112 + * 113 + * Returns: A valid pointer, or, when an error occurs, the return 114 + * value is encoded using ERR_PTR(). Use IS_ERR() to check and 115 + * PTR_ERR() to obtain the numeric return value. 116 + */ 117 + struct v4l2_flash *v4l2_flash_init( 118 + struct device *dev, struct device_node *of_node, 119 + struct led_classdev_flash *fled_cdev, 120 + struct led_classdev_flash *iled_cdev, 121 + const struct v4l2_flash_ops *ops, 122 + struct v4l2_flash_config *config); 123 + 124 + /** 125 + * v4l2_flash_release - release V4L2 Flash sub-device 126 + * @flash: the V4L2 Flash sub-device to release 127 + * 128 + * Release V4L2 Flash sub-device. 129 + */ 130 + void v4l2_flash_release(struct v4l2_flash *v4l2_flash); 131 + 132 + #else 133 + static inline struct v4l2_flash *v4l2_flash_init( 134 + struct device *dev, struct device_node *of_node, 135 + struct led_classdev_flash *fled_cdev, 136 + struct led_classdev_flash *iled_cdev, 137 + const struct v4l2_flash_ops *ops, 138 + struct v4l2_flash_config *config) 139 + { 140 + return NULL; 141 + } 142 + 143 + static inline void v4l2_flash_release(struct v4l2_flash *v4l2_flash) 144 + { 145 + } 146 + #endif /* CONFIG_V4L2_FLASH_LED_CLASS */ 147 + 148 + #endif /* _V4L2_FLASH_H */
+2
include/media/v4l2-subdev.h
··· 605 605 struct video_device *devnode; 606 606 /* pointer to the physical device, if any */ 607 607 struct device *dev; 608 + /* The device_node of the subdev, usually the same as dev->of_node. */ 609 + struct device_node *of_node; 608 610 /* Links this subdev to a global subdev_list or @notifier->done list. */ 609 611 struct list_head async_list; 610 612 /* Pointer to respective struct v4l2_async_subdev. */