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

Merge tag 'backlight-next-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight

Pull backlight updates from Lee Jones:
"Core Framework:
- Add backlight_device_get_by_name() to the API

New Device Support:
- Add support for WLED5 to Qualcomm WLED

Fix-ups:
- Convert to GPIO descriptors in l4f00242t03
- Device Tree fix-ups for qcom-wled

Bug Fixes:
- Properly disable regulators on .probe() failure"

* tag 'backlight-next-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
backlight: Add backlight_device_get_by_name()
backlight: qcom-wled: Add support for WLED5 peripheral that is present on PM8150L PMICs
dt-bindings: backlight: qcom-wled: Add WLED5 bindings
backlight: qcom-wled: Add callback functions
dt-bindings: backlight: qcom-wled: Convert the wled bindings to .yaml format
backlight: l4f00242t03: Convert to GPIO descriptors
backlight: lp855x: Ensure regulators are disabled on probe failure

+867 -286
-154
Documentation/devicetree/bindings/leds/backlight/qcom-wled.txt
··· 1 - Binding for Qualcomm Technologies, Inc. WLED driver 2 - 3 - WLED (White Light Emitting Diode) driver is used for controlling display 4 - backlight that is part of PMIC on Qualcomm Technologies, Inc. reference 5 - platforms. The PMIC is connected to the host processor via SPMI bus. 6 - 7 - - compatible 8 - Usage: required 9 - Value type: <string> 10 - Definition: should be one of: 11 - "qcom,pm8941-wled" 12 - "qcom,pmi8998-wled" 13 - "qcom,pm660l-wled" 14 - 15 - - reg 16 - Usage: required 17 - Value type: <prop encoded array> 18 - Definition: Base address of the WLED modules. 19 - 20 - - default-brightness 21 - Usage: optional 22 - Value type: <u32> 23 - Definition: brightness value on boot, value from: 0-4095. 24 - Default: 2048 25 - 26 - - label 27 - Usage: required 28 - Value type: <string> 29 - Definition: The name of the backlight device 30 - 31 - - qcom,cs-out 32 - Usage: optional 33 - Value type: <bool> 34 - Definition: enable current sink output. 35 - This property is supported only for PM8941. 36 - 37 - - qcom,cabc 38 - Usage: optional 39 - Value type: <bool> 40 - Definition: enable content adaptive backlight control. 41 - 42 - - qcom,ext-gen 43 - Usage: optional 44 - Value type: <bool> 45 - Definition: use externally generated modulator signal to dim. 46 - This property is supported only for PM8941. 47 - 48 - - qcom,current-limit 49 - Usage: optional 50 - Value type: <u32> 51 - Definition: mA; per-string current limit; value from 0 to 25 with 52 - 1 mA step. Default 20 mA. 53 - This property is supported only for pm8941. 54 - 55 - - qcom,current-limit-microamp 56 - Usage: optional 57 - Value type: <u32> 58 - Definition: uA; per-string current limit; value from 0 to 30000 with 59 - 2500 uA step. Default 25 mA. 60 - 61 - - qcom,current-boost-limit 62 - Usage: optional 63 - Value type: <u32> 64 - Definition: mA; boost current limit. 65 - For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400, 66 - 1680. Default: 805 mA. 67 - For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300, 68 - 1500. Default: 970 mA. 69 - 70 - - qcom,switching-freq 71 - Usage: optional 72 - Value type: <u32> 73 - Definition: kHz; switching frequency; one of: 600, 640, 685, 738, 74 - 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, 75 - 4800, 9600. 76 - Default: for pm8941: 1600 kHz 77 - for pmi8998: 800 kHz 78 - 79 - - qcom,ovp 80 - Usage: optional 81 - Value type: <u32> 82 - Definition: V; Over-voltage protection limit; one of: 83 - 27, 29, 32, 35. Default: 29V 84 - This property is supported only for PM8941. 85 - 86 - - qcom,ovp-millivolt 87 - Usage: optional 88 - Value type: <u32> 89 - Definition: mV; Over-voltage protection limit; 90 - For pmi8998: one of 18100, 19600, 29600, 31100. 91 - Default 29600 mV. 92 - If this property is not specified for PM8941, it 93 - falls back to "qcom,ovp" property. 94 - 95 - - qcom,num-strings 96 - Usage: optional 97 - Value type: <u32> 98 - Definition: #; number of led strings attached; 99 - value: For PM8941 from 1 to 3. Default: 2 100 - For PMI8998 from 1 to 4. 101 - 102 - - interrupts 103 - Usage: optional 104 - Value type: <prop encoded array> 105 - Definition: Interrupts associated with WLED. This should be 106 - "short" and "ovp" interrupts. Interrupts can be 107 - specified as per the encoding listed under 108 - Documentation/devicetree/bindings/spmi/ 109 - qcom,spmi-pmic-arb.txt. 110 - 111 - - interrupt-names 112 - Usage: optional 113 - Value type: <string> 114 - Definition: Interrupt names associated with the interrupts. 115 - Must be "short" and "ovp". The short circuit detection 116 - is not supported for PM8941. 117 - 118 - - qcom,enabled-strings 119 - Usage: optional 120 - Value tyoe: <u32 array> 121 - Definition: Array of the WLED strings numbered from 0 to 3. Each 122 - string of leds are operated individually. Specify the 123 - list of strings used by the device. Any combination of 124 - led strings can be used. 125 - 126 - - qcom,external-pfet 127 - Usage: optional 128 - Value type: <bool> 129 - Definition: Specify if external PFET control for short circuit 130 - protection is used. This property is supported only 131 - for PMI8998. 132 - 133 - - qcom,auto-string-detection 134 - Usage: optional 135 - Value type: <bool> 136 - Definition: Enables auto-detection of the WLED string configuration. 137 - This feature is not supported for PM8941. 138 - 139 - 140 - Example: 141 - 142 - pm8941-wled@d800 { 143 - compatible = "qcom,pm8941-wled"; 144 - reg = <0xd800>; 145 - label = "backlight"; 146 - 147 - qcom,cs-out; 148 - qcom,current-limit = <20>; 149 - qcom,current-boost-limit = <805>; 150 - qcom,switching-freq = <1600>; 151 - qcom,ovp = <29>; 152 - qcom,num-strings = <2>; 153 - qcom,enabled-strings = <0 1>; 154 - };
+261
Documentation/devicetree/bindings/leds/backlight/qcom-wled.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/leds/backlight/qcom-wled.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Binding for Qualcomm Technologies, Inc. WLED driver 8 + 9 + maintainers: 10 + - Bjorn Andersson <bjorn.andersson@linaro.org> 11 + - Kiran Gunda <kgunda@codeaurora.org> 12 + 13 + description: | 14 + WLED (White Light Emitting Diode) driver is used for controlling display 15 + backlight that is part of PMIC on Qualcomm Technologies, Inc. reference 16 + platforms. The PMIC is connected to the host processor via SPMI bus. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - qcom,pm8941-wled 22 + - qcom,pmi8998-wled 23 + - qcom,pm660l-wled 24 + - qcom,pm8150l-wled 25 + 26 + reg: 27 + maxItems: 1 28 + 29 + default-brightness: 30 + description: | 31 + brightness value on boot. 32 + 33 + label: true 34 + 35 + max-brightness: 36 + description: | 37 + Maximum brightness level. 38 + 39 + qcom,cs-out: 40 + description: | 41 + enable current sink output. 42 + This property is supported only for WLED3. 43 + type: boolean 44 + 45 + qcom,cabc: 46 + description: | 47 + enable content adaptive backlight control. 48 + type: boolean 49 + 50 + qcom,ext-gen: 51 + description: | 52 + use externally generated modulator signal to dim. 53 + This property is supported only for WLED3. 54 + type: boolean 55 + 56 + qcom,current-limit: 57 + description: | 58 + mA; per-string current limit. 59 + This property is supported only for WLED3. 60 + allOf: 61 + - $ref: /schemas/types.yaml#/definitions/uint32 62 + default: 20 63 + minimum: 0 64 + maximum: 25 65 + 66 + qcom,current-limit-microamp: 67 + description: | 68 + uA; per-string current limit. 69 + default: 25 70 + minimum: 0 71 + maximum: 30000 72 + multipleOf: 25 73 + 74 + qcom,current-boost-limit: 75 + description: | 76 + mA; boost current limit. 77 + allOf: 78 + - $ref: /schemas/types.yaml#/definitions/uint32 79 + 80 + qcom,switching-freq: 81 + description: | 82 + kHz; switching frequency. 83 + allOf: 84 + - $ref: /schemas/types.yaml#/definitions/uint32 85 + - enum: [ 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200, 4800, 9600 ] 86 + 87 + qcom,ovp: 88 + description: | 89 + V; Over-voltage protection limit. 90 + This property is supported only for WLED3. 91 + allOf: 92 + - $ref: /schemas/types.yaml#/definitions/uint32 93 + - enum: [ 27, 29, 32, 35 ] 94 + - default: 29 95 + 96 + qcom,ovp-millivolt: 97 + description: | 98 + Over-voltage protection limit. This property is for WLED4 only. 99 + allOf: 100 + - $ref: /schemas/types.yaml#/definitions/uint32 101 + - enum: [ 18100, 19600, 29600, 31100 ] 102 + - default: 29600 103 + 104 + qcom,num-strings: 105 + description: | 106 + number of led strings attached. 107 + allOf: 108 + - $ref: /schemas/types.yaml#/definitions/uint32 109 + 110 + qcom,enabled-strings: 111 + description: | 112 + Array of the WLED strings numbered from 0 to 3. Each 113 + string of leds are operated individually. Specify the 114 + list of strings used by the device. Any combination of 115 + led strings can be used. 116 + allOf: 117 + - $ref: /schemas/types.yaml#/definitions/uint32-array 118 + minItems: 1 119 + maxItems: 4 120 + 121 + qcom,external-pfet: 122 + description: | 123 + Specify if external PFET control for short circuit 124 + protection is used. This property is supported only 125 + for WLED4. 126 + type: boolean 127 + 128 + qcom,auto-string-detection: 129 + description: | 130 + Enables auto-detection of the WLED string configuration. 131 + This feature is not supported for WLED3. 132 + type: boolean 133 + 134 + interrupts: 135 + minItems: 1 136 + items: 137 + - description: over voltage protection interrupt. 138 + - description: short circuit interrupt. 139 + 140 + interrupt-names: 141 + minItems: 1 142 + items: 143 + - const: ovp 144 + - const: short 145 + 146 + qcom,modulator-sel: 147 + description: | 148 + Selects the modulator used for brightness modulation. 149 + Allowed values are, 150 + 0 - Modulator A 151 + 1 - Modulator B 152 + This property is applicable only to WLED5 peripheral. 153 + allOf: 154 + - $ref: /schemas/types.yaml#/definitions/uint32 155 + - enum: [ 0, 1 ] 156 + - default: 0 157 + 158 + qcom,cabc-sel: 159 + description: | 160 + Selects the CABC pin signal used for brightness modulation. 161 + Allowed values are, 162 + 0 - CABC disabled 163 + 1 - CABC 1 164 + 2 - CABC 2 165 + 3 - External signal (e.g. LPG) is used for dimming 166 + This property is applicable only to WLED5 peripheral. 167 + allOf: 168 + - $ref: /schemas/types.yaml#/definitions/uint32 169 + - enum: [ 0, 1, 2, 3 ] 170 + 171 + allOf: 172 + - if: 173 + properties: 174 + compatible: 175 + contains: 176 + const: qcom,pm8941-wled 177 + 178 + then: 179 + properties: 180 + qcom,current-boost-limit: 181 + enum: [ 105, 385, 525, 805, 980, 1260, 1400, 1680 ] 182 + default: 805 183 + 184 + qcom,switching-freq: 185 + default: 1600 186 + 187 + qcom,num-strings: 188 + enum: [ 1, 2, 3 ] 189 + 190 + interrupts: 191 + maxItems: 1 192 + 193 + interrupt-names: 194 + maxItems: 1 195 + 196 + else: 197 + properties: 198 + qcom,current-boost-limit: 199 + enum: [ 105, 280, 450, 620, 970, 1150, 1300, 1500 ] 200 + default: 970 201 + 202 + qcom,switching-freq: 203 + default: 800 204 + 205 + qcom,num-strings: 206 + enum: [ 1, 2, 3, 4 ] 207 + 208 + interrupts: 209 + minItems: 2 210 + 211 + interrupt-names: 212 + minItems: 2 213 + - if: 214 + properties: 215 + compatible: 216 + contains: 217 + enum: 218 + - qcom,pm8150l-wled 219 + 220 + then: 221 + properties: 222 + default-brightness: 223 + minimum: 0 224 + maximum: 32767 225 + 226 + max-brightness: 227 + minimum: 0 228 + maximum: 32767 229 + 230 + else: 231 + properties: 232 + default-brightness: 233 + minimum: 0 234 + maximum: 4095 235 + 236 + max-brightness: 237 + minimum: 0 238 + maximum: 4095 239 + 240 + required: 241 + - compatible 242 + - reg 243 + - label 244 + 245 + additionalProperties: false 246 + 247 + examples: 248 + - | 249 + backlight@d800 { 250 + compatible = "qcom,pm8941-wled"; 251 + reg = <0xd800 0x100>; 252 + label = "backlight"; 253 + 254 + qcom,cs-out; 255 + qcom,current-limit = <20>; 256 + qcom,current-boost-limit = <805>; 257 + qcom,switching-freq = <1600>; 258 + qcom,ovp = <29>; 259 + qcom,num-strings = <2>; 260 + qcom,enabled-strings = <0 1>; 261 + };
+15 -6
arch/arm/mach-imx/mach-mx27_3ds.c
··· 13 13 14 14 #include <linux/platform_device.h> 15 15 #include <linux/gpio.h> 16 + #include <linux/gpio/machine.h> 16 17 #include <linux/irq.h> 17 18 #include <linux/usb/otg.h> 18 19 #include <linux/usb/ulpi.h> ··· 21 20 #include <linux/mfd/mc13783.h> 22 21 #include <linux/spi/spi.h> 23 22 #include <linux/regulator/machine.h> 24 - #include <linux/spi/l4f00242t03.h> 25 - 26 23 27 24 #include <asm/mach-types.h> 28 25 #include <asm/mach/arch.h> ··· 350 351 }; 351 352 352 353 /* LCD */ 353 - static struct l4f00242t03_pdata mx27_3ds_lcd_pdata = { 354 - .reset_gpio = LCD_RESET, 355 - .data_enable_gpio = LCD_ENABLE, 354 + static struct gpiod_lookup_table mx27_3ds_lcd_gpiod_table = { 355 + .dev_id = "spi0.0", /* Bus 0 chipselect 0 */ 356 + .table = { 357 + /* 358 + * The i.MX27 has the i.MX21 GPIO controller, the GPIOs 359 + * numbered IMX_GPIO_NR(1, 3) and IMX_GPIO_NR(1, 31) 360 + * are in "bank 1" which is subtracted by one in the macro 361 + * so these are actually bank 0 on "imx21-gpio.0". 362 + */ 363 + GPIO_LOOKUP("imx21-gpio.0", 3, "reset", GPIO_ACTIVE_HIGH), 364 + GPIO_LOOKUP("imx21-gpio.0", 31, "enable", GPIO_ACTIVE_HIGH), 365 + { }, 366 + }, 356 367 }; 357 368 358 369 static struct spi_board_info mx27_3ds_spi_devs[] __initdata = { ··· 379 370 .max_speed_hz = 5000000, 380 371 .bus_num = 0, 381 372 .chip_select = 0, /* SS0 */ 382 - .platform_data = &mx27_3ds_lcd_pdata, 383 373 }, 384 374 }; 385 375 ··· 424 416 if (!otg_mode_host) 425 417 imx27_add_fsl_usb2_udc(&otg_device_pdata); 426 418 419 + gpiod_add_lookup_table(&mx27_3ds_lcd_gpiod_table); 427 420 mx27_3ds_spi_devs[0].irq = gpio_to_irq(PMIC_INT); 428 421 spi_register_board_info(mx27_3ds_spi_devs, 429 422 ARRAY_SIZE(mx27_3ds_spi_devs));
+19 -5
arch/arm/mach-imx/mach-mx31_3ds.c
··· 10 10 #include <linux/clk.h> 11 11 #include <linux/irq.h> 12 12 #include <linux/gpio.h> 13 + #include <linux/gpio/machine.h> 13 14 #include <linux/platform_device.h> 14 15 #include <linux/mfd/mc13783.h> 15 16 #include <linux/spi/spi.h> 16 - #include <linux/spi/l4f00242t03.h> 17 17 #include <linux/regulator/machine.h> 18 18 #include <linux/usb/otg.h> 19 19 #include <linux/usb/ulpi.h> ··· 160 160 }; 161 161 162 162 /* LCD */ 163 - static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = { 164 - .reset_gpio = IOMUX_TO_GPIO(MX31_PIN_LCS1), 165 - .data_enable_gpio = IOMUX_TO_GPIO(MX31_PIN_SER_RS), 163 + static struct gpiod_lookup_table mx31_3ds_lcd_gpiod_table = { 164 + .dev_id = "spi0.2", /* Bus 0 chipselect 2 */ 165 + .table = { 166 + /* 167 + * "reset" has IOMUX_TO_GPIO(IOMUX_PIN(88, 28)). 168 + * The macro only shifts 88 to bits 9..16 and then 169 + * mask it and shift it back. The GPIO number is 88. 170 + * 88 is 2*32+24 171 + */ 172 + GPIO_LOOKUP("imx31-gpio.2", 24, "reset", GPIO_ACTIVE_HIGH), 173 + /* 174 + * Same reasoning as above for 175 + * IOMUX_TO_GPIO(IOMUX_PIN(89, 27), pin 89 is 2*32+25. 176 + */ 177 + GPIO_LOOKUP("imx31-gpio.2", 25, "enable", GPIO_ACTIVE_HIGH), 178 + { }, 179 + }, 166 180 }; 167 181 168 182 /* ··· 401 387 .max_speed_hz = 5000000, 402 388 .bus_num = 0, 403 389 .chip_select = 2, /* SS2 */ 404 - .platform_data = &mx31_3ds_l4f00242t03_pdata, 405 390 }, 406 391 }; 407 392 ··· 579 566 580 567 static void __init mx31_3ds_late(void) 581 568 { 569 + gpiod_add_lookup_table(&mx31_3ds_lcd_gpiod_table); 582 570 mx31_3ds_spi_devs[0].irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3)); 583 571 spi_register_board_info(mx31_3ds_spi_devs, 584 572 ARRAY_SIZE(mx31_3ds_spi_devs));
+21
drivers/video/backlight/backlight.c
··· 433 433 EXPORT_SYMBOL(backlight_device_get_by_type); 434 434 435 435 /** 436 + * backlight_device_get_by_name - Get backlight device by name 437 + * @name: Device name 438 + * 439 + * This function looks up a backlight device by its name. It obtains a reference 440 + * on the backlight device and it is the caller's responsibility to drop the 441 + * reference by calling backlight_put(). 442 + * 443 + * Returns: 444 + * A pointer to the backlight device if found, otherwise NULL. 445 + */ 446 + struct backlight_device *backlight_device_get_by_name(const char *name) 447 + { 448 + struct device *dev; 449 + 450 + dev = class_find_device_by_name(backlight_class, name); 451 + 452 + return dev ? to_backlight_device(dev) : NULL; 453 + } 454 + EXPORT_SYMBOL(backlight_device_get_by_name); 455 + 456 + /** 436 457 * backlight_device_unregister - unregisters a backlight device object. 437 458 * @bd: the backlight device object to be unregistered and freed. 438 459 *
+18 -27
drivers/video/backlight/l4f00242t03.c
··· 14 14 #include <linux/kernel.h> 15 15 #include <linux/delay.h> 16 16 #include <linux/module.h> 17 - #include <linux/gpio.h> 17 + #include <linux/gpio/consumer.h> 18 18 #include <linux/lcd.h> 19 19 #include <linux/slab.h> 20 20 #include <linux/regulator/consumer.h> 21 - 22 21 #include <linux/spi/spi.h> 23 - #include <linux/spi/l4f00242t03.h> 24 22 25 23 struct l4f00242t03_priv { 26 24 struct spi_device *spi; ··· 26 28 int lcd_state; 27 29 struct regulator *io_reg; 28 30 struct regulator *core_reg; 31 + struct gpio_desc *reset; 32 + struct gpio_desc *enable; 29 33 }; 30 34 31 - static void l4f00242t03_reset(unsigned int gpio) 35 + static void l4f00242t03_reset(struct gpio_desc *gpiod) 32 36 { 33 37 pr_debug("l4f00242t03_reset.\n"); 34 - gpio_set_value(gpio, 1); 38 + gpiod_set_value(gpiod, 1); 35 39 mdelay(100); 36 - gpio_set_value(gpio, 0); 40 + gpiod_set_value(gpiod, 0); 37 41 mdelay(10); /* tRES >= 100us */ 38 - gpio_set_value(gpio, 1); 42 + gpiod_set_value(gpiod, 1); 39 43 mdelay(20); 40 44 } 41 45 ··· 45 45 46 46 static void l4f00242t03_lcd_init(struct spi_device *spi) 47 47 { 48 - struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); 49 48 struct l4f00242t03_priv *priv = spi_get_drvdata(spi); 50 49 const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) }; 51 50 int ret; ··· 75 76 return; 76 77 } 77 78 78 - l4f00242t03_reset(pdata->reset_gpio); 79 + l4f00242t03_reset(priv->reset); 79 80 80 - gpio_set_value(pdata->data_enable_gpio, 1); 81 + gpiod_set_value(priv->enable, 1); 81 82 msleep(60); 82 83 spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16)); 83 84 } 84 85 85 86 static void l4f00242t03_lcd_powerdown(struct spi_device *spi) 86 87 { 87 - struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); 88 88 struct l4f00242t03_priv *priv = spi_get_drvdata(spi); 89 89 90 90 dev_dbg(&spi->dev, "Powering down LCD\n"); 91 91 92 - gpio_set_value(pdata->data_enable_gpio, 0); 92 + gpiod_set_value(priv->enable, 0); 93 93 94 94 regulator_disable(priv->io_reg); 95 95 regulator_disable(priv->core_reg); ··· 166 168 static int l4f00242t03_probe(struct spi_device *spi) 167 169 { 168 170 struct l4f00242t03_priv *priv; 169 - struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); 170 - int ret; 171 - 172 - if (pdata == NULL) { 173 - dev_err(&spi->dev, "Uninitialized platform data.\n"); 174 - return -EINVAL; 175 - } 176 171 177 172 priv = devm_kzalloc(&spi->dev, sizeof(struct l4f00242t03_priv), 178 173 GFP_KERNEL); ··· 178 187 179 188 priv->spi = spi; 180 189 181 - ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio, 182 - GPIOF_OUT_INIT_HIGH, "lcd l4f00242t03 reset"); 183 - if (ret) { 190 + priv->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH); 191 + if (IS_ERR(priv->reset)) { 184 192 dev_err(&spi->dev, 185 193 "Unable to get the lcd l4f00242t03 reset gpio.\n"); 186 - return ret; 194 + return PTR_ERR(priv->reset); 187 195 } 196 + gpiod_set_consumer_name(priv->reset, "lcd l4f00242t03 reset"); 188 197 189 - ret = devm_gpio_request_one(&spi->dev, pdata->data_enable_gpio, 190 - GPIOF_OUT_INIT_LOW, "lcd l4f00242t03 data enable"); 191 - if (ret) { 198 + priv->enable = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); 199 + if (IS_ERR(priv->enable)) { 192 200 dev_err(&spi->dev, 193 201 "Unable to get the lcd l4f00242t03 data en gpio.\n"); 194 - return ret; 202 + return PTR_ERR(priv->enable); 195 203 } 204 + gpiod_set_consumer_name(priv->enable, "lcd l4f00242t03 data enable"); 196 205 197 206 priv->io_reg = devm_regulator_get(&spi->dev, "vdd"); 198 207 if (IS_ERR(priv->io_reg)) {
+16 -4
drivers/video/backlight/lp855x_bl.c
··· 456 456 ret = regulator_enable(lp->enable); 457 457 if (ret < 0) { 458 458 dev_err(lp->dev, "failed to enable vddio: %d\n", ret); 459 - return ret; 459 + goto disable_supply; 460 460 } 461 461 462 462 /* ··· 471 471 ret = lp855x_configure(lp); 472 472 if (ret) { 473 473 dev_err(lp->dev, "device config err: %d", ret); 474 - return ret; 474 + goto disable_vddio; 475 475 } 476 476 477 477 ret = lp855x_backlight_register(lp); 478 478 if (ret) { 479 479 dev_err(lp->dev, 480 480 "failed to register backlight. err: %d\n", ret); 481 - return ret; 481 + goto disable_vddio; 482 482 } 483 483 484 484 ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group); 485 485 if (ret) { 486 486 dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret); 487 - return ret; 487 + goto disable_vddio; 488 488 } 489 489 490 490 backlight_update_status(lp->bl); 491 + 491 492 return 0; 493 + 494 + disable_vddio: 495 + if (lp->enable) 496 + regulator_disable(lp->enable); 497 + disable_supply: 498 + if (lp->supply) 499 + regulator_disable(lp->supply); 500 + 501 + return ret; 492 502 } 493 503 494 504 static int lp855x_remove(struct i2c_client *cl) ··· 507 497 508 498 lp->bl->props.brightness = 0; 509 499 backlight_update_status(lp->bl); 500 + if (lp->enable) 501 + regulator_disable(lp->enable); 510 502 if (lp->supply) 511 503 regulator_disable(lp->supply); 512 504 sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
+516 -73
drivers/video/backlight/qcom-wled.c
··· 15 15 16 16 /* From DT binding */ 17 17 #define WLED_MAX_STRINGS 4 18 + #define MOD_A 0 19 + #define MOD_B 1 18 20 19 21 #define WLED_DEFAULT_BRIGHTNESS 2048 20 22 #define WLED_SOFT_START_DLY_US 10000 21 23 #define WLED3_SINK_REG_BRIGHT_MAX 0xFFF 24 + #define WLED5_SINK_REG_BRIGHT_MAX_12B 0xFFF 25 + #define WLED5_SINK_REG_BRIGHT_MAX_15B 0x7FFF 22 26 23 27 /* WLED3/WLED4 control registers */ 24 28 #define WLED3_CTRL_REG_FAULT_STATUS 0x08 25 29 #define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0) 26 30 #define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1) 27 31 #define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2) 32 + #define WLED5_CTRL_REG_OVP_PRE_ALARM_BIT BIT(4) 28 33 29 34 #define WLED3_CTRL_REG_INT_RT_STS 0x10 30 35 #define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1) ··· 45 40 46 41 #define WLED3_CTRL_REG_OVP 0x4d 47 42 #define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0) 43 + #define WLED5_CTRL_REG_OVP_MASK GENMASK(3, 0) 48 44 49 45 #define WLED3_CTRL_REG_ILIMIT 0x4e 50 46 #define WLED3_CTRL_REG_ILIMIT_MASK GENMASK(2, 0) ··· 107 101 108 102 #define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10)) 109 103 104 + /* WLED5 specific control registers */ 105 + #define WLED5_CTRL_REG_OVP_INT_CTL 0x5f 106 + #define WLED5_CTRL_REG_OVP_INT_TIMER_MASK GENMASK(2, 0) 107 + 108 + /* WLED5 specific sink registers */ 109 + #define WLED5_SINK_REG_MOD_A_EN 0x50 110 + #define WLED5_SINK_REG_MOD_B_EN 0x60 111 + #define WLED5_SINK_REG_MOD_EN_MASK BIT(7) 112 + 113 + #define WLED5_SINK_REG_MOD_A_SRC_SEL 0x51 114 + #define WLED5_SINK_REG_MOD_B_SRC_SEL 0x61 115 + #define WLED5_SINK_REG_MOD_SRC_SEL_HIGH 0 116 + #define WLED5_SINK_REG_MOD_SRC_SEL_EXT 0x03 117 + #define WLED5_SINK_REG_MOD_SRC_SEL_MASK GENMASK(1, 0) 118 + 119 + #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL 0x52 120 + #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL 0x62 121 + #define WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B 0 122 + #define WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B 1 123 + 124 + #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB 0x53 125 + #define WLED5_SINK_REG_MOD_A_BRIGHTNESS_MSB 0x54 126 + #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB 0x63 127 + #define WLED5_SINK_REG_MOD_B_BRIGHTNESS_MSB 0x64 128 + 129 + #define WLED5_SINK_REG_MOD_SYNC_BIT 0x65 130 + #define WLED5_SINK_REG_SYNC_MOD_A_BIT BIT(0) 131 + #define WLED5_SINK_REG_SYNC_MOD_B_BIT BIT(1) 132 + #define WLED5_SINK_REG_SYNC_MASK GENMASK(1, 0) 133 + 134 + /* WLED5 specific per-'string' registers below */ 135 + #define WLED5_SINK_REG_STR_FULL_SCALE_CURR(n) (0x72 + (n * 0x10)) 136 + 137 + #define WLED5_SINK_REG_STR_SRC_SEL(n) (0x73 + (n * 0x10)) 138 + #define WLED5_SINK_REG_SRC_SEL_MOD_A 0 139 + #define WLED5_SINK_REG_SRC_SEL_MOD_B 1 140 + #define WLED5_SINK_REG_SRC_SEL_MASK GENMASK(1, 0) 141 + 110 142 struct wled_var_cfg { 111 143 const u32 *values; 112 144 u32 (*fn)(u32); ··· 169 125 u32 num_strings; 170 126 u32 string_i_limit; 171 127 u32 enabled_strings[WLED_MAX_STRINGS]; 128 + u32 mod_sel; 129 + u32 cabc_sel; 172 130 bool cs_out_en; 173 131 bool ext_gen; 174 132 bool cabc; ··· 193 147 u32 max_brightness; 194 148 u32 short_count; 195 149 u32 auto_detect_count; 150 + u32 version; 196 151 bool disabled_by_short; 197 152 bool has_short_detect; 153 + bool cabc_disabled; 198 154 int short_irq; 199 155 int ovp_irq; 200 156 201 157 struct wled_config cfg; 202 158 struct delayed_work ovp_work; 159 + 160 + /* Configures the brightness. Applicable for wled3, wled4 and wled5 */ 203 161 int (*wled_set_brightness)(struct wled *wled, u16 brightness); 162 + 163 + /* Configures the cabc register. Applicable for wled4 and wled5 */ 164 + int (*wled_cabc_config)(struct wled *wled, bool enable); 165 + 166 + /* 167 + * Toggles the sync bit for the brightness update to take place. 168 + * Applicable for WLED3, WLED4 and WLED5. 169 + */ 170 + int (*wled_sync_toggle)(struct wled *wled); 171 + 172 + /* 173 + * Time to wait before checking the OVP status after wled module enable. 174 + * Applicable for WLED4 and WLED5. 175 + */ 176 + int (*wled_ovp_delay)(struct wled *wled); 177 + 178 + /* 179 + * Determines if the auto string detection is required. 180 + * Applicable for WLED4 and WLED5 181 + */ 182 + bool (*wled_auto_detection_required)(struct wled *wled); 204 183 }; 205 184 206 185 static int wled3_set_brightness(struct wled *wled, u16 brightness) ··· 269 198 return 0; 270 199 } 271 200 201 + static int wled5_set_brightness(struct wled *wled, u16 brightness) 202 + { 203 + int rc, offset; 204 + u16 low_limit = wled->max_brightness * 1 / 1000; 205 + u8 v[2]; 206 + 207 + /* WLED5's lower limit is 0.1% */ 208 + if (brightness < low_limit) 209 + brightness = low_limit; 210 + 211 + v[0] = brightness & 0xff; 212 + v[1] = (brightness >> 8) & 0x7f; 213 + 214 + offset = (wled->cfg.mod_sel == MOD_A) ? 215 + WLED5_SINK_REG_MOD_A_BRIGHTNESS_LSB : 216 + WLED5_SINK_REG_MOD_B_BRIGHTNESS_LSB; 217 + 218 + rc = regmap_bulk_write(wled->regmap, wled->sink_addr + offset, 219 + v, 2); 220 + return rc; 221 + } 222 + 272 223 static void wled_ovp_work(struct work_struct *work) 273 224 { 274 225 struct wled *wled = container_of(work, ··· 330 237 return 0; 331 238 } 332 239 333 - static int wled_sync_toggle(struct wled *wled) 240 + static int wled3_sync_toggle(struct wled *wled) 334 241 { 335 242 int rc; 336 243 unsigned int mask = GENMASK(wled->max_string_count - 1, 0); ··· 346 253 mask, WLED3_SINK_REG_SYNC_CLEAR); 347 254 348 255 return rc; 256 + } 257 + 258 + static int wled5_sync_toggle(struct wled *wled) 259 + { 260 + int rc; 261 + u8 val; 262 + 263 + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_SYNC_MOD_A_BIT : 264 + WLED5_SINK_REG_SYNC_MOD_B_BIT; 265 + rc = regmap_update_bits(wled->regmap, 266 + wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 267 + WLED5_SINK_REG_SYNC_MASK, val); 268 + if (rc < 0) 269 + return rc; 270 + 271 + return regmap_update_bits(wled->regmap, 272 + wled->sink_addr + WLED5_SINK_REG_MOD_SYNC_BIT, 273 + WLED5_SINK_REG_SYNC_MASK, 0); 274 + } 275 + 276 + static int wled_ovp_fault_status(struct wled *wled, bool *fault_set) 277 + { 278 + int rc; 279 + u32 int_rt_sts, fault_sts; 280 + 281 + *fault_set = false; 282 + rc = regmap_read(wled->regmap, 283 + wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, 284 + &int_rt_sts); 285 + if (rc < 0) { 286 + dev_err(wled->dev, "Failed to read INT_RT_STS rc=%d\n", rc); 287 + return rc; 288 + } 289 + 290 + rc = regmap_read(wled->regmap, 291 + wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS, 292 + &fault_sts); 293 + if (rc < 0) { 294 + dev_err(wled->dev, "Failed to read FAULT_STATUS rc=%d\n", rc); 295 + return rc; 296 + } 297 + 298 + if (int_rt_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS) 299 + *fault_set = true; 300 + 301 + if (wled->version == 4 && (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT)) 302 + *fault_set = true; 303 + 304 + if (wled->version == 5 && (fault_sts & (WLED3_CTRL_REG_OVP_FAULT_BIT | 305 + WLED5_CTRL_REG_OVP_PRE_ALARM_BIT))) 306 + *fault_set = true; 307 + 308 + if (*fault_set) 309 + dev_dbg(wled->dev, "WLED OVP fault detected, int_rt_sts=0x%x fault_sts=0x%x\n", 310 + int_rt_sts, fault_sts); 311 + 312 + return rc; 313 + } 314 + 315 + static int wled4_ovp_delay(struct wled *wled) 316 + { 317 + return WLED_SOFT_START_DLY_US; 318 + } 319 + 320 + static int wled5_ovp_delay(struct wled *wled) 321 + { 322 + int rc, delay_us; 323 + u32 val; 324 + u8 ovp_timer_ms[8] = {1, 2, 4, 8, 12, 16, 20, 24}; 325 + 326 + /* For WLED5, get the delay based on OVP timer */ 327 + rc = regmap_read(wled->regmap, wled->ctrl_addr + 328 + WLED5_CTRL_REG_OVP_INT_CTL, &val); 329 + if (rc < 0) 330 + delay_us = 331 + ovp_timer_ms[val & WLED5_CTRL_REG_OVP_INT_TIMER_MASK] * 1000; 332 + else 333 + delay_us = 2 * WLED_SOFT_START_DLY_US; 334 + 335 + dev_dbg(wled->dev, "delay_time_us: %d\n", delay_us); 336 + 337 + return delay_us; 349 338 } 350 339 351 340 static int wled_update_status(struct backlight_device *bl) ··· 450 275 goto unlock_mutex; 451 276 } 452 277 453 - rc = wled_sync_toggle(wled); 278 + rc = wled->wled_sync_toggle(wled); 454 279 if (rc < 0) { 455 280 dev_err(wled->dev, "wled sync failed rc:%d\n", rc); 456 281 goto unlock_mutex; ··· 471 296 mutex_unlock(&wled->lock); 472 297 473 298 return rc; 299 + } 300 + 301 + static int wled4_cabc_config(struct wled *wled, bool enable) 302 + { 303 + int i, j, rc; 304 + u8 val; 305 + 306 + for (i = 0; i < wled->cfg.num_strings; i++) { 307 + j = wled->cfg.enabled_strings[i]; 308 + 309 + val = enable ? WLED4_SINK_REG_STR_CABC_MASK : 0; 310 + rc = regmap_update_bits(wled->regmap, wled->sink_addr + 311 + WLED4_SINK_REG_STR_CABC(j), 312 + WLED4_SINK_REG_STR_CABC_MASK, val); 313 + if (rc < 0) 314 + return rc; 315 + } 316 + 317 + return 0; 318 + } 319 + 320 + static int wled5_cabc_config(struct wled *wled, bool enable) 321 + { 322 + int rc, offset; 323 + u8 reg; 324 + 325 + if (wled->cabc_disabled) 326 + return 0; 327 + 328 + reg = enable ? wled->cfg.cabc_sel : 0; 329 + offset = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_A_SRC_SEL : 330 + WLED5_SINK_REG_MOD_B_SRC_SEL; 331 + 332 + rc = regmap_update_bits(wled->regmap, wled->sink_addr + offset, 333 + WLED5_SINK_REG_MOD_SRC_SEL_MASK, reg); 334 + if (rc < 0) { 335 + pr_err("Error in configuring CABC rc=%d\n", rc); 336 + return rc; 337 + } 338 + 339 + if (!wled->cfg.cabc_sel) 340 + wled->cabc_disabled = true; 341 + 342 + return 0; 474 343 } 475 344 476 345 #define WLED_SHORT_DLY_MS 20 ··· 564 345 565 346 static void wled_auto_string_detection(struct wled *wled) 566 347 { 567 - int rc = 0, i; 568 - u32 sink_config = 0, int_sts; 348 + int rc = 0, i, delay_time_us; 349 + u32 sink_config = 0; 569 350 u8 sink_test = 0, sink_valid = 0, val; 351 + bool fault_set; 570 352 571 353 /* Read configured sink configuration */ 572 354 rc = regmap_read(wled->regmap, wled->sink_addr + ··· 596 376 } 597 377 598 378 if (wled->cfg.cabc) { 599 - for (i = 0; i < wled->cfg.num_strings; i++) { 600 - rc = regmap_update_bits(wled->regmap, wled->sink_addr + 601 - WLED4_SINK_REG_STR_CABC(i), 602 - WLED4_SINK_REG_STR_CABC_MASK, 603 - 0); 604 - if (rc < 0) 605 - goto failed_detect; 606 - } 379 + rc = wled->wled_cabc_config(wled, false); 380 + if (rc < 0) 381 + goto failed_detect; 607 382 } 608 383 609 384 /* Disable all sinks */ ··· 642 427 goto failed_detect; 643 428 } 644 429 645 - usleep_range(WLED_SOFT_START_DLY_US, 646 - WLED_SOFT_START_DLY_US + 1000); 430 + delay_time_us = wled->wled_ovp_delay(wled); 431 + usleep_range(delay_time_us, delay_time_us + 1000); 647 432 648 - rc = regmap_read(wled->regmap, wled->ctrl_addr + 649 - WLED3_CTRL_REG_INT_RT_STS, &int_sts); 433 + rc = wled_ovp_fault_status(wled, &fault_set); 650 434 if (rc < 0) { 651 - dev_err(wled->dev, "Error in reading WLED3_CTRL_INT_RT_STS rc=%d\n", 435 + dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 652 436 rc); 653 437 goto failed_detect; 654 438 } 655 439 656 - if (int_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS) 440 + if (fault_set) 657 441 dev_dbg(wled->dev, "WLED OVP fault detected with SINK %d\n", 658 442 i + 1); 659 443 else ··· 692 478 } 693 479 694 480 /* Enable valid sinks */ 695 - for (i = 0; i < wled->cfg.num_strings; i++) { 696 - if (wled->cfg.cabc) { 697 - rc = regmap_update_bits(wled->regmap, wled->sink_addr + 698 - WLED4_SINK_REG_STR_CABC(i), 699 - WLED4_SINK_REG_STR_CABC_MASK, 700 - WLED4_SINK_REG_STR_CABC_MASK); 701 - if (rc < 0) 481 + if (wled->version == 4) { 482 + for (i = 0; i < wled->cfg.num_strings; i++) { 483 + if (sink_config & 484 + BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i)) 485 + val = WLED4_SINK_REG_STR_MOD_MASK; 486 + else 487 + /* Disable modulator_en for unused sink */ 488 + val = 0; 489 + 490 + rc = regmap_write(wled->regmap, wled->sink_addr + 491 + WLED4_SINK_REG_STR_MOD_EN(i), val); 492 + if (rc < 0) { 493 + dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n", 494 + rc); 702 495 goto failed_detect; 703 - } 704 - 705 - if (sink_config & BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i)) 706 - val = WLED4_SINK_REG_STR_MOD_MASK; 707 - else 708 - val = 0x0; /* Disable modulator_en for unused sink */ 709 - 710 - rc = regmap_write(wled->regmap, wled->sink_addr + 711 - WLED4_SINK_REG_STR_MOD_EN(i), val); 712 - if (rc < 0) { 713 - dev_err(wled->dev, "Failed to configure MODULATOR_EN rc=%d\n", 714 - rc); 715 - goto failed_detect; 496 + } 716 497 } 717 498 } 499 + 500 + /* Enable CABC */ 501 + rc = wled->wled_cabc_config(wled, true); 502 + if (rc < 0) 503 + goto failed_detect; 718 504 719 505 /* Restore the feedback setting */ 720 506 rc = regmap_write(wled->regmap, ··· 748 534 749 535 #define WLED_AUTO_DETECT_OVP_COUNT 5 750 536 #define WLED_AUTO_DETECT_CNT_DLY_US USEC_PER_SEC 751 - static bool wled_auto_detection_required(struct wled *wled) 537 + 538 + static bool wled4_auto_detection_required(struct wled *wled) 752 539 { 753 540 s64 elapsed_time_us; 754 541 ··· 782 567 return false; 783 568 } 784 569 570 + static bool wled5_auto_detection_required(struct wled *wled) 571 + { 572 + if (!wled->cfg.auto_detection_enabled) 573 + return false; 574 + 575 + /* 576 + * Unlike WLED4, WLED5 has OVP fault density interrupt configuration 577 + * i.e. to count the number of OVP alarms for a certain duration before 578 + * triggering OVP fault interrupt. By default, number of OVP fault 579 + * events counted before an interrupt is fired is 32 and the time 580 + * interval is 12 ms. If we see one OVP fault interrupt, then that 581 + * should qualify for a real OVP fault condition to run auto detection 582 + * algorithm. 583 + */ 584 + return true; 585 + } 586 + 785 587 static int wled_auto_detection_at_init(struct wled *wled) 786 588 { 787 589 int rc; 788 - u32 fault_status, rt_status; 590 + bool fault_set; 789 591 790 592 if (!wled->cfg.auto_detection_enabled) 791 593 return 0; 792 594 793 - rc = regmap_read(wled->regmap, 794 - wled->ctrl_addr + WLED3_CTRL_REG_INT_RT_STS, 795 - &rt_status); 595 + rc = wled_ovp_fault_status(wled, &fault_set); 796 596 if (rc < 0) { 797 - dev_err(wled->dev, "Failed to read RT status rc=%d\n", rc); 597 + dev_err(wled->dev, "Error in getting OVP fault_sts, rc=%d\n", 598 + rc); 798 599 return rc; 799 600 } 800 601 801 - rc = regmap_read(wled->regmap, 802 - wled->ctrl_addr + WLED3_CTRL_REG_FAULT_STATUS, 803 - &fault_status); 804 - if (rc < 0) { 805 - dev_err(wled->dev, "Failed to read fault status rc=%d\n", rc); 806 - return rc; 807 - } 808 - 809 - if ((rt_status & WLED3_CTRL_REG_OVP_FAULT_STATUS) || 810 - (fault_status & WLED3_CTRL_REG_OVP_FAULT_BIT)) { 602 + if (fault_set) { 811 603 mutex_lock(&wled->lock); 812 604 wled_auto_string_detection(wled); 813 605 mutex_unlock(&wled->lock); ··· 851 629 int_sts, fault_sts); 852 630 853 631 if (fault_sts & WLED3_CTRL_REG_OVP_FAULT_BIT) { 854 - if (wled_auto_detection_required(wled)) { 632 + if (wled->wled_auto_detection_required(wled)) { 855 633 mutex_lock(&wled->lock); 856 634 wled_auto_string_detection(wled); 857 635 mutex_unlock(&wled->lock); ··· 1033 811 wled->cfg.string_i_limit); 1034 812 if (rc < 0) 1035 813 return rc; 1036 - 1037 - addr = wled->sink_addr + 1038 - WLED4_SINK_REG_STR_CABC(j); 1039 - rc = regmap_update_bits(wled->regmap, addr, 1040 - WLED4_SINK_REG_STR_CABC_MASK, 1041 - wled->cfg.cabc ? 1042 - WLED4_SINK_REG_STR_CABC_MASK : 0); 1043 - if (rc < 0) 1044 - return rc; 1045 814 } 815 + 816 + rc = wled4_cabc_config(wled, wled->cfg.cabc); 817 + if (rc < 0) 818 + return rc; 1046 819 1047 820 rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + 1048 821 WLED3_CTRL_REG_MOD_EN, ··· 1052 835 if (rc < 0) 1053 836 return rc; 1054 837 1055 - rc = wled_sync_toggle(wled); 838 + rc = wled->wled_sync_toggle(wled); 1056 839 if (rc < 0) { 1057 840 dev_err(wled->dev, "Failed to toggle sync reg rc:%d\n", rc); 1058 841 return rc; ··· 1069 852 .ovp = 1, 1070 853 .num_strings = 4, 1071 854 .switch_freq = 11, 855 + .cabc = false, 856 + .external_pfet = false, 857 + .auto_detection_enabled = false, 858 + }; 859 + 860 + static int wled5_setup(struct wled *wled) 861 + { 862 + int rc, temp, i, j, offset; 863 + u8 sink_en = 0; 864 + u16 addr; 865 + u32 val; 866 + 867 + rc = regmap_update_bits(wled->regmap, 868 + wled->ctrl_addr + WLED3_CTRL_REG_OVP, 869 + WLED5_CTRL_REG_OVP_MASK, wled->cfg.ovp); 870 + if (rc < 0) 871 + return rc; 872 + 873 + rc = regmap_update_bits(wled->regmap, 874 + wled->ctrl_addr + WLED3_CTRL_REG_ILIMIT, 875 + WLED3_CTRL_REG_ILIMIT_MASK, 876 + wled->cfg.boost_i_limit); 877 + if (rc < 0) 878 + return rc; 879 + 880 + rc = regmap_update_bits(wled->regmap, 881 + wled->ctrl_addr + WLED3_CTRL_REG_FREQ, 882 + WLED3_CTRL_REG_FREQ_MASK, 883 + wled->cfg.switch_freq); 884 + if (rc < 0) 885 + return rc; 886 + 887 + /* Per sink/string configuration */ 888 + for (i = 0; i < wled->cfg.num_strings; ++i) { 889 + j = wled->cfg.enabled_strings[i]; 890 + addr = wled->sink_addr + 891 + WLED4_SINK_REG_STR_FULL_SCALE_CURR(j); 892 + rc = regmap_update_bits(wled->regmap, addr, 893 + WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK, 894 + wled->cfg.string_i_limit); 895 + if (rc < 0) 896 + return rc; 897 + 898 + addr = wled->sink_addr + WLED5_SINK_REG_STR_SRC_SEL(j); 899 + rc = regmap_update_bits(wled->regmap, addr, 900 + WLED5_SINK_REG_SRC_SEL_MASK, 901 + wled->cfg.mod_sel == MOD_A ? 902 + WLED5_SINK_REG_SRC_SEL_MOD_A : 903 + WLED5_SINK_REG_SRC_SEL_MOD_B); 904 + 905 + temp = j + WLED4_SINK_REG_CURR_SINK_SHFT; 906 + sink_en |= 1 << temp; 907 + } 908 + 909 + rc = wled5_cabc_config(wled, wled->cfg.cabc_sel ? true : false); 910 + if (rc < 0) 911 + return rc; 912 + 913 + /* Enable one of the modulators A or B based on mod_sel */ 914 + addr = wled->sink_addr + WLED5_SINK_REG_MOD_A_EN; 915 + val = (wled->cfg.mod_sel == MOD_A) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 916 + rc = regmap_update_bits(wled->regmap, addr, 917 + WLED5_SINK_REG_MOD_EN_MASK, val); 918 + if (rc < 0) 919 + return rc; 920 + 921 + addr = wled->sink_addr + WLED5_SINK_REG_MOD_B_EN; 922 + val = (wled->cfg.mod_sel == MOD_B) ? WLED5_SINK_REG_MOD_EN_MASK : 0; 923 + rc = regmap_update_bits(wled->regmap, addr, 924 + WLED5_SINK_REG_MOD_EN_MASK, val); 925 + if (rc < 0) 926 + return rc; 927 + 928 + offset = (wled->cfg.mod_sel == MOD_A) ? 929 + WLED5_SINK_REG_MOD_A_BRIGHTNESS_WIDTH_SEL : 930 + WLED5_SINK_REG_MOD_B_BRIGHTNESS_WIDTH_SEL; 931 + 932 + addr = wled->sink_addr + offset; 933 + val = (wled->max_brightness == WLED5_SINK_REG_BRIGHT_MAX_15B) ? 934 + WLED5_SINK_REG_BRIGHTNESS_WIDTH_15B : 935 + WLED5_SINK_REG_BRIGHTNESS_WIDTH_12B; 936 + rc = regmap_write(wled->regmap, addr, val); 937 + if (rc < 0) 938 + return rc; 939 + 940 + rc = regmap_update_bits(wled->regmap, 941 + wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 942 + WLED4_SINK_REG_CURR_SINK_MASK, sink_en); 943 + if (rc < 0) 944 + return rc; 945 + 946 + /* This updates only FSC configuration in WLED5 */ 947 + rc = wled->wled_sync_toggle(wled); 948 + if (rc < 0) { 949 + pr_err("Failed to toggle sync reg rc:%d\n", rc); 950 + return rc; 951 + } 952 + 953 + rc = wled_auto_detection_at_init(wled); 954 + if (rc < 0) 955 + return rc; 956 + 957 + return 0; 958 + } 959 + 960 + static const struct wled_config wled5_config_defaults = { 961 + .boost_i_limit = 5, 962 + .string_i_limit = 10, 963 + .ovp = 4, 964 + .num_strings = 4, 965 + .switch_freq = 11, 966 + .mod_sel = 0, 967 + .cabc_sel = 0, 1072 968 .cabc = false, 1073 969 .external_pfet = false, 1074 970 .auto_detection_enabled = false, ··· 1205 875 .size = ARRAY_SIZE(wled4_boost_i_limit_values), 1206 876 }; 1207 877 878 + static inline u32 wled5_boost_i_limit_values_fn(u32 idx) 879 + { 880 + return 525 + (idx * 175); 881 + } 882 + 883 + static const struct wled_var_cfg wled5_boost_i_limit_cfg = { 884 + .fn = wled5_boost_i_limit_values_fn, 885 + .size = 8, 886 + }; 887 + 1208 888 static const u32 wled3_ovp_values[] = { 1209 889 35, 32, 29, 27, 1210 890 }; ··· 1231 891 static const struct wled_var_cfg wled4_ovp_cfg = { 1232 892 .values = wled4_ovp_values, 1233 893 .size = ARRAY_SIZE(wled4_ovp_values), 894 + }; 895 + 896 + static inline u32 wled5_ovp_values_fn(u32 idx) 897 + { 898 + /* 899 + * 0000 - 38.5 V 900 + * 0001 - 37 V .. 901 + * 1111 - 16 V 902 + */ 903 + return 38500 - (idx * 1500); 904 + } 905 + 906 + static const struct wled_var_cfg wled5_ovp_cfg = { 907 + .fn = wled5_ovp_values_fn, 908 + .size = 16, 1234 909 }; 1235 910 1236 911 static u32 wled3_num_strings_values_fn(u32 idx) ··· 1295 940 .size = 16, 1296 941 }; 1297 942 943 + static const struct wled_var_cfg wled5_mod_sel_cfg = { 944 + .size = 2, 945 + }; 946 + 947 + static const struct wled_var_cfg wled5_cabc_sel_cfg = { 948 + .size = 4, 949 + }; 950 + 1298 951 static u32 wled_values(const struct wled_var_cfg *cfg, u32 idx) 1299 952 { 1300 953 if (idx >= cfg->size) ··· 1314 951 return idx; 1315 952 } 1316 953 1317 - static int wled_configure(struct wled *wled, int version) 954 + static int wled_configure(struct wled *wled) 1318 955 { 1319 956 struct wled_config *cfg = &wled->cfg; 1320 957 struct device *dev = wled->dev; ··· 1379 1016 }, 1380 1017 }; 1381 1018 1019 + const struct wled_u32_opts wled5_opts[] = { 1020 + { 1021 + .name = "qcom,current-boost-limit", 1022 + .val_ptr = &cfg->boost_i_limit, 1023 + .cfg = &wled5_boost_i_limit_cfg, 1024 + }, 1025 + { 1026 + .name = "qcom,current-limit-microamp", 1027 + .val_ptr = &cfg->string_i_limit, 1028 + .cfg = &wled4_string_i_limit_cfg, 1029 + }, 1030 + { 1031 + .name = "qcom,ovp-millivolt", 1032 + .val_ptr = &cfg->ovp, 1033 + .cfg = &wled5_ovp_cfg, 1034 + }, 1035 + { 1036 + .name = "qcom,switching-freq", 1037 + .val_ptr = &cfg->switch_freq, 1038 + .cfg = &wled3_switch_freq_cfg, 1039 + }, 1040 + { 1041 + .name = "qcom,num-strings", 1042 + .val_ptr = &cfg->num_strings, 1043 + .cfg = &wled4_num_strings_cfg, 1044 + }, 1045 + { 1046 + .name = "qcom,modulator-sel", 1047 + .val_ptr = &cfg->mod_sel, 1048 + .cfg = &wled5_mod_sel_cfg, 1049 + }, 1050 + { 1051 + .name = "qcom,cabc-sel", 1052 + .val_ptr = &cfg->cabc_sel, 1053 + .cfg = &wled5_cabc_sel_cfg, 1054 + }, 1055 + }; 1056 + 1382 1057 const struct wled_bool_opts bool_opts[] = { 1383 1058 { "qcom,cs-out", &cfg->cs_out_en, }, 1384 1059 { "qcom,ext-gen", &cfg->ext_gen, }, ··· 1436 1035 if (rc) 1437 1036 wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node); 1438 1037 1439 - switch (version) { 1038 + switch (wled->version) { 1440 1039 case 3: 1441 1040 u32_opts = wled3_opts; 1442 1041 size = ARRAY_SIZE(wled3_opts); 1443 1042 *cfg = wled3_config_defaults; 1444 1043 wled->wled_set_brightness = wled3_set_brightness; 1044 + wled->wled_sync_toggle = wled3_sync_toggle; 1445 1045 wled->max_string_count = 3; 1446 1046 wled->sink_addr = wled->ctrl_addr; 1447 1047 break; ··· 1452 1050 size = ARRAY_SIZE(wled4_opts); 1453 1051 *cfg = wled4_config_defaults; 1454 1052 wled->wled_set_brightness = wled4_set_brightness; 1053 + wled->wled_sync_toggle = wled3_sync_toggle; 1054 + wled->wled_cabc_config = wled4_cabc_config; 1055 + wled->wled_ovp_delay = wled4_ovp_delay; 1056 + wled->wled_auto_detection_required = 1057 + wled4_auto_detection_required; 1058 + wled->max_string_count = 4; 1059 + 1060 + prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); 1061 + if (!prop_addr) { 1062 + dev_err(wled->dev, "invalid IO resources\n"); 1063 + return -EINVAL; 1064 + } 1065 + wled->sink_addr = be32_to_cpu(*prop_addr); 1066 + break; 1067 + 1068 + case 5: 1069 + u32_opts = wled5_opts; 1070 + size = ARRAY_SIZE(wled5_opts); 1071 + *cfg = wled5_config_defaults; 1072 + wled->wled_set_brightness = wled5_set_brightness; 1073 + wled->wled_sync_toggle = wled5_sync_toggle; 1074 + wled->wled_cabc_config = wled5_cabc_config; 1075 + wled->wled_ovp_delay = wled5_ovp_delay; 1076 + wled->wled_auto_detection_required = 1077 + wled5_auto_detection_required; 1455 1078 wled->max_string_count = 4; 1456 1079 1457 1080 prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); ··· 1613 1186 struct backlight_device *bl; 1614 1187 struct wled *wled; 1615 1188 struct regmap *regmap; 1616 - int version; 1617 1189 u32 val; 1618 1190 int rc; 1619 1191 ··· 1629 1203 wled->regmap = regmap; 1630 1204 wled->dev = &pdev->dev; 1631 1205 1632 - version = (uintptr_t)of_device_get_match_data(&pdev->dev); 1633 - if (!version) { 1206 + wled->version = (uintptr_t)of_device_get_match_data(&pdev->dev); 1207 + if (!wled->version) { 1634 1208 dev_err(&pdev->dev, "Unknown device version\n"); 1635 1209 return -ENODEV; 1636 1210 } 1637 1211 1638 1212 mutex_init(&wled->lock); 1639 - rc = wled_configure(wled, version); 1213 + rc = wled_configure(wled); 1640 1214 if (rc) 1641 1215 return rc; 1642 1216 1643 - switch (version) { 1217 + val = WLED3_SINK_REG_BRIGHT_MAX; 1218 + of_property_read_u32(pdev->dev.of_node, "max-brightness", &val); 1219 + wled->max_brightness = val; 1220 + 1221 + switch (wled->version) { 1644 1222 case 3: 1645 1223 wled->cfg.auto_detection_enabled = false; 1646 1224 rc = wled3_setup(wled); ··· 1659 1229 rc = wled4_setup(wled); 1660 1230 if (rc) { 1661 1231 dev_err(&pdev->dev, "wled4_setup failed\n"); 1232 + return rc; 1233 + } 1234 + break; 1235 + 1236 + case 5: 1237 + wled->has_short_detect = true; 1238 + if (wled->cfg.cabc_sel) 1239 + wled->max_brightness = WLED5_SINK_REG_BRIGHT_MAX_12B; 1240 + 1241 + rc = wled5_setup(wled); 1242 + if (rc) { 1243 + dev_err(&pdev->dev, "wled5_setup failed\n"); 1662 1244 return rc; 1663 1245 } 1664 1246 break; ··· 1696 1254 memset(&props, 0, sizeof(struct backlight_properties)); 1697 1255 props.type = BACKLIGHT_RAW; 1698 1256 props.brightness = val; 1699 - props.max_brightness = WLED3_SINK_REG_BRIGHT_MAX; 1257 + props.max_brightness = wled->max_brightness; 1700 1258 bl = devm_backlight_device_register(&pdev->dev, wled->name, 1701 1259 &pdev->dev, wled, 1702 1260 &wled_ops, &props); ··· 1719 1277 { .compatible = "qcom,pm8941-wled", .data = (void *)3 }, 1720 1278 { .compatible = "qcom,pmi8998-wled", .data = (void *)4 }, 1721 1279 { .compatible = "qcom,pm660l-wled", .data = (void *)4 }, 1280 + { .compatible = "qcom,pm8150l-wled", .data = (void *)5 }, 1722 1281 {} 1723 1282 }; 1724 1283 MODULE_DEVICE_TABLE(of, wled_match_table);
+1
include/linux/backlight.h
··· 190 190 extern int backlight_register_notifier(struct notifier_block *nb); 191 191 extern int backlight_unregister_notifier(struct notifier_block *nb); 192 192 extern struct backlight_device *backlight_device_get_by_type(enum backlight_type type); 193 + struct backlight_device *backlight_device_get_by_name(const char *name); 193 194 extern int backlight_device_set_brightness(struct backlight_device *bd, unsigned long brightness); 194 195 195 196 #define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)
-17
include/linux/spi/l4f00242t03.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * l4f00242t03.h -- Platform glue for Epson L4F00242T03 LCD 4 - * 5 - * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> 6 - * Based on Marek Vasut work in lms283gf05.h 7 - */ 8 - 9 - #ifndef _INCLUDE_LINUX_SPI_L4F00242T03_H_ 10 - #define _INCLUDE_LINUX_SPI_L4F00242T03_H_ 11 - 12 - struct l4f00242t03_pdata { 13 - unsigned int reset_gpio; 14 - unsigned int data_enable_gpio; 15 - }; 16 - 17 - #endif /* _INCLUDE_LINUX_SPI_L4F00242T03_H_ */