On Tue, 21 May 2019, Stefan Mavrodiev wrote: > RK805 has SLEEP signal, which can put the device into SLEEP or OFF > mode. The default is SLEEP mode. > > However, when the kernel performs power-off (actually the ATF) the > device will not go fully off and this will result in higher power > consumption and inability to wake the device with RTC alarm. > > The solution is to enable pm_power_off_prepare function, which will > configure SLEEP pin for OFF function. > > Signed-off-by: Stefan Mavrodiev <ste...@olimex.com> > --- > Changes for v2: > - Move pm_pwroff_prep_fn to header > - Check pm_power_off_prepare before make it NULL > > drivers/mfd/rk808.c | 29 +++++++++++++++++++++++++++++ > include/linux/mfd/rk808.h | 1 + > 2 files changed, 30 insertions(+) > > diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c > index c0b179792bbf..fb6cdf900899 100644 > --- a/drivers/mfd/rk808.c > +++ b/drivers/mfd/rk808.c > @@ -387,6 +387,24 @@ static void rk805_device_shutdown(void) > dev_err(&rk808_i2c_client->dev, "power off error!\n"); > } > > +static void rk805_device_shutdown_prepare(void) > +{ > + int ret; > + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); > + > + if (!rk808) { > + dev_warn(&rk808_i2c_client->dev, > + "have no rk805, so do nothing here\n");
No need for this message I think. If it's not available, just return. > + return; > + } > + > + ret = regmap_update_bits(rk808->regmap, > + RK805_GPIO_IO_POL_REG, > + SLP_SD_MSK, SHUTDOWN_FUN); > + if (ret) > + dev_err(&rk808_i2c_client->dev, "power off error!\n"); > +} "Failed to shutdown device" > static void rk808_device_shutdown(void) > { > int ret; > @@ -475,6 +493,7 @@ static int rk808_probe(struct i2c_client *client, > cells = rk805s; > nr_cells = ARRAY_SIZE(rk805s); > rk808->pm_pwroff_fn = rk805_device_shutdown; > + rk808->pm_pwroff_prep_fn = rk805_device_shutdown_prepare; > break; > case RK808_ID: > rk808->regmap_cfg = &rk808_regmap_config; > @@ -550,6 +569,12 @@ static int rk808_probe(struct i2c_client *client, > pm_power_off = rk808->pm_pwroff_fn; > } > > + if (pm_off && !pm_power_off_prepare) { > + if (!rk808_i2c_client) > + rk808_i2c_client = client; > + pm_power_off_prepare = rk808->pm_pwroff_prep_fn; > + } > + > return 0; > > err_irq: > @@ -566,6 +591,10 @@ static int rk808_remove(struct i2c_client *client) > if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn) > pm_power_off = NULL; > > + if (rk808->pm_pwroff_prep_fn && > + pm_power_off_prepare == rk808->pm_pwroff_prep_fn) > + pm_power_off_prepare = NULL; I think this block would benefit from a comment. > return 0; > } > > diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h > index 8b5d68a7bb9c..ec928173e507 100644 > --- a/include/linux/mfd/rk808.h > +++ b/include/linux/mfd/rk808.h > @@ -454,5 +454,6 @@ struct rk808 { > const struct regmap_config *regmap_cfg; > const struct regmap_irq_chip *regmap_irq_chip; > void (*pm_pwroff_fn)(void); > + void (*pm_pwroff_prep_fn)(void); > }; > #endif /* __LINUX_REGULATOR_RK808_H */ -- Lee Jones [李琼斯] Linaro Services Technical Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog