From patchwork Fri Dec 6 17:07:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "A. Sverdlin" X-Patchwork-Id: 847977 Received: from mta-64-225.siemens.flowmailer.net (mta-64-225.siemens.flowmailer.net [185.136.64.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F6201F3D49 for ; Fri, 6 Dec 2024 17:08:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.136.64.225 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733504932; cv=none; b=mqDoh4H+5O/dPDYZhN3pZqBTgiM9EWZbGeSIJD3yeMJcORQSDPgzNaz+8mGf3FITmCVubBoyP1N/bi0ql8uPYqGc4y+pULzAznZch8azu7X9twFtLTvZ5hkfKWFAmi+fYZb99CbAr2RLwWGQjIEu1vm4bPxH0WS1xKgPzzsLnwQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733504932; c=relaxed/simple; bh=Ll2rzZbtm6JssXOsxLQuzDBP/THgk4I2PFSzsese9to=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M2g4tIJMjuM3PR+orJIl3BXe3vhSIJ5HvMD4K4Zf9+RBPh2UTreArlflq9P07QtPh3unCwHtnseQHc0pgAbleY15kEH/QVIPrpvOtSkaHa4/kfOTmooqKWYZlDZe2/1jB28Dn/Ia29CNdvSyFWL9xcd/ZyQK3eZa6tBjF/8uVbA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=siemens.com; spf=pass smtp.mailfrom=rts-flowmailer.siemens.com; dkim=pass (2048-bit key) header.d=siemens.com header.i=alexander.sverdlin@siemens.com header.b=Uy/g40pK; arc=none smtp.client-ip=185.136.64.225 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=siemens.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rts-flowmailer.siemens.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=siemens.com header.i=alexander.sverdlin@siemens.com header.b="Uy/g40pK" Received: by mta-64-225.siemens.flowmailer.net with ESMTPSA id 2024120617084074d5587ee0f0b4fc3c for ; Fri, 06 Dec 2024 18:08:40 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=alexander.sverdlin@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=nFgpbr9ICMll5siYBTjeBnhfrpbASPh3GUsaLse4SlY=; b=Uy/g40pKnJOGA0ubGEHMel5IVJlab1WTXv31IzQLQCOMke8TiYEpWc3j0aXad4lWBYIRUd hJCo+9VHQdpCX7Qy+K9i16CHp6eVVZNIM7ZZdjEPzkE4rubt13VnZEQAa3cB4CnF5VHg2/BM 5OQGWGkLmWAMvX6wd7mRq8ISy8Yne85ZD7NodL0OEx8XQX8Vzq2xoBioQheEjLdJwGP7yvfg mD/6dXR7OS3OkkPFISMrYgN6vuzETjisUExFVCcicu//E8WXoVG+f4H7xhi3gt0uwA8p4Tpq rSU+yYCv17TELBo8s85YhGPxP5zfHDp8gUXr3/u42l3Yafp4skFhjuLg==; From: "A. Sverdlin" To: Dan Murphy , linux-leds@vger.kernel.org, devicetree@vger.kernel.org Cc: Alexander Sverdlin , dri-devel@lists.freedesktop.org, Lee Jones , Daniel Thompson , Jingoo Han , Pavel Machek , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Davis Subject: [PATCH 1/2] dt-bindings: backlight: Convert LP8860 into YAML format adding LP886x Date: Fri, 6 Dec 2024 18:07:12 +0100 Message-ID: <20241206170717.1090206-2-alexander.sverdlin@siemens.com> In-Reply-To: <20241206170717.1090206-1-alexander.sverdlin@siemens.com> References: <20241206170717.1090206-1-alexander.sverdlin@siemens.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-456497:519-21489:flowmailer From: Alexander Sverdlin Add Texas Instruments' LP8864/LP8866 bindings into LP8860 converting them into YAML format simultaneously. While here, drop the index of the "led" subnode, this one is neither used nor mandated by the drivers. All the *-cells properties are therefore not required. Move the file into backlight directory because all of the LP886x drivers are special backlight products. Signed-off-by: Alexander Sverdlin --- .../bindings/leds/backlight/ti,lp8860.yaml | 86 +++++++++++++++++++ .../devicetree/bindings/leds/leds-lp8860.txt | 50 ----------- 2 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/backlight/ti,lp8860.yaml delete mode 100644 Documentation/devicetree/bindings/leds/leds-lp8860.txt diff --git a/Documentation/devicetree/bindings/leds/backlight/ti,lp8860.yaml b/Documentation/devicetree/bindings/leds/backlight/ti,lp8860.yaml new file mode 100644 index 0000000000000..3ece2f6fc3f02 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/ti,lp8860.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/ti,lp8860.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments - LP886x 4/6-Channel LED Driver family + +maintainers: + - Andrew Davis + - Alexander Sverdlin + +description: | + The LP8860-Q1 is an high-efficiency LED driver with boost controller. + It has 4 high-precision current sinks that can be controlled by a PWM input + signal, a SPI/I2C master, or both. + + LP8866-Q1, LP8866S-Q1, LP8864-Q1, LP8864S-Q1 are newer products offering + similar functionality with 4/6 channels. + + For more product information please see the links below: + https://www.ti.com/product/lp8860-q1 + https://www.ti.com/product/LP8864-Q1 + https://www.ti.com/product/LP8864S-Q1 + https://www.ti.com/product/LP8866-Q1 + https://www.ti.com/product/LP8866S-Q1 + +properties: + compatible: + enum: + - ti,lp8860 + - ti,lp8864 + + reg: + maxItems: 1 + description: I2C slave address + + enable-gpios: + maxItems: 1 + description: GPIO pin to enable (active high) / disable the device + + vled-supply: + description: LED supply + + led: + type: object + $ref: common.yaml# + properties: + function: true + color: true + label: true + linux,default-trigger: true + + additionalProperties: false + +required: + - compatible + - reg + - led + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@2d { + compatible = "ti,lp8860"; + reg = <0x2d>; + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; + + led { + function = LED_FUNCTION_BACKLIGHT; + color = ; + linux,default-trigger = "backlight"; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt deleted file mode 100644 index 8bb25749a3da3..0000000000000 --- a/Documentation/devicetree/bindings/leds/leds-lp8860.txt +++ /dev/null @@ -1,50 +0,0 @@ -* Texas Instruments - lp8860 4-Channel LED Driver - -The LP8860-Q1 is an high-efficiency LED -driver with boost controller. It has 4 high-precision -current sinks that can be controlled by a PWM input -signal, a SPI/I2C master, or both. - -Required properties: - - compatible : - "ti,lp8860" - - reg : I2C slave address - - #address-cells : 1 - - #size-cells : 0 - -Optional properties: - - enable-gpios : gpio pin to enable (active high)/disable the device. - - vled-supply : LED supply - -Required child properties: - - reg : 0 - -Optional child properties: - - function : see Documentation/devicetree/bindings/leds/common.txt - - color : see Documentation/devicetree/bindings/leds/common.txt - - label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) - - linux,default-trigger : - see Documentation/devicetree/bindings/leds/common.txt - -Example: - -#include - -led-controller@2d { - compatible = "ti,lp8860"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x2d>; - enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; - vled-supply = <&vbatt>; - - led@0 { - reg = <0>; - function = LED_FUNCTION_BACKLIGHT; - color = ; - linux,default-trigger = "backlight"; - }; -} - -For more product information please see the link below: -https://www.ti.com/product/lp8860-q1 From patchwork Fri Dec 6 17:07:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "A. Sverdlin" X-Patchwork-Id: 847973 Received: from mta-64-226.siemens.flowmailer.net (mta-64-226.siemens.flowmailer.net [185.136.64.226]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF21122068F for ; Fri, 6 Dec 2024 17:48:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.136.64.226 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733507344; cv=none; b=Yw5OKAxuSZoIgP0k4zUtoqDdyYSBQDrEN6y9Eiz01BZbp/P7ld5MIk9TKt9OkW3n1cRhOVDRgc2kTnG1oHRMKTZGNVyl61+jfTK10AahwOD3AoeuVernFcTDsxKoUCAi2TT3hCxaRzafKnm4YKCbfGvznBlse3UNUGR8AdnBTvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733507344; c=relaxed/simple; bh=FIrpJaVLZP5iAZsFWKrxZsQ/1cv8NaemLoZty8gCsbg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XE31Y8ztFULZRSfKxjYZKUca02rFZiriw2Pyy4dpTX6ChJ2B9ZxZhNgoYCTL+2PmxTAViaYjlLp3isEMjcTEJPGsg4ds0FIy/jyCkgzqD0BfdLSwlIs7lEC8qK7jHmLSx4KYYg2HnIZPYdTFTs0mxbUVibNiu+X3lfIkMtvz8nc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=siemens.com; spf=pass smtp.mailfrom=rts-flowmailer.siemens.com; dkim=pass (2048-bit key) header.d=siemens.com header.i=alexander.sverdlin@siemens.com header.b=dq9XSGFG; arc=none smtp.client-ip=185.136.64.226 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=siemens.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rts-flowmailer.siemens.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=siemens.com header.i=alexander.sverdlin@siemens.com header.b="dq9XSGFG" Received: by mta-64-226.siemens.flowmailer.net with ESMTPSA id 20241206170840f7e1cc5a2a3242cd20 for ; Fri, 06 Dec 2024 18:08:40 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=alexander.sverdlin@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=O1U6B92QInT24F+zuJGFeS5+Da6wGoI/umcLEfXgUp8=; b=dq9XSGFGCWguHksVQ2d1MD6z1A0xEpGuPSMw1RmtDQl5YfY4QFMpW5UAfV9MMCzPSRWlGK 3z7REitsRTfPyBkhMWbsXXYRGcc3nBxwmzfB04x3ZO748iwFlDnk/VSDKoQaP/7Mik9oupZF 7fz+Xs4i/c0MLBWIKHmfSYCWl49exOdpwWahmacrzgWqVnDVlCgJJrWm1FdWcpiOCHlE20np VOkU+iCNJuWhWMyXv+XL36eWxqXOe7tDkIync4wMjFfLtTEPBDsbw2XSFYLhx71Uk8j32SGK WZ3Yx2QQg3xcx9D9VjkbC7oG4m7pjwDHMyIOGyWOq1fD82KhxXpezAiw==; From: "A. Sverdlin" To: Dan Murphy , linux-leds@vger.kernel.org, devicetree@vger.kernel.org Cc: Alexander Sverdlin , dri-devel@lists.freedesktop.org, Lee Jones , Daniel Thompson , Jingoo Han , Pavel Machek , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Andrew Davis Subject: [PATCH 2/2] leds: lp8864: New driver Date: Fri, 6 Dec 2024 18:07:13 +0100 Message-ID: <20241206170717.1090206-3-alexander.sverdlin@siemens.com> In-Reply-To: <20241206170717.1090206-1-alexander.sverdlin@siemens.com> References: <20241206170717.1090206-1-alexander.sverdlin@siemens.com> Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-456497:519-21489:flowmailer From: Alexander Sverdlin Add driver for TI LP8864, LP8864S, LP8866 4/6 channel LED-backlight drivers with I2C interface. Link: https://www.ti.com/lit/gpn/lp8866-q1 Link: https://www.ti.com/lit/gpn/lp8864-q1 Link: https://www.ti.com/lit/gpn/lp8864s-q1 Signed-off-by: Alexander Sverdlin --- MAINTAINERS | 7 + drivers/leds/Kconfig | 12 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-lp8864.c | 320 +++++++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 drivers/leds/leds-lp8864.c diff --git a/MAINTAINERS b/MAINTAINERS index 21f855fe468bc..14e87b6b37b8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23262,6 +23262,13 @@ S: Supported F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml F: drivers/iio/dac/ti-dac7612.c +TEXAS INSTRUMENTS' LB8864 LED BACKLIGHT DRIVER +M: Alexander Sverdlin +L: linux-leds@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/leds/backlight/ti,lp8860.yaml +F: drivers/leds/leds-lp8864.c + TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER M: Nishanth Menon M: Tero Kristo diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index b784bb74a8378..6d0e88e501614 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -511,6 +511,18 @@ config LEDS_LP8860 on the LP8860 4 channel LED driver using the I2C communication bus. +config LEDS_LP8864 + tristate "LED support for the TI LP8864/LP8866 4/6 channel LED drivers" + depends on LEDS_CLASS && I2C && OF + select REGMAP_I2C + help + If you say yes here you get support for the TI LP8864-Q1, + LP8864S-Q1, LP8866-Q1, LP8866S-Q1 4/6 channel LED backlight + drivers with I2C interface. + + To compile this driver as a module, choose M here: the + module will be called leds-lp8864. + config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook" depends on LEDS_CLASS && BROKEN diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 18afbb5a23ee5..f66bf2e13665f 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o +obj-$(CONFIG_LEDS_LP8864) += leds-lp8864.o obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o diff --git a/drivers/leds/leds-lp8864.c b/drivers/leds/leds-lp8864.c new file mode 100644 index 0000000000000..da02e29bbf4b7 --- /dev/null +++ b/drivers/leds/leds-lp8864.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI LP8864/LP8866 4/6 Channel LED Driver + * + * Copyright (C) 2024 Siemens AG + * + * Based on LP8860 driver by Dan Murphy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LP8864_BRT_CONTROL 0x00 +#define LP8864_USER_CONFIG1 0x04 +#define LP8864_BRT_MODE_MASK GENMASK(9, 8) +/* Brightness controlled by DISPLAY_BRT register */ +#define LP8864_BRT_MODE_REG BIT(9) +#define LP8864_SUPPLY_STATUS 0x0e +#define LP8864_BOOST_STATUS 0x10 +#define LP8864_LED_STATUS 0x12 +/* Writeable bits in the LED_STATUS register */ +#define LP8864_LED_STATUS_WR_MASK GENMASK(14, 9) + +/* Textual meaning for every register bit */ +static const char *const lp8864_supply_status_msg[] = { + NULL, "Vin under-voltage fault", + NULL, "Vin over-voltage fault", + NULL, "Vdd under-voltage fault", + NULL, "Vin over-current fault", + NULL, "Missing charge pump fault", + NULL, "Charge pump fault", + NULL, "Missing boost sync fault", + NULL, "CRC error fault ", +}; + +/* Textual meaning for every register bit */ +static const char *const lp8864_boost_status_msg[] = { + NULL, "Boost OVP low fault", + NULL, "Boost OVP high fault", + NULL, "Boost over-current fault", + NULL, "Missing boost FSET resistor fault", + NULL, "Missing MODE SEL resistor fault", + NULL, "Missing LED resistor fault", + NULL, "ISET resistor short to ground fault", + NULL, "Thermal shutdown fault", +}; + +/* Textual meaning for every register bit */ +static const char *const lp8864_led_status_msg[] = { + "LED 1 fault", + "LED 2 fault", + "LED 3 fault", + "LED 4 fault", + "LED 5 fault", + "LED 6 fault", + "LED open fault", + "LED internal short fault", + "LED short to GND fault", + NULL, NULL, NULL, + "Invalid string configuration fault", + NULL, + "I2C time out fault", +}; + +/** + * struct lp8864_led + * @client: Pointer to the I2C client + * @led_dev: led class device pointer + * @regmap: Devices register map + * @led_status_mask: Helps to report LED fault only once + */ +struct lp8864_led { + struct i2c_client *client; + struct led_classdev led_dev; + struct regmap *regmap; + u16 led_status_mask; +}; + +static int lp8864_fault_check(struct lp8864_led *led) +{ + int ret, i; + unsigned int buf; + + ret = regmap_read(led->regmap, LP8864_SUPPLY_STATUS, &buf); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(lp8864_supply_status_msg); i++) + if (lp8864_supply_status_msg[i] && buf & BIT(i)) + dev_err(&led->client->dev, "%s\n", + lp8864_supply_status_msg[i]); + + /* + * Clear bits have an index preceding the corresponding Status bits; + * both have to be written "1" simultaneously to clear the corresponding + * Status bit. + */ + if (buf) + ret = regmap_write(led->regmap, LP8864_SUPPLY_STATUS, + buf >> 1 | buf); + if (ret) + goto err; + + ret = regmap_read(led->regmap, LP8864_BOOST_STATUS, &buf); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(lp8864_boost_status_msg); i++) + if (lp8864_boost_status_msg[i] && buf & BIT(i)) + dev_err(&led->client->dev, "%s\n", + lp8864_boost_status_msg[i]); + + if (buf) + ret = regmap_write(led->regmap, LP8864_BOOST_STATUS, + buf >> 1 | buf); + if (ret) + goto err; + + ret = regmap_read(led->regmap, LP8864_LED_STATUS, &buf); + if (ret) + goto err; + + /* + * Clear already reported faults that maintain their value until device + * power-down + */ + buf &= ~led->led_status_mask; + + for (i = 0; i < ARRAY_SIZE(lp8864_led_status_msg); i++) + if (lp8864_led_status_msg[i] && buf & BIT(i)) + dev_err(&led->client->dev, "%s\n", + lp8864_led_status_msg[i]); + + /* + * Mark those which maintain their value until device power-down as + * "already reported" + */ + led->led_status_mask |= buf & ~LP8864_LED_STATUS_WR_MASK; + + /* + * Only bits 14, 12, 10 have to be cleared here, but others are RO, + * we don't care what we write to them. + */ + if (buf & LP8864_LED_STATUS_WR_MASK) + ret = regmap_write(led->regmap, LP8864_LED_STATUS, + buf >> 1 | buf); + if (ret) + goto err; + + return 0; + +err: + dev_err(&led->client->dev, "Cannot read/clear faults (%pe)\n", + ERR_PTR(ret)); + + return ret; +} + +static int lp8864_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lp8864_led *led = container_of(led_cdev, struct lp8864_led, + led_dev); + unsigned int val = brt_val * 0xffff / LED_FULL; + int ret; + + ret = lp8864_fault_check(led); + if (ret) + return ret; + + ret = regmap_write(led->regmap, LP8864_BRT_CONTROL, val); + if (ret) + dev_err(&led->client->dev, "Cannot write BRT_CONTROL\n"); + + return ret; +} + +static enum led_brightness lp8864_brightness_get(struct led_classdev *led_cdev) +{ + struct lp8864_led *led = container_of(led_cdev, struct lp8864_led, + led_dev); + unsigned int buf; + int ret; + + ret = regmap_read(led->regmap, LP8864_BRT_CONTROL, &buf); + if (ret) { + dev_err(&led->client->dev, "Cannot read BRT_CONTROL\n"); + return ret; + } + + return buf * LED_FULL / 0xffff; +} + +static int lp8864_init(struct lp8864_led *led) +{ + int ret; + + /* Control brightness by DISPLAY_BRT register */ + ret = regmap_update_bits(led->regmap, LP8864_USER_CONFIG1, + LP8864_BRT_MODE_MASK, LP8864_BRT_MODE_REG); + if (ret) { + dev_err(&led->client->dev, "Cannot write USER_CONFIG1\n"); + return ret; + } + + return lp8864_fault_check(led); +} + +static const struct regmap_config lp8864_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + .cache_type = REGCACHE_NONE, +}; + +static void lp8864_disable_gpio(void *data) +{ + struct gpio_desc *gpio = data; + + gpiod_set_value(gpio, 0); +} + +static int lp8864_probe(struct i2c_client *client) +{ + int ret; + struct lp8864_led *led; + struct device_node *np = dev_of_node(&client->dev); + struct device_node *child_node; + struct led_init_data init_data = {}; + struct gpio_desc *enable_gpio; + + led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + child_node = of_get_next_available_child(np, NULL); + if (!child_node) { + dev_err(&client->dev, "No LED function defined\n"); + return -EINVAL; + } + + ret = devm_regulator_get_enable_optional(&client->dev, "vled"); + if (ret && ret != -ENODEV) + return dev_err_probe(&client->dev, ret, + "Failed to enable vled regulator (%pe)\n", + ERR_PTR(ret)); + + enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(enable_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(enable_gpio), + "Failed to get enable GPIO (%pe)\n", + enable_gpio); + + ret = devm_add_action_or_reset(&client->dev, lp8864_disable_gpio, + enable_gpio); + + led->client = client; + led->led_dev.brightness_set_blocking = lp8864_brightness_set; + led->led_dev.brightness_get = lp8864_brightness_get; + + i2c_set_clientdata(client, led); + + led->regmap = devm_regmap_init_i2c(client, &lp8864_regmap_config); + if (IS_ERR(led->regmap)) { + dev_err(&client->dev, "Failed to allocate register map (%pe)\n", + led->regmap); + return PTR_ERR(led->regmap); + } + + ret = lp8864_init(led); + if (ret) + return ret; + + init_data.fwnode = of_fwnode_handle(child_node); + init_data.devicename = "lp8864"; + init_data.default_label = ":display_cluster"; + + ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev, + &init_data); + if (ret) + dev_err(&client->dev, "Failed to register LED device (%pe)\n", + ERR_PTR(ret)); + + return ret; +} + +static const struct i2c_device_id lp8864_id[] = { + { "lp8864" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, lp8864_id); + +static const struct of_device_id of_lp8864_leds_match[] = { + { .compatible = "ti,lp8864" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_lp8864_leds_match); + +static struct i2c_driver lp8864_driver = { + .driver = { + .name = "lp8864", + .of_match_table = of_lp8864_leds_match, + }, + .probe = lp8864_probe, + .id_table = lp8864_id, +}; +module_i2c_driver(lp8864_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8864/LP8866 LED driver"); +MODULE_AUTHOR("Alexander Sverdlin "); +MODULE_LICENSE("GPL");