diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/twl6030-madc.c | 44 | ||||
-rw-r--r-- | drivers/mfd/twl6030-power.c | 111 |
2 files changed, 152 insertions, 3 deletions
diff --git a/drivers/mfd/twl6030-madc.c b/drivers/mfd/twl6030-madc.c index 96bfa9f..ebff3d7 100644 --- a/drivers/mfd/twl6030-madc.c +++ b/drivers/mfd/twl6030-madc.c @@ -68,6 +68,7 @@ struct twl6030_madc_data { }; static struct twl6030_madc_data *twl6030_madc; +static u8 gpadc_ctrl_reg; static inline int twl6030_madc_start_conversion(struct twl6030_madc_data *madc) { @@ -288,12 +289,55 @@ static int __devexit twl6030_madc_remove(struct platform_device *pdev) return 0; } +static int twl6030_madc_suspend(struct device *pdev) +{ + int ret; + u8 reg_val; + + ret = twl_i2c_read_u8(TWL_MODULE_MADC, ®_val, TWL6030_MADC_CTRL); + if (!ret) { + reg_val &= ~(TWL6030_MADC_TEMP1_EN); + ret = twl_i2c_write_u8(TWL_MODULE_MADC, reg_val, + TWL6030_MADC_CTRL); + } + + if (ret) { + dev_err(twl6030_madc->dev, "unable to disable madc temp1!\n"); + gpadc_ctrl_reg = TWL6030_MADC_TEMP1_EN; + } else + gpadc_ctrl_reg = reg_val; + + return 0; +}; + +static int twl6030_madc_resume(struct device *pdev) +{ + int ret; + + if (!(gpadc_ctrl_reg & TWL6030_MADC_TEMP1_EN)) { + gpadc_ctrl_reg |= TWL6030_MADC_TEMP1_EN; + ret = twl_i2c_write_u8(TWL_MODULE_MADC, gpadc_ctrl_reg, + TWL6030_MADC_CTRL); + if (ret) + dev_err(twl6030_madc->dev, + "unable to enable madc temp1!\n"); + } + + return 0; +}; + +static const struct dev_pm_ops twl6030_madc_pm_ops = { + .suspend = twl6030_madc_suspend, + .resume = twl6030_madc_resume, +}; + static struct platform_driver twl6030_madc_driver = { .probe = twl6030_madc_probe, .remove = __exit_p(twl6030_madc_remove), .driver = { .name = "twl6030_madc", .owner = THIS_MODULE, + .pm = &twl6030_madc_pm_ops, }, }; diff --git a/drivers/mfd/twl6030-power.c b/drivers/mfd/twl6030-power.c index 84a8a22..2bbea1a 100644 --- a/drivers/mfd/twl6030-power.c +++ b/drivers/mfd/twl6030-power.c @@ -18,11 +18,14 @@ #include <linux/pm.h> #include <linux/i2c/twl.h> #include <linux/platform_device.h> +#include <linux/suspend.h> #include <asm/mach-types.h> #define VREG_GRP 0 +static u8 dev_on_group; + /** * struct twl6030_resource_map - describe the resource mapping for TWL6030 * @name: name of the resource @@ -70,11 +73,60 @@ static __initdata struct twl6030_resource_map twl6030_res_map[] = { /* TEMP cannot be modified */ }; +static struct twl4030_system_config twl6030_sys_config[] = { + {.name = "DEV_ON", .group = DEV_GRP_P1,}, +}; + /* Actual power groups that TWL understands */ #define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */ #define P2_GRP_6030 BIT(1) /* "peripherals" */ #define P1_GRP_6030 BIT(0) /* CPU/Linux */ +static __init void twl6030_process_system_config(void) +{ + u8 grp; + int r; + bool i = false; + + struct twl4030_system_config *sys_config; + sys_config = twl6030_sys_config; + + while (sys_config && sys_config->name) { + if (!strcmp(sys_config->name, "DEV_ON")) { + dev_on_group = sys_config->group; + i = true; + break; + } + sys_config++; + } + if (!i) + pr_err("%s: Couldn't find DEV_ON resource configuration!" + " MOD & CON group would be kept active.\n", __func__); + + if (dev_on_group) { + r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp, + TWL6030_PHOENIX_DEV_ON); + if (r) { + pr_err("%s: Error(%d) reading {addr=0x%02x}", + __func__, r, TWL6030_PHOENIX_DEV_ON); + /* + * On error resetting to 0, so that all the process + * groups are kept active. + */ + dev_on_group = 0; + } else { + /* + * Unmapped processor groups are disabled by writing + * 1 to corresponding group in DEV_ON. + */ + grp |= (dev_on_group & DEV_GRP_P1) ? 0 : P1_GRP_6030; + grp |= (dev_on_group & DEV_GRP_P2) ? 0 : P2_GRP_6030; + grp |= (dev_on_group & DEV_GRP_P3) ? 0 : P3_GRP_6030; + dev_on_group = grp; + } + } +} + static __init void twl6030_program_map(void) { struct twl6030_resource_map *res = twl6030_res_map; @@ -98,6 +150,24 @@ static __init void twl6030_program_map(void) } } +static __init void twl6030_update_system_map + (struct twl4030_system_config *sys_list) +{ + int i; + struct twl4030_system_config *sys_res; + + while (sys_list && sys_list->name) { + sys_res = twl6030_sys_config; + for (i = 0; i < ARRAY_SIZE(twl6030_sys_config); i++) { + if (!strcmp(sys_res->name, sys_list->name)) + sys_res->group = sys_list->group & + (DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3); + sys_res++; + } + sys_list++; + } +} + static __init void twl6030_update_map(struct twl4030_resconfig *res_list) { int i, res_idx = 0; @@ -124,6 +194,29 @@ static __init void twl6030_update_map(struct twl4030_resconfig *res_list) } } + +static int twl6030_power_notifier_cb(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + int r = 0; + + switch (pm_event) { + case PM_SUSPEND_PREPARE: + r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, dev_on_group, + TWL6030_PHOENIX_DEV_ON); + if (r) + pr_err("%s: Error(%d) programming {addr=0x%02x}", + __func__, r, TWL6030_PHOENIX_DEV_ON); + break; + } + + return notifier_from_errno(r); +} + +static struct notifier_block twl6030_power_pm_notifier = { + .notifier_call = twl6030_power_notifier_cb, +}; + /** * twl6030_power_init() - Update the power map to reflect connectivity of board * @power_data: power resource map to update (OPTIONAL) - use this if a resource @@ -131,16 +224,28 @@ static __init void twl6030_update_map(struct twl4030_resconfig *res_list) */ void __init twl6030_power_init(struct twl4030_power_data *power_data) { - if (power_data && !power_data->resource_config) { - pr_err("%s: power data from platform without resources!\n", + int r; + + if (power_data && (!power_data->resource_config && + !power_data->sys_config)) { + pr_err("%s: power data from platform without configuration!\n", __func__); return; } - if (power_data) + if (power_data && power_data->resource_config) twl6030_update_map(power_data->resource_config); + if (power_data && power_data->sys_config) + twl6030_update_system_map(power_data->sys_config); + + twl6030_process_system_config(); + twl6030_program_map(); + r = register_pm_notifier(&twl6030_power_pm_notifier); + if (r) + pr_err("%s: twl6030 power registration failed!\n", __func__); + return; } |