aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-11-03 22:09:11 -0700
committerColin Cross <ccross@android.com>2011-11-03 22:09:11 -0700
commitf1e5f49f2f2ed46e5356e091de1e86dc08b20d85 (patch)
treebfc8970948e006af8069a5f732bbd59c0f18bf34 /drivers/mfd
parent70c7a98bb28405787cf7aaf9d8a216b559bd4a35 (diff)
parent90672f17369273aba3fb402d5c41752686c65d53 (diff)
downloadkernel_samsung_tuna-f1e5f49f2f2ed46e5356e091de1e86dc08b20d85.tar.gz
kernel_samsung_tuna-f1e5f49f2f2ed46e5356e091de1e86dc08b20d85.tar.bz2
kernel_samsung_tuna-f1e5f49f2f2ed46e5356e091de1e86dc08b20d85.zip
Merge branch 'android-omap-3.0' into android-omap-tuna-3.0
Conflicts: arch/arm/mach-omap2/dpll3xxx.c Change-Id: Ie53daed5cabbadef73d18969263ff2f7b77b3dc7
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/twl6030-madc.c44
-rw-r--r--drivers/mfd/twl6030-power.c111
2 files changed, 152 insertions, 3 deletions
diff --git a/drivers/mfd/twl6030-madc.c b/drivers/mfd/twl6030-madc.c
index 96bfa9f466d..ebff3d7504f 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, &reg_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 84a8a225f31..2bbea1a37d5 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;
}