From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qv1-f46.google.com (mail-qv1-f46.google.com [209.85.219.46]) (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 73FC533DEDB for ; Wed, 4 Feb 2026 16:54:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.46 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770224096; cv=none; b=bJYSeXfqCQ1N6UGYdt7mbI2dkm9Z+8c1bmcysBB+aSs2CS89a0XphLzUur0O3AyiH9xOa9THgVKBDlhG8w1nNi0LhvlXKR3DZJT2FWumyDxivbldJanCga8Zlsc1qhlxoHUfI3N/wcDodOBOh/8IEF7hAzmEktdxmv5x2s3A2fI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770224096; c=relaxed/simple; bh=iiapcZ/DGEP/cwCQIyrmgJLGryp0jX6aBFaErKOZYUI=; h=Message-ID:Subject:From:To:Cc:Date:In-Reply-To:References: Content-Type:MIME-Version; b=aCAwPnpmEePcrux9Q9RgF1F10I43O+HV6UyfNgcjxupQOQh+8T43S62q+ErU3m1KINvZuAxDz1UH2xDsaWOaYEZlPCJ+ZKsS+cmvSHYYdqBuhkpVAjfQXwbtt0gHC/B4PfbB06kOk6hJw+lXAMZZkielRy747sFbG4T3bIMYqBw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=QrTz+Iue; arc=none smtp.client-ip=209.85.219.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="QrTz+Iue" Received: by mail-qv1-f46.google.com with SMTP id 6a1803df08f44-8946e0884afso654346d6.1 for ; Wed, 04 Feb 2026 08:54:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1770224095; x=1770828895; darn=vger.kernel.org; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject :date:message-id:reply-to; bh=pj16dI3qaH0YVk42KgqHTQPPBcA62LkSoA1Q8YJmVwU=; b=QrTz+Iuej7m3JtXVBuDN/j3zVnZaMVvrwBcGCoIZzHXXF0X3grWj4n051n0GxuvvBJ TcIcvZkKrCU1pxouG+OuX84eZKBtv7rKrZfZmmLJYbIe2NHTSxWAYyL+Db6S8RSoINeh scifuex8SSK7ITLkwfUFuuPwyLgMYoZDI8kGMeVk6ipOaj20v2no68qxssbombxj9iQ7 bLsHeaMskGEbux2dU05tqNIal7RxZFjZeUCwp66VL5QYPS+2HzXLzNw5bWvtdqiCI36a wGLmuzmgqW199JyV6fnuIbpsxoyxlbW/A7zPvXWkwTn3GQ1ucQN3jnzrNp1xT7zhxfQP tw6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770224095; x=1770828895; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=pj16dI3qaH0YVk42KgqHTQPPBcA62LkSoA1Q8YJmVwU=; b=c5XWYKBWHUnO94Q2UjqAvvY9l+qE+NKgb8Y1vtD7iNC93QTcfA+LFWzb3FGhdg7w+J CUTQNRSTO4l+BaqzllZxGVl+B8H3d3pDpGzqG8GIk2rTAhx9tg7FYtj64rD4VYPtAJxu sx0P526Lgp2ulKvrXz2uBuGT6JAg+e/ceXWUOPxZXg2ntYlDXxZsIKOkmg/kyBZHBCnv /nm2A/D4hYeYbwhBAFKn19qDTaATWpz5WQZRaiONA9HQ4jW1LH4MvYa01Xq5x+Fqx7zp KBPwKee22VRU9zMEEvZZllw9LgivR7+sAe5R4L9VdwSllhknRvq68yXQlRmOmIGZtsEK +tkA== X-Forwarded-Encrypted: i=1; AJvYcCX+im5WivwTnyzxj5YFSc7hNcDf+Vx+Uni7+DVq/buVp8Joj2rPR6mx4O01Kdw7qWUfXvb+2FNQYDTwGNA=@vger.kernel.org X-Gm-Message-State: AOJu0YyWSHFvKtluA7zSIQ6dzGV9Q8K7eRk1bbpfezG5MOz3p/TtISXE ZjyOTKpX6gTeVuSPmwVa6mhvQRudmUuV9Aj5kaj5lmAPgV3IaaUNJDT04Gguo/VSZhw= X-Gm-Gg: AZuq6aKE9xx7EplYDMT55vjzRJYeMXFNjGoqLZfWYJbh94LFNvAWghTo0+vOY+GK56H jnElM5g9CENEfZExg6e9Xkoq1ol6dj31GVpdmJ/A8+CQ0T6Sj/b1xgjZm2RofVbJIK9XugcJa3S 9kMwQ7AswszJl6Gwxg5i9V3JEcgBjDSsM/NzT/0I2jKWE/Qlk+jFhFISz7nankqJiCWwoDPQzlW fhzpiKkbWeGPUc9nIv3C/kJXFBAjuw87lRB4Adn/XOs5L5C/fZBYl2HmVbvFQ0DvgzsVixOM9h9 VozOenizQvnHy7dih07xi7n3fiviCqqNjJclm0Dle3ydpB3BDfBJoy/ydt0JpytQthW6jzSm0KZ btddmqI4769YOUNsp5xGD3mCRx4LnCEaCeOEEQWxcbPWj/TuYSwuOx7WbDhnpVGuVDIlhwCHudH MZFvCPfiom2nmaUsDDQg== X-Received: by 2002:a05:6214:2469:b0:894:7051:bd9d with SMTP id 6a1803df08f44-895220f553bmr47201306d6.9.1770224095252; Wed, 04 Feb 2026 08:54:55 -0800 (PST) Received: from draszik.lan ([212.129.76.169]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-89521cf87fcsm25696886d6.30.2026.02.04.08.54.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Feb 2026 08:54:54 -0800 (PST) Message-ID: Subject: Re: [PATCH v2 08/12] leds: flash: add support for Samsung S2M series PMIC flash LED device From: =?ISO-8859-1?Q?Andr=E9?= Draszik To: Kaustabh Chakraborty , Lee Jones , Pavel Machek , Rob Herring , Krzysztof Kozlowski , Conor Dooley , MyungJoo Ham , Chanwoo Choi , Sebastian Reichel , Krzysztof Kozlowski , Alexandre Belloni , Jonathan Corbet , Shuah Khan Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-rtc@vger.kernel.org, linux-doc@vger.kernel.org Date: Wed, 04 Feb 2026 16:55:11 +0000 In-Reply-To: <20260126-s2mu005-pmic-v2-8-78f1a75f547a@disroot.org> References: <20260126-s2mu005-pmic-v2-0-78f1a75f547a@disroot.org> <20260126-s2mu005-pmic-v2-8-78f1a75f547a@disroot.org> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.56.2-2+build4 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Hi, On Mon, 2026-01-26 at 00:37 +0530, Kaustabh Chakraborty wrote: > Add support for flash LEDs found in certain Samsung S2M series PMICs. > The device has two channels for LEDs, typically for the back and front > cameras in mobile devices. Both channels can be independently > controlled, and can be operated in torch or flash modes. >=20 > The driver includes initial support for the S2MU005 PMIC flash LEDs. >=20 > Signed-off-by: Kaustabh Chakraborty > --- > =C2=A0drivers/leds/flash/Kconfig=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 |=C2=A0 12 ++ > =C2=A0drivers/leds/flash/Makefile=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 |=C2=A0=C2=A0 1 + > =C2=A0drivers/leds/flash/leds-s2m-flash.c | 410 +++++++++++++++++++++++++= +++++++++++ > =C2=A03 files changed, 423 insertions(+) >=20 > diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig > index 5e08102a67841..be62e05277429 100644 > --- a/drivers/leds/flash/Kconfig > +++ b/drivers/leds/flash/Kconfig > @@ -114,6 +114,18 @@ config LEDS_RT8515 > =C2=A0 =C2=A0 To compile this driver as a module, choose M here: the modu= le > =C2=A0 =C2=A0 will be called leds-rt8515. > =C2=A0 > +config LEDS_S2M_FLASH > + tristate "Samsung S2M series PMICs flash/torch LED support" > + depends on LEDS_CLASS > + depends on MFD_SEC_CORE > + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS > + select REGMAP_IRQ > + help > + =C2=A0 This option enables support for the flash/torch LEDs found in > + =C2=A0 certain Samsung S2M series PMICs, such as the S2MU005. It has > + =C2=A0 a LED channel dedicated for every physical LED. The LEDs can > + =C2=A0 be controlled in flash and torch modes. > + > =C2=A0config LEDS_SGM3140 > =C2=A0 tristate "LED support for the SGM3140" > =C2=A0 depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS > diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile > index 712fb737a428e..44e6c1b4beb37 100644 > --- a/drivers/leds/flash/Makefile > +++ b/drivers/leds/flash/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_MAX77693) +=3D leds-max77693.o > =C2=A0obj-$(CONFIG_LEDS_QCOM_FLASH) +=3D leds-qcom-flash.o > =C2=A0obj-$(CONFIG_LEDS_RT4505) +=3D leds-rt4505.o > =C2=A0obj-$(CONFIG_LEDS_RT8515) +=3D leds-rt8515.o > +obj-$(CONFIG_LEDS_S2M_FLASH) +=3D leds-s2m-flash.o > =C2=A0obj-$(CONFIG_LEDS_SGM3140) +=3D leds-sgm3140.o > =C2=A0obj-$(CONFIG_LEDS_SY7802) +=3D leds-sy7802.o > =C2=A0obj-$(CONFIG_LEDS_TPS6131X) +=3D leds-tps6131x.o > diff --git a/drivers/leds/flash/leds-s2m-flash.c b/drivers/leds/flash/led= s-s2m-flash.c > new file mode 100644 > index 0000000000000..1be2745c475bf > --- /dev/null > +++ b/drivers/leds/flash/leds-s2m-flash.c > @@ -0,0 +1,410 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Flash and Torch LED Driver for Samsung S2M series PMICs. > + * > + * Copyright (c) 2015 Samsung Electronics Co., Ltd > + * Copyright (c) 2025 Kaustabh Chakraborty > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define MAX_CHANNELS 2 > + > +struct s2m_fled { > + struct device *dev; > + struct regmap *regmap; > + struct led_classdev_flash cdev; > + struct v4l2_flash *v4l2_flash; > + struct mutex lock; Please add a (brief) comment describing what the mutex protects. > + const struct s2m_fled_spec *spec; > + unsigned int pmic_revision; > + u8 channel; > + u8 flash_brightness; > + u8 flash_timeout; > +}; > + > +struct s2m_fled_spec { > + u8 num_channels; > + u32 torch_max_brightness; > + u32 flash_min_current_ua; > + u32 flash_max_current_ua; > + u32 flash_min_timeout_us; > + u32 flash_max_timeout_us; > + int (*torch_brightness_set_blocking)(struct led_classdev *led_cdev, > + =C2=A0=C2=A0=C2=A0=C2=A0 enum led_brightness brightness); > + const struct led_flash_ops *flash_ops; > +}; > + > +static struct led_classdev_flash *to_cdev_flash(struct led_classdev *cde= v) > +{ > + return container_of(cdev, struct led_classdev_flash, led_cdev); > +} > + > +static struct s2m_fled *to_led_priv(struct led_classdev_flash *cdev) > +{ > + return container_of(cdev, struct s2m_fled, cdev); > +} > + > +static int s2m_fled_flash_brightness_set(struct led_classdev_flash *cdev= , > + u32 brightness) > +{ > + struct s2m_fled *priv =3D to_led_priv(cdev); > + struct led_flash_setting *setting =3D &cdev->brightness; > + > + priv->flash_brightness =3D (brightness - setting->min) / setting->step; > + > + return 0; > +} > + > +static int s2m_fled_flash_timeout_set(struct led_classdev_flash *cdev, > + =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 u32 timeout) > +{ > + struct s2m_fled *priv =3D to_led_priv(cdev); > + struct led_flash_setting *setting =3D &cdev->timeout; > + > + priv->flash_timeout =3D (timeout - setting->min) / setting->step; > + > + return 0; > +} > + > +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) > +static int s2m_fled_flash_external_strobe_set(struct v4l2_flash *v4l2_fl= ash, > + =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 bool enable) > +{ > + struct s2m_fled *priv =3D to_led_priv(v4l2_flash->fled_cdev); > + > + mutex_lock(&priv->lock); > + > + priv->cdev.ops->strobe_set(&priv->cdev, enable); > + > + mutex_unlock(&priv->lock); > + > + return 0; > +} > + > +static const struct v4l2_flash_ops s2m_fled_v4l2_flash_ops =3D { > + .external_strobe_set =3D s2m_fled_flash_external_strobe_set, > +}; > +#else > +static const struct v4l2_flash_ops s2m_fled_v4l2_flash_ops; > +#endif > + > +static int s2mu005_fled_torch_brightness_set(struct led_classdev *cdev, > + =C2=A0=C2=A0=C2=A0=C2=A0 enum led_brightness value) > +{ > + struct s2m_fled *priv =3D to_led_priv(to_cdev_flash(cdev)); > + struct regmap *regmap =3D priv->regmap; > + u8 channel =3D priv->channel; > + unsigned int reg_enable; > + int ret; > + > + mutex_lock(&priv->lock); > + > + /* > + * Get the LED enable register address. Revision EVT0 has the > + * register at CTRL4, while EVT1 and higher have it at CTRL6. > + */ > + if (priv->pmic_revision =3D=3D 0) > + reg_enable =3D S2MU005_REG_FLED_CTRL4; > + else > + reg_enable =3D S2MU005_REG_FLED_CTRL6; You could REG_FIELD() and friends for this and everywhere else with similar if / else. > + > + if (value =3D=3D LED_OFF) { > + ret =3D regmap_clear_bits(regmap, reg_enable, > + S2MU005_FLED_TORCH_EN(channel)); > + if (ret < 0) > + dev_err(priv->dev, "failed to disable torch LED\n"); > + goto unlock; > + } > + > + ret =3D regmap_update_bits(regmap, S2MU005_REG_FLED_CH_CTRL1(channel), > + S2MU005_FLED_TORCH_IOUT, > + FIELD_PREP(S2MU005_FLED_TORCH_IOUT, value - 1)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to set torch current\n"); > + goto unlock; > + } > + > + ret =3D regmap_set_bits(regmap, reg_enable, S2MU005_FLED_TORCH_EN(chann= el)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to enable torch LED\n"); > + goto unlock; > + } > + > +unlock: > + mutex_unlock(&priv->lock); > + > + return ret; > +} > + > +static int s2mu005_fled_flash_strobe_set(struct led_classdev_flash *cdev= , > + bool state) > +{ > + struct s2m_fled *priv =3D to_led_priv(cdev); > + struct regmap *regmap =3D priv->regmap; > + u8 channel =3D priv->channel; > + unsigned int reg_enable; > + int ret; > + > + mutex_lock(&priv->lock); > + > + /* > + * Get the LED enable register address. Revision EVT0 has the > + * register at CTRL4, while EVT1 and higher have it at CTRL6. > + */ > + if (priv->pmic_revision =3D=3D 0) > + reg_enable =3D S2MU005_REG_FLED_CTRL4; > + else > + reg_enable =3D S2MU005_REG_FLED_CTRL6; > + > + ret =3D regmap_clear_bits(regmap, reg_enable, S2MU005_FLED_FLASH_EN(cha= nnel)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to disable flash LED\n"); > + goto unlock; > + } > + > + if (!state) > + goto unlock; > + > + ret =3D regmap_update_bits(regmap, S2MU005_REG_FLED_CH_CTRL0(channel), > + S2MU005_FLED_FLASH_IOUT, > + FIELD_PREP(S2MU005_FLED_FLASH_IOUT, > + =C2=A0=C2=A0=C2=A0 priv->flash_brightness)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to set flash brightness\n"); > + goto unlock; > + } > + > + ret =3D regmap_update_bits(regmap, S2MU005_REG_FLED_CH_CTRL3(channel), > + S2MU005_FLED_FLASH_TIMEOUT, > + FIELD_PREP(S2MU005_FLED_FLASH_TIMEOUT, > + =C2=A0=C2=A0=C2=A0 priv->flash_timeout)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to set flash timeout\n"); > + goto unlock; > + } > + > + ret =3D regmap_set_bits(regmap, reg_enable, S2MU005_FLED_FLASH_EN(chann= el)); > + if (ret < 0) { > + dev_err(priv->dev, "failed to enable flash LED\n"); > + goto unlock; > + } > + > +unlock: > + mutex_unlock(&priv->lock); > + > + return 0; > +} > + > +static int s2mu005_fled_flash_strobe_get(struct led_classdev_flash *cdev= , > + bool *state) > +{ > + struct s2m_fled *priv =3D to_led_priv(cdev); > + struct regmap *regmap =3D priv->regmap; > + u8 channel =3D priv->channel; > + u32 val; > + int ret; > + > + mutex_lock(&priv->lock); > + > + ret =3D regmap_read(regmap, S2MU005_REG_FLED_STATUS, &val); > + if (ret < 0) { > + dev_err(priv->dev, "failed to fetch LED status"); > + goto unlock; > + } > + > + *state =3D !!(val & S2MU005_FLED_FLASH_STATUS(channel)); > + > +unlock: > + mutex_unlock(&priv->lock); > + > + return ret; > +} > + > +static const struct led_flash_ops s2mu005_fled_flash_ops =3D { > + .flash_brightness_set =3D s2m_fled_flash_brightness_set, > + .timeout_set =3D s2m_fled_flash_timeout_set, > + .strobe_set =3D s2mu005_fled_flash_strobe_set, > + .strobe_get =3D s2mu005_fled_flash_strobe_get, > +}; > + > +static const struct s2m_fled_spec s2mu005_fled_spec =3D { > + .num_channels =3D 2, > + .torch_max_brightness =3D 16, > + .flash_min_current_ua =3D 25000, > + .flash_max_current_ua =3D 375000, /* 400000 causes flickering */ > + .flash_min_timeout_us =3D 62000, > + .flash_max_timeout_us =3D 992000, > + .torch_brightness_set_blocking =3D s2mu005_fled_torch_brightness_set, > + .flash_ops =3D &s2mu005_fled_flash_ops, > +}; > + > +static int s2m_fled_init_channel(struct device *dev, struct fwnode_handl= e *fwnp, > + struct s2m_fled *priv) > +{ > + struct led_classdev *led =3D &priv->cdev.led_cdev; > + struct led_init_data init_data =3D {}; > + struct v4l2_flash_config v4l2_cfg =3D {}; > + int ret; > + > + led->max_brightness =3D priv->spec->torch_max_brightness; > + led->brightness_set_blocking =3D priv->spec->torch_brightness_set_block= ing; > + led->flags |=3D LED_DEV_CAP_FLASH; > + > + priv->cdev.timeout.min =3D priv->spec->flash_min_timeout_us; > + priv->cdev.timeout.step =3D priv->spec->flash_min_timeout_us; > + priv->cdev.timeout.max =3D priv->spec->flash_max_timeout_us; > + priv->cdev.timeout.val =3D priv->spec->flash_max_timeout_us; > + > + priv->cdev.brightness.min =3D priv->spec->flash_min_current_ua; > + priv->cdev.brightness.step =3D priv->spec->flash_min_current_ua; > + priv->cdev.brightness.max =3D priv->spec->flash_max_current_ua; > + priv->cdev.brightness.val =3D priv->spec->flash_max_current_ua; > + > + s2m_fled_flash_timeout_set(&priv->cdev, priv->cdev.timeout.val); > + s2m_fled_flash_brightness_set(&priv->cdev, priv->cdev.brightness.val); > + > + priv->cdev.ops =3D priv->spec->flash_ops; > + > + init_data.fwnode =3D fwnp; > + ret =3D devm_led_classdev_flash_register_ext(dev, &priv->cdev, &init_da= ta); > + if (ret < 0) { > + dev_err(dev, "failed to create LED flash device\n"); > + return ret; dev_err_probe()? > + } > + > + v4l2_cfg.intensity.min =3D priv->spec->flash_min_current_ua; > + v4l2_cfg.intensity.step =3D priv->spec->flash_min_current_ua; > + v4l2_cfg.intensity.max =3D priv->spec->flash_max_current_ua; > + v4l2_cfg.intensity.val =3D priv->spec->flash_max_current_ua; > + > + v4l2_cfg.has_external_strobe =3D true; > + > + priv->v4l2_flash =3D v4l2_flash_init(dev, fwnp, &priv->cdev, > + =C2=A0=C2=A0 &s2m_fled_v4l2_flash_ops, &v4l2_cfg); > + if (IS_ERR(priv->v4l2_flash)) { > + dev_err(dev, "failed to create V4L2 flash device\n"); > + v4l2_flash_release(priv->v4l2_flash); > + return PTR_ERR(priv->v4l2_flash); dev_err_probe()? > + } > + > + return devm_add_action_or_reset(dev, (void *)v4l2_flash_release, > + priv->v4l2_flash); maybe add dev_err_probe() here, and drop the extra message in s2m_fled_prob= e(). > +} > + > +static int s2m_fled_probe(struct platform_device *pdev) > +{ > + struct device *dev =3D &pdev->dev; > + struct sec_pmic_dev *pmic_drvdata =3D dev_get_drvdata(dev->parent); > + struct s2m_fled *priv; > + struct fwnode_handle *child; > + struct regmap *regmap; > + const struct s2m_fled_spec *spec; > + int ret; > + > + priv =3D devm_kzalloc(dev, sizeof(*priv) * MAX_CHANNELS, GFP_KERNEL); > + if (!priv) > + return dev_err_probe(dev, -ENOMEM, "failed to allocate driver private\= n"); > + > + platform_set_drvdata(pdev, priv); > + regmap =3D pmic_drvdata->regmap_pmic; > + > + switch (platform_get_device_id(pdev)->driver_data) { > + case S2MU005: > + spec =3D &s2mu005_fled_spec; > + /* Enable the LED channels. */ > + ret =3D regmap_set_bits(regmap, S2MU005_REG_FLED_CTRL1, > + =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 S2MU005_FLED_CH_EN); > + if (ret < 0) > + return dev_err_probe(dev, ret, "failed to enable LED channels\n"); > + break; > + default: > + return dev_err_probe(dev, -ENODEV, > + =C2=A0=C2=A0=C2=A0=C2=A0 "device type %d is not supported by driver\= n", > + =C2=A0=C2=A0=C2=A0=C2=A0 pmic_drvdata->device_type); > + } > + > + device_for_each_child_node(dev, child) { > + u32 reg; > + > + if (fwnode_property_read_u32(child, "reg", ®)) > + goto next_child; > + > + if (reg >=3D spec->num_channels) { > + dev_warn(dev, "channel %d is non-existent\n", reg); > + goto next_child; > + } > + > + if (priv[reg].dev) { > + dev_warn(dev, "duplicate node for channel %d\n", reg); > + goto next_child; > + } > + > + priv[reg].dev =3D dev; > + priv[reg].regmap =3D regmap; > + priv[reg].channel =3D (u8)reg; > + priv[reg].spec =3D spec; > + priv[reg].pmic_revision =3D pmic_drvdata->revision; > + > + ret =3D devm_mutex_init(dev, &priv[reg].lock); > + if (ret) > + return dev_err_probe(dev, ret, "failed to create mutex lock\n"); > + > + ret =3D s2m_fled_init_channel(dev, child, &priv[reg]); > + if (ret < 0) > + dev_warn(dev, "channel init failed (%d)\n", ret); s2m_fled_init_channel() already prints a message on (most) errors, and then there's another one here. Also, is it really OK to continue ignoring the error? > + > +next_child: > + fwnode_handle_put(child); > + } > + > + return 0; > +} > + > +static const struct platform_device_id s2m_fled_id_table[] =3D { > + { "s2mu005-flash", S2MU005 }, > + { /* sentinel */ }, > +}; > +MODULE_DEVICE_TABLE(platform, s2m_fled_id_table); > + > +#ifdef CONFIG_OF I believe the general recommendation is to not use ifdef CONFIG_OF Cheers, Andre > +/* > + * Device is instantiated through parent MFD device and device matching > + * is done through platform_device_id. > + * > + * However if device's DT node contains proper compatible and driver is > + * built as a module, then the *module* matching will be done through DT > + * aliases. This requires of_device_id table. In the same time this will > + * not change the actual *device* matching so do not add .of_match_table= . > + */ > +static const struct of_device_id s2m_fled_of_match_table[] =3D { > + { > + .compatible =3D "samsung,s2mu005-flash", > + .data =3D (void *)S2MU005, > + }, { > + /* sentinel */ > + }, > +}; > +MODULE_DEVICE_TABLE(of, s2m_fled_of_match_table); > +#endif > + > +static struct platform_driver s2m_fled_driver =3D { > + .driver =3D { > + .name =3D "s2m-flash", > + }, > + .probe =3D s2m_fled_probe, > + .id_table =3D s2m_fled_id_table, > +}; > +module_platform_driver(s2m_fled_driver); > + > +MODULE_DESCRIPTION("Flash/Torch LED Driver For Samsung S2M Series PMICs"= ); > +MODULE_AUTHOR("Kaustabh Chakraborty "); > +MODULE_LICENSE("GPL");