- 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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAl3f2c8ACgkQUa+KL4f8
 d2HFlg//Y7NRP+FdSYC74S94fmG6H73H+/iGp7qfRF9qud41Ux87/ERbCXj180d1
 i0TSfynGUfk367kM08GUGdVuABeq/0UObJeOplIXEOJF6P/B7Dc+grbmilzC2CjE
 ygjLp4iPcbl6HuIBr2zMu7S3RWi9lbM4ClOhjSjP4cACnZCr4p8Z4RTATQaOhx2B
 vXez5PbYfs43FyLqXDnVsmykHzer8Y5MU7APS7KXxt1elqX87yS8AHOMnjTjoiif
 xe0r06H9zda1YVkRoQnDyc1OVZmYqKNT4zeATrm2r9La9IO3quelBs9NAD0bl9Rw
 ES6mmEbUJ8nTnYS+Om0T9aKe6jrsCUMY5+a5Sct33FAiHAXyMpCCtjfZIlkEb2iv
 Hew9Xp4aFrTEh5tPV4F15jyMgu9JJoTS4k0d7STj/eWigsdh3Ir+fMt+VGqDLW5G
 epLEPuNMT4fchsETPangnkTKb+3CWkK9YyEjtC5zaM/WmFh2VIcTLyYdmuHbT5Yo
 +BoyqWMAUgCSS8ytclaLOAEvZ8OxCMUaTSCUqvRGVk661uJm5w1gabIUs2p16bMA
 nTba3hqHdgSCFFZfgkJa3ZD+Hcbc49BN3qxHJjim6pezTKiLZKmDDcW1JaX9uHrW
 75gC3Ka9nfYAjZqocoMywNSDAKRr4pJ1DpPX6z6gc6oP6Vb2Bjs=
 =8RxV
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2019-12-01 16:13:39 -08:00
commit 38edc3dff9
19 changed files with 1658 additions and 617 deletions

View File

@ -0,0 +1,28 @@
led-backlight bindings
This binding is used to describe a basic backlight device made of LEDs.
It can also be used to describe a backlight device controlled by the output of
a LED driver.
Required properties:
- compatible: "led-backlight"
- leds: a list of LEDs
Optional properties:
- brightness-levels: Array of distinct brightness levels. The levels must be
in the range accepted by the underlying LED devices.
This is used to translate a backlight brightness level
into a LED brightness level. If it is not provided, the
identity mapping is used.
- default-brightness-level: The default brightness level.
Example:
backlight {
compatible = "led-backlight";
leds = <&led1>, <&led2>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
};

View File

@ -29,6 +29,10 @@ properties:
'#size-cells':
const: 0
enable-gpios:
description: GPIO to use to enable/disable the backlight (HWEN pin).
maxItems: 1
required:
- compatible
- reg
@ -89,6 +93,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
@ -96,6 +101,7 @@ examples:
led-controller@38 {
compatible = "ti,lm3630a";
reg = <0x38>;
enable-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -1,42 +0,0 @@
Binding for Qualcomm PM8941 WLED driver
Required properties:
- compatible: should be "qcom,pm8941-wled"
- reg: slave address
Optional properties:
- default-brightness: brightness value on boot, value from: 0-4095
default: 2048
- label: The name of the backlight device
- qcom,cs-out: bool; enable current sink output
- qcom,cabc: bool; enable content adaptive backlight control
- qcom,ext-gen: bool; use externally generated modulator signal to dim
- qcom,current-limit: mA; per-string current limit; value from 0 to 25
default: 20mA
- qcom,current-boost-limit: mA; boost current limit; one of:
105, 385, 525, 805, 980, 1260, 1400, 1680
default: 805mA
- qcom,switching-freq: kHz; switching frequency; one of:
600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
1600, 1920, 2400, 3200, 4800, 9600,
default: 1600kHz
- qcom,ovp: V; Over-voltage protection limit; one of:
27, 29, 32, 35
default: 29V
- qcom,num-strings: #; number of led strings attached; value from 1 to 3
default: 2
Example:
pm8941-wled@d800 {
compatible = "qcom,pm8941-wled";
reg = <0xd800>;
label = "backlight";
qcom,cs-out;
qcom,current-limit = <20>;
qcom,current-boost-limit = <805>;
qcom,switching-freq = <1600>;
qcom,ovp = <29>;
qcom,num-strings = <2>;
};

View File

@ -0,0 +1,154 @@
Binding for Qualcomm Technologies, Inc. WLED driver
WLED (White Light Emitting Diode) driver is used for controlling display
backlight that is part of PMIC on Qualcomm Technologies, Inc. reference
platforms. The PMIC is connected to the host processor via SPMI bus.
- compatible
Usage: required
Value type: <string>
Definition: should be one of:
"qcom,pm8941-wled"
"qcom,pmi8998-wled"
"qcom,pm660l-wled"
- reg
Usage: required
Value type: <prop encoded array>
Definition: Base address of the WLED modules.
- default-brightness
Usage: optional
Value type: <u32>
Definition: brightness value on boot, value from: 0-4095.
Default: 2048
- label
Usage: required
Value type: <string>
Definition: The name of the backlight device
- qcom,cs-out
Usage: optional
Value type: <bool>
Definition: enable current sink output.
This property is supported only for PM8941.
- qcom,cabc
Usage: optional
Value type: <bool>
Definition: enable content adaptive backlight control.
- qcom,ext-gen
Usage: optional
Value type: <bool>
Definition: use externally generated modulator signal to dim.
This property is supported only for PM8941.
- qcom,current-limit
Usage: optional
Value type: <u32>
Definition: mA; per-string current limit; value from 0 to 25 with
1 mA step. Default 20 mA.
This property is supported only for pm8941.
- qcom,current-limit-microamp
Usage: optional
Value type: <u32>
Definition: uA; per-string current limit; value from 0 to 30000 with
2500 uA step. Default 25 mA.
- qcom,current-boost-limit
Usage: optional
Value type: <u32>
Definition: mA; boost current limit.
For pm8941: one of: 105, 385, 525, 805, 980, 1260, 1400,
1680. Default: 805 mA.
For pmi8998: one of: 105, 280, 450, 620, 970, 1150, 1300,
1500. Default: 970 mA.
- qcom,switching-freq
Usage: optional
Value type: <u32>
Definition: kHz; switching frequency; one of: 600, 640, 685, 738,
800, 872, 960, 1066, 1200, 1371, 1600, 1920, 2400, 3200,
4800, 9600.
Default: for pm8941: 1600 kHz
for pmi8998: 800 kHz
- qcom,ovp
Usage: optional
Value type: <u32>
Definition: V; Over-voltage protection limit; one of:
27, 29, 32, 35. Default: 29V
This property is supported only for PM8941.
- qcom,ovp-millivolt
Usage: optional
Value type: <u32>
Definition: mV; Over-voltage protection limit;
For pmi8998: one of 18100, 19600, 29600, 31100.
Default 29600 mV.
If this property is not specified for PM8941, it
falls back to "qcom,ovp" property.
- qcom,num-strings
Usage: optional
Value type: <u32>
Definition: #; number of led strings attached;
value: For PM8941 from 1 to 3. Default: 2
For PMI8998 from 1 to 4.
- interrupts
Usage: optional
Value type: <prop encoded array>
Definition: Interrupts associated with WLED. This should be
"short" and "ovp" interrupts. Interrupts can be
specified as per the encoding listed under
Documentation/devicetree/bindings/spmi/
qcom,spmi-pmic-arb.txt.
- interrupt-names
Usage: optional
Value type: <string>
Definition: Interrupt names associated with the interrupts.
Must be "short" and "ovp". The short circuit detection
is not supported for PM8941.
- qcom,enabled-strings
Usage: optional
Value tyoe: <u32 array>
Definition: Array of the WLED strings numbered from 0 to 3. Each
string of leds are operated individually. Specify the
list of strings used by the device. Any combination of
led strings can be used.
- qcom,external-pfet
Usage: optional
Value type: <bool>
Definition: Specify if external PFET control for short circuit
protection is used. This property is supported only
for PMI8998.
- qcom,auto-string-detection
Usage: optional
Value type: <bool>
Definition: Enables auto-detection of the WLED string configuration.
This feature is not supported for PM8941.
Example:
pm8941-wled@d800 {
compatible = "qcom,pm8941-wled";
reg = <0xd800>;
label = "backlight";
qcom,cs-out;
qcom,current-limit = <20>;
qcom,current-boost-limit = <805>;
qcom,switching-freq = <1600>;
qcom,ovp = <29>;
qcom,num-strings = <2>;
qcom,enabled-strings = <0 1>;
};

View File

@ -72,18 +72,6 @@
#define TOSA_GPIO_BAT0_TH_ON (TOSA_TC6393XB_GPIO_BASE + 14)
#define TOSA_GPIO_BAT1_TH_ON (TOSA_TC6393XB_GPIO_BASE + 15)
/*
* Timing Generator
*/
#define TG_PNLCTL 0x00
#define TG_TPOSCTL 0x01
#define TG_DUTYCTL 0x02
#define TG_GPOSR 0x03
#define TG_GPODR1 0x04
#define TG_GPODR2 0x05
#define TG_PINICTL 0x06
#define TG_HPOSCTL 0x07
/*
* PXA GPIOs
*/
@ -192,7 +180,4 @@
#define TOSA_KEY_MAIL KEY_MAIL
#endif
struct spi_device;
extern int tosa_bl_enable(struct spi_device *spi, int enable);
#endif /* _ASM_ARCH_TOSA_H_ */

View File

@ -813,6 +813,26 @@ static struct pxa2xx_spi_controller pxa_ssp_master_info = {
.num_chipselect = 1,
};
static struct gpiod_lookup_table tosa_lcd_gpio_table = {
.dev_id = "spi2.0",
.table = {
GPIO_LOOKUP("tc6393xb",
TOSA_GPIO_TG_ON - TOSA_TC6393XB_GPIO_BASE,
"tg #pwr", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct gpiod_lookup_table tosa_lcd_bl_gpio_table = {
.dev_id = "i2c-tosa-bl",
.table = {
GPIO_LOOKUP("tc6393xb",
TOSA_GPIO_BL_C20MA - TOSA_TC6393XB_GPIO_BASE,
"backlight", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct spi_board_info spi_board_info[] __initdata = {
{
.modalias = "tosa-lcd",
@ -923,6 +943,8 @@ static void __init tosa_init(void)
platform_scoop_config = &tosa_pcmcia_config;
pxa2xx_set_spi_info(2, &pxa_ssp_master_info);
gpiod_add_lookup_table(&tosa_lcd_gpio_table);
gpiod_add_lookup_table(&tosa_lcd_bl_gpio_table);
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
clk_add_alias("CLK_CK3P6MI", tc6393xb_device.name, "GPIO11_CLK", NULL);

View File

@ -371,20 +371,32 @@ static struct platform_device lcdc_device = {
},
};
static struct gpio_backlight_platform_data gpio_backlight_data = {
.fbdev = &lcdc_device.dev,
.gpio = GPIO_PTR1,
.def_value = 1,
.name = "backlight",
};
static struct platform_device gpio_backlight_device = {
.name = "gpio-backlight",
.dev = {
.platform_data = &gpio_backlight_data,
static struct gpiod_lookup_table gpio_backlight_lookup = {
.dev_id = "gpio-backlight.0",
.table = {
GPIO_LOOKUP("sh7724_pfc", GPIO_PTR1, NULL, GPIO_ACTIVE_HIGH),
{ }
},
};
static struct property_entry gpio_backlight_props[] = {
PROPERTY_ENTRY_BOOL("default-on"),
{ }
};
static struct gpio_backlight_platform_data gpio_backlight_data = {
.fbdev = &lcdc_device.dev,
};
static const struct platform_device_info gpio_backlight_device_info = {
.name = "gpio-backlight",
.data = &gpio_backlight_data,
.size_data = sizeof(gpio_backlight_data),
.properties = gpio_backlight_props,
};
static struct platform_device *gpio_backlight_device;
/* CEU0 */
static struct ceu_platform_data ceu0_pdata = {
.num_subdevs = 2,
@ -1006,7 +1018,6 @@ static struct platform_device *ecovec_devices[] __initdata = {
&usb1_common_device,
&usbhs_device,
&lcdc_device,
&gpio_backlight_device,
&keysc_device,
&cn12_power,
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
@ -1462,6 +1473,12 @@ static int __init arch_setup(void)
#endif
#endif
gpiod_add_lookup_table(&gpio_backlight_lookup);
gpio_backlight_device = platform_device_register_full(
&gpio_backlight_device_info);
if (IS_ERR(gpio_backlight_device))
return PTR_ERR(gpio_backlight_device);
return platform_add_devices(ecovec_devices,
ARRAY_SIZE(ecovec_devices));
}

View File

@ -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"

View File

@ -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

View File

@ -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)
static int gpio_backlight_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret;
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, init_brightness, def_value;
gbl->def_value = device_property_read_bool(dev, "default-on");
gbl = devm_kzalloc(dev, sizeof(*gbl), GFP_KERNEL);
if (gbl == NULL)
return -ENOMEM;
if (pdata)
gbl->fbdev = pdata->fbdev;
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) {
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 backlight_properties props;
struct backlight_device *bl;
struct gpio_backlight *gbl;
int ret;
gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
if (gbl == NULL)
return -ENOMEM;
gbl->dev = &pdev->dev;
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;
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;
}
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;

View File

@ -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,

View File

@ -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 = {

View File

@ -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");

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@
#include <asm/mach/sharpsl_param.h>
#include <mach/tosa.h>
#include "tosa_bl.h"
#define COMADJ_DEFAULT 97
@ -28,6 +28,7 @@
struct tosa_bl_data {
struct i2c_client *i2c;
struct backlight_device *bl;
struct gpio_desc *gpio;
int comadj;
};
@ -42,7 +43,7 @@ static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness)
i2c_smbus_write_byte_data(data->i2c, DAC_CH2, (u8)(brightness & 0xff));
/* SetBacklightVR */
gpio_set_value(TOSA_GPIO_BL_C20MA, brightness & 0x100);
gpiod_set_value(data->gpio, brightness & 0x100);
tosa_bl_enable(spi, brightness);
}
@ -87,9 +88,8 @@ static int tosa_bl_probe(struct i2c_client *client,
return -ENOMEM;
data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
ret = devm_gpio_request_one(&client->dev, TOSA_GPIO_BL_C20MA,
GPIOF_OUT_INIT_LOW, "backlight");
data->gpio = devm_gpiod_get(&client->dev, "backlight", GPIOD_OUT_LOW);
ret = PTR_ERR_OR_ZERO(data->gpio);
if (ret) {
dev_dbg(&data->bl->dev, "Unable to request gpio!\n");
return ret;

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _TOSA_BL_H
#define _TOSA_BL_H
struct spi_device;
extern int tosa_bl_enable(struct spi_device *spi, int enable);
#endif

View File

@ -19,7 +19,7 @@
#include <asm/mach/sharpsl_param.h>
#include <mach/tosa.h>
#include "tosa_bl.h"
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
@ -28,12 +28,26 @@
#define TG_REG0_UD 0x0004
#define TG_REG0_LR 0x0008
/*
* Timing Generator
*/
#define TG_PNLCTL 0x00
#define TG_TPOSCTL 0x01
#define TG_DUTYCTL 0x02
#define TG_GPOSR 0x03
#define TG_GPODR1 0x04
#define TG_GPODR2 0x05
#define TG_PINICTL 0x06
#define TG_HPOSCTL 0x07
#define DAC_BASE 0x4e
struct tosa_lcd_data {
struct spi_device *spi;
struct lcd_device *lcd;
struct i2c_client *i2c;
struct gpio_desc *gpiod_tg;
int lcd_power;
bool is_vga;
@ -66,7 +80,7 @@ EXPORT_SYMBOL(tosa_bl_enable);
static void tosa_lcd_tg_init(struct tosa_lcd_data *data)
{
/* TG on */
gpio_set_value(TOSA_GPIO_TG_ON, 0);
gpiod_set_value(data->gpiod_tg, 0);
mdelay(60);
@ -100,6 +114,7 @@ static void tosa_lcd_tg_on(struct tosa_lcd_data *data)
*/
struct i2c_adapter *adap = i2c_get_adapter(0);
struct i2c_board_info info = {
.dev_name = "tosa-bl",
.type = "tosa-bl",
.addr = DAC_BASE,
.platform_data = data->spi,
@ -121,7 +136,7 @@ static void tosa_lcd_tg_off(struct tosa_lcd_data *data)
mdelay(50);
/* TG Off */
gpio_set_value(TOSA_GPIO_TG_ON, 1);
gpiod_set_value(data->gpiod_tg, 1);
mdelay(100);
}
@ -191,10 +206,9 @@ static int tosa_lcd_probe(struct spi_device *spi)
data->spi = spi;
spi_set_drvdata(spi, data);
ret = devm_gpio_request_one(&spi->dev, TOSA_GPIO_TG_ON,
GPIOF_OUT_INIT_LOW, "tg #pwr");
if (ret < 0)
return ret;
data->gpiod_tg = devm_gpiod_get(&spi->dev, "tg #pwr", GPIOD_OUT_LOW);
if (IS_ERR(data->gpiod_tg))
return PTR_ERR(data->gpiod_tg);
mdelay(60);

View File

@ -9,9 +9,6 @@ struct device;
struct gpio_backlight_platform_data {
struct device *fbdev;
int gpio;
int def_value;
const char *name;
};
#endif