From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ed1-f53.google.com (mail-ed1-f53.google.com [209.85.208.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12ABB37CD20 for ; Sun, 3 May 2026 16:45:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.53 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777826714; cv=none; b=qoaZRTv4m+kpCa+816GhUO4MeZ7QAZnPFRCe/Z/zpVKrHrQUZ1vQ/VIvViBzd08/qkUKxQxJG1qUgwlEU0mZEhCCL2GJPUE0HR/f1ks35utlx1luSEGG1ai9f2LsTWuAa1mKpX+AUBHtclYVEpjpPPvmbFivE0/f3DeyQwynays= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777826714; c=relaxed/simple; bh=PXMbL35meuA3K4hWiUmh26Ifh+2vO6KRGqztajociNo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JGcgpI8H2qY23MTVfSCHC+KfspezSUSsXcOt6BH3k6fQZhPhcdauTCMdYPr4gKIidyhpIZL6vBch8/rROj+faSZNtg21h0/WRBmixhkL7AloKSoWTI9IPUrm8f7WfsOzSNcdrG02TnvtHghbUt7l4Ru3GAqfQ24vuGlgo3yypWg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ElGr9luZ; arc=none smtp.client-ip=209.85.208.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ElGr9luZ" Received: by mail-ed1-f53.google.com with SMTP id 4fb4d7f45d1cf-65c4152313fso4673575a12.1 for ; Sun, 03 May 2026 09:45:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777826704; x=1778431504; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sRXkstlVfDTEdoKTn7b1ddY7nla/Jav5UO7h+m11Go8=; b=ElGr9luZA0OJ5FVLJTAGW7vaysrroq6JUTWHJLSizlBnhGbc+KWWvi1LFYVgv1AbxC GC5ML+UZupBN8CSarMuTOKFW9XdjvMlMPq8AtURO7u4Luom1dfkHPTv9b8JKyAnIkSR6 3Yp5N3D90g885uJONZgupf4ShUTvdM53Nn1tGyw+Hpxhs4816bjfxinnDT8yLE+Z6cz3 GWtBpYaRuXtrjzYB9jankuJm8MEeoEWeWpyLWx3sy/3bxXiRtL2cIpQNvvL2MCqS+78a 37M8tELMGYjqdbWIp7KpB8/KAGe3Ll+RcB0U5rOzIls2SCgN7ub27OKvMZYEGgzkzNvb nHFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777826704; x=1778431504; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=sRXkstlVfDTEdoKTn7b1ddY7nla/Jav5UO7h+m11Go8=; b=ChqsvkmswdeQrrwnGzIcdx1Vr3JApcfJVuALeYajsOkb7mY6n6AJvgxlqcCQk1pWHw Ui2VnY2QXh/s1U0yGgWuVsyIrzmg5NRv0qN5xP9/4pZN5jpRJS6LmeRN5IGBBCq/CyKq WC0d81CRe7Yh7cMMpIpWROy2NlVjQtVEsoONO0UJLPG6ql9p06qX8claBnwaoFm4p0xG MQnSUtPUQUg3awP/+KIpZOlP7Ftr9U08RfnRun2kaXbwwUvO6wXemMwGi7JZxqr8MWt7 /iiEs0EAZMMmqBS3m5grhcAByFtDxu7urfa08oVmGidQXDGSzEiPF0fUd5sXhXzAqtHJ m2sw== X-Forwarded-Encrypted: i=1; AFNElJ+njhiRaQVFJTi0gnVtTYp5TqzWKraSA0YufehOYE8HQvfZv9Z3Aly/AYpvI95hX8u3gipxAHYrr7q9wGs=@vger.kernel.org X-Gm-Message-State: AOJu0Yxq2EY9ST5BJP+sOe5c+vatPZeivudxpsIz4E4WkpwyKwU3u5Rx 7k7FBx3BnouW+S+SoY92ghnhiAjoWUBfs0wuusxWLBze2LYrB4eDk0c/ X-Gm-Gg: AeBDievM4WBkA1LDQa8m5JFIcqQybZ47c8o5EEg9RWiLeYA75+dbIQqxqCE4ll/qJAB oqaiE5O5QiaMPg0G37OMwonIZwULPpM/zpFAlw3mU971tXsL3CiW73bS1yGGLc3PepPpAmx0H8M 5a2tWlO0pRU6Fx8OPG0MN/xnP/czjlejawMoCzZfLhP++DYyBkFU/2639IN2rB41C08+0blLkBf e5booV7katutxqely12fx2vjIyh2mC6qvgxqcr8/j5UQkyzKLI45Elh46IpeTJx1OzRPkDSpYnE u62fwG9Z/sJxIhwIMj/t73ipYGrHGnZ/IXIxEt7wO2aKP4Nq34i0bTHOg9j/McY6OADCba6jv9J 5JVBhz/JXQYQxPk0/CtZ1B7RPwGI2wUA60G+spS4RAqJKhVMlQdtfH6kUzwu/HGLQ0rLNnhUPtn sQmoVb+RzQ09jO6XorMdJ0lGQ= X-Received: by 2002:a17:907:930d:b0:bad:52bd:8764 with SMTP id a640c23a62f3a-bbffcf919b4mr313501666b.24.1777826704242; Sun, 03 May 2026 09:45:04 -0700 (PDT) Received: from xeon ([188.163.112.56]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-bc237ef8297sm27430566b.57.2026.05.03.09.45.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 03 May 2026 09:45:03 -0700 (PDT) From: Svyatoslav Ryhel To: Lee Jones , Pavel Machek , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Sakari Ailus , Mauro Carvalho Chehab , Svyatoslav Ryhel Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH v5 5/6] media: i2c: lm3560: Add support for PM features Date: Sun, 3 May 2026 19:44:44 +0300 Message-ID: <20260503164445.215540-6-clamor95@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260503164445.215540-1-clamor95@gmail.com> References: <20260503164445.215540-1-clamor95@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add support for power management features to better control the LM3560 within the media framework. To achieve the desired PM support, the HWEN GPIO and VIN power supply were added and configured into power on/off sequences. Added PM operations along with the PM configuration setup. Signed-off-by: Svyatoslav Ryhel --- drivers/media/i2c/lm3560.c | 117 ++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index ce4b09d1f208..15741ea5684f 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -12,13 +12,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -49,6 +52,8 @@ enum led_enable { * @dev: pointer to &struct device * @regmap: reg. map for i2c * @lock: muxtex for serial access. + * @hwen_gpio: line connected to HWEN pin + * @vin_supply: line connected to IN supply (2.5V - 5.5V) * @led_mode: V4L2 LED mode * @ctrls_led: V4L2 controls * @subdev_led: V4L2 subdev @@ -63,6 +68,9 @@ struct lm3560_flash { struct regmap *regmap; struct mutex lock; + struct gpio_desc *hwen_gpio; + struct regulator *vin_supply; + enum v4l2_flash_led_mode led_mode; struct v4l2_ctrl_handler ctrls_led[LM3560_LED_MAX]; struct v4l2_subdev subdev_led[LM3560_LED_MAX]; @@ -177,12 +185,17 @@ static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no); int rval = -EINVAL; + if (!pm_runtime_get_if_in_use(flash->dev)) + return 0; + if (ctrl->id == V4L2_CID_FLASH_FAULT) { s32 fault = 0; unsigned int reg_val; rval = regmap_read(flash->regmap, REG_FLAG, ®_val); - if (rval < 0) + if (rval < 0) { + pm_runtime_put(flash->dev); return rval; + } if (reg_val & FAULT_SHORT_CIRCUIT) fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; if (reg_val & FAULT_OVERTEMP) @@ -192,6 +205,8 @@ static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) ctrl->cur.val = fault; } + pm_runtime_put(flash->dev); + return rval; } @@ -201,6 +216,9 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) u8 tout_bits; int rval = -EINVAL; + if (!pm_runtime_get_if_in_use(flash->dev)) + return 0; + switch (ctrl->id) { case V4L2_CID_FLASH_LED_MODE: flash->led_mode = ctrl->val; @@ -246,6 +264,8 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no) break; } + pm_runtime_put(flash->dev); + return rval; } @@ -409,6 +429,38 @@ static int lm3560_init_device(struct lm3560_flash *flash) return rval; } +static int __maybe_unused lm3560_power_off(struct device *dev) +{ + struct lm3560_flash *flash = dev_get_drvdata(dev); + + gpiod_set_value_cansleep(flash->hwen_gpio, 0); + regulator_disable(flash->vin_supply); + + return 0; +} + +static int __maybe_unused lm3560_power_on(struct device *dev) +{ + struct lm3560_flash *flash = dev_get_drvdata(dev); + int rval; + + rval = regulator_enable(flash->vin_supply); + if (rval < 0) { + dev_err(flash->dev, "failed to enable vin power supply\n"); + return rval; + } + + gpiod_set_value_cansleep(flash->hwen_gpio, 1); + + rval = lm3560_init_device(flash); + if (rval < 0) { + lm3560_power_off(dev); + return rval; + } + + return 0; +} + static void lm3560_subdev_cleanup(struct lm3560_flash *flash) { int led_no; @@ -442,6 +494,17 @@ static int lm3560_probe(struct i2c_client *client) bitmap_zero(flash->led_id, LM3560_LED_MAX); + flash->hwen_gpio = devm_gpiod_get_optional(flash->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(flash->hwen_gpio)) + return dev_err_probe(flash->dev, PTR_ERR(flash->hwen_gpio), + "failed to get hwen gpio\n"); + + flash->vin_supply = devm_regulator_get(flash->dev, "vin"); + if (IS_ERR(flash->vin_supply)) + return dev_err_probe(flash->dev, PTR_ERR(flash->vin_supply), + "failed to get vin-supply\n"); + flash->peak = LM3560_PEAK_1600mA; rval = device_property_read_u32(flash->dev, "ti,peak-current-microamp", &peak_ua); @@ -469,9 +532,19 @@ static int lm3560_probe(struct i2c_client *client) &flash->max_flash_timeout); flash->max_flash_timeout /= 1000; + rval = regulator_enable(flash->vin_supply); + if (rval < 0) + return dev_err_probe(flash->dev, rval, + "failed to enable vin power supply\n"); + + gpiod_set_value_cansleep(flash->hwen_gpio, 1); + rval = lm3560_init_device(flash); if (rval < 0) - return rval; + goto error_disable; + + pm_runtime_set_active(flash->dev); + pm_runtime_enable(flash->dev); for_each_available_child_of_node(dev_of_node(flash->dev), node) { u32 reg; @@ -492,10 +565,10 @@ static int lm3560_probe(struct i2c_client *client) rval = lm3560_subdev_init(flash, reg, node); if (rval < 0) { - lm3560_subdev_cleanup(flash); - return dev_err_probe(flash->dev, rval, - "failed to register led%d\n", - reg); + dev_err(flash->dev, + "failed to register led%d: %d\n", + reg, rval); + goto error_clean; } set_bit(reg, flash->led_id); @@ -504,7 +577,23 @@ static int lm3560_probe(struct i2c_client *client) i2c_set_clientdata(client, flash); + pm_runtime_set_autosuspend_delay(flash->dev, 1000); + pm_runtime_use_autosuspend(flash->dev); + pm_runtime_idle(flash->dev); + return 0; + +error_clean: + pm_runtime_disable(flash->dev); + pm_runtime_set_suspended(flash->dev); + + lm3560_subdev_cleanup(flash); + +error_disable: + gpiod_set_value_cansleep(flash->hwen_gpio, 0); + regulator_disable(flash->vin_supply); + + return rval; } static void lm3560_remove(struct i2c_client *client) @@ -512,8 +601,22 @@ static void lm3560_remove(struct i2c_client *client) struct lm3560_flash *flash = i2c_get_clientdata(client); lm3560_subdev_cleanup(flash); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) { + lm3560_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } } +static const struct dev_pm_ops lm3560_pm_ops = { + SET_RUNTIME_PM_OPS(lm3560_power_off, lm3560_power_on, NULL) +}; + static const struct of_device_id lm3560_of_match[] = { { .compatible = "ti,lm3559" }, { .compatible = "ti,lm3560" }, @@ -532,7 +635,7 @@ MODULE_DEVICE_TABLE(i2c, lm3560_id_table); static struct i2c_driver lm3560_i2c_driver = { .driver = { .name = LM3560_NAME, - .pm = NULL, + .pm = pm_ptr(&lm3560_pm_ops), .of_match_table = lm3560_of_match, }, .probe = lm3560_probe, -- 2.51.0