RE: [PATCH v3 2/2] backlight: mp3309c: Add support for MPS MP3309C

2023-10-03 Thread Flavio Suligoi
Hi Daniel,

...

> > +static int mp3309c_bl_update_status(struct backlight_device *bl) {
> > +   struct mp3309c_chip *chip = bl_get_data(bl);
> > +   int brightness = backlight_get_brightness(bl);
> > +   struct pwm_state pwmstate;
> > +   unsigned int analog_val, bits_val;
> > +   int i, ret;
> > +
> > +   if (chip->pdata->dimming_mode == DIMMING_PWM) {
> > +   /*
> > +* PWM dimming mode
> > +*/
> > +   pwm_get_state(chip->pwmd, );
> > +   pwm_set_relative_duty_cycle(, brightness,
> > +   chip->pdata->max_brightness);
> > +   pwmstate.enabled = true;
> > +   ret = pwm_apply_state(chip->pwmd, );
> > +   if (ret)
> > +   return ret;
> > +
> > +   switch (chip->pdata->status) {
> > +   case FIRST_POWER_ON:
> > +   case BACKLIGHT_OFF:
> > +   /*
> > +* After 20ms of low pwm signal level, the chip turns
> > +  off automatically. In this case, before enabling the
> > +  chip again, we must wait about 10ms for pwm signal
> to
> > +  stabilize.
> > +*/
> > +   if (brightness > 0) {
> > +   msleep(10);
> > +   mp3309c_enable_device(chip);
> > +   chip->pdata->status = BACKLIGHT_ON;
> > +   } else {
> > +   chip->pdata->status = BACKLIGHT_OFF;
> > +   }
> > +   break;
> > +   case BACKLIGHT_ON:
> > +   if (brightness == 0)
> > +   chip->pdata->status = BACKLIGHT_OFF;
> > +   break;
> > +   }
> > +   } else {
> > +   /*
> > +* Analog dimming (by I2C command) dimming mode
> > +*
> > +* The first time, before setting brightness, we must enable the
> > +* device
> > +*/
> > +   if (chip->pdata->status == FIRST_POWER_ON)
> > +   mp3309c_enable_device(chip);
> > +
> > +   /*
> > +* Dimming mode I2C command
> > +*
> > +* The 5 bits of the dimming analog value D4..D0 is allocated
> > +* in the I2C register #0, in the following way:
> > +*
> > +* +--+--+--+--+--+--+--+--+
> > +* |EN|D0|D1|D2|D3|D4|XX|XX|
> > +* +--+--+--+--+--+--+--+--+
> > +*/
> > +   analog_val = DIV_ROUND_UP(ANALOG_MAX_VAL *
> brightness,
> > + chip->pdata->max_brightness);
> 
> Sorry to only notice after sharing a Reviewed-by:[1] but...
> 
> Scaling brightness here isn't right. When running in I2C dimming mode then
> max_brightness *must* be 31 or lower, meaning the value in brightness can
> be applied directly to the hardware without scaling.

ok, right; max brightness is 31, fixed

> 
> Quoting the DT binding docs about how max-brightness should be
> interpretted:
> 
>   Normally the maximum brightness is determined by the hardware and this
>   property is not required. This property is used to put a software
>   limit on the brightness apart from what the driver says, as it could
>   happen that a LED can be made so bright that it gets damaged or causes
>   damage due to restrictions in a specific system, such as mounting
>   conditions.
> 

ok

> 
> Daniel.
> 
> 
> [1] I remember checking if this code could overflow the field but I was
> so distracted by that I ended up missing the obvious!

Thanks and best regards,
Flavio


Re: [PATCH v3 2/2] backlight: mp3309c: Add support for MPS MP3309C

2023-09-26 Thread Daniel Thompson
On Mon, Sep 25, 2023 at 02:26:09PM +0200, Flavio Suligoi wrote:
> diff --git a/drivers/video/backlight/mp3309c.c 
> b/drivers/video/backlight/mp3309c.c
> new file mode 100644
> index ..923ac7f7b291
> --- /dev/null
> +++ b/drivers/video/backlight/mp3309c.c
> @@ -0,0 +1,398 @@
> ...
> +static int mp3309c_bl_update_status(struct backlight_device *bl)
> +{
> + struct mp3309c_chip *chip = bl_get_data(bl);
> + int brightness = backlight_get_brightness(bl);
> + struct pwm_state pwmstate;
> + unsigned int analog_val, bits_val;
> + int i, ret;
> +
> + if (chip->pdata->dimming_mode == DIMMING_PWM) {
> + /*
> +  * PWM dimming mode
> +  */
> + pwm_get_state(chip->pwmd, );
> + pwm_set_relative_duty_cycle(, brightness,
> + chip->pdata->max_brightness);
> + pwmstate.enabled = true;
> + ret = pwm_apply_state(chip->pwmd, );
> + if (ret)
> + return ret;
> +
> + switch (chip->pdata->status) {
> + case FIRST_POWER_ON:
> + case BACKLIGHT_OFF:
> + /*
> +  * After 20ms of low pwm signal level, the chip turns
> +off automatically. In this case, before enabling the
> +chip again, we must wait about 10ms for pwm signal to
> +stabilize.
> +  */
> + if (brightness > 0) {
> + msleep(10);
> + mp3309c_enable_device(chip);
> + chip->pdata->status = BACKLIGHT_ON;
> + } else {
> + chip->pdata->status = BACKLIGHT_OFF;
> + }
> + break;
> + case BACKLIGHT_ON:
> + if (brightness == 0)
> + chip->pdata->status = BACKLIGHT_OFF;
> + break;
> + }
> + } else {
> + /*
> +  * Analog dimming (by I2C command) dimming mode
> +  *
> +  * The first time, before setting brightness, we must enable the
> +  * device
> +  */
> + if (chip->pdata->status == FIRST_POWER_ON)
> + mp3309c_enable_device(chip);
> +
> + /*
> +  * Dimming mode I2C command
> +  *
> +  * The 5 bits of the dimming analog value D4..D0 is allocated
> +  * in the I2C register #0, in the following way:
> +  *
> +  * +--+--+--+--+--+--+--+--+
> +  * |EN|D0|D1|D2|D3|D4|XX|XX|
> +  * +--+--+--+--+--+--+--+--+
> +  */
> + analog_val = DIV_ROUND_UP(ANALOG_MAX_VAL * brightness,
> +   chip->pdata->max_brightness);

Sorry to only notice after sharing a Reviewed-by:[1] but...

Scaling brightness here isn't right. When running in I2C dimming mode then
max_brightness *must* be 31 or lower, meaning the value in brightness can
be applied directly to the hardware without scaling.

Quoting the DT binding docs about how max-brightness should be
interpretted:

  Normally the maximum brightness is determined by the hardware and this
  property is not required. This property is used to put a software
  limit on the brightness apart from what the driver says, as it could
  happen that a LED can be made so bright that it gets damaged or causes
  damage due to restrictions in a specific system, such as mounting
  conditions.


Daniel.


[1] I remember checking if this code could overflow the field but I was
so distracted by that I ended up missing the obvious!


[PATCH v3 2/2] backlight: mp3309c: Add support for MPS MP3309C

2023-09-26 Thread Flavio Suligoi
The Monolithic Power (MPS) MP3309C is a WLED step-up converter, featuring a
programmable switching frequency to optimize efficiency.
The brightness can be controlled either by I2C commands (called "analog"
mode) or by a PWM input signal (PWM mode).
This driver supports both modes.

For DT configuration details, please refer to:
- Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml

The datasheet is available at:
- https://www.monolithicpower.com/en/mp3309c.html

Signed-off-by: Flavio Suligoi 
Reviewed-by: Daniel Thompson 
---

v3:
 - fix SPDX obsolete spelling
 - in mp3309c_bl_update_status, change from msleep_interruptible() to msleep()
   and improve the related comment
v2:
 - fix dependecies in Kconfig
 - fix Kconfig MP3309C entry order
 - remove switch-on-delay-ms property
 - remove optional gpio property to reset external devices
 - remove dimming-mode property (the analog-i2c dimming mode is the default; the
   presence of the pwms property, in DT, selects automatically the pwm dimming
   mode)
 - substitute three boolean properties, used for the overvoltage-protection
   values, with a single enum property
 - drop simple tracing messages
 - use dev_err_probe() in probe function
 - change device name from mp3309c_bl to the simple mp3309c
 - remove shutdown function
v1:
 - first version

 MAINTAINERS   |   6 +
 drivers/video/backlight/Kconfig   |  11 +
 drivers/video/backlight/Makefile  |   1 +
 drivers/video/backlight/mp3309c.c | 398 ++
 4 files changed, 416 insertions(+)
 create mode 100644 drivers/video/backlight/mp3309c.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3be1bdfe8ecc..f779df433af1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14333,6 +14333,12 @@ S: Maintained
 F: Documentation/driver-api/tty/moxa-smartio.rst
 F: drivers/tty/mxser.*
 
+MP3309C BACKLIGHT DRIVER
+M: Flavio Suligoi 
+S: Maintained
+F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
+F: drivers/video/backlight/mp3309c.c
+
 MR800 AVERMEDIA USB FM RADIO DRIVER
 M: Alexey Klimov 
 L: linux-me...@vger.kernel.org
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 51387b1ef012..1144a54a35c0 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -402,6 +402,17 @@ config BACKLIGHT_LP8788
help
  This supports TI LP8788 backlight driver.
 
+config BACKLIGHT_MP3309C
+   tristate "Backlight Driver for MPS MP3309C"
+   depends on I2C && PWM
+   select REGMAP_I2C
+   help
+ This supports MPS MP3309C backlight WLED driver in both PWM and
+ analog/I2C dimming modes.
+
+ To compile this driver as a module, choose M here: the module will
+ be called mp3309c.
+
 config BACKLIGHT_PANDORA
tristate "Backlight driver for Pandora console"
depends on TWL4030_CORE
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index f72e1c3c59e9..1af583de665b 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X)+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)   += lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)+= max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_MP3309C)+= mp3309c.o
 obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)  += omap1_bl.o
 obj-$(CONFIG_BACKLIGHT_PANDORA)+= pandora_bl.o
diff --git a/drivers/video/backlight/mp3309c.c 
b/drivers/video/backlight/mp3309c.c
new file mode 100644
index ..923ac7f7b291
--- /dev/null
+++ b/drivers/video/backlight/mp3309c.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for MPS MP3309C White LED driver with I2C interface
+ *
+ * Copyright (C) 2023 ASEM Srl
+ * Author: Flavio Suligoi 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define REG_I2C_0  0x00
+#define REG_I2C_1  0x01
+
+#define REG_I2C_0_EN   0x80
+#define REG_I2C_0_D0   0x40
+#define REG_I2C_0_D1   0x20
+#define REG_I2C_0_D2   0x10
+#define REG_I2C_0_D3   0x08
+#define REG_I2C_0_D4   0x04
+#define REG_I2C_0_RSRV10x02
+#define REG_I2C_0_RSRV20x01
+
+#define REG_I2C_1_RSRV10x80
+#define REG_I2C_1_DIMS 0x40
+#define REG_I2C_1_SYNC 0x20
+#define REG_I2C_1_OVP0 0x10
+#define REG_I2C_1_OVP1 0x08
+#define REG_I2C_1_VOS  0x04
+#define REG_I2C_1_LEDO 0x02
+#define REG_I2C_1_OTP  0x01
+
+#define ANALOG_MAX_VAL 31
+#define ANALOG_REG_MASK 0x7c
+
+enum mp3309c_status_value {
+   FIRST_POWER_ON,
+   BACKLIGHT_OFF,
+   BACKLIGHT_ON,
+};
+
+enum mp3309c_dimming_mode_value {
+   DIMMING_PWM,
+   DIMMING_ANALOG_I2C,
+};
+
+struct mp3309c_platform_data {
+   u32 max_brightness;
+   u32 default_brightness;
+   u8