summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Mavrodiev <stefan@olimex.com>2019-06-07 08:42:26 -0400
committerLee Jones <lee.jones@linaro.org>2019-07-02 07:11:31 -0400
commitac195d94280a783f030a01ee84998a198b779d99 (patch)
tree19111b780e4026f406709e9cd6c2fe77f1b01a50
parent76304994645028accc0cfe287652344b696f4470 (diff)
mfd: rk808: Prepare rk805 for poweroff
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 <stefan@olimex.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--drivers/mfd/rk808.c50
-rw-r--r--include/linux/mfd/rk808.h1
2 files changed, 36 insertions, 15 deletions
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index e234720fee02..09fc8d3da541 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -474,17 +474,29 @@ static void rk805_device_shutdown(void)
474 int ret; 474 int ret;
475 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); 475 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
476 476
477 if (!rk808) { 477 if (!rk808)
478 dev_warn(&rk808_i2c_client->dev,
479 "have no rk805, so do nothing here\n");
480 return; 478 return;
481 }
482 479
483 ret = regmap_update_bits(rk808->regmap, 480 ret = regmap_update_bits(rk808->regmap,
484 RK805_DEV_CTRL_REG, 481 RK805_DEV_CTRL_REG,
485 DEV_OFF, DEV_OFF); 482 DEV_OFF, DEV_OFF);
486 if (ret) 483 if (ret)
487 dev_err(&rk808_i2c_client->dev, "power off error!\n"); 484 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
485}
486
487static void rk805_device_shutdown_prepare(void)
488{
489 int ret;
490 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
491
492 if (!rk808)
493 return;
494
495 ret = regmap_update_bits(rk808->regmap,
496 RK805_GPIO_IO_POL_REG,
497 SLP_SD_MSK, SHUTDOWN_FUN);
498 if (ret)
499 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
488} 500}
489 501
490static void rk808_device_shutdown(void) 502static void rk808_device_shutdown(void)
@@ -492,17 +504,14 @@ static void rk808_device_shutdown(void)
492 int ret; 504 int ret;
493 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); 505 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
494 506
495 if (!rk808) { 507 if (!rk808)
496 dev_warn(&rk808_i2c_client->dev,
497 "have no rk808, so do nothing here\n");
498 return; 508 return;
499 }
500 509
501 ret = regmap_update_bits(rk808->regmap, 510 ret = regmap_update_bits(rk808->regmap,
502 RK808_DEVCTRL_REG, 511 RK808_DEVCTRL_REG,
503 DEV_OFF_RST, DEV_OFF_RST); 512 DEV_OFF_RST, DEV_OFF_RST);
504 if (ret) 513 if (ret)
505 dev_err(&rk808_i2c_client->dev, "power off error!\n"); 514 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
506} 515}
507 516
508static void rk818_device_shutdown(void) 517static void rk818_device_shutdown(void)
@@ -510,17 +519,14 @@ static void rk818_device_shutdown(void)
510 int ret; 519 int ret;
511 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); 520 struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
512 521
513 if (!rk808) { 522 if (!rk808)
514 dev_warn(&rk808_i2c_client->dev,
515 "have no rk818, so do nothing here\n");
516 return; 523 return;
517 }
518 524
519 ret = regmap_update_bits(rk808->regmap, 525 ret = regmap_update_bits(rk808->regmap,
520 RK818_DEVCTRL_REG, 526 RK818_DEVCTRL_REG,
521 DEV_OFF, DEV_OFF); 527 DEV_OFF, DEV_OFF);
522 if (ret) 528 if (ret)
523 dev_err(&rk808_i2c_client->dev, "power off error!\n"); 529 dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
524} 530}
525 531
526static void rk8xx_syscore_shutdown(void) 532static void rk8xx_syscore_shutdown(void)
@@ -609,6 +615,7 @@ static int rk808_probe(struct i2c_client *client,
609 cells = rk805s; 615 cells = rk805s;
610 nr_cells = ARRAY_SIZE(rk805s); 616 nr_cells = ARRAY_SIZE(rk805s);
611 rk808->pm_pwroff_fn = rk805_device_shutdown; 617 rk808->pm_pwroff_fn = rk805_device_shutdown;
618 rk808->pm_pwroff_prep_fn = rk805_device_shutdown_prepare;
612 break; 619 break;
613 case RK808_ID: 620 case RK808_ID:
614 rk808->regmap_cfg = &rk808_regmap_config; 621 rk808->regmap_cfg = &rk808_regmap_config;
@@ -694,6 +701,12 @@ static int rk808_probe(struct i2c_client *client,
694 pm_power_off = rk808->pm_pwroff_fn; 701 pm_power_off = rk808->pm_pwroff_fn;
695 } 702 }
696 703
704 if (pm_off && !pm_power_off_prepare) {
705 if (!rk808_i2c_client)
706 rk808_i2c_client = client;
707 pm_power_off_prepare = rk808->pm_pwroff_prep_fn;
708 }
709
697 return 0; 710 return 0;
698 711
699err_irq: 712err_irq:
@@ -714,6 +727,13 @@ static int rk808_remove(struct i2c_client *client)
714 if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn) 727 if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn)
715 pm_power_off = NULL; 728 pm_power_off = NULL;
716 729
730 /**
731 * As above, check if the pointer is set by us before overwrite.
732 */
733 if (rk808->pm_pwroff_prep_fn &&
734 pm_power_off_prepare == rk808->pm_pwroff_prep_fn)
735 pm_power_off_prepare = NULL;
736
717 return 0; 737 return 0;
718} 738}
719 739
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index 286316375636..b264ac794c74 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -629,5 +629,6 @@ struct rk808 {
629 const struct regmap_config *regmap_cfg; 629 const struct regmap_config *regmap_cfg;
630 const struct regmap_irq_chip *regmap_irq_chip; 630 const struct regmap_irq_chip *regmap_irq_chip;
631 void (*pm_pwroff_fn)(void); 631 void (*pm_pwroff_fn)(void);
632 void (*pm_pwroff_prep_fn)(void);
632}; 633};
633#endif /* __LINUX_REGULATOR_RK808_H */ 634#endif /* __LINUX_REGULATOR_RK808_H */