Re: [PATCH v2 5/7] regulator: qcom-labibb: Implement short-circuit and over-current IRQs

2021-01-17 Thread AngeloGioacchino Del Regno

Il 15/01/21 06:31, Bjorn Andersson ha scritto:

On Wed 13 Jan 13:42 CST 2021, AngeloGioacchino Del Regno wrote:


Short-Circuit Protection (SCP) and Over-Current Protection (OCP) are
very important for regulators like LAB and IBB, which are designed to
provide from very small to relatively big amounts of current to the
device (normally, a display).

Now that this regulator supports both voltage setting and current
limiting in this driver, to me it looked like being somehow essential
to provide support for SCP and OCP, for two reasons:
1. SCP is a drastic measure to prevent damaging "more" hardware in
the worst situations, if any was damaged, preventing potentially
drastic issues;
2. OCP is a great way to protect the hardware that we're powering
through these regulators as if anything bad happens, the HW will
draw more current than expected: in this case, the OCP interrupt
will fire and the regulators will be immediately shut down,
preventing hardware damage in many cases.


So when the OCP fires it stops the regulator? Is it automatically
enabled by the re-enabling of the OCP interrupt (if so please mention
this in a comment or so in the code), or does it simply signal the
client driver and it will have to re-enable the regulator?



I am sorry if my comments in the driver are not clear enough but,
before giving you an answer, let me explain my comment logic:

In function qcom_labibb_ocp_isr():
/* Signal overcurrent event to drivers */
/* Schedule the recovery work */

In function qcom_labibb_ocp_recovery_worker():
if (vreg->ocp_irq_count >= LABIBB_MAX_OCP_COUNT)
/*

 * If we tried to disable the regulator multiple times but

 * we kept failing, there's only one last hope to save our

 * hardware from the death: raise a kernel bug, reboot and

 * hope that the bootloader kindly saves us. This, though

 * is done only as paranoid checking, because failing the

 * regmap write to disable the vreg is almost impossible,

 * since we got here after multiple regmap R/W.

 */

ret = qcom_labibb_ocp_hw_enable(vreg->rdev);
if (ret)
/* We cannot trust it without OCP enabled. */
(hence, reschedule worker)
/* Everything went fine: reset the OCP count! */

vreg->ocp_irq_count = 0;

So, schematically:
1. Signals overcurrent event to the driver that is attached;
   the driver will have to take action on its own - it's not
   our problem, for now;
2. Schedules a recovery worker, which waits until we stop reading
   "OUCH! OVERCURRENT!" from the hardware and reschedules itself
   for 4 times
3. Did the driver take action? Did the hardware just stabilize its
   current draw for whatever reason? Now it may be our problem.
   3a. (Yes!) Great, we're done, everything is fine;
   3b. (No! The driver didn't care, or the hardware is really at
fault!) Force disabling the regulator to protect HW;
   3b-alt. We couldn't disable the regulator, something is seriously
   wrong, we are frying the HW. PRESS THE RED BUTTON! Panic
   and pray that the bootloader saves us and that it's not
   too late. We really can't do anything more than that.


Is the flow clear now?
How would you improve the comments in this commit, if necessary?



Both interrupts were successfully tested in a "sort-of" controlled
manner, with the following methodology:

Short-Circuit Protection (SCP):
1. Set LAB/IBB to 4.6/-1.4V, current limit 200mA/50mA;
2. Connect a 10 KOhm resistor to LAB/IBB by poking the right traces
on a FxTec Pro1 smartphone for a very brief time (in short words,
"just a rapid touch with flying wires");
3. The Short-Circuit protection trips: IRQ raises, regulators get
cut. Recovery OK, test repeated without rebooting, OK.

Over-Current Protection (OCP):
1. Set LAB/IBB to the expected voltage to power up the display of
a Sony Xperia XZ Premium smartphone (Sharp LS055D1SX04), set
current limit to LAB 200mA, IBB 50mA (the values that this
display unit needs are 200/800mA);
2. Boot the kernel: OCP fires. Recovery never happens because
the selected current limit is too low, but that's expected.
Test OK.

3. Set LAB/IBB to the expected current limits for XZ Premium
(LAB 200mA, IBB 800mA), but lower than expected voltage,
specifically LAB 5.4V, IBB -5.6V (instead of 5.6, -5.8V);
4. Boot the kernel: OCP fires. Recovery never happens because
the selected voltage (still in the working range limits)
is producing a current draw of more than 200mA on LAB.
Test OK.

Signed-off-by: AngeloGioacchino Del Regno 

---
  drivers/regulator/qcom-labibb-regulator.c | 447 +-
  1 file changed, 444 insertions(+), 3 deletions(-)

diff --git a/drivers/regulator/qcom-labibb-regulator.c 

Re: [PATCH v2 5/7] regulator: qcom-labibb: Implement short-circuit and over-current IRQs

2021-01-14 Thread Bjorn Andersson
On Wed 13 Jan 13:42 CST 2021, AngeloGioacchino Del Regno wrote:

> Short-Circuit Protection (SCP) and Over-Current Protection (OCP) are
> very important for regulators like LAB and IBB, which are designed to
> provide from very small to relatively big amounts of current to the
> device (normally, a display).
> 
> Now that this regulator supports both voltage setting and current
> limiting in this driver, to me it looked like being somehow essential
> to provide support for SCP and OCP, for two reasons:
> 1. SCP is a drastic measure to prevent damaging "more" hardware in
>the worst situations, if any was damaged, preventing potentially
>drastic issues;
> 2. OCP is a great way to protect the hardware that we're powering
>through these regulators as if anything bad happens, the HW will
>draw more current than expected: in this case, the OCP interrupt
>will fire and the regulators will be immediately shut down,
>preventing hardware damage in many cases.

So when the OCP fires it stops the regulator? Is it automatically
enabled by the re-enabling of the OCP interrupt (if so please mention
this in a comment or so in the code), or does it simply signal the
client driver and it will have to re-enable the regulator?

> 
> Both interrupts were successfully tested in a "sort-of" controlled
> manner, with the following methodology:
> 
> Short-Circuit Protection (SCP):
> 1. Set LAB/IBB to 4.6/-1.4V, current limit 200mA/50mA;
> 2. Connect a 10 KOhm resistor to LAB/IBB by poking the right traces
>on a FxTec Pro1 smartphone for a very brief time (in short words,
>"just a rapid touch with flying wires");
> 3. The Short-Circuit protection trips: IRQ raises, regulators get
>cut. Recovery OK, test repeated without rebooting, OK.
> 
> Over-Current Protection (OCP):
> 1. Set LAB/IBB to the expected voltage to power up the display of
>a Sony Xperia XZ Premium smartphone (Sharp LS055D1SX04), set
>current limit to LAB 200mA, IBB 50mA (the values that this
>display unit needs are 200/800mA);
> 2. Boot the kernel: OCP fires. Recovery never happens because
>the selected current limit is too low, but that's expected.
>Test OK.
> 
> 3. Set LAB/IBB to the expected current limits for XZ Premium
>(LAB 200mA, IBB 800mA), but lower than expected voltage,
>specifically LAB 5.4V, IBB -5.6V (instead of 5.6, -5.8V);
> 4. Boot the kernel: OCP fires. Recovery never happens because
>the selected voltage (still in the working range limits)
>is producing a current draw of more than 200mA on LAB.
>Test OK.
> 
> Signed-off-by: AngeloGioacchino Del Regno 
> 
> ---
>  drivers/regulator/qcom-labibb-regulator.c | 447 +-
>  1 file changed, 444 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/regulator/qcom-labibb-regulator.c 
> b/drivers/regulator/qcom-labibb-regulator.c
> index 38ab1eba1c59..38763625241e 100644
> --- a/drivers/regulator/qcom-labibb-regulator.c
> +++ b/drivers/regulator/qcom-labibb-regulator.c
> @@ -17,8 +17,20 @@
>  
>  #define PMI8998_LAB_REG_BASE 0xde00
>  #define PMI8998_IBB_REG_BASE 0xdc00
> +#define PMI8998_IBB_LAB_REG_OFFSET   0x200
>  
>  #define REG_LABIBB_STATUS1   0x08
> + #define LABIBB_STATUS1_SC_BIT   BIT(6)
> + #define LABIBB_STATUS1_VREG_OK_BIT  BIT(7)
> +
> +#define REG_LABIBB_INT_SET_TYPE  0x11
> +#define REG_LABIBB_INT_POLARITY_HIGH 0x12
> +#define REG_LABIBB_INT_POLARITY_LOW  0x13
> +#define REG_LABIBB_INT_LATCHED_CLR   0x14
> +#define REG_LABIBB_INT_EN_SET0x15
> +#define REG_LABIBB_INT_EN_CLR0x16
> + #define LABIBB_INT_VREG_OK  BIT(0)
> + #define LABIBB_INT_VREG_TYPE_LEVEL  0
>  
>  #define REG_LABIBB_VOLTAGE   0x41
>   #define LABIBB_VOLTAGE_OVERRIDE_EN  BIT(7)
> @@ -26,8 +38,7 @@
>   #define IBB_VOLTAGE_SET_MASKGENMASK(5, 0)
>  
>  #define REG_LABIBB_ENABLE_CTL0x46
> -#define LABIBB_STATUS1_VREG_OK_BIT   BIT(7)
> -#define LABIBB_CONTROL_ENABLEBIT(7)
> + #define LABIBB_CONTROL_ENABLE   BIT(7)
>  
>  #define REG_LABIBB_PD_CTL0x47
>   #define LAB_PD_CTL_MASK GENMASK(1, 0)
> @@ -56,6 +67,11 @@
>  #define LAB_ENABLE_TIME  (LABIBB_OFF_ON_DELAY * 2)
>  #define IBB_ENABLE_TIME  (LABIBB_OFF_ON_DELAY * 10)
>  #define LABIBB_POLL_ENABLED_TIME 1000
> +#define OCP_RECOVERY_INTERVAL_MS 500
> +#define SC_RECOVERY_INTERVAL_MS  250
> +#define LABIBB_MAX_OCP_COUNT 4
> +#define LABIBB_MAX_SC_COUNT  3
> +#define LABIBB_MAX_FATAL_COUNT   2
>  
>  struct labibb_current_limits {
>   u32 uA_min;
> @@ -69,10 +85,17 @@ struct labibb_regulator {
>   struct regmap   *regmap;
>   struct regulator_dev*rdev;
>   struct labibb_current_limitsuA_limits;
> + struct delayed_work ocp_recovery_work;