From patchwork Mon Jun 24 21:25:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= X-Patchwork-Id: 807131 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 35AC21A08B4; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; cv=none; b=e3a4KxxIKX/9Jphl1TU3a4sTwmf73agezwSnpr/tm66O7Gzdvkqb4KCrdbo1p7gEbVFtqAZS4FxldY9y+WDtfcRSIU049npDPdQzkpuSaQoFzSxjOlrX0dsnYU/z/z1jlVisH5oAcsyFxxhtyR89947t6QAWru3oiB4Zr7TzmAw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; c=relaxed/simple; bh=q9GXhOh3W08vpuSX8OidiiDwOJ5B27G64mh/6LPDIq4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=F8dVaEJBQW65r/le1DXByNjm+N++JpOWiQPjPN9wgCQibhIu8yGiqQ4RF9AfDcmS+MG7NOyOSnp0veDpbiN/IhFJZeO7nvj4s9l8kbGlL7NzJaxyt9bWybfFtEAA0nlDxsQal1aQkYGd1q7kVU8Q6HDhWj9ne+EvxyfO9T2X0uI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Bm5qn8WV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Bm5qn8WV" Received: by smtp.kernel.org (Postfix) with ESMTPS id BD336C32781; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719264306; bh=q9GXhOh3W08vpuSX8OidiiDwOJ5B27G64mh/6LPDIq4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Bm5qn8WVEHFrOFXLXyDKEJ9wSz4PIhE4QEIMuLj3M47wkX3i8aQnTU9+Q9Ed5S2eq roDnlb7UnIUYftGPfGHRpi8DXkG9IgPPMpZ7pgzXTw1/Ta18dkLspSx9Np6mMIcGv2 4jlra7Saa6JcrHsjqSAalik7JLR277nz/5Y//S+hLNtKLzq5+gv20nfxQNCu75fU/m VTPUiVy03H01F1CWsMhfPK6yQr0oEl3Wz4cdyvzeb/L9Uh9cqiOaA6Pd0QEchpwWiP GO6DjpPWwRAY6iZP9LFiSsCwuZsJjjWAbH5JTBQgBUPHkaufW0ueRTofRPLXLbs463 wlgov2vcVeM0w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AE4F0C30653; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) From: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= Date: Mon, 24 Jun 2024 23:25:12 +0200 Subject: [PATCH v5 1/3] dt-bindings: leds: Add Silergy SY7802 flash LED Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240624-sy7802-v5-1-7abc9d96bfa6@apitzsch.eu> References: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> In-Reply-To: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> To: Pavel Machek , Lee Jones , Rob Herring , Conor Dooley , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Christophe JAILLET , Trilok Soni , Krzysztof Kozlowski , Kees Cook Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, linux-arm-msm@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Apitzsch?= X-Mailer: b4 0.14.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1719264314; l=2858; i=git@apitzsch.eu; s=20240325; h=from:subject:message-id; bh=422MAQ8Zc9rOtjrkcDNrU+gTouN3Oof9bf0EyTO505k=; b=kPJWmXeldK97qQkM+tolXro4Vm6iC38kA9MXEcTiypyoYjTBP0Kf1CjDn45WaBvs97fue9o37 +btwCE0m8dYCixMUibGf1kv3NQ9jwu9ijIqvkoe51Yj+Ci/WBpbcLJQ X-Developer-Key: i=git@apitzsch.eu; a=ed25519; pk=wxovcZRfvNYBMcTw4QFFtNEP4qv39gnBfnfyImXZxiU= X-Endpoint-Received: by B4 Relay for git@apitzsch.eu/20240325 with auth_id=142 X-Original-From: =?utf-8?q?Andr=C3=A9_Apitzsch?= Reply-To: git@apitzsch.eu From: André Apitzsch Document Silergy SY7802 flash LED driver devicetree bindings. Reviewed-by: Rob Herring Signed-off-by: André Apitzsch --- .../devicetree/bindings/leds/silergy,sy7802.yaml | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/silergy,sy7802.yaml b/Documentation/devicetree/bindings/leds/silergy,sy7802.yaml new file mode 100644 index 000000000000..46b8e5452b62 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/silergy,sy7802.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/silergy,sy7802.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silergy SY7802 1800mA Boost Charge Pump LED Driver + +maintainers: + - André Apitzsch + +description: | + The SY7802 is a current-regulated charge pump which can regulate two current + levels for Flash and Torch modes. + + The SY7802 is a high-current synchronous boost converter with 2-channel + high side current sources. Each channel is able to deliver 900mA current. + +properties: + compatible: + enum: + - silergy,sy7802 + + reg: + maxItems: 1 + + enable-gpios: + maxItems: 1 + description: A connection to the 'EN' pin. + + flash-gpios: + maxItems: 1 + description: A connection to the 'FLEN' pin. + + vin-supply: + description: Regulator providing power to the 'VIN' pin. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-1]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: Index of the LED. + minimum: 0 + maximum: 1 + + led-sources: + minItems: 1 + maxItems: 2 + items: + minimum: 0 + maximum: 1 + + required: + - reg + - led-sources + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - enable-gpios + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + flash-led-controller@53 { + compatible = "silergy,sy7802"; + reg = <0x53>; + #address-cells = <1>; + #size-cells = <0>; + + enable-gpios = <&tlmm 16 GPIO_ACTIVE_HIGH>; + + led@0 { + reg = <0>; + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <0>, <1>; + }; + }; + }; From patchwork Mon Jun 24 21:25:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= X-Patchwork-Id: 807664 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 35A7C1A0702; Mon, 24 Jun 2024 21:25:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; cv=none; b=gZzaWhVQc/AI4/6cCmGCOyxV7FIJZEpnuhWiPVi3Hmrgo2sGX5pABGso6QgulQNt0QScllWg6p1bAlgf5GlQHKUVmtAJZ2ApPvlp2jGVXpMukXwoh4QXNzUTv3QjWRYuEwDdzu1LVbBIqXlUft+CfD+JLvRMPqHVBzGmjpui0+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; c=relaxed/simple; bh=xlUl951miqMjfm7vdMSh252CPs/hwNbLk7V3MBE9mFw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MswsNS7ahUOc1rk6/d3N0kfD2ArQowhOLVXZng0u90utK6+UB+xeKnz2mmQwgMoCiUOlJ87q6zRtMqLB+wqDcrqdJKWeMO1ipsZFRmgegOi+HZWNUcstG5SroNBraOhXxI9iRGu4rOrkMMbpQDF4vpLxddfWFLSZrkrit6bnwnM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oAXpdo6n; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oAXpdo6n" Received: by smtp.kernel.org (Postfix) with ESMTPS id D8EA5C4AF0F; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719264306; bh=xlUl951miqMjfm7vdMSh252CPs/hwNbLk7V3MBE9mFw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=oAXpdo6n5MINc05nOV2kZuEajit9t7yheQVEHgIw8yfRxxVrszfVZsty5zexmuIC0 7sSN75WxhLvu3JOMV8IL2Wrvc0Z3+9DjonKLlLbq9yicG/E0gAqplJ5tcTPos5vV9u lpRIjFR6qPX/w944UZVkGly8oIYSRynLMZDdPkrGcPQnHgMuk/ooXdo5m+zsSUBnmy RRDq40bmEjMLr+Jybx8dsgL7NmlxVzu/3pADW79g2ZbVizlaW0pBrCadHK2Ts6Bjrd Lgawdvl8YRE+XkxCoBD204iCOwWP4xQPXtTAryl6zUGBvPnmZ0i4EzIrAp0A9Hur5O 1aZRA8rab+BnA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2AF1C3065A; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) From: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= Date: Mon, 24 Jun 2024 23:25:13 +0200 Subject: [PATCH v5 2/3] leds: sy7802: Add support for Silergy SY7802 flash LED controller Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240624-sy7802-v5-2-7abc9d96bfa6@apitzsch.eu> References: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> In-Reply-To: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> To: Pavel Machek , Lee Jones , Rob Herring , Conor Dooley , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Christophe JAILLET , Trilok Soni , Krzysztof Kozlowski , Kees Cook Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, linux-arm-msm@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Apitzsch?= X-Mailer: b4 0.14.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1719264314; l=17294; i=git@apitzsch.eu; s=20240325; h=from:subject:message-id; bh=YofSPwfFeezmJP6PWVmV1Q0tOcJ3NqpdHHPWFC6a90c=; b=PwBFm1vdQfLgv7e0Sb0SFmWCvIu8MP11dUtKRzbwcHzrC+zdM4EEcN/MPErUGg3N7R7B51x1K mcVCH0T+P5mDWRC/KzjDLD53n4IKoQxpOQsXLsPvlhoygPbLgnF8Ggw X-Developer-Key: i=git@apitzsch.eu; a=ed25519; pk=wxovcZRfvNYBMcTw4QFFtNEP4qv39gnBfnfyImXZxiU= X-Endpoint-Received: by B4 Relay for git@apitzsch.eu/20240325 with auth_id=142 X-Original-From: =?utf-8?q?Andr=C3=A9_Apitzsch?= Reply-To: git@apitzsch.eu From: André Apitzsch The SY7802 is a current-regulated charge pump which can regulate two current levels for Flash and Torch modes. It is a high-current synchronous boost converter with 2-channel high side current sources. Each channel is able to deliver 900mA current. Acked-by: Lee Jones Signed-off-by: André Apitzsch --- drivers/leds/flash/Kconfig | 11 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-sy7802.c | 539 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 551 insertions(+) diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index 809b6d98bb3e..f39f0bfe6eef 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -121,4 +121,15 @@ config LEDS_SGM3140 This option enables support for the SGM3140 500mA Buck/Boost Charge Pump LED Driver. +config LEDS_SY7802 + tristate "LED support for the Silergy SY7802" + depends on I2C && OF + depends on GPIOLIB + select REGMAP_I2C + help + This option enables support for the SY7802 flash LED controller. + SY7802 includes torch and flash functions with programmable current. + + This driver can be built as a module, it will be called "leds-sy7802". + endif # LEDS_CLASS_FLASH diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile index 91d60a4b7952..48860eeced79 100644 --- a/drivers/leds/flash/Makefile +++ b/drivers/leds/flash/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_LEDS_QCOM_FLASH) += leds-qcom-flash.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o +obj-$(CONFIG_LEDS_SY7802) += leds-sy7802.o diff --git a/drivers/leds/flash/leds-sy7802.c b/drivers/leds/flash/leds-sy7802.c new file mode 100644 index 000000000000..ddac836762af --- /dev/null +++ b/drivers/leds/flash/leds-sy7802.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Silergy SY7802 flash LED driver with an I2C interface + * + * Copyright 2024 André Apitzsch + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SY7802_MAX_LEDS 2 +#define SY7802_LED_JOINT 2 + +#define SY7802_REG_ENABLE 0x10 +#define SY7802_REG_TORCH_BRIGHTNESS 0xa0 +#define SY7802_REG_FLASH_BRIGHTNESS 0xb0 +#define SY7802_REG_FLASH_DURATION 0xc0 +#define SY7802_REG_FLAGS 0xd0 +#define SY7802_REG_CONFIG_1 0xe0 +#define SY7802_REG_CONFIG_2 0xf0 +#define SY7802_REG_VIN_MONITOR 0x80 +#define SY7802_REG_LAST_FLASH 0x81 +#define SY7802_REG_VLED_MONITOR 0x30 +#define SY7802_REG_ADC_DELAY 0x31 +#define SY7802_REG_DEV_ID 0xff + +#define SY7802_MODE_OFF 0 +#define SY7802_MODE_TORCH 2 +#define SY7802_MODE_FLASH 3 +#define SY7802_MODE_MASK GENMASK(1, 0) + +#define SY7802_LEDS_SHIFT 3 +#define SY7802_LEDS_MASK(_id) (BIT(_id) << SY7802_LEDS_SHIFT) +#define SY7802_LEDS_MASK_ALL (SY7802_LEDS_MASK(0) | SY7802_LEDS_MASK(1)) + +#define SY7802_TORCH_CURRENT_SHIFT 3 +#define SY7802_TORCH_CURRENT_MASK(_id) \ + (GENMASK(2, 0) << (SY7802_TORCH_CURRENT_SHIFT * (_id))) +#define SY7802_TORCH_CURRENT_MASK_ALL \ + (SY7802_TORCH_CURRENT_MASK(0) | SY7802_TORCH_CURRENT_MASK(1)) + +#define SY7802_FLASH_CURRENT_SHIFT 4 +#define SY7802_FLASH_CURRENT_MASK(_id) \ + (GENMASK(3, 0) << (SY7802_FLASH_CURRENT_SHIFT * (_id))) +#define SY7802_FLASH_CURRENT_MASK_ALL \ + (SY7802_FLASH_CURRENT_MASK(0) | SY7802_FLASH_CURRENT_MASK(1)) + +#define SY7802_TIMEOUT_DEFAULT_US 512000U +#define SY7802_TIMEOUT_MIN_US 32000U +#define SY7802_TIMEOUT_MAX_US 1024000U +#define SY7802_TIMEOUT_STEPSIZE_US 32000U + +#define SY7802_TORCH_BRIGHTNESS_MAX 8 + +#define SY7802_FLASH_BRIGHTNESS_DEFAULT 14 +#define SY7802_FLASH_BRIGHTNESS_MIN 0 +#define SY7802_FLASH_BRIGHTNESS_MAX 15 +#define SY7802_FLASH_BRIGHTNESS_STEP 1 + +#define SY7802_FLAG_TIMEOUT BIT(0) +#define SY7802_FLAG_THERMAL_SHUTDOWN BIT(1) +#define SY7802_FLAG_LED_FAULT BIT(2) +#define SY7802_FLAG_TX1_INTERRUPT BIT(3) +#define SY7802_FLAG_TX2_INTERRUPT BIT(4) +#define SY7802_FLAG_LED_THERMAL_FAULT BIT(5) +#define SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW BIT(6) +#define SY7802_FLAG_INPUT_VOLTAGE_LOW BIT(7) + +#define SY7802_CHIP_ID 0x51 + +static const struct reg_default sy7802_regmap_defs[] = { + { SY7802_REG_ENABLE, SY7802_LEDS_MASK_ALL }, + { SY7802_REG_TORCH_BRIGHTNESS, 0x92 }, + { SY7802_REG_FLASH_BRIGHTNESS, SY7802_FLASH_BRIGHTNESS_DEFAULT | + SY7802_FLASH_BRIGHTNESS_DEFAULT << SY7802_FLASH_CURRENT_SHIFT }, + { SY7802_REG_FLASH_DURATION, 0x6f }, + { SY7802_REG_FLAGS, 0x0 }, + { SY7802_REG_CONFIG_1, 0x68 }, + { SY7802_REG_CONFIG_2, 0xf0 }, +}; + +struct sy7802_led { + struct led_classdev_flash flash; + struct sy7802 *chip; + u8 led_id; +}; + +struct sy7802 { + struct device *dev; + struct regmap *regmap; + struct mutex mutex; + + struct gpio_desc *enable_gpio; + struct regulator *vin_regulator; + + unsigned int fled_strobe_used; + unsigned int fled_torch_used; + unsigned int leds_active; + int num_leds; + struct sy7802_led leds[] __counted_by(num_leds); +}; + +static int sy7802_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness brightness) +{ + struct sy7802_led *led = container_of(lcdev, struct sy7802_led, flash.led_cdev); + struct sy7802 *chip = led->chip; + u32 fled_torch_used_tmp; + u32 led_enable_mask; + u32 enable_mask; + u32 torch_mask; + u32 val; + int ret; + + mutex_lock(&chip->mutex); + + if (chip->fled_strobe_used) { + dev_warn(chip->dev, "Cannot set torch brightness whilst strobe is enabled\n"); + ret = -EBUSY; + goto unlock; + } + + if (brightness) + fled_torch_used_tmp = chip->fled_torch_used | BIT(led->led_id); + else + fled_torch_used_tmp = chip->fled_torch_used & ~BIT(led->led_id); + + led_enable_mask = led->led_id == SY7802_LED_JOINT ? + SY7802_LEDS_MASK_ALL : + SY7802_LEDS_MASK(led->led_id); + + val = brightness ? led_enable_mask : SY7802_MODE_OFF; + if (fled_torch_used_tmp) + val |= SY7802_MODE_TORCH; + + /* Disable torch to apply brightness */ + ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_MASK, + SY7802_MODE_OFF); + if (ret) + goto unlock; + + torch_mask = led->led_id == SY7802_LED_JOINT ? + SY7802_TORCH_CURRENT_MASK_ALL : + SY7802_TORCH_CURRENT_MASK(led->led_id); + + /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */ + if (brightness) + brightness -= 1; + + brightness |= (brightness << SY7802_TORCH_CURRENT_SHIFT); + + ret = regmap_update_bits(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, torch_mask, brightness); + if (ret) + goto unlock; + + enable_mask = SY7802_MODE_MASK | led_enable_mask; + ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val); + if (ret) + goto unlock; + + chip->fled_torch_used = fled_torch_used_tmp; + +unlock: + mutex_unlock(&chip->mutex); + return ret; +} + +static int sy7802_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness) +{ + struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); + struct led_flash_setting *s = &fl_cdev->brightness; + u32 val = (brightness - s->min) / s->step; + struct sy7802 *chip = led->chip; + u32 flash_mask; + int ret; + + val |= (val << SY7802_FLASH_CURRENT_SHIFT); + flash_mask = led->led_id == SY7802_LED_JOINT ? + SY7802_FLASH_CURRENT_MASK_ALL : + SY7802_FLASH_CURRENT_MASK(led->led_id); + + mutex_lock(&chip->mutex); + ret = regmap_update_bits(chip->regmap, SY7802_REG_FLASH_BRIGHTNESS, flash_mask, val); + mutex_unlock(&chip->mutex); + + return ret; +} + +static int sy7802_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); + struct sy7802 *chip = led->chip; + u32 fled_strobe_used_tmp; + u32 led_enable_mask; + u32 enable_mask; + u32 val; + int ret; + + mutex_lock(&chip->mutex); + + if (chip->fled_torch_used) { + dev_warn(chip->dev, "Cannot set strobe brightness whilst torch is enabled\n"); + ret = -EBUSY; + goto unlock; + } + + if (state) + fled_strobe_used_tmp = chip->fled_strobe_used | BIT(led->led_id); + else + fled_strobe_used_tmp = chip->fled_strobe_used & ~BIT(led->led_id); + + led_enable_mask = led->led_id == SY7802_LED_JOINT ? + SY7802_LEDS_MASK_ALL : + SY7802_LEDS_MASK(led->led_id); + + val = state ? led_enable_mask : SY7802_MODE_OFF; + if (fled_strobe_used_tmp) + val |= SY7802_MODE_FLASH; + + enable_mask = SY7802_MODE_MASK | led_enable_mask; + ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val); + + if (ret) + goto unlock; + + chip->fled_strobe_used = fled_strobe_used_tmp; + +unlock: + mutex_unlock(&chip->mutex); + return ret; +} + +static int sy7802_strobe_get(struct led_classdev_flash *fl_cdev, bool *state) +{ + struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); + struct sy7802 *chip = led->chip; + + mutex_lock(&chip->mutex); + *state = !!(chip->fled_strobe_used & BIT(led->led_id)); + mutex_unlock(&chip->mutex); + + return 0; +} + +static int sy7802_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) +{ + struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); + struct led_flash_setting *s = &fl_cdev->timeout; + u32 val = (timeout - s->min) / s->step; + struct sy7802 *chip = led->chip; + + return regmap_write(chip->regmap, SY7802_REG_FLASH_DURATION, val); +} + +static int sy7802_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) +{ + struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash); + struct sy7802 *chip = led->chip; + u32 val, led_faults = 0; + int ret; + + /* NOTE: reading register clears fault status */ + ret = regmap_read(chip->regmap, SY7802_REG_FLAGS, &val); + if (ret) + return ret; + + if (val & (SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW | SY7802_FLAG_INPUT_VOLTAGE_LOW)) + led_faults |= LED_FAULT_INPUT_VOLTAGE; + + if (val & SY7802_FLAG_THERMAL_SHUTDOWN) + led_faults |= LED_FAULT_OVER_TEMPERATURE; + + if (val & SY7802_FLAG_TIMEOUT) + led_faults |= LED_FAULT_TIMEOUT; + + *fault = led_faults; + return 0; +} + +static const struct led_flash_ops sy7802_flash_ops = { + .flash_brightness_set = sy7802_flash_brightness_set, + .strobe_set = sy7802_strobe_set, + .strobe_get = sy7802_strobe_get, + .timeout_set = sy7802_timeout_set, + .fault_get = sy7802_fault_get, +}; + +static void sy7802_init_flash_brightness(struct led_classdev_flash *fl_cdev) +{ + struct led_flash_setting *s; + + /* Init flash brightness setting */ + s = &fl_cdev->brightness; + s->min = SY7802_FLASH_BRIGHTNESS_MIN; + s->max = SY7802_FLASH_BRIGHTNESS_MAX; + s->step = SY7802_FLASH_BRIGHTNESS_STEP; + s->val = SY7802_FLASH_BRIGHTNESS_DEFAULT; +} + +static void sy7802_init_flash_timeout(struct led_classdev_flash *fl_cdev) +{ + struct led_flash_setting *s; + + /* Init flash timeout setting */ + s = &fl_cdev->timeout; + s->min = SY7802_TIMEOUT_MIN_US; + s->max = SY7802_TIMEOUT_MAX_US; + s->step = SY7802_TIMEOUT_STEPSIZE_US; + s->val = SY7802_TIMEOUT_DEFAULT_US; +} + +static int sy7802_led_register(struct device *dev, struct sy7802_led *led, + struct device_node *np) +{ + struct led_init_data init_data = {}; + int ret; + + init_data.fwnode = of_fwnode_handle(np); + + ret = devm_led_classdev_flash_register_ext(dev, &led->flash, &init_data); + if (ret) { + dev_err(dev, "Couldn't register flash %d\n", led->led_id); + return ret; + } + + return 0; +} + +static int sy7802_init_flash_properties(struct device *dev, struct sy7802_led *led, + struct device_node *np) +{ + struct led_classdev_flash *flash = &led->flash; + struct led_classdev *lcdev = &flash->led_cdev; + u32 sources[SY7802_MAX_LEDS]; + int i, num, ret; + + num = of_property_count_u32_elems(np, "led-sources"); + if (num < 1) { + dev_err(dev, "Not specified or wrong number of led-sources\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(np, "led-sources", sources, num); + if (ret) + return ret; + + for (i = 0; i < num; i++) { + if (sources[i] >= SY7802_MAX_LEDS) + return -EINVAL; + if (led->chip->leds_active & BIT(sources[i])) + return -EINVAL; + led->chip->leds_active |= BIT(sources[i]); + } + + /* If both channels are specified in 'led-sources', joint flash output mode is used */ + led->led_id = num == 2 ? SY7802_LED_JOINT : sources[0]; + + lcdev->max_brightness = SY7802_TORCH_BRIGHTNESS_MAX; + lcdev->brightness_set_blocking = sy7802_torch_brightness_set; + lcdev->flags |= LED_DEV_CAP_FLASH; + + flash->ops = &sy7802_flash_ops; + + sy7802_init_flash_brightness(flash); + sy7802_init_flash_timeout(flash); + + return 0; +} + +static int sy7802_chip_check(struct sy7802 *chip) +{ + struct device *dev = chip->dev; + u32 chipid; + int ret; + + ret = regmap_read(chip->regmap, SY7802_REG_DEV_ID, &chipid); + if (ret) + return dev_err_probe(dev, ret, "Failed to read chip ID\n"); + + if (chipid != SY7802_CHIP_ID) + return dev_err_probe(dev, -ENODEV, "Unsupported chip detected: %x\n", chipid); + + return 0; +} + +static void sy7802_enable(struct sy7802 *chip) +{ + gpiod_set_value_cansleep(chip->enable_gpio, 1); + usleep_range(200, 300); +} + +static void sy7802_disable(struct sy7802 *chip) +{ + gpiod_set_value_cansleep(chip->enable_gpio, 0); +} + +static int sy7802_probe_dt(struct sy7802 *chip) +{ + struct device_node *np = dev_of_node(chip->dev); + int child_num; + int ret; + + regmap_write(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_OFF); + regmap_write(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, LED_OFF); + + child_num = 0; + for_each_available_child_of_node_scoped(np, child) { + struct sy7802_led *led = chip->leds + child_num; + + led->chip = chip; + led->led_id = child_num; + + ret = sy7802_init_flash_properties(chip->dev, led, child); + if (ret) + return ret; + + ret = sy7802_led_register(chip->dev, led, child); + if (ret) + return ret; + + child_num++; + } + return 0; +} + +static void sy7802_chip_disable_action(void *data) +{ + struct sy7802 *chip = data; + + sy7802_disable(chip); +} + +static void sy7802_regulator_disable_action(void *data) +{ + struct sy7802 *chip = data; + + regulator_disable(chip->vin_regulator); +} + +static const struct regmap_config sy7802_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_MAPLE, + .reg_defaults = sy7802_regmap_defs, + .num_reg_defaults = ARRAY_SIZE(sy7802_regmap_defs), +}; + +static int sy7802_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct sy7802 *chip; + size_t count; + int ret; + + count = device_get_child_node_count(dev); + if (!count || count > SY7802_MAX_LEDS) + return dev_err_probe(dev, -EINVAL, "Invalid amount of LED nodes %zu\n", count); + + chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->num_leds = count; + + chip->dev = dev; + i2c_set_clientdata(client, chip); + + chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + ret = PTR_ERR_OR_ZERO(chip->enable_gpio); + if (ret) + return dev_err_probe(dev, ret, "Failed to request enable gpio\n"); + + chip->vin_regulator = devm_regulator_get(dev, "vin"); + ret = PTR_ERR_OR_ZERO(chip->vin_regulator); + if (ret) + return dev_err_probe(dev, ret, "Failed to request regulator\n"); + + ret = regulator_enable(chip->vin_regulator); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + ret = devm_add_action_or_reset(dev, sy7802_regulator_disable_action, chip); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &chip->mutex); + if (ret) + return ret; + + mutex_lock(&chip->mutex); + + chip->regmap = devm_regmap_init_i2c(client, &sy7802_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err_probe(dev, ret, "Failed to allocate register map\n"); + goto error; + } + + ret = sy7802_probe_dt(chip); + if (ret < 0) + goto error; + + sy7802_enable(chip); + + ret = devm_add_action_or_reset(dev, sy7802_chip_disable_action, chip); + if (ret) + goto error; + + ret = sy7802_chip_check(chip); + +error: + mutex_unlock(&chip->mutex); + return ret; +} + +static const struct of_device_id __maybe_unused sy7802_leds_match[] = { + { .compatible = "silergy,sy7802", }, + {} +}; +MODULE_DEVICE_TABLE(of, sy7802_leds_match); + +static struct i2c_driver sy7802_driver = { + .driver = { + .name = "sy7802", + .of_match_table = of_match_ptr(sy7802_leds_match), + }, + .probe = sy7802_probe, +}; +module_i2c_driver(sy7802_driver); + +MODULE_AUTHOR("André Apitzsch "); +MODULE_DESCRIPTION("Silergy SY7802 flash LED driver"); +MODULE_LICENSE("GPL"); From patchwork Mon Jun 24 21:25:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= X-Patchwork-Id: 807132 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 35A3919FA81; Mon, 24 Jun 2024 21:25:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; cv=none; b=LAI/Bu10AAWWnvZn1N9C0gsT8GhC3Y58xG+ZONPWBBlVLfGM1tvt2tL0zCnqzChCuB2tJN19Q7ZKUz8e7yvxp4RaxodGxC1eu7DhkyQbx2fTXvMAWz0A9DRBfTGAdEUbdERNTeRFnHMkLJDDMZb+M0hQkzInYgHF9tW9L1lJn1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719264307; c=relaxed/simple; bh=2/D3y84MWExMUe/+ohdAcL5JtZ0TFzz2ZC4d4ub2oGU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=W2TteI9ewFA/pI0Yh1kHmLmBVan9Jp1f4GfIBS2TEckMC09KHKeyJ8/eOmjqaobHadJG2Mlzk1iW+BOhS93YSlico+PfKOQ1RVOXPXrmcGhTNsabhpzVEFL51aCYXDeBA/OwdEJMCVeRsRDez7vbNLOV+IzE7OCE6mPQ4Av0Vw0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cwXHosJw; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cwXHosJw" Received: by smtp.kernel.org (Postfix) with ESMTPS id E4BF4C4AF17; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719264307; bh=2/D3y84MWExMUe/+ohdAcL5JtZ0TFzz2ZC4d4ub2oGU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=cwXHosJwT/Na/x6XNpTVsjhLSuoIzS5QUDHdjk4TO4qEyTKrh7GhqCCXF7TlT74j3 98QLXr5+/kfwaE3paHwNAkacx3FIcV6zWgseBB+cYWywP3c9Q8Cm8mNkTfcx9D867R Sesf5/4PQiiopGuM8vN94aTgKQEk59k1g4jQkzHyGQXwDHXeEKXSDM2bc3a9XBfvzJ ZR98vrHj0mY9y/7yr8ex+eyr3NEtYLj7KdHbriR5NSIGPgkJvPUP9cASoizKJB/z9V 928kMcbd0eqablgPpV7SgAj+lWM8HlP4qJxIh1XYJ5lokigx72NLDGjOpa8QKKwWsP q6AkfM58ejksg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D657EC2BD09; Mon, 24 Jun 2024 21:25:06 +0000 (UTC) From: =?utf-8?q?Andr=C3=A9_Apitzsch_via_B4_Relay?= Date: Mon, 24 Jun 2024 23:25:14 +0200 Subject: [PATCH v5 3/3] arm64: dts: qcom: msm8939-longcheer-l9100: Add rear flash Precedence: bulk X-Mailing-List: linux-leds@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240624-sy7802-v5-3-7abc9d96bfa6@apitzsch.eu> References: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> In-Reply-To: <20240624-sy7802-v5-0-7abc9d96bfa6@apitzsch.eu> To: Pavel Machek , Lee Jones , Rob Herring , Conor Dooley , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Christophe JAILLET , Trilok Soni , Krzysztof Kozlowski , Kees Cook Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, linux-arm-msm@vger.kernel.org, ~postmarketos/upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Apitzsch?= X-Mailer: b4 0.14.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1719264314; l=1408; i=git@apitzsch.eu; s=20240325; h=from:subject:message-id; bh=5PZFGehTShxKe3OFkYq1lO6OPdXhGy4wNq5owjXoJG0=; b=oDPZXMmOvhZAvs35W+AMotHZ0o845LK2xy/6wJrfMoJEC9S9QIh9P4AKXB5Yphutt0FvIy5DU l14UvbAQRItC7IXucDZiEx2vfROezgknXjhz19eMZnc6MNHfCo3ZQE6 X-Developer-Key: i=git@apitzsch.eu; a=ed25519; pk=wxovcZRfvNYBMcTw4QFFtNEP4qv39gnBfnfyImXZxiU= X-Endpoint-Received: by B4 Relay for git@apitzsch.eu/20240325 with auth_id=142 X-Original-From: =?utf-8?q?Andr=C3=A9_Apitzsch?= Reply-To: git@apitzsch.eu From: André Apitzsch The phone has a Silergy SY7802 flash LED controller. Signed-off-by: André Apitzsch Reviewed-by: Konrad Dybcio --- .../boot/dts/qcom/msm8939-longcheer-l9100.dts | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts index e3404c4455cf..528737929274 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts @@ -159,6 +159,25 @@ led@2 { }; }; }; + + flash-led-controller@53 { + compatible = "silergy,sy7802"; + reg = <0x53>; + #address-cells = <1>; + #size-cells = <0>; + + enable-gpios = <&tlmm 16 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&camera_rear_flash_default>; + pinctrl-names = "default"; + + led@0 { + reg = <0>; + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <0>, <1>; + }; + }; }; &blsp_i2c3 { @@ -318,6 +337,13 @@ camera_front_flash_default: camera-front-flash-default-state { bias-disable; }; + camera_rear_flash_default: camera-rear-flash-default-state { + pins = "gpio9", "gpio16", "gpio51"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + gpio_hall_sensor_default: gpio-hall-sensor-default-state { pins = "gpio20"; function = "gpio";