From 208ce417cb0382ed34e723c837504699f7b9fcbb Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Mon, 14 Aug 2017 17:54:06 +0800 Subject: [PATCH] mfd: rk808: add suspend and resume register setting for rk805 Because Buck3 don't have sleep state register, so we need a manual switch: set BUCK3 suspend as Auto PWM mode and resume as FPWM mode. This is for power saving in system suspend. Change-Id: I67db458e650b6e85ed4267f0b0dcdb01dff4c635 Signed-off-by: Joseph Chen --- drivers/mfd/rk808.c | 60 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/rk808.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index dadecc76e48e..8c2efc8fdb6f 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -546,9 +546,19 @@ static const struct rk808_reg_data rk805_pre_init_reg[] = { {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C}, }; +static struct rk808_reg_data rk805_suspend_reg[] = { + {RK805_BUCK3_CONFIG_REG, PWM_MODE_MSK, AUTO_PWM_MODE}, +}; + +static struct rk808_reg_data rk805_resume_reg[] = { + {RK805_BUCK3_CONFIG_REG, PWM_MODE_MSK, FPWM_MODE}, +}; + static int (*pm_shutdown)(struct regmap *regmap); static int (*pm_shutdown_prepare)(struct regmap *regmap); static struct i2c_client *rk808_i2c_client; +static struct rk808_reg_data *suspend_reg, *resume_reg; +static int suspend_reg_num, resume_reg_num; static void rk808_device_shutdown_prepare(void) { @@ -738,6 +748,10 @@ static int rk808_probe(struct i2c_client *client, pm_shutdown_prepare_fn = rk805_shutdown_prepare; on_source = RK805_ON_SOURCE_REG; off_source = RK805_OFF_SOURCE_REG; + suspend_reg = rk805_suspend_reg; + suspend_reg_num = ARRAY_SIZE(rk805_suspend_reg); + resume_reg = rk805_resume_reg; + resume_reg_num = ARRAY_SIZE(rk805_resume_reg); break; default: dev_err(&client->dev, "unsupported RK8XX ID 0x%lx\n", @@ -829,6 +843,46 @@ err_irq: return ret; } +static int rk808_suspend(struct device *dev) +{ + int i, ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + for (i = 0; i < suspend_reg_num; i++) { + ret = regmap_update_bits(rk808->regmap, + suspend_reg[i].addr, + suspend_reg[i].mask, + suspend_reg[i].value); + if (ret) { + dev_err(dev, "0x%x write err\n", + suspend_reg[i].addr); + return ret; + } + } + + return 0; +} + +static int rk808_resume(struct device *dev) +{ + int i, ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + for (i = 0; i < resume_reg_num; i++) { + ret = regmap_update_bits(rk808->regmap, + resume_reg[i].addr, + resume_reg[i].mask, + resume_reg[i].value); + if (ret) { + dev_err(dev, "0x%x write err\n", + resume_reg[i].addr); + return ret; + } + } + + return 0; +} + static int rk808_remove(struct i2c_client *client) { struct rk808 *rk808 = i2c_get_clientdata(client); @@ -843,6 +897,11 @@ static int rk808_remove(struct i2c_client *client) return 0; } +static const struct dev_pm_ops rk808_pm_ops = { + .suspend = rk808_suspend, + .resume = rk808_resume, +}; + static const struct i2c_device_id rk808_ids[] = { { "rk805" }, { "rk808" }, @@ -856,6 +915,7 @@ static struct i2c_driver rk808_i2c_driver = { .driver = { .name = "rk808", .of_match_table = rk808_of_match, + .pm = &rk808_pm_ops, }, .probe = rk808_probe, .remove = rk808_remove, diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 20d24c079961..f92eeb74c6c0 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -690,7 +690,9 @@ enum rk805_reg { #define SHUTDOWN_FUN (0x2 << 2) #define SLEEP_FUN (0x1 << 2) #define RK8XX_ID_MSK 0xfff0 +#define PWM_MODE_MSK BIT(7) #define FPWM_MODE BIT(7) +#define AUTO_PWM_MODE 0 enum { BUCK_ILMIN_50MA,