From 2f230f300497f695bec65439b20df3293eabf889 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:09 -0500 Subject: [PATCH 01/11] dt-bindings: mfd: LMU: Add the ramp up/down property Document the ramp-up and ramp-down property in the binding. Removing the "sec" from the property definition as seconds is implied. Signed-off-by: Dan Murphy Reviewed-by: Rob Herring Acked-by: Lee Jones Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/mfd/ti-lmu.txt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt index 86ca786d54fc..160eb0a5e21a 100644 --- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt +++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt @@ -23,8 +23,14 @@ Required properties: 0x36 for LM3633, LM3697 0x63 for LM3695 -Optional property: +Optional properties: - enable-gpios: A GPIO specifier for hardware enable pin. + - ramp-up-us: Current ramping from one brightness level to + the a higher brightness level. + Range from 2048 us - 117.44 s + - ramp-down-us: Current ramping from one brightness level to + the a lower brightness level. + Range from 2048 us - 117.44 s Required node: - backlight: All LMU devices have backlight child nodes. @@ -90,7 +96,7 @@ lm3631@29 { lcd_bl { led-sources = <0 1>; - ramp-up-msec = <300>; + ramp-up-us = <300000>; }; }; }; @@ -152,15 +158,15 @@ lm3633@36 { main { label = "main_lcd"; led-sources = <1 2>; - ramp-up-msec = <500>; - ramp-down-msec = <500>; + ramp-up-us = <500000>; + ramp-down-us = <500000>; }; front { label = "front_lcd"; led-sources = <0>; - ramp-up-msec = <1000>; - ramp-down-msec = <0>; + ramp-up-us = <1000000>; + ramp-down-us = <0>; }; }; @@ -212,8 +218,8 @@ lm3697@36 { lcd { led-sources = <0 1 2>; - ramp-up-msec = <200>; - ramp-down-msec = <200>; + ramp-up-us = <200000>; + ramp-down-us = <200000>; }; }; From d0147554d004e7cc427f6cfecf871916e34e8b67 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:10 -0500 Subject: [PATCH 02/11] dt-bindings: mfd: LMU: Add ti,brightness-resolution Add ti,brightness-resolution to the TI LMU binding to define whether the device uses 8-bit brightness or 11-bit brightness. Signed-off-by: Dan Murphy Reviewed-by: Rob Herring Signed-off-by: Jacek Anaszewski --- Documentation/devicetree/bindings/mfd/ti-lmu.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt index 160eb0a5e21a..e3efefb194c5 100644 --- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt +++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt @@ -31,6 +31,16 @@ Optional properties: - ramp-down-us: Current ramping from one brightness level to the a lower brightness level. Range from 2048 us - 117.44 s + - ti,brightness-resolution - This determines whether to use 8 bit brightness + mode or 11 bit brightness mode. If this value is + not set the device is defaulted to the preferred + 8bit brightness mode per 7.3.4.1 of the data + sheet. This setting can either be in the parent + node or as part of the LED child nodes. This + is determined by the part itself if the strings + have a common brightness register or individual + brightness registers. + The values are 255 (8bit) or 2047 (11bit). Required node: - backlight: All LMU devices have backlight child nodes. @@ -217,6 +227,7 @@ lm3697@36 { compatible = "ti,lm3697-backlight"; lcd { + ti,brightness-resolution = <255>; led-sources = <0 1 2>; ramp-up-us = <200000>; ramp-down-us = <200000>; From 3fce8e1eb9945c2771360542b71ff717460ba4d7 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:11 -0500 Subject: [PATCH 03/11] leds: TI LMU: Add common code for TI LMU devices Create a TI LMU common framework for TI LMU devices that share common features. Currently the runtime ramp and brightness setting have been identified as common features with common register settings. This work is derived from Milo Kims TI LMU MFD code. Signed-off-by: Dan Murphy Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/leds/Kconfig | 9 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-ti-lmu-common.c | 156 +++++++++++++++++++++++++++++ include/linux/leds-ti-lmu-common.h | 47 +++++++++ 4 files changed, 213 insertions(+) create mode 100644 drivers/leds/leds-ti-lmu-common.c create mode 100644 include/linux/leds-ti-lmu-common.h diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 71be87bdb926..4e262696be19 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -783,6 +783,15 @@ config LEDS_NIC78BX To compile this driver as a module, choose M here: the module will be called leds-nic78bx. +config LEDS_TI_LMU_COMMON + tristate "LED driver for TI LMU" + depends on LEDS_CLASS + depends on REGMAP + help + Say Y to enable the LED driver for TI LMU devices. + This supports common features between the TI LM3532, LM3631, LM3632, + LM3633, LM3695 and LM3697. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 1e9702ebffee..84c49339a8e3 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o +obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c new file mode 100644 index 000000000000..adc7293004f1 --- /dev/null +++ b/drivers/leds/leds-ti-lmu-common.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2015 Texas Instruments +// Copyright 2018 Sebastian Reichel +// Copyright 2018 Pavel Machek +// TI LMU LED common framework, based on previous work from +// Milo Kim + +#include +#include +#include + +#include + +const static int ramp_table[16] = {2048, 262000, 524000, 1049000, 2090000, + 4194000, 8389000, 16780000, 33550000, 41940000, + 50330000, 58720000, 67110000, 83880000, + 100660000, 117440000}; + +static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank, + int brightness) +{ + struct regmap *regmap = lmu_bank->regmap; + u8 reg, val; + int ret; + + /* + * Brightness register update + * + * 11 bit dimming: update LSB bits and write MSB byte. + * MSB brightness should be shifted. + * 8 bit dimming: write MSB byte. + */ + if (lmu_bank->max_brightness == MAX_BRIGHTNESS_11BIT) { + reg = lmu_bank->lsb_brightness_reg; + ret = regmap_update_bits(regmap, reg, + LMU_11BIT_LSB_MASK, + brightness); + if (ret) + return ret; + + val = brightness >> LMU_11BIT_MSB_SHIFT; + } else { + val = brightness; + } + + reg = lmu_bank->msb_brightness_reg; + + return regmap_write(regmap, reg, val); +} + +int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness) +{ + return ti_lmu_common_update_brightness(lmu_bank, brightness); +} +EXPORT_SYMBOL(ti_lmu_common_set_brightness); + +static int ti_lmu_common_convert_ramp_to_index(unsigned int usec) +{ + int size = ARRAY_SIZE(ramp_table); + int i; + + if (usec <= ramp_table[0]) + return 0; + + if (usec > ramp_table[size - 1]) + return size - 1; + + for (i = 1; i < size; i++) { + if (usec == ramp_table[i]) + return i; + + /* Find an approximate index by looking up the table */ + if (usec > ramp_table[i - 1] && usec < ramp_table[i]) { + if (usec - ramp_table[i - 1] < ramp_table[i] - usec) + return i - 1; + else + return i; + } + } + + return -EINVAL; +} + +int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank) +{ + struct regmap *regmap = lmu_bank->regmap; + u8 ramp, ramp_up, ramp_down; + + if (lmu_bank->ramp_up_usec == 0 && lmu_bank->ramp_down_usec == 0) { + ramp_up = 0; + ramp_down = 0; + } else { + ramp_up = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_up_usec); + ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec); + } + + if (ramp_up < 0 || ramp_down < 0) + return -EINVAL; + + ramp = (ramp_up << 4) | ramp_down; + + return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp); + +} +EXPORT_SYMBOL(ti_lmu_common_set_ramp); + +int ti_lmu_common_get_ramp_params(struct device *dev, + struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data) +{ + int ret; + + ret = fwnode_property_read_u32(child, "ramp-up-us", + &lmu_data->ramp_up_usec); + if (ret) + dev_warn(dev, "ramp-up-us property missing\n"); + + + ret = fwnode_property_read_u32(child, "ramp-down-us", + &lmu_data->ramp_down_usec); + if (ret) + dev_warn(dev, "ramp-down-us property missing\n"); + + return 0; +} +EXPORT_SYMBOL(ti_lmu_common_get_ramp_params); + +int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data) +{ + int ret; + + ret = device_property_read_u32(dev, "ti,brightness-resolution", + &lmu_data->max_brightness); + if (ret) + ret = fwnode_property_read_u32(child, + "ti,brightness-resolution", + &lmu_data->max_brightness); + if (lmu_data->max_brightness <= 0) { + lmu_data->max_brightness = MAX_BRIGHTNESS_8BIT; + return ret; + } + + if (lmu_data->max_brightness > MAX_BRIGHTNESS_11BIT) + lmu_data->max_brightness = MAX_BRIGHTNESS_11BIT; + + + return 0; +} +EXPORT_SYMBOL(ti_lmu_common_get_brt_res); + +MODULE_DESCRIPTION("TI LMU common LED framework"); +MODULE_AUTHOR("Sebastian Reichel"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("ti-lmu-led-common"); diff --git a/include/linux/leds-ti-lmu-common.h b/include/linux/leds-ti-lmu-common.h new file mode 100644 index 000000000000..5eb111f38803 --- /dev/null +++ b/include/linux/leds-ti-lmu-common.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// TI LMU Common Core +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#ifndef _TI_LMU_COMMON_H_ +#define _TI_LMU_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LMU_11BIT_LSB_MASK (BIT(0) | BIT(1) | BIT(2)) +#define LMU_11BIT_MSB_SHIFT 3 + +#define MAX_BRIGHTNESS_8BIT 255 +#define MAX_BRIGHTNESS_11BIT 2047 + +struct ti_lmu_bank { + struct regmap *regmap; + + int max_brightness; + + u8 lsb_brightness_reg; + u8 msb_brightness_reg; + + u8 runtime_ramp_reg; + u32 ramp_up_usec; + u32 ramp_down_usec; +}; + +int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness); + +int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank); + +int ti_lmu_common_get_ramp_params(struct device *dev, + struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data); + +int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child, + struct ti_lmu_bank *lmu_data); + +#endif /* _TI_LMU_COMMON_H_ */ From 1372bbe66a59528e65d10ae67416835d3ec2452e Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:12 -0500 Subject: [PATCH 04/11] dt-bindings: ti-lmu: Modify dt bindings for the LM3697 The LM3697 is a single function LED driver. The single function LED driver needs to reside in the LED directory as a dedicated LED driver and not as a MFD device. The device does have common brightness and ramp features and those can be accomodated by a TI LMU framework. The LM3697 dt binding needs to be moved from the ti-lmu.txt and a dedicated LED dt binding needs to be added. The new LM3697 LED dt binding will then reside in the Documentation/devicetree/bindings/leds directory and follow the current LED and general bindings guidelines. Signed-off-by: Dan Murphy Reviewed-by: Rob Herring Acked-by: Lee Jones Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/leds/leds-lm3697.txt | 73 +++++++++++++++++++ .../devicetree/bindings/mfd/ti-lmu.txt | 27 +------ 2 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/leds-lm3697.txt diff --git a/Documentation/devicetree/bindings/leds/leds-lm3697.txt b/Documentation/devicetree/bindings/leds/leds-lm3697.txt new file mode 100644 index 000000000000..63992d732959 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lm3697.txt @@ -0,0 +1,73 @@ +* Texas Instruments - LM3697 Highly Efficient White LED Driver + +The LM3697 11-bit LED driver provides high- +performance backlight dimming for 1, 2, or 3 series +LED strings while delivering up to 90% efficiency. + +This device is suitable for display and keypad lighting + +Required properties: + - compatible: + "ti,lm3697" + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 + +Optional properties: + - enable-gpios : GPIO pin to enable/disable the device + - vled-supply : LED supply + +Required child properties: + - reg : 0 - LED is Controlled by bank A + 1 - LED is Controlled by bank B + - led-sources : Indicates which HVLED string is associated to which + control bank. This is a zero based property so + HVLED1 = 0, HVLED2 = 1, HVLED3 = 2. + Additional information is contained + in Documentation/devicetree/bindings/leds/common.txt + +Optional child properties: + - ti,brightness-resolution - see Documentation/devicetree/bindings/mfd/ti-lmu.txt + - ramp-up-us: see Documentation/devicetree/bindings/mfd/ti-lmu.txt + - ramp-down-us: see Documentation/devicetree/bindings/mfd/ti-lmu.txt + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +HVLED string 1 and 3 are controlled by control bank A and HVLED 2 string is +controlled by control bank B. + +led-controller@36 { + compatible = "ti,lm3697"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x36>; + + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; + + led@0 { + reg = <0>; + led-sources = <0 2>; + ti,brightness-resolution = <2047>; + ramp-up-us = <5000>; + ramp-down-us = <1000>; + label = "white:first_backlight_cluster"; + linux,default-trigger = "backlight"; + }; + + led@1 { + reg = <1>; + led-sources = <1>; + ti,brightness-resolution = <255>; + ramp-up-us = <500>; + ramp-down-us = <1000>; + label = "white:second_backlight_cluster"; + linux,default-trigger = "backlight"; + }; +} + +For more product information please see the link below: +http://www.ti.com/lit/ds/symlink/lm3697.pdf diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt index e3efefb194c5..782d3c9812ed 100644 --- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt +++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt @@ -8,7 +8,6 @@ TI LMU driver supports lighting devices below. LM3632 Backlight and regulator LM3633 Backlight, LED and fault monitor LM3695 Backlight - LM3697 Backlight and fault monitor Required properties: - compatible: Should be one of: @@ -16,11 +15,10 @@ Required properties: "ti,lm3632" "ti,lm3633" "ti,lm3695" - "ti,lm3697" - reg: I2C slave address. 0x11 for LM3632 0x29 for LM3631 - 0x36 for LM3633, LM3697 + 0x36 for LM3633 0x63 for LM3695 Optional properties: @@ -51,7 +49,6 @@ Optional nodes: Required properties: - compatible: Should be one of: "ti,lm3633-fault-monitor" - "ti,lm3697-fault-monitor" - leds: LED properties for LM3633. Please refer to [2]. - regulators: Regulator properties for LM3631 and LM3632. Please refer to [3]. @@ -216,25 +213,3 @@ lm3695@63 { }; }; }; - -lm3697@36 { - compatible = "ti,lm3697"; - reg = <0x36>; - - enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; - - backlight { - compatible = "ti,lm3697-backlight"; - - lcd { - ti,brightness-resolution = <255>; - led-sources = <0 1 2>; - ramp-up-us = <200000>; - ramp-down-us = <200000>; - }; - }; - - fault-monitor { - compatible = "ti,lm3697-fault-monitor"; - }; -}; From b86b9ba55a2e0d1013db26084385d83dd7d0b475 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:13 -0500 Subject: [PATCH 05/11] mfd: ti-lmu: Remove support for LM3697 Remove support for the LM3697 from the ti-lmu driver in favor of a dedicated LED driver. Signed-off-by: Dan Murphy Acked-by: Lee Jones Signed-off-by: Jacek Anaszewski --- drivers/mfd/Kconfig | 2 +- drivers/mfd/ti-lmu.c | 17 ----------- include/linux/mfd/ti-lmu-register.h | 44 ----------------------------- include/linux/mfd/ti-lmu.h | 1 - 4 files changed, 1 insertion(+), 63 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 294d9567cc71..8933485b28e7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1336,7 +1336,7 @@ config MFD_TI_LMU help Say yes here to enable support for TI LMU chips. - TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. + TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, and LM3695. It consists of backlight, LED and regulator driver. It provides consistent device controls for lighting functions. diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c index b06cb908d1aa..89b1c5b584af 100644 --- a/drivers/mfd/ti-lmu.c +++ b/drivers/mfd/ti-lmu.c @@ -111,20 +111,6 @@ static const struct mfd_cell lm3695_devices[] = { }, }; -static const struct mfd_cell lm3697_devices[] = { - { - .name = "ti-lmu-backlight", - .id = LM3697, - .of_compatible = "ti,lm3697-backlight", - }, - /* Monitoring driver for open/short circuit detection */ - { - .name = "ti-lmu-fault-monitor", - .id = LM3697, - .of_compatible = "ti,lm3697-fault-monitor", - }, -}; - #define TI_LMU_DATA(chip, max_reg) \ static const struct ti_lmu_data chip##_data = \ { \ @@ -137,7 +123,6 @@ TI_LMU_DATA(lm3631, LM3631_MAX_REG); TI_LMU_DATA(lm3632, LM3632_MAX_REG); TI_LMU_DATA(lm3633, LM3633_MAX_REG); TI_LMU_DATA(lm3695, LM3695_MAX_REG); -TI_LMU_DATA(lm3697, LM3697_MAX_REG); static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id) { @@ -206,7 +191,6 @@ static const struct of_device_id ti_lmu_of_match[] = { { .compatible = "ti,lm3632", .data = &lm3632_data }, { .compatible = "ti,lm3633", .data = &lm3633_data }, { .compatible = "ti,lm3695", .data = &lm3695_data }, - { .compatible = "ti,lm3697", .data = &lm3697_data }, { } }; MODULE_DEVICE_TABLE(of, ti_lmu_of_match); @@ -216,7 +200,6 @@ static const struct i2c_device_id ti_lmu_ids[] = { { "lm3632", LM3632 }, { "lm3633", LM3633 }, { "lm3695", LM3695 }, - { "lm3697", LM3697 }, { } }; MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); diff --git a/include/linux/mfd/ti-lmu-register.h b/include/linux/mfd/ti-lmu-register.h index f09510561a55..76998b01764b 100644 --- a/include/linux/mfd/ti-lmu-register.h +++ b/include/linux/mfd/ti-lmu-register.h @@ -189,48 +189,4 @@ #define LM3695_REG_BRT_MSB 0x14 #define LM3695_MAX_REG 0x14 - -/* LM3697 */ -#define LM3697_REG_HVLED_OUTPUT_CFG 0x10 -#define LM3697_HVLED1_CFG_MASK BIT(0) -#define LM3697_HVLED2_CFG_MASK BIT(1) -#define LM3697_HVLED3_CFG_MASK BIT(2) -#define LM3697_HVLED1_CFG_SHIFT 0 -#define LM3697_HVLED2_CFG_SHIFT 1 -#define LM3697_HVLED3_CFG_SHIFT 2 - -#define LM3697_REG_BL0_RAMP 0x11 -#define LM3697_REG_BL1_RAMP 0x12 -#define LM3697_RAMPUP_MASK 0xF0 -#define LM3697_RAMPUP_SHIFT 4 -#define LM3697_RAMPDN_MASK 0x0F -#define LM3697_RAMPDN_SHIFT 0 - -#define LM3697_REG_RAMP_CONF 0x14 -#define LM3697_RAMP_MASK 0x0F -#define LM3697_RAMP_EACH 0x05 - -#define LM3697_REG_PWM_CFG 0x1C -#define LM3697_PWM_A_MASK BIT(0) -#define LM3697_PWM_B_MASK BIT(1) - -#define LM3697_REG_IMAX_A 0x17 -#define LM3697_REG_IMAX_B 0x18 - -#define LM3697_REG_FEEDBACK_ENABLE 0x19 - -#define LM3697_REG_BRT_A_LSB 0x20 -#define LM3697_REG_BRT_A_MSB 0x21 -#define LM3697_REG_BRT_B_LSB 0x22 -#define LM3697_REG_BRT_B_MSB 0x23 - -#define LM3697_REG_ENABLE 0x24 - -#define LM3697_REG_OPEN_FAULT_STATUS 0xB0 - -#define LM3697_REG_SHORT_FAULT_STATUS 0xB2 - -#define LM3697_REG_MONITOR_ENABLE 0xB4 - -#define LM3697_MAX_REG 0xB4 #endif diff --git a/include/linux/mfd/ti-lmu.h b/include/linux/mfd/ti-lmu.h index 7762c1bce55d..54e9d272e81c 100644 --- a/include/linux/mfd/ti-lmu.h +++ b/include/linux/mfd/ti-lmu.h @@ -26,7 +26,6 @@ enum ti_lmu_id { LM3632, LM3633, LM3695, - LM3697, LMU_MAX_ID, }; From 5c1d824cda9f6059ee5fb6cc83cd4f47c85cf215 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 6 May 2019 14:16:14 -0500 Subject: [PATCH 06/11] leds: lm3697: Introduce the lm3697 driver Introduce the lm3697 LED driver for backlighting and display. Datasheet location: http://www.ti.com/lit/ds/symlink/lm3697.pdf Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/Kconfig | 8 + drivers/leds/Makefile | 1 + drivers/leds/leds-lm3697.c | 395 +++++++++++++++++++++++++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 drivers/leds/leds-lm3697.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4e262696be19..ba14b4894855 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -792,6 +792,14 @@ config LEDS_TI_LMU_COMMON This supports common features between the TI LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. +config LEDS_LM3697 + tristate "LED driver for LM3697" + depends on LEDS_TI_LMU_COMMON + depends on I2C && OF + help + Say Y to enable the LM3697 LED driver for TI LMU devices. + This supports the LED device LM3697. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 84c49339a8e3..6c3350404ede 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o +obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c new file mode 100644 index 000000000000..54e0e35df824 --- /dev/null +++ b/drivers/leds/leds-lm3697.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0 +// TI LM3697 LED chip family driver +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include + +#define LM3697_REV 0x0 +#define LM3697_RESET 0x1 +#define LM3697_OUTPUT_CONFIG 0x10 +#define LM3697_CTRL_A_RAMP 0x11 +#define LM3697_CTRL_B_RAMP 0x12 +#define LM3697_CTRL_A_B_RT_RAMP 0x13 +#define LM3697_CTRL_A_B_RAMP_CFG 0x14 +#define LM3697_CTRL_A_B_BRT_CFG 0x16 +#define LM3697_CTRL_A_FS_CURR_CFG 0x17 +#define LM3697_CTRL_B_FS_CURR_CFG 0x18 +#define LM3697_PWM_CFG 0x1c +#define LM3697_CTRL_A_BRT_LSB 0x20 +#define LM3697_CTRL_A_BRT_MSB 0x21 +#define LM3697_CTRL_B_BRT_LSB 0x22 +#define LM3697_CTRL_B_BRT_MSB 0x23 +#define LM3697_CTRL_ENABLE 0x24 + +#define LM3697_SW_RESET BIT(0) + +#define LM3697_CTRL_A_EN BIT(0) +#define LM3697_CTRL_B_EN BIT(1) +#define LM3697_CTRL_A_B_EN (LM3697_CTRL_A_EN | LM3697_CTRL_B_EN) + +#define LM3697_MAX_LED_STRINGS 3 + +#define LM3697_CONTROL_A 0 +#define LM3697_CONTROL_B 1 +#define LM3697_MAX_CONTROL_BANKS 2 + +/** + * struct lm3697_led - + * @hvled_strings: Array of LED strings associated with a control bank + * @label: LED label + * @led_dev: LED class device + * @priv: Pointer to the device struct + * @lmu_data: Register and setting values for common code + * @control_bank: Control bank the LED is associated to. 0 is control bank A + * 1 is control bank B + */ +struct lm3697_led { + u32 hvled_strings[LM3697_MAX_LED_STRINGS]; + char label[LED_MAX_NAME_SIZE]; + struct led_classdev led_dev; + struct lm3697 *priv; + struct ti_lmu_bank lmu_data; + int control_bank; + int enabled; + int num_leds; +}; + +/** + * struct lm3697 - + * @enable_gpio: Hardware enable gpio + * @regulator: LED supply regulator pointer + * @client: Pointer to the I2C client + * @regmap: Devices register map + * @dev: Pointer to the devices device struct + * @lock: Lock for reading/writing the device + * @leds: Array of LED strings + */ +struct lm3697 { + struct gpio_desc *enable_gpio; + struct regulator *regulator; + struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + struct mutex lock; + + int bank_cfg; + + struct lm3697_led leds[]; +}; + +static const struct reg_default lm3697_reg_defs[] = { + {LM3697_OUTPUT_CONFIG, 0x6}, + {LM3697_CTRL_A_RAMP, 0x0}, + {LM3697_CTRL_B_RAMP, 0x0}, + {LM3697_CTRL_A_B_RT_RAMP, 0x0}, + {LM3697_CTRL_A_B_RAMP_CFG, 0x0}, + {LM3697_CTRL_A_B_BRT_CFG, 0x0}, + {LM3697_CTRL_A_FS_CURR_CFG, 0x13}, + {LM3697_CTRL_B_FS_CURR_CFG, 0x13}, + {LM3697_PWM_CFG, 0xc}, + {LM3697_CTRL_A_BRT_LSB, 0x0}, + {LM3697_CTRL_A_BRT_MSB, 0x0}, + {LM3697_CTRL_B_BRT_LSB, 0x0}, + {LM3697_CTRL_B_BRT_MSB, 0x0}, + {LM3697_CTRL_ENABLE, 0x0}, +}; + +static const struct regmap_config lm3697_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LM3697_CTRL_ENABLE, + .reg_defaults = lm3697_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs), + .cache_type = REGCACHE_FLAT, +}; + +static int lm3697_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm3697_led *led = container_of(led_cdev, struct lm3697_led, + led_dev); + int ctrl_en_val = (1 << led->control_bank); + int ret; + + mutex_lock(&led->priv->lock); + + if (brt_val == LED_OFF) { + ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE, + ctrl_en_val, ~ctrl_en_val); + if (ret) { + dev_err(&led->priv->client->dev, "Cannot write ctrl register\n"); + goto brightness_out; + } + + led->enabled = LED_OFF; + } else { + ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot write brightness\n"); + goto brightness_out; + } + + if (!led->enabled) { + ret = regmap_update_bits(led->priv->regmap, + LM3697_CTRL_ENABLE, + ctrl_en_val, ctrl_en_val); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot enable the device\n"); + goto brightness_out; + } + + led->enabled = brt_val; + } + } + +brightness_out: + mutex_unlock(&led->priv->lock); + return ret; +} + +static int lm3697_init(struct lm3697 *priv) +{ + struct lm3697_led *led; + int i, ret; + + if (priv->enable_gpio) { + gpiod_direction_output(priv->enable_gpio, 1); + } else { + ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET); + if (ret) { + dev_err(&priv->client->dev, "Cannot reset the device\n"); + goto out; + } + } + + ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0); + if (ret) { + dev_err(&priv->client->dev, "Cannot write ctrl enable\n"); + goto out; + } + + ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg); + if (ret) + dev_err(&priv->client->dev, "Cannot write OUTPUT config\n"); + + for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) { + led = &priv->leds[i]; + ret = ti_lmu_common_set_ramp(&led->lmu_data); + if (ret) + dev_err(&priv->client->dev, "Setting the ramp rate failed\n"); + } +out: + return ret; +} + +static int lm3697_probe_dt(struct lm3697 *priv) +{ + struct fwnode_handle *child = NULL; + struct lm3697_led *led; + const char *name; + int control_bank; + size_t i = 0; + int ret = -EINVAL; + int j; + + priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->enable_gpio)) { + ret = PTR_ERR(priv->enable_gpio); + dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n", + ret); + return ret; + } + + priv->regulator = devm_regulator_get(&priv->client->dev, "vled"); + if (IS_ERR(priv->regulator)) + priv->regulator = NULL; + + device_for_each_child_node(priv->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &control_bank); + if (ret) { + dev_err(&priv->client->dev, "reg property missing\n"); + fwnode_handle_put(child); + goto child_out; + } + + if (control_bank > LM3697_CONTROL_B) { + dev_err(&priv->client->dev, "reg property is invalid\n"); + ret = -EINVAL; + fwnode_handle_put(child); + goto child_out; + } + + led = &priv->leds[i]; + + ret = ti_lmu_common_get_brt_res(&priv->client->dev, + child, &led->lmu_data); + if (ret) + dev_warn(&priv->client->dev, "brightness resolution property missing\n"); + + led->control_bank = control_bank; + led->lmu_data.regmap = priv->regmap; + led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP + + control_bank; + led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB + + led->control_bank * 2; + led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB + + led->control_bank * 2; + + led->num_leds = fwnode_property_read_u32_array(child, + "led-sources", + NULL, 0); + + if (led->num_leds > LM3697_MAX_LED_STRINGS) { + dev_err(&priv->client->dev, "To many LED strings defined\n"); + continue; + } + + ret = fwnode_property_read_u32_array(child, "led-sources", + led->hvled_strings, + led->num_leds); + if (ret) { + dev_err(&priv->client->dev, "led-sources property missing\n"); + fwnode_handle_put(child); + goto child_out; + } + + for (j = 0; j < led->num_leds; j++) + priv->bank_cfg |= + (led->control_bank << led->hvled_strings[j]); + + ret = ti_lmu_common_get_ramp_params(&priv->client->dev, + child, &led->lmu_data); + if (ret) + dev_warn(&priv->client->dev, "runtime-ramp properties missing\n"); + + fwnode_property_read_string(child, "linux,default-trigger", + &led->led_dev.default_trigger); + + ret = fwnode_property_read_string(child, "label", &name); + if (ret) + snprintf(led->label, sizeof(led->label), + "%s::", priv->client->name); + else + snprintf(led->label, sizeof(led->label), + "%s:%s", priv->client->name, name); + + led->priv = priv; + led->led_dev.name = led->label; + led->led_dev.max_brightness = led->lmu_data.max_brightness; + led->led_dev.brightness_set_blocking = lm3697_brightness_set; + + ret = devm_led_classdev_register(priv->dev, &led->led_dev); + if (ret) { + dev_err(&priv->client->dev, "led register err: %d\n", + ret); + fwnode_handle_put(child); + goto child_out; + } + + i++; + } + +child_out: + return ret; +} + +static int lm3697_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3697 *led; + int count; + int ret; + + count = device_get_child_node_count(&client->dev); + if (!count) { + dev_err(&client->dev, "LEDs are not defined in device tree!"); + return -ENODEV; + } + + led = devm_kzalloc(&client->dev, struct_size(led, leds, count), + GFP_KERNEL); + if (!led) + return -ENOMEM; + + mutex_init(&led->lock); + i2c_set_clientdata(client, led); + + led->client = client; + led->dev = &client->dev; + led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = lm3697_probe_dt(led); + if (ret) + return ret; + + return lm3697_init(led); +} + +static int lm3697_remove(struct i2c_client *client) +{ + struct lm3697 *led = i2c_get_clientdata(client); + int ret; + + ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE, + LM3697_CTRL_A_B_EN, 0); + if (ret) { + dev_err(&led->client->dev, "Failed to disable the device\n"); + return ret; + } + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + mutex_destroy(&led->lock); + + return 0; +} + +static const struct i2c_device_id lm3697_id[] = { + { "lm3697", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm3697_id); + +static const struct of_device_id of_lm3697_leds_match[] = { + { .compatible = "ti,lm3697", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lm3697_leds_match); + +static struct i2c_driver lm3697_driver = { + .driver = { + .name = "lm3697", + .of_match_table = of_lm3697_leds_match, + }, + .probe = lm3697_probe, + .remove = lm3697_remove, + .id_table = lm3697_id, +}; +module_i2c_driver(lm3697_driver); + +MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL v2"); From 4665743276c3e8efaa4da54eabe8f54b2f99e335 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 5 Jun 2019 07:56:30 -0500 Subject: [PATCH 07/11] dt-bindings: mfd: Add lm36274 bindings to ti-lmu Add the LM36274 backlight driver with regulator support. This is a multi-function device for backlight applications. Backlight properties will be documented in it's a supplemental bindings document. Regulator support is documented in the regulator/lm363x-regulator.txt http://www.ti.com/lit/ds/symlink/lm36274.pdf Signed-off-by: Dan Murphy Reviewed-by: Rob Herring Acked-by: Lee Jones Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/mfd/ti-lmu.txt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt index 782d3c9812ed..2296b8f24de4 100644 --- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt +++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt @@ -8,6 +8,7 @@ TI LMU driver supports lighting devices below. LM3632 Backlight and regulator LM3633 Backlight, LED and fault monitor LM3695 Backlight + LM36274 Backlight and regulator Required properties: - compatible: Should be one of: @@ -15,11 +16,13 @@ Required properties: "ti,lm3632" "ti,lm3633" "ti,lm3695" + "ti,lm36274" - reg: I2C slave address. 0x11 for LM3632 0x29 for LM3631 0x36 for LM3633 0x63 for LM3695 + 0x11 for LM36274 Optional properties: - enable-gpios: A GPIO specifier for hardware enable pin. @@ -50,12 +53,14 @@ Optional nodes: - compatible: Should be one of: "ti,lm3633-fault-monitor" - leds: LED properties for LM3633. Please refer to [2]. + LED properties for LM36274. Please refer to [4]. - regulators: Regulator properties for LM3631 and LM3632. Please refer to [3]. [1] ../leds/backlight/ti-lmu-backlight.txt [2] ../leds/leds-lm3633.txt [3] ../regulator/lm363x-regulator.txt +[4] ../leds/leds-lm36274.txt lm3631@29 { compatible = "ti,lm3631"; @@ -213,3 +218,52 @@ lm3695@63 { }; }; }; + +lm36274@11 { + compatible = "ti,lm36274"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; + regulators { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,lm363x-regulator"; + + enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>, + <&pioC 1 GPIO_ACTIVE_HIGH>; + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <7150000>; + regulator-always-on; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6500000>; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6500000>; + }; + }; + + backlight { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,lm36274-backlight"; + + led@0 { + reg = <0>; + led-sources = <0 2>; + label = "white:backlight_cluster"; + linux,default-trigger = "backlight"; + }; + }; +}; From 9c523efb749de01f0ec172d1160bb6ef8d1620a4 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 5 Jun 2019 07:56:31 -0500 Subject: [PATCH 08/11] mfd: ti-lmu: Add LM36274 support to the ti-lmu Add the LM36274 register support to the ti-lmu MFD driver. Signed-off-by: Dan Murphy Acked-by: Lee Jones Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/mfd/Kconfig | 5 ++--- drivers/mfd/ti-lmu.c | 14 ++++++++++++++ include/linux/mfd/ti-lmu-register.h | 23 +++++++++++++++++++++++ include/linux/mfd/ti-lmu.h | 4 ++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8933485b28e7..a69aca3c2dab 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1335,9 +1335,8 @@ config MFD_TI_LMU select REGMAP_I2C help Say yes here to enable support for TI LMU chips. - - TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, and LM3695. - It consists of backlight, LED and regulator driver. + TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and + LM36274. It consists of backlight, LED and regulator driver. It provides consistent device controls for lighting functions. config MFD_OMAP_USB_HOST diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c index 89b1c5b584af..691ab9dd6236 100644 --- a/drivers/mfd/ti-lmu.c +++ b/drivers/mfd/ti-lmu.c @@ -111,6 +111,17 @@ static const struct mfd_cell lm3695_devices[] = { }, }; +static const struct mfd_cell lm36274_devices[] = { + LM363X_REGULATOR(LM36274_BOOST), + LM363X_REGULATOR(LM36274_LDO_POS), + LM363X_REGULATOR(LM36274_LDO_NEG), + { + .name = "lm36274-leds", + .id = LM36274, + .of_compatible = "ti,lm36274-backlight", + }, +}; + #define TI_LMU_DATA(chip, max_reg) \ static const struct ti_lmu_data chip##_data = \ { \ @@ -123,6 +134,7 @@ TI_LMU_DATA(lm3631, LM3631_MAX_REG); TI_LMU_DATA(lm3632, LM3632_MAX_REG); TI_LMU_DATA(lm3633, LM3633_MAX_REG); TI_LMU_DATA(lm3695, LM3695_MAX_REG); +TI_LMU_DATA(lm36274, LM36274_MAX_REG); static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id) { @@ -191,6 +203,7 @@ static const struct of_device_id ti_lmu_of_match[] = { { .compatible = "ti,lm3632", .data = &lm3632_data }, { .compatible = "ti,lm3633", .data = &lm3633_data }, { .compatible = "ti,lm3695", .data = &lm3695_data }, + { .compatible = "ti,lm36274", .data = &lm36274_data }, { } }; MODULE_DEVICE_TABLE(of, ti_lmu_of_match); @@ -200,6 +213,7 @@ static const struct i2c_device_id ti_lmu_ids[] = { { "lm3632", LM3632 }, { "lm3633", LM3633 }, { "lm3695", LM3695 }, + { "lm36274", LM36274 }, { } }; MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); diff --git a/include/linux/mfd/ti-lmu-register.h b/include/linux/mfd/ti-lmu-register.h index 76998b01764b..076d8dea38fd 100644 --- a/include/linux/mfd/ti-lmu-register.h +++ b/include/linux/mfd/ti-lmu-register.h @@ -189,4 +189,27 @@ #define LM3695_REG_BRT_MSB 0x14 #define LM3695_MAX_REG 0x14 + +/* LM36274 */ +#define LM36274_REG_REV 0x01 +#define LM36274_REG_BL_CFG_1 0x02 +#define LM36274_REG_BL_CFG_2 0x03 +#define LM36274_REG_BRT_LSB 0x04 +#define LM36274_REG_BRT_MSB 0x05 +#define LM36274_REG_BL_EN 0x08 + +#define LM36274_REG_BIAS_CONFIG_1 0x09 +#define LM36274_EXT_EN_MASK BIT(0) +#define LM36274_EN_VNEG_MASK BIT(1) +#define LM36274_EN_VPOS_MASK BIT(2) + +#define LM36274_REG_BIAS_CONFIG_2 0x0a +#define LM36274_REG_BIAS_CONFIG_3 0x0b +#define LM36274_REG_VOUT_BOOST 0x0c +#define LM36274_REG_VOUT_POS 0x0d +#define LM36274_REG_VOUT_NEG 0x0e +#define LM36274_VOUT_MASK 0x3F + +#define LM36274_MAX_REG 0x13 + #endif diff --git a/include/linux/mfd/ti-lmu.h b/include/linux/mfd/ti-lmu.h index 54e9d272e81c..0957598c7d41 100644 --- a/include/linux/mfd/ti-lmu.h +++ b/include/linux/mfd/ti-lmu.h @@ -26,6 +26,7 @@ enum ti_lmu_id { LM3632, LM3633, LM3695, + LM36274, LMU_MAX_ID, }; @@ -67,6 +68,9 @@ enum lm363x_regulator_id { LM3632_BOOST, /* Boost output */ LM3632_LDO_POS, /* Positive display bias output */ LM3632_LDO_NEG, /* Negative display bias output */ + LM36274_BOOST, /* Boost output */ + LM36274_LDO_POS, /* Positive display bias output */ + LM36274_LDO_NEG, /* Negative display bias output */ }; /** From bff5e8071533e8a298a060ff4a257eb5e818661b Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 5 Jun 2019 07:56:32 -0500 Subject: [PATCH 09/11] regulator: lm363x: Add support for LM36274 Adding regulator support for the LM36274 backlight driver. This device can leverage this existing code as the functionality and registers are common enough between the LM36274 and the LM363x series of devices. Signed-off-by: Dan Murphy Acked-by: Mark Brown Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/regulator/Kconfig | 2 +- drivers/regulator/lm363x-regulator.c | 78 ++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6c37f0df9323..34e03691dd00 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -363,7 +363,7 @@ config REGULATOR_LM363X tristate "TI LM363X voltage regulators" depends on MFD_TI_LMU help - This driver supports LM3631 and LM3632 voltage regulators for + This driver supports LM3631, LM3632 and LM36274 voltage regulators for the LCD bias. One boost output voltage is configurable and always on. Other LDOs are used for the display module. diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index e02fdd1dd092..12b6007a23ad 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -37,6 +37,11 @@ #define LM3632_VBOOST_MIN 4500000 #define LM3632_VLDO_MIN 4000000 +/* LM36274 */ +#define LM36274_BOOST_VSEL_MAX 0x3f +#define LM36274_LDO_VSEL_MAX 0x34 +#define LM36274_VOLTAGE_MIN 4000000 + /* Common */ #define LM363X_STEP_50mV 50000 #define LM363X_STEP_500mV 500000 @@ -217,6 +222,51 @@ static const struct regulator_desc lm363x_regulator_desc[] = { .enable_reg = LM3632_REG_BIAS_CONFIG, .enable_mask = LM3632_EN_VNEG_MASK, }, + + /* LM36274 */ + { + .name = "vboost", + .of_match = "vboost", + .id = LM36274_BOOST, + .ops = &lm363x_boost_voltage_table_ops, + .n_voltages = LM36274_BOOST_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_BOOST, + .vsel_mask = LM36274_VOUT_MASK, + }, + { + .name = "ldo_vpos", + .of_match = "vpos", + .id = LM36274_LDO_POS, + .ops = &lm363x_regulator_voltage_table_ops, + .n_voltages = LM36274_LDO_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_POS, + .vsel_mask = LM36274_VOUT_MASK, + .enable_reg = LM36274_REG_BIAS_CONFIG_1, + .enable_mask = LM36274_EN_VPOS_MASK, + }, + { + .name = "ldo_vneg", + .of_match = "vneg", + .id = LM36274_LDO_NEG, + .ops = &lm363x_regulator_voltage_table_ops, + .n_voltages = LM36274_LDO_VSEL_MAX, + .min_uV = LM36274_VOLTAGE_MIN, + .uV_step = LM363X_STEP_50mV, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .vsel_reg = LM36274_REG_VOUT_NEG, + .vsel_mask = LM36274_VOUT_MASK, + .enable_reg = LM36274_REG_BIAS_CONFIG_1, + .enable_mask = LM36274_EN_VNEG_MASK, + }, }; static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id) @@ -229,9 +279,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, */ switch (id) { case LM3632_LDO_POS: + case LM36274_LDO_POS: return gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); case LM3632_LDO_NEG: + case LM36274_LDO_NEG: return gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); default: @@ -239,6 +291,27 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, } } +static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id) +{ + int ext_en_mask = 0; + + switch (id) { + case LM3632_LDO_POS: + case LM3632_LDO_NEG: + ext_en_mask = LM3632_EXT_EN_MASK; + break; + case LM36274_LDO_POS: + case LM36274_LDO_NEG: + ext_en_mask = LM36274_EXT_EN_MASK; + break; + default: + return -ENODEV; + } + + return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg, + ext_en_mask, ext_en_mask); +} + static int lm363x_regulator_probe(struct platform_device *pdev) { struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); @@ -263,10 +336,7 @@ static int lm363x_regulator_probe(struct platform_device *pdev) if (gpiod) { cfg.ena_gpiod = gpiod; - - ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG, - LM3632_EXT_EN_MASK, - LM3632_EXT_EN_MASK); + ret = lm363x_regulator_set_ext_en(regmap, id); if (ret) { gpiod_put(gpiod); dev_err(dev, "External pin err: %d\n", ret); From 04f4dc1bc5f0f64640026497f97e2f3c063f7831 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 5 Jun 2019 07:56:33 -0500 Subject: [PATCH 10/11] dt-bindings: leds: Add LED bindings for the LM36274 Add the LM36274 LED specific bindings. Signed-off-by: Dan Murphy Reviewed-by: Rob Herring Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/leds/leds-lm36274.txt | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-lm36274.txt diff --git a/Documentation/devicetree/bindings/leds/leds-lm36274.txt b/Documentation/devicetree/bindings/leds/leds-lm36274.txt new file mode 100644 index 000000000000..456a589c65f0 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lm36274.txt @@ -0,0 +1,85 @@ +* Texas Instruments LM36274 4-Channel LCD Backlight Driver w/Integrated Bias + +The LM36274 is an integrated four-channel WLED driver and LCD bias supply. +The backlight boost provides the power to bias four parallel LED strings with +up to 29V total output voltage. The 11-bit LED current is programmable via +the I2C bus and/or controlled via a logic level PWM input from 60 uA to 30 mA. + +Parent device properties are documented in +Documentation/devicetree/bindings/mfd/ti_lmu.txt + +Regulator properties are documented in +Documentation/devicetree/bindings/regulator/lm363x-regulator.txt + +Required backlight properties: + - compatible: + "ti,lm36274-backlight" + - reg : 0 + - #address-cells : 1 + - #size-cells : 0 + - led-sources : Indicates which LED strings will be enabled. + Values from 0-3, sources is 0 based so strings will be + source value + 1. + +Optional backlight properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +HVLED string 1 and 3 are controlled by control bank A and HVLED 2 string is +controlled by control bank B. + +lm36274@11 { + compatible = "ti,lm36274"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11>; + + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,lm363x-regulator"; + + enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>, + <&pioC 1 GPIO_ACTIVE_HIGH>; + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <7150000>; + regulator-always-on; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6500000>; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6500000>; + }; + }; + + backlight { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,lm36274-backlight"; + + led@0 { + reg = <0>; + led-sources = <0 2>; + label = "white:backlight_cluster"; + linux,default-trigger = "backlight"; + }; + }; +}; + +For more product information please see the link below: +http://www.ti.com/lit/ds/symlink/lm36274.pdf From 11e1bbc116a75d4a93122ea0a3b2be814922d864 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 5 Jun 2019 07:56:34 -0500 Subject: [PATCH 11/11] leds: lm36274: Introduce the TI LM36274 LED driver Introduce the LM36274 LED driver. This driver uses the ti-lmu MFD driver to probe this LED driver. The driver configures only the LED registers and enables the outputs according to the config file. The driver utilizes the TI LMU (Lighting Management Unit) LED common framework to set the brightness bits. Signed-off-by: Dan Murphy Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- drivers/leds/Kconfig | 8 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-lm36274.c | 172 ++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/leds/leds-lm36274.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ba14b4894855..c36cbabdd9c6 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -800,6 +800,14 @@ config LEDS_LM3697 Say Y to enable the LM3697 LED driver for TI LMU devices. This supports the LED device LM3697. +config LEDS_LM36274 + tristate "LED driver for LM36274" + depends on LEDS_TI_LMU_COMMON + depends on MFD_TI_LMU + help + Say Y to enable the LM36274 LED driver for TI LMU devices. + This supports the LED device LM36274. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 6c3350404ede..c52934732c1a 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o +obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c new file mode 100644 index 000000000000..ed9dc857ec8f --- /dev/null +++ b/drivers/leds/leds-lm36274.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +// TI LM36274 LED chip family driver +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define LM36274_MAX_STRINGS 4 +#define LM36274_BL_EN BIT(4) + +/** + * struct lm36274 + * @pdev: platform device + * @led_dev: led class device + * @lmu_data: Register and setting values for common code + * @regmap: Devices register map + * @dev: Pointer to the devices device struct + * @led_sources - The LED strings supported in this array + * @num_leds - Number of LED strings are supported in this array + */ +struct lm36274 { + struct platform_device *pdev; + struct led_classdev led_dev; + struct ti_lmu_bank lmu_data; + struct regmap *regmap; + struct device *dev; + + u32 led_sources[LM36274_MAX_STRINGS]; + int num_leds; +}; + +static int lm36274_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev); + + return ti_lmu_common_set_brightness(&led->lmu_data, brt_val); +} + +static int lm36274_init(struct lm36274 *lm36274_data) +{ + int enable_val = 0; + int i; + + for (i = 0; i < lm36274_data->num_leds; i++) + enable_val |= (1 << lm36274_data->led_sources[i]); + + if (!enable_val) { + dev_err(lm36274_data->dev, "No LEDs were enabled\n"); + return -EINVAL; + } + + enable_val |= LM36274_BL_EN; + + return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN, + enable_val); +} + +static int lm36274_parse_dt(struct lm36274 *lm36274_data) +{ + struct fwnode_handle *child = NULL; + char label[LED_MAX_NAME_SIZE]; + struct device *dev = &lm36274_data->pdev->dev; + const char *name; + int child_cnt; + int ret = -EINVAL; + + /* There should only be 1 node */ + child_cnt = device_get_child_node_count(dev); + if (child_cnt != 1) + return -EINVAL; + + device_for_each_child_node(dev, child) { + ret = fwnode_property_read_string(child, "label", &name); + if (ret) + snprintf(label, sizeof(label), + "%s::", lm36274_data->pdev->name); + else + snprintf(label, sizeof(label), + "%s:%s", lm36274_data->pdev->name, name); + + lm36274_data->num_leds = fwnode_property_read_u32_array(child, + "led-sources", + NULL, 0); + if (lm36274_data->num_leds <= 0) + return -ENODEV; + + ret = fwnode_property_read_u32_array(child, "led-sources", + lm36274_data->led_sources, + lm36274_data->num_leds); + if (ret) { + dev_err(dev, "led-sources property missing\n"); + return ret; + } + + fwnode_property_read_string(child, "linux,default-trigger", + &lm36274_data->led_dev.default_trigger); + + } + + lm36274_data->lmu_data.regmap = lm36274_data->regmap; + lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; + lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; + lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; + + lm36274_data->led_dev.name = label; + lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; + lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set; + + return 0; +} + +static int lm36274_probe(struct platform_device *pdev) +{ + struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); + struct lm36274 *lm36274_data; + int ret; + + lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data), + GFP_KERNEL); + if (!lm36274_data) + return -ENOMEM; + + lm36274_data->pdev = pdev; + lm36274_data->dev = lmu->dev; + lm36274_data->regmap = lmu->regmap; + dev_set_drvdata(&pdev->dev, lm36274_data); + + ret = lm36274_parse_dt(lm36274_data); + if (ret) { + dev_err(lm36274_data->dev, "Failed to parse DT node\n"); + return ret; + } + + ret = lm36274_init(lm36274_data); + if (ret) { + dev_err(lm36274_data->dev, "Failed to init the device\n"); + return ret; + } + + return devm_led_classdev_register(lm36274_data->dev, + &lm36274_data->led_dev); +} + +static const struct of_device_id of_lm36274_leds_match[] = { + { .compatible = "ti,lm36274-backlight", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lm36274_leds_match); + +static struct platform_driver lm36274_driver = { + .probe = lm36274_probe, + .driver = { + .name = "lm36274-leds", + }, +}; +module_platform_driver(lm36274_driver) + +MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL v2");