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

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

Pull backlight updates from Lee Jones:
"New Drivers:
- Add support for Richtek RT4831 Backlight

New Device Support:
- Add support for Qualcomm PMI8994 WLED Backlight

Fix-ups:
- Device Tree adaptions to richtek,rt4831-backlight
- Trivial spelling, whitespace, etc in Kconfig
- Use Atomic PWM API in lm3630a_bl

Bug Fixes:
- Fix Firmware Node Leak in error path in lm3630a_bl
- Fix erroneous return codes in lm3630a_bl"

* tag 'backlight-next-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
backlight: lm3630a: Convert to atomic PWM API and check for errors
backlight: lm3630a: Fix return code of .update_status() callback
backlight: Kconfig whitespace and indentation cleanups
video: backlight: qcom-wled: Add PMI8994 compatible
backlight: rt4831: Adds support for Richtek RT4831 backlight
backlight: rt4831: Adds DT binding document for Richtek RT4831 backlight
backlight: lm3630a_bl: Put fwnode in error case during ->probe()

+250 -39
+19 -11
drivers/video/backlight/Kconfig
··· 128 128 If you have a HX-8357 LCD panel, say Y to enable its LCD control 129 129 driver. 130 130 131 - config LCD_OTM3225A 132 - tristate "ORISE Technology OTM3225A support" 133 - depends on SPI 134 - help 135 - If you have a panel based on the OTM3225A controller 136 - chip then say y to include a driver for it. 131 + config LCD_OTM3225A 132 + tristate "ORISE Technology OTM3225A support" 133 + depends on SPI 134 + help 135 + If you have a panel based on the OTM3225A controller 136 + chip then say y to include a driver for it. 137 137 138 138 endif # LCD_CLASS_DEVICE 139 139 ··· 269 269 WLED output, say Y here to enable this driver. 270 270 271 271 config BACKLIGHT_APPLE 272 - tristate "Apple Backlight Driver" 273 - depends on X86 && ACPI 274 - help 275 - If you have an Intel-based Apple say Y to enable a driver for its 276 - backlight. 272 + tristate "Apple Backlight Driver" 273 + depends on X86 && ACPI 274 + help 275 + If you have an Intel-based Apple say Y to enable a driver for its 276 + backlight. 277 277 278 278 config BACKLIGHT_TOSA 279 279 tristate "Sharp SL-6000 Backlight Driver" ··· 288 288 help 289 289 If you have the Qualcomm PMIC, say Y to enable a driver for the 290 290 WLED block. Currently it supports PM8941 and PMI8998. 291 + 292 + config BACKLIGHT_RT4831 293 + tristate "Richtek RT4831 Backlight Driver" 294 + depends on MFD_RT4831 295 + help 296 + This enables support for Richtek RT4831 Backlight driver. 297 + It's commonly used to drive the display WLED. There're four channels 298 + inisde, and each channel can provide up to 30mA current. 291 299 292 300 config BACKLIGHT_SAHARA 293 301 tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
+1
drivers/video/backlight/Makefile
··· 49 49 obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o 50 50 obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o 51 51 obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o 52 + obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o 52 53 obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o 53 54 obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o 54 55 obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
+26 -28
drivers/video/backlight/lm3630a_bl.c
··· 52 52 struct gpio_desc *enable_gpio; 53 53 struct regmap *regmap; 54 54 struct pwm_device *pwmd; 55 + struct pwm_state pwmd_state; 55 56 }; 56 57 57 58 /* i2c access */ ··· 168 167 return rval; 169 168 } 170 169 171 - static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) 170 + static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) 172 171 { 173 - unsigned int period = pchip->pdata->pwm_period; 174 - unsigned int duty = br * period / br_max; 172 + int err; 175 173 176 - pwm_config(pchip->pwmd, duty, period); 177 - if (duty) 178 - pwm_enable(pchip->pwmd); 179 - else 180 - pwm_disable(pchip->pwmd); 174 + pchip->pwmd_state.period = pchip->pdata->pwm_period; 175 + 176 + err = pwm_set_relative_duty_cycle(&pchip->pwmd_state, br, br_max); 177 + if (err) 178 + return err; 179 + 180 + pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false; 181 + 182 + return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state); 181 183 } 182 184 183 185 /* update and get brightness */ ··· 191 187 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 192 188 193 189 /* pwm control */ 194 - if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 195 - lm3630a_pwm_ctrl(pchip, bl->props.brightness, 196 - bl->props.max_brightness); 197 - return bl->props.brightness; 198 - } 190 + if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) 191 + return lm3630a_pwm_ctrl(pchip, bl->props.brightness, 192 + bl->props.max_brightness); 199 193 200 194 /* disable sleep */ 201 195 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); ··· 212 210 return 0; 213 211 214 212 out_i2c_err: 215 - dev_err(pchip->dev, "i2c failed to access\n"); 216 - return bl->props.brightness; 213 + dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret)); 214 + return ret; 217 215 } 218 216 219 217 static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) ··· 266 264 enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 267 265 268 266 /* pwm control */ 269 - if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 270 - lm3630a_pwm_ctrl(pchip, bl->props.brightness, 271 - bl->props.max_brightness); 272 - return bl->props.brightness; 273 - } 267 + if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) 268 + return lm3630a_pwm_ctrl(pchip, bl->props.brightness, 269 + bl->props.max_brightness); 274 270 275 271 /* disable sleep */ 276 272 ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); ··· 287 287 return 0; 288 288 289 289 out_i2c_err: 290 - dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); 291 - return bl->props.brightness; 290 + dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret)); 291 + return ret; 292 292 } 293 293 294 294 static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) ··· 482 482 483 483 device_for_each_child_node(pchip->dev, node) { 484 484 ret = lm3630a_parse_bank(pdata, node, &seen_led_sources); 485 - if (ret) 485 + if (ret) { 486 + fwnode_handle_put(node); 486 487 return ret; 488 + } 487 489 } 488 490 489 491 return ret; ··· 565 563 return PTR_ERR(pchip->pwmd); 566 564 } 567 565 568 - /* 569 - * FIXME: pwm_apply_args() should be removed when switching to 570 - * the atomic PWM API. 571 - */ 572 - pwm_apply_args(pchip->pwmd); 566 + pwm_init_state(pchip->pwmd, &pchip->pwmd_state); 573 567 } 574 568 575 569 /* interrupt enable : irq 0 is not allowed */
+1
drivers/video/backlight/qcom-wled.c
··· 1717 1717 1718 1718 static const struct of_device_id wled_match_table[] = { 1719 1719 { .compatible = "qcom,pm8941-wled", .data = (void *)3 }, 1720 + { .compatible = "qcom,pmi8994-wled", .data = (void *)4 }, 1720 1721 { .compatible = "qcom,pmi8998-wled", .data = (void *)4 }, 1721 1722 { .compatible = "qcom,pm660l-wled", .data = (void *)4 }, 1722 1723 { .compatible = "qcom,pm8150l-wled", .data = (void *)5 },
+203
drivers/video/backlight/rt4831-backlight.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <dt-bindings/leds/rt4831-backlight.h> 4 + #include <linux/backlight.h> 5 + #include <linux/bitops.h> 6 + #include <linux/kernel.h> 7 + #include <linux/module.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/property.h> 10 + #include <linux/regmap.h> 11 + 12 + #define RT4831_REG_BLCFG 0x02 13 + #define RT4831_REG_BLDIML 0x04 14 + #define RT4831_REG_ENABLE 0x08 15 + 16 + #define RT4831_BLMAX_BRIGHTNESS 2048 17 + 18 + #define RT4831_BLOVP_MASK GENMASK(7, 5) 19 + #define RT4831_BLOVP_SHIFT 5 20 + #define RT4831_BLPWMEN_MASK BIT(0) 21 + #define RT4831_BLEN_MASK BIT(4) 22 + #define RT4831_BLCH_MASK GENMASK(3, 0) 23 + #define RT4831_BLDIML_MASK GENMASK(2, 0) 24 + #define RT4831_BLDIMH_MASK GENMASK(10, 3) 25 + #define RT4831_BLDIMH_SHIFT 3 26 + 27 + struct rt4831_priv { 28 + struct device *dev; 29 + struct regmap *regmap; 30 + struct backlight_device *bl; 31 + }; 32 + 33 + static int rt4831_bl_update_status(struct backlight_device *bl_dev) 34 + { 35 + struct rt4831_priv *priv = bl_get_data(bl_dev); 36 + int brightness = backlight_get_brightness(bl_dev); 37 + unsigned int enable = brightness ? RT4831_BLEN_MASK : 0; 38 + u8 v[2]; 39 + int ret; 40 + 41 + if (brightness) { 42 + v[0] = (brightness - 1) & RT4831_BLDIML_MASK; 43 + v[1] = ((brightness - 1) & RT4831_BLDIMH_MASK) >> RT4831_BLDIMH_SHIFT; 44 + 45 + ret = regmap_raw_write(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v)); 46 + if (ret) 47 + return ret; 48 + } 49 + 50 + return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLEN_MASK, enable); 51 + 52 + } 53 + 54 + static int rt4831_bl_get_brightness(struct backlight_device *bl_dev) 55 + { 56 + struct rt4831_priv *priv = bl_get_data(bl_dev); 57 + unsigned int val; 58 + u8 v[2]; 59 + int ret; 60 + 61 + ret = regmap_read(priv->regmap, RT4831_REG_ENABLE, &val); 62 + if (ret) 63 + return ret; 64 + 65 + if (!(val & RT4831_BLEN_MASK)) 66 + return 0; 67 + 68 + ret = regmap_raw_read(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v)); 69 + if (ret) 70 + return ret; 71 + 72 + ret = (v[1] << RT4831_BLDIMH_SHIFT) + (v[0] & RT4831_BLDIML_MASK) + 1; 73 + 74 + return ret; 75 + } 76 + 77 + static const struct backlight_ops rt4831_bl_ops = { 78 + .options = BL_CORE_SUSPENDRESUME, 79 + .update_status = rt4831_bl_update_status, 80 + .get_brightness = rt4831_bl_get_brightness, 81 + }; 82 + 83 + static int rt4831_parse_backlight_properties(struct rt4831_priv *priv, 84 + struct backlight_properties *bl_props) 85 + { 86 + struct device *dev = priv->dev; 87 + u8 propval; 88 + u32 brightness; 89 + unsigned int val = 0; 90 + int ret; 91 + 92 + /* common properties */ 93 + ret = device_property_read_u32(dev, "max-brightness", &brightness); 94 + if (ret) 95 + brightness = RT4831_BLMAX_BRIGHTNESS; 96 + 97 + bl_props->max_brightness = min_t(u32, brightness, RT4831_BLMAX_BRIGHTNESS); 98 + 99 + ret = device_property_read_u32(dev, "default-brightness", &brightness); 100 + if (ret) 101 + brightness = bl_props->max_brightness; 102 + 103 + bl_props->brightness = min_t(u32, brightness, bl_props->max_brightness); 104 + 105 + /* vendor properties */ 106 + if (device_property_read_bool(dev, "richtek,pwm-enable")) 107 + val = RT4831_BLPWMEN_MASK; 108 + 109 + ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLPWMEN_MASK, val); 110 + if (ret) 111 + return ret; 112 + 113 + ret = device_property_read_u8(dev, "richtek,bled-ovp-sel", &propval); 114 + if (ret) 115 + propval = RT4831_BLOVPLVL_21V; 116 + 117 + propval = min_t(u8, propval, RT4831_BLOVPLVL_29V); 118 + ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLOVP_MASK, 119 + propval << RT4831_BLOVP_SHIFT); 120 + if (ret) 121 + return ret; 122 + 123 + ret = device_property_read_u8(dev, "richtek,channel-use", &propval); 124 + if (ret) { 125 + dev_err(dev, "richtek,channel-use DT property missing\n"); 126 + return ret; 127 + } 128 + 129 + if (!(propval & RT4831_BLCH_MASK)) { 130 + dev_err(dev, "No channel specified\n"); 131 + return -EINVAL; 132 + } 133 + 134 + return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLCH_MASK, propval); 135 + } 136 + 137 + static int rt4831_bl_probe(struct platform_device *pdev) 138 + { 139 + struct rt4831_priv *priv; 140 + struct backlight_properties bl_props = { .type = BACKLIGHT_RAW, 141 + .scale = BACKLIGHT_SCALE_LINEAR }; 142 + int ret; 143 + 144 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 145 + if (!priv) 146 + return -ENOMEM; 147 + 148 + priv->dev = &pdev->dev; 149 + 150 + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); 151 + if (!priv->regmap) { 152 + dev_err(&pdev->dev, "Failed to init regmap\n"); 153 + return -ENODEV; 154 + } 155 + 156 + ret = rt4831_parse_backlight_properties(priv, &bl_props); 157 + if (ret) { 158 + dev_err(&pdev->dev, "Failed to parse backlight properties\n"); 159 + return ret; 160 + } 161 + 162 + priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, priv, 163 + &rt4831_bl_ops, &bl_props); 164 + if (IS_ERR(priv->bl)) { 165 + dev_err(&pdev->dev, "Failed to register backlight\n"); 166 + return PTR_ERR(priv->bl); 167 + } 168 + 169 + backlight_update_status(priv->bl); 170 + platform_set_drvdata(pdev, priv); 171 + 172 + return 0; 173 + } 174 + 175 + static int rt4831_bl_remove(struct platform_device *pdev) 176 + { 177 + struct rt4831_priv *priv = platform_get_drvdata(pdev); 178 + struct backlight_device *bl_dev = priv->bl; 179 + 180 + bl_dev->props.brightness = 0; 181 + backlight_update_status(priv->bl); 182 + 183 + return 0; 184 + } 185 + 186 + static const struct of_device_id __maybe_unused rt4831_bl_of_match[] = { 187 + { .compatible = "richtek,rt4831-backlight", }, 188 + {} 189 + }; 190 + MODULE_DEVICE_TABLE(of, rt4831_bl_of_match); 191 + 192 + static struct platform_driver rt4831_bl_driver = { 193 + .driver = { 194 + .name = "rt4831-backlight", 195 + .of_match_table = rt4831_bl_of_match, 196 + }, 197 + .probe = rt4831_bl_probe, 198 + .remove = rt4831_bl_remove, 199 + }; 200 + module_platform_driver(rt4831_bl_driver); 201 + 202 + MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 203 + MODULE_LICENSE("GPL v2");