summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 16:13:39 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 16:13:39 -0800
commit38edc3dff9d2805c48e0a171667e7ca820336ab7 (patch)
tree1e69585093b00ef56bc58f945fd7e2ae6f18bec9 /drivers/video
parent8b233da0cc825166b5fa06c898517a7477b54388 (diff)
parent102a1b382177d89f75bc49b931c329a317cf531f (diff)
downloadlinux-38edc3dff9d2805c48e0a171667e7ca820336ab7.tar.gz
linux-38edc3dff9d2805c48e0a171667e7ca820336ab7.tar.bz2
linux-38edc3dff9d2805c48e0a171667e7ca820336ab7.zip
Merge tag 'backlight-next-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight
Pull backlight updates from Lee Jones: "New Functionality: - Add support for an enable GPIO; lm3630a_bl - Add support for short circuit handling; qcom-wled - Add support for automatic string detection; qcom-wled Fix-ups: - Update Device Tree bindings; lm3630a-backlight, led-backlight, qcom-wled - Constify; ipaq_micro_bl - Optimise for CPU cycles; pwm_bl - Coding style fix-ups; pwm_bl - Trivial fix-ups (white space, comments, renaming); pwm_bl, gpio_backlight, qcom-wled - Kconfig dependency hacking; LCD_HP700 - Rename, refactor and add peripherals; pm8941-wled => qcom-wled - Make use of GPIO look-up tables; tosa_bl, tosa_lcd - Remove superfluous code; gpio_backlight - Adapt GPIO direction handling; gpio_backlight - Remove legacy use of platform data; gpio_backlight Bug Fixes: - Provide modules aliases; lm3630a_bl" * tag 'backlight-next-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: (32 commits) backlight: qcom-wled: Fix spelling mistake "trigged" -> "triggered" backlight: gpio: Pull gpio_backlight_initial_power_state() into probe backlight: gpio: Use a helper variable for &pdev->dev backlight: gpio: Remove unused fields from platform data sh: ecovec24: don't set unused fields in platform data backlight: gpio: Simplify the platform data handling sh: ecovec24: add additional properties to the backlight device backlight: gpio: Explicitly set the direction of the GPIO backlight: gpio: Remove stray newline backlight: gpio: Remove unneeded include video: backlight: tosa: Use GPIO lookup table backlight: qcom-wled: Add auto string detection logic backlight: qcom-wled: Add support for short circuit handling backlight: qcom-wled: Add support for WLED4 peripheral backlight: qcom-wled: Restructure the driver for WLED3 backlight: qcom-wled: Rename PM8941* to WLED3 backlight: qcom-wled: Add new properties for PMI8998 backlight: qcom-wled: Restructure the qcom-wled bindings backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c dt-bindings: backlight: lm3630a: Fix missing include ...
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/backlight/Kconfig12
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/gpio_backlight.c128
-rw-r--r--drivers/video/backlight/ipaq_micro_bl.c2
-rw-r--r--drivers/video/backlight/lm3630a_bl.c13
-rw-r--r--drivers/video/backlight/pm8941-wled.c424
-rw-r--r--drivers/video/backlight/pwm_bl.c39
-rw-r--r--drivers/video/backlight/qcom-wled.c1296
-rw-r--r--drivers/video/backlight/tosa_bl.c10
-rw-r--r--drivers/video/backlight/tosa_bl.h8
-rw-r--r--drivers/video/backlight/tosa_lcd.c28
11 files changed, 1418 insertions, 544 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 40676be2e46a..403707a3e503 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -99,7 +99,7 @@ config LCD_TOSA
config LCD_HP700
tristate "HP Jornada 700 series LCD Driver"
- depends on SA1100_JORNADA720_SSP && !PREEMPT
+ depends on SA1100_JORNADA720_SSP && !PREEMPTION
default y
help
If you have an HP Jornada 700 series handheld (710/720/728)
@@ -228,7 +228,7 @@ config BACKLIGHT_HP680
config BACKLIGHT_HP700
tristate "HP Jornada 700 series Backlight Driver"
- depends on SA1100_JORNADA720_SSP && !PREEMPT
+ depends on SA1100_JORNADA720_SSP && !PREEMPTION
default y
help
If you have an HP Jornada 700 series,
@@ -282,12 +282,12 @@ config BACKLIGHT_TOSA
If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its backlight
-config BACKLIGHT_PM8941_WLED
- tristate "Qualcomm PM8941 WLED Driver"
+config BACKLIGHT_QCOM_WLED
+ tristate "Qualcomm PMIC WLED Driver"
select REGMAP
help
- If you have the Qualcomm PM8941, say Y to enable a driver for the
- WLED block.
+ If you have the Qualcomm PMIC, say Y to enable a driver for the
+ WLED block. Currently it supports PM8941 and PMI8998.
config BACKLIGHT_SAHARA
tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 63c507c07437..6f8777037c37 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -48,8 +48,8 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
-obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index 18e053e4716c..75409ddfba3e 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -6,29 +6,23 @@
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/fb.h>
-#include <linux/gpio.h> /* Only for legacy support */
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_data/gpio_backlight.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
struct gpio_backlight {
- struct device *dev;
struct device *fbdev;
-
struct gpio_desc *gpiod;
- int def_value;
};
-static int gpio_backlight_update_status(struct backlight_device *bl)
+static int gpio_backlight_get_next_brightness(struct backlight_device *bl)
{
- struct gpio_backlight *gbl = bl_get_data(bl);
int brightness = bl->props.brightness;
if (bl->props.power != FB_BLANK_UNBLANK ||
@@ -36,6 +30,14 @@ static int gpio_backlight_update_status(struct backlight_device *bl)
bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
brightness = 0;
+ return brightness;
+}
+
+static int gpio_backlight_update_status(struct backlight_device *bl)
+{
+ struct gpio_backlight *gbl = bl_get_data(bl);
+ int brightness = gpio_backlight_get_next_brightness(bl);
+
gpiod_set_value_cansleep(gbl->gpiod, brightness);
return 0;
@@ -55,105 +57,63 @@ static const struct backlight_ops gpio_backlight_ops = {
.check_fb = gpio_backlight_check_fb,
};
-static int gpio_backlight_probe_dt(struct platform_device *pdev,
- struct gpio_backlight *gbl)
-{
- struct device *dev = &pdev->dev;
- int ret;
-
- gbl->def_value = device_property_read_bool(dev, "default-on");
-
- gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
- if (IS_ERR(gbl->gpiod)) {
- ret = PTR_ERR(gbl->gpiod);
-
- if (ret != -EPROBE_DEFER) {
- dev_err(dev,
- "Error: The gpios parameter is missing or invalid.\n");
- }
- return ret;
- }
-
- return 0;
-}
-
-static int gpio_backlight_initial_power_state(struct gpio_backlight *gbl)
-{
- struct device_node *node = gbl->dev->of_node;
-
- /* Not booted with device tree or no phandle link to the node */
- if (!node || !node->phandle)
- return gbl->def_value ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
-
- /* if the enable GPIO is disabled, do not enable the backlight */
- if (gpiod_get_value_cansleep(gbl->gpiod) == 0)
- return FB_BLANK_POWERDOWN;
-
- return FB_BLANK_UNBLANK;
-}
-
-
static int gpio_backlight_probe(struct platform_device *pdev)
{
- struct gpio_backlight_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct gpio_backlight_platform_data *pdata = dev_get_platdata(dev);
+ struct device_node *of_node = dev->of_node;
struct backlight_properties props;
struct backlight_device *bl;
struct gpio_backlight *gbl;
- int ret;
+ int ret, init_brightness, def_value;
- gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
+ gbl = devm_kzalloc(dev, sizeof(*gbl), GFP_KERNEL);
if (gbl == NULL)
return -ENOMEM;
- gbl->dev = &pdev->dev;
+ if (pdata)
+ gbl->fbdev = pdata->fbdev;
- if (pdev->dev.fwnode) {
- ret = gpio_backlight_probe_dt(pdev, gbl);
- if (ret)
- return ret;
- } else if (pdata) {
- /*
- * Legacy platform data GPIO retrieveal. Do not expand
- * the use of this code path, currently only used by one
- * SH board.
- */
- unsigned long flags = GPIOF_DIR_OUT;
+ def_value = device_property_read_bool(dev, "default-on");
- gbl->fbdev = pdata->fbdev;
- gbl->def_value = pdata->def_value;
- flags |= gbl->def_value ? GPIOF_INIT_HIGH : GPIOF_INIT_LOW;
-
- ret = devm_gpio_request_one(gbl->dev, pdata->gpio, flags,
- pdata ? pdata->name : "backlight");
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to request GPIO\n");
- return ret;
- }
- gbl->gpiod = gpio_to_desc(pdata->gpio);
- if (!gbl->gpiod)
- return -EINVAL;
- } else {
- dev_err(&pdev->dev,
- "failed to find platform data or device tree node.\n");
- return -ENODEV;
+ gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
+ if (IS_ERR(gbl->gpiod)) {
+ ret = PTR_ERR(gbl->gpiod);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev,
+ "Error: The gpios parameter is missing or invalid.\n");
+ return ret;
}
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
props.max_brightness = 1;
- bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
- &pdev->dev, gbl, &gpio_backlight_ops,
- &props);
+ bl = devm_backlight_device_register(dev, dev_name(dev), dev, gbl,
+ &gpio_backlight_ops, &props);
if (IS_ERR(bl)) {
- dev_err(&pdev->dev, "failed to register backlight\n");
+ dev_err(dev, "failed to register backlight\n");
return PTR_ERR(bl);
}
- bl->props.power = gpio_backlight_initial_power_state(gbl);
+ /* Set the initial power state */
+ if (!of_node || !of_node->phandle)
+ /* Not booted with device tree or no phandle link to the node */
+ bl->props.power = def_value ? FB_BLANK_UNBLANK
+ : FB_BLANK_POWERDOWN;
+ else if (gpiod_get_direction(gbl->gpiod) == 0 &&
+ gpiod_get_value_cansleep(gbl->gpiod) == 0)
+ bl->props.power = FB_BLANK_POWERDOWN;
+ else
+ bl->props.power = FB_BLANK_UNBLANK;
+
bl->props.brightness = 1;
- backlight_update_status(bl);
+ init_brightness = gpio_backlight_get_next_brightness(bl);
+ ret = gpiod_direction_output(gbl->gpiod, init_brightness);
+ if (ret) {
+ dev_err(dev, "failed to set initial brightness\n");
+ return ret;
+ }
platform_set_drvdata(pdev, bl);
return 0;
diff --git a/drivers/video/backlight/ipaq_micro_bl.c b/drivers/video/backlight/ipaq_micro_bl.c
index 1123f67c12b3..85b16cc82878 100644
--- a/drivers/video/backlight/ipaq_micro_bl.c
+++ b/drivers/video/backlight/ipaq_micro_bl.c
@@ -44,7 +44,7 @@ static const struct backlight_ops micro_bl_ops = {
.update_status = micro_bl_update_status,
};
-static struct backlight_properties micro_bl_props = {
+static const struct backlight_properties micro_bl_props = {
.type = BACKLIGHT_RAW,
.max_brightness = 255,
.power = FB_BLANK_UNBLANK,
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 2d8e8192e4e2..ee320883b710 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -12,6 +12,7 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
#include <linux/pwm.h>
#include <linux/platform_data/lm3630a_bl.h>
@@ -48,6 +49,7 @@ struct lm3630a_chip {
struct lm3630a_platform_data *pdata;
struct backlight_device *bleda;
struct backlight_device *bledb;
+ struct gpio_desc *enable_gpio;
struct regmap *regmap;
struct pwm_device *pwmd;
};
@@ -534,6 +536,13 @@ static int lm3630a_probe(struct i2c_client *client,
}
pchip->pdata = pdata;
+ pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(pchip->enable_gpio)) {
+ rval = PTR_ERR(pchip->enable_gpio);
+ return rval;
+ }
+
/* chip initialize */
rval = lm3630a_chip_init(pchip);
if (rval < 0) {
@@ -598,12 +607,14 @@ static const struct i2c_device_id lm3630a_id[] = {
{}
};
+MODULE_DEVICE_TABLE(i2c, lm3630a_id);
+
static const struct of_device_id lm3630a_match_table[] = {
{ .compatible = "ti,lm3630a", },
{ },
};
-MODULE_DEVICE_TABLE(i2c, lm3630a_id);
+MODULE_DEVICE_TABLE(of, lm3630a_match_table);
static struct i2c_driver lm3630a_i2c_driver = {
.driver = {
diff --git a/drivers/video/backlight/pm8941-wled.c b/drivers/video/backlight/pm8941-wled.c
deleted file mode 100644
index 82b85725a22a..000000000000
--- a/drivers/video/backlight/pm8941-wled.c
+++ /dev/null
@@ -1,424 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015, Sony Mobile Communications, AB.
- */
-
-#include <linux/kernel.h>
-#include <linux/backlight.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-
-/* From DT binding */
-#define PM8941_WLED_DEFAULT_BRIGHTNESS 2048
-
-#define PM8941_WLED_REG_VAL_BASE 0x40
-#define PM8941_WLED_REG_VAL_MAX 0xFFF
-
-#define PM8941_WLED_REG_MOD_EN 0x46
-#define PM8941_WLED_REG_MOD_EN_BIT BIT(7)
-#define PM8941_WLED_REG_MOD_EN_MASK BIT(7)
-
-#define PM8941_WLED_REG_SYNC 0x47
-#define PM8941_WLED_REG_SYNC_MASK 0x07
-#define PM8941_WLED_REG_SYNC_LED1 BIT(0)
-#define PM8941_WLED_REG_SYNC_LED2 BIT(1)
-#define PM8941_WLED_REG_SYNC_LED3 BIT(2)
-#define PM8941_WLED_REG_SYNC_ALL 0x07
-#define PM8941_WLED_REG_SYNC_CLEAR 0x00
-
-#define PM8941_WLED_REG_FREQ 0x4c
-#define PM8941_WLED_REG_FREQ_MASK 0x0f
-
-#define PM8941_WLED_REG_OVP 0x4d
-#define PM8941_WLED_REG_OVP_MASK 0x03
-
-#define PM8941_WLED_REG_BOOST 0x4e
-#define PM8941_WLED_REG_BOOST_MASK 0x07
-
-#define PM8941_WLED_REG_SINK 0x4f
-#define PM8941_WLED_REG_SINK_MASK 0xe0
-#define PM8941_WLED_REG_SINK_SHFT 0x05
-
-/* Per-'string' registers below */
-#define PM8941_WLED_REG_STR_OFFSET 0x10
-
-#define PM8941_WLED_REG_STR_MOD_EN_BASE 0x60
-#define PM8941_WLED_REG_STR_MOD_MASK BIT(7)
-#define PM8941_WLED_REG_STR_MOD_EN BIT(7)
-
-#define PM8941_WLED_REG_STR_SCALE_BASE 0x62
-#define PM8941_WLED_REG_STR_SCALE_MASK 0x1f
-
-#define PM8941_WLED_REG_STR_MOD_SRC_BASE 0x63
-#define PM8941_WLED_REG_STR_MOD_SRC_MASK 0x01
-#define PM8941_WLED_REG_STR_MOD_SRC_INT 0x00
-#define PM8941_WLED_REG_STR_MOD_SRC_EXT 0x01
-
-#define PM8941_WLED_REG_STR_CABC_BASE 0x66
-#define PM8941_WLED_REG_STR_CABC_MASK BIT(7)
-#define PM8941_WLED_REG_STR_CABC_EN BIT(7)
-
-struct pm8941_wled_config {
- u32 i_boost_limit;
- u32 ovp;
- u32 switch_freq;
- u32 num_strings;
- u32 i_limit;
- bool cs_out_en;
- bool ext_gen;
- bool cabc_en;
-};
-
-struct pm8941_wled {
- const char *name;
- struct regmap *regmap;
- u16 addr;
-
- struct pm8941_wled_config cfg;
-};
-
-static int pm8941_wled_update_status(struct backlight_device *bl)
-{
- struct pm8941_wled *wled = bl_get_data(bl);
- u16 val = bl->props.brightness;
- u8 ctrl = 0;
- int rc;
- int i;
-
- if (bl->props.power != FB_BLANK_UNBLANK ||
- bl->props.fb_blank != FB_BLANK_UNBLANK ||
- bl->props.state & BL_CORE_FBBLANK)
- val = 0;
-
- if (val != 0)
- ctrl = PM8941_WLED_REG_MOD_EN_BIT;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_MOD_EN,
- PM8941_WLED_REG_MOD_EN_MASK, ctrl);
- if (rc)
- return rc;
-
- for (i = 0; i < wled->cfg.num_strings; ++i) {
- u8 v[2] = { val & 0xff, (val >> 8) & 0xf };
-
- rc = regmap_bulk_write(wled->regmap,
- wled->addr + PM8941_WLED_REG_VAL_BASE + 2 * i,
- v, 2);
- if (rc)
- return rc;
- }
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_SYNC,
- PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_ALL);
- if (rc)
- return rc;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_SYNC,
- PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_CLEAR);
- return rc;
-}
-
-static int pm8941_wled_setup(struct pm8941_wled *wled)
-{
- int rc;
- int i;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_OVP,
- PM8941_WLED_REG_OVP_MASK, wled->cfg.ovp);
- if (rc)
- return rc;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_BOOST,
- PM8941_WLED_REG_BOOST_MASK, wled->cfg.i_boost_limit);
- if (rc)
- return rc;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_FREQ,
- PM8941_WLED_REG_FREQ_MASK, wled->cfg.switch_freq);
- if (rc)
- return rc;
-
- if (wled->cfg.cs_out_en) {
- u8 all = (BIT(wled->cfg.num_strings) - 1)
- << PM8941_WLED_REG_SINK_SHFT;
-
- rc = regmap_update_bits(wled->regmap,
- wled->addr + PM8941_WLED_REG_SINK,
- PM8941_WLED_REG_SINK_MASK, all);
- if (rc)
- return rc;
- }
-
- for (i = 0; i < wled->cfg.num_strings; ++i) {
- u16 addr = wled->addr + PM8941_WLED_REG_STR_OFFSET * i;
-
- rc = regmap_update_bits(wled->regmap,
- addr + PM8941_WLED_REG_STR_MOD_EN_BASE,
- PM8941_WLED_REG_STR_MOD_MASK,
- PM8941_WLED_REG_STR_MOD_EN);
- if (rc)
- return rc;
-
- if (wled->cfg.ext_gen) {
- rc = regmap_update_bits(wled->regmap,
- addr + PM8941_WLED_REG_STR_MOD_SRC_BASE,
- PM8941_WLED_REG_STR_MOD_SRC_MASK,
- PM8941_WLED_REG_STR_MOD_SRC_EXT);
- if (rc)
- return rc;
- }
-
- rc = regmap_update_bits(wled->regmap,
- addr + PM8941_WLED_REG_STR_SCALE_BASE,
- PM8941_WLED_REG_STR_SCALE_MASK,
- wled->cfg.i_limit);
- if (rc)
- return rc;
-
- rc = regmap_update_bits(wled->regmap,
- addr + PM8941_WLED_REG_STR_CABC_BASE,
- PM8941_WLED_REG_STR_CABC_MASK,
- wled->cfg.cabc_en ?
- PM8941_WLED_REG_STR_CABC_EN : 0);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-static const struct pm8941_wled_config pm8941_wled_config_defaults = {
- .i_boost_limit = 3,
- .i_limit = 20,
- .ovp = 2,
- .switch_freq = 5,
- .num_strings = 0,
- .cs_out_en = false,
- .ext_gen = false,
- .cabc_en = false,
-};
-
-struct pm8941_wled_var_cfg {
- const u32 *values;
- u32 (*fn)(u32);
- int size;
-};
-
-static const u32 pm8941_wled_i_boost_limit_values[] = {
- 105, 385, 525, 805, 980, 1260, 1400, 1680,
-};
-
-static const struct pm8941_wled_var_cfg pm8941_wled_i_boost_limit_cfg = {
- .values = pm8941_wled_i_boost_limit_values,
- .size = ARRAY_SIZE(pm8941_wled_i_boost_limit_values),
-};
-
-static const u32 pm8941_wled_ovp_values[] = {
- 35, 32, 29, 27,
-};
-
-static const struct pm8941_wled_var_cfg pm8941_wled_ovp_cfg = {
- .values = pm8941_wled_ovp_values,
- .size = ARRAY_SIZE(pm8941_wled_ovp_values),
-};
-
-static u32 pm8941_wled_num_strings_values_fn(u32 idx)
-{
- return idx + 1;
-}
-
-static const struct pm8941_wled_var_cfg pm8941_wled_num_strings_cfg = {
- .fn = pm8941_wled_num_strings_values_fn,
- .size = 3,
-};
-
-static u32 pm8941_wled_switch_freq_values_fn(u32 idx)
-{
- return 19200 / (2 * (1 + idx));
-}
-
-static const struct pm8941_wled_var_cfg pm8941_wled_switch_freq_cfg = {
- .fn = pm8941_wled_switch_freq_values_fn,
- .size = 16,
-};
-
-static const struct pm8941_wled_var_cfg pm8941_wled_i_limit_cfg = {
- .size = 26,
-};
-
-static u32 pm8941_wled_values(const struct pm8941_wled_var_cfg *cfg, u32 idx)
-{
- if (idx >= cfg->size)
- return UINT_MAX;
- if (cfg->fn)
- return cfg->fn(idx);
- if (cfg->values)
- return cfg->values[idx];
- return idx;
-}
-
-static int pm8941_wled_configure(struct pm8941_wled *wled, struct device *dev)
-{
- struct pm8941_wled_config *cfg = &wled->cfg;
- u32 val;
- int rc;
- u32 c;
- int i;
- int j;
-
- const struct {
- const char *name;
- u32 *val_ptr;
- const struct pm8941_wled_var_cfg *cfg;
- } u32_opts[] = {
- {
- "qcom,current-boost-limit",
- &cfg->i_boost_limit,
- .cfg = &pm8941_wled_i_boost_limit_cfg,
- },
- {
- "qcom,current-limit",
- &cfg->i_limit,
- .cfg = &pm8941_wled_i_limit_cfg,
- },
- {
- "qcom,ovp",
- &cfg->ovp,
- .cfg = &pm8941_wled_ovp_cfg,
- },
- {
- "qcom,switching-freq",
- &cfg->switch_freq,
- .cfg = &pm8941_wled_switch_freq_cfg,
- },
- {
- "qcom,num-strings",
- &cfg->num_strings,
- .cfg = &pm8941_wled_num_strings_cfg,
- },
- };
- const struct {
- const char *name;
- bool *val_ptr;
- } bool_opts[] = {
- { "qcom,cs-out", &cfg->cs_out_en, },
- { "qcom,ext-gen", &cfg->ext_gen, },
- { "qcom,cabc", &cfg->cabc_en, },
- };
-
- rc = of_property_read_u32(dev->of_node, "reg", &val);
- if (rc || val > 0xffff) {
- dev_err(dev, "invalid IO resources\n");
- return rc ? rc : -EINVAL;
- }
- wled->addr = val;
-
- rc = of_property_read_string(dev->of_node, "label", &wled->name);
- if (rc)
- wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
-
- *cfg = pm8941_wled_config_defaults;
- for (i = 0; i < ARRAY_SIZE(u32_opts); ++i) {
- rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val);
- if (rc == -EINVAL) {
- continue;
- } else if (rc) {
- dev_err(dev, "error reading '%s'\n", u32_opts[i].name);
- return rc;
- }
-
- c = UINT_MAX;
- for (j = 0; c != val; j++) {
- c = pm8941_wled_values(u32_opts[i].cfg, j);
- if (c == UINT_MAX) {
- dev_err(dev, "invalid value for '%s'\n",
- u32_opts[i].name);
- return -EINVAL;
- }
- }
-
- dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c);
- *u32_opts[i].val_ptr = j;
- }
-
- for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) {
- if (of_property_read_bool(dev->of_node, bool_opts[i].name))
- *bool_opts[i].val_ptr = true;
- }
-
- cfg->num_strings = cfg->num_strings + 1;
-
- return 0;
-}
-
-static const struct backlight_ops pm8941_wled_ops = {
- .update_status = pm8941_wled_update_status,
-};
-
-static int pm8941_wled_probe(struct platform_device *pdev)
-{
- struct backlight_properties props;
- struct backlight_device *bl;
- struct pm8941_wled *wled;
- struct regmap *regmap;
- u32 val;
- int rc;
-
- regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!regmap) {
- dev_err(&pdev->dev, "Unable to get regmap\n");
- return -EINVAL;
- }
-
- wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL);
- if (!wled)
- return -ENOMEM;
-
- wled->regmap = regmap;
-
- rc = pm8941_wled_configure(wled, &pdev->dev);
- if (rc)
- return rc;
-
- rc = pm8941_wled_setup(wled);
- if (rc)
- return rc;
-
- val = PM8941_WLED_DEFAULT_BRIGHTNESS;
- of_property_read_u32(pdev->dev.of_node, "default-brightness", &val);
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.brightness = val;
- props.max_brightness = PM8941_WLED_REG_VAL_MAX;
- bl = devm_backlight_device_register(&pdev->dev, wled->name,
- &pdev->dev, wled,
- &pm8941_wled_ops, &props);
- return PTR_ERR_OR_ZERO(bl);
-};
-
-static const struct of_device_id pm8941_wled_match_table[] = {
- { .compatible = "qcom,pm8941-wled" },
- {}
-};
-MODULE_DEVICE_TABLE(of, pm8941_wled_match_table);
-
-static struct platform_driver pm8941_wled_driver = {
- .probe = pm8941_wled_probe,
- .driver = {
- .name = "pm8941-wled",
- .of_match_table = pm8941_wled_match_table,
- },
-};
-
-module_platform_driver(pm8941_wled_driver);
-
-MODULE_DESCRIPTION("pm8941 wled driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 746eebc411df..efb4efc2a13d 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -125,8 +125,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
state.duty_cycle = compute_duty_cycle(pb, brightness);
pwm_apply_state(pb->pwm, &state);
pwm_backlight_power_on(pb);
- } else
+ } else {
pwm_backlight_power_off(pb);
+ }
if (pb->notify_after)
pb->notify_after(pb->dev, brightness);
@@ -148,15 +149,16 @@ static const struct backlight_ops pwm_backlight_ops = {
};
#ifdef CONFIG_OF
-#define PWM_LUMINANCE_SCALE 10000 /* luminance scale */
+#define PWM_LUMINANCE_SHIFT 16
+#define PWM_LUMINANCE_SCALE (1 << PWM_LUMINANCE_SHIFT) /* luminance scale */
/*
* CIE lightness to PWM conversion.
*
* The CIE 1931 lightness formula is what actually describes how we perceive
* light:
- * Y = (L* / 902.3) if L* ≤ 0.08856
- * Y = ((L* + 16) / 116)^3 if L* > 0.08856
+ * Y = (L* / 903.3) if L* ≤ 8
+ * Y = ((L* + 16) / 116)^3 if L* > 8
*
* Where Y is the luminance, the amount of light coming out of the screen, and
* is a number between 0.0 and 1.0; and L* is the lightness, how bright a human
@@ -165,16 +167,25 @@ static const struct backlight_ops pwm_backlight_ops = {
* The following function does the fixed point maths needed to implement the
* above formula.
*/
-static u64 cie1931(unsigned int lightness, unsigned int scale)
+static u64 cie1931(unsigned int lightness)
{
u64 retval;
+ /*
+ * @lightness is given as a number between 0 and 1, expressed
+ * as a fixed-point number in scale
+ * PWM_LUMINANCE_SCALE. Convert to a percentage, still
+ * expressed as a fixed-point number, so the above formulas
+ * can be applied.
+ */
lightness *= 100;
- if (lightness <= (8 * scale)) {
- retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023);
+ if (lightness <= (8 * PWM_LUMINANCE_SCALE)) {
+ retval = DIV_ROUND_CLOSEST(lightness * 10, 9033);
} else {
- retval = int_pow((lightness + (16 * scale)) / 116, 3);
- retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale));
+ retval = (lightness + (16 * PWM_LUMINANCE_SCALE)) / 116;
+ retval *= retval * retval;
+ retval += 1ULL << (2*PWM_LUMINANCE_SHIFT - 1);
+ retval >>= 2*PWM_LUMINANCE_SHIFT;
}
return retval;
@@ -208,8 +219,7 @@ int pwm_backlight_brightness_default(struct device *dev,
/* Fill the table using the cie1931 algorithm */
for (i = 0; i < data->max_brightness; i++) {
retval = cie1931((i * PWM_LUMINANCE_SCALE) /
- data->max_brightness, PWM_LUMINANCE_SCALE) *
- period;
+ data->max_brightness) * period;
retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE);
if (retval > UINT_MAX)
return -EINVAL;
@@ -564,18 +574,17 @@ static int pwm_backlight_probe(struct platform_device *pdev)
memset(&props, 0, sizeof(struct backlight_properties));
if (data->levels) {
+ pb->levels = data->levels;
+
/*
* For the DT case, only when brightness levels is defined
* data->levels is filled. For the non-DT case, data->levels
* can come from platform data, however is not usual.
*/
- for (i = 0; i <= data->max_brightness; i++) {
+ for (i = 0; i <= data->max_brightness; i++)
if (data->levels[i] > pb->scale)
pb->scale = data->levels[i];
- pb->levels = data->levels;
- }
-
if (pwm_backlight_is_linear(data))
props.scale = BACKLIGHT_SCALE_LINEAR;
else
diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c
new file mode 100644
index 000000000000..d46052d8ff41
--- /dev/null
+++ b/drivers/video/backlight/qcom-wled.c
@@ -0,0 +1,1296 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015, Sony Mobile Communications, AB.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include <linux/kernel.h>
+#include <linux/backlight.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+/* From DT binding */
+#define WLED_MAX_STRINGS 4
+
+#define WLED_DEFAULT_BRIGHTNESS 2048
+#define WLED_SOFT_START_DLY_US 10000
+#define WLED3_SINK_REG_BRIGHT_MAX 0xFFF
+
+/* WLED3/WLED4 control registers */
+#define WLED3_CTRL_REG_FAULT_STATUS 0x08
+#define WLED3_CTRL_REG_ILIM_FAULT_BIT BIT(0)
+#define WLED3_CTRL_REG_OVP_FAULT_BIT BIT(1)
+#define WLED4_CTRL_REG_SC_FAULT_BIT BIT(2)
+
+#define WLED3_CTRL_REG_INT_RT_STS 0x10
+#define WLED3_CTRL_REG_OVP_FAULT_STATUS BIT(1)
+
+#define WLED3_CTRL_REG_MOD_EN 0x46
+#define WLED3_CTRL_REG_MOD_EN_MASK BIT(7)
+#define WLED3_CTRL_REG_MOD_EN_SHIFT 7
+
+#define WLED3_CTRL_REG_FEEDBACK_CONTROL 0x48
+
+#define WLED3_CTRL_REG_FREQ 0x4c
+#define WLED3_CTRL_REG_FREQ_MASK GENMASK(3, 0)
+
+#define WLED3_CTRL_REG_OVP 0x4d
+#define WLED3_CTRL_REG_OVP_MASK GENMASK(1, 0)
+
+#define WLED3_CTRL_REG_ILIMIT 0x4e
+#define WLED3_CTRL_REG_ILIMIT_MASK GENMASK(2, 0)
+
+/* WLED3/WLED4 sink registers */
+#define WLED3_SINK_REG_SYNC 0x47
+#define WLED3_SINK_REG_SYNC_CLEAR 0x00
+
+#define WLED3_SINK_REG_CURR_SINK 0x4f
+#define WLED3_SINK_REG_CURR_SINK_MASK GENMASK(7, 5)
+#define WLED3_SINK_REG_CURR_SINK_SHFT 5
+
+/* WLED3 specific per-'string' registers below */
+#define WLED3_SINK_REG_BRIGHT(n) (0x40 + n)
+
+#define WLED3_SINK_REG_STR_MOD_EN(n) (0x60 + (n * 0x10))
+#define WLED3_SINK_REG_STR_MOD_MASK BIT(7)
+
+#define WLED3_SINK_REG_STR_FULL_SCALE_CURR(n) (0x62 + (n * 0x10))
+#define WLED3_SINK_REG_STR_FULL_SCALE_CURR_MASK GENMASK(4, 0)
+
+#define WLED3_SINK_REG_STR_MOD_SRC(n) (0x63 + (n * 0x10))
+#define WLED3_SINK_REG_STR_MOD_SRC_MASK BIT(0)
+#define WLED3_SINK_REG_STR_MOD_SRC_INT 0x00
+#define WLED3_SINK_REG_STR_MOD_SRC_EXT 0x01
+
+#define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10))
+#define WLED3_SINK_REG_STR_CABC_MASK BIT(7)
+
+/* WLED4 specific control registers */
+#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e
+#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7)
+
+#define WLED4_CTRL_REG_SEC_ACCESS 0xd0
+#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5
+
+#define WLED4_CTRL_REG_TEST1 0xe2
+#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09
+
+/* WLED4 specific sink registers */
+#define WLED4_SINK_REG_CURR_SINK 0x46
+#define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4)
+#define WLED4_SINK_REG_CURR_SINK_SHFT 4
+
+/* WLED4 specific per-'string' registers below */
+#define WLED4_SINK_REG_STR_MOD_EN(n) (0x50 + (n * 0x10))
+#define WLED4_SINK_REG_STR_MOD_MASK BIT(7)
+
+#define WLED4_SINK_REG_STR_FULL_SCALE_CURR(n) (0x52 + (n * 0x10))
+#define WLED4_SINK_REG_STR_FULL_SCALE_CURR_MASK GENMASK(3, 0)
+
+#define WLED4_SINK_REG_STR_MOD_SRC(n) (0x53 + (n * 0x10))
+#define WLED4_SINK_REG_STR_MOD_SRC_MASK BIT(0)
+#define WLED4_SINK_REG_STR_MOD_SRC_INT 0x00
+#define WLED4_SINK_REG_STR_MOD_SRC_EXT 0x01
+
+#define WLED4_SINK_REG_STR_CABC(n) (0x56 + (n * 0x10))
+#define WLED4_SINK_REG_STR_CABC_MASK BIT(7)
+
+#define WLED4_SINK_REG_BRIGHT(n) (0x57 + (n * 0x10))
+
+struct wled_var_cfg {
+ const u32 *values;
+ u32 (*fn)(u32);
+ int size;
+};
+
+struct wled_u32_opts {
+ con