diff options
author | Samu Onkalo <samu.p.onkalo@nokia.com> | 2010-10-22 07:57:24 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2010-10-25 17:11:38 -0400 |
commit | f9deb41f91c41d9d91a24c84a555ec7fe82620da (patch) | |
tree | c301a8324c3bbc779b752cdf47236575a87a26d2 /drivers/hwmon/lis3lv02d_i2c.c | |
parent | 2a346996626ecbb4269c239e9ff7372a182907e9 (diff) |
hwmon: lis3: regulator control
Based on pm_runtime control, turn lis3 regulators on and off.
Perform context save and restore on transitions.
Feature is optional and must be enabled in platform data.
Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Acked-by: Eric Piel <eric.piel@tremplin-utc.net>
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon/lis3lv02d_i2c.c')
-rw-r--r-- | drivers/hwmon/lis3lv02d_i2c.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c index d52095603e03..ec35c87819c0 100644 --- a/drivers/hwmon/lis3lv02d_i2c.c +++ b/drivers/hwmon/lis3lv02d_i2c.c | |||
@@ -30,10 +30,29 @@ | |||
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/i2c.h> | 31 | #include <linux/i2c.h> |
32 | #include <linux/pm_runtime.h> | 32 | #include <linux/pm_runtime.h> |
33 | #include <linux/delay.h> | ||
33 | #include "lis3lv02d.h" | 34 | #include "lis3lv02d.h" |
34 | 35 | ||
35 | #define DRV_NAME "lis3lv02d_i2c" | 36 | #define DRV_NAME "lis3lv02d_i2c" |
36 | 37 | ||
38 | static const char reg_vdd[] = "Vdd"; | ||
39 | static const char reg_vdd_io[] = "Vdd_IO"; | ||
40 | |||
41 | static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state) | ||
42 | { | ||
43 | int ret; | ||
44 | if (state == LIS3_REG_OFF) { | ||
45 | ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators), | ||
46 | lis3->regulators); | ||
47 | } else { | ||
48 | ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators), | ||
49 | lis3->regulators); | ||
50 | /* Chip needs time to wakeup. Not mentioned in datasheet */ | ||
51 | usleep_range(10000, 20000); | ||
52 | } | ||
53 | return ret; | ||
54 | } | ||
55 | |||
37 | static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) | 56 | static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) |
38 | { | 57 | { |
39 | struct i2c_client *c = lis3->bus_priv; | 58 | struct i2c_client *c = lis3->bus_priv; |
@@ -52,6 +71,13 @@ static int lis3_i2c_init(struct lis3lv02d *lis3) | |||
52 | u8 reg; | 71 | u8 reg; |
53 | int ret; | 72 | int ret; |
54 | 73 | ||
74 | if (lis3->reg_ctrl) | ||
75 | lis3_reg_ctrl(lis3, LIS3_REG_ON); | ||
76 | |||
77 | lis3->read(lis3, WHO_AM_I, ®); | ||
78 | if (reg != lis3->whoami) | ||
79 | printk(KERN_ERR "lis3: power on failure\n"); | ||
80 | |||
55 | /* power up the device */ | 81 | /* power up the device */ |
56 | ret = lis3->read(lis3, CTRL_REG1, ®); | 82 | ret = lis3->read(lis3, CTRL_REG1, ®); |
57 | if (ret < 0) | 83 | if (ret < 0) |
@@ -72,6 +98,10 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, | |||
72 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; | 98 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; |
73 | 99 | ||
74 | if (pdata) { | 100 | if (pdata) { |
101 | /* Regulator control is optional */ | ||
102 | if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL) | ||
103 | lis3_dev.reg_ctrl = lis3_reg_ctrl; | ||
104 | |||
75 | if (pdata->axis_x) | 105 | if (pdata->axis_x) |
76 | lis3lv02d_axis_map.x = pdata->axis_x; | 106 | lis3lv02d_axis_map.x = pdata->axis_x; |
77 | 107 | ||
@@ -88,6 +118,16 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, | |||
88 | goto fail; | 118 | goto fail; |
89 | } | 119 | } |
90 | 120 | ||
121 | if (lis3_dev.reg_ctrl) { | ||
122 | lis3_dev.regulators[0].supply = reg_vdd; | ||
123 | lis3_dev.regulators[1].supply = reg_vdd_io; | ||
124 | ret = regulator_bulk_get(&client->dev, | ||
125 | ARRAY_SIZE(lis3_dev.regulators), | ||
126 | lis3_dev.regulators); | ||
127 | if (ret < 0) | ||
128 | goto fail; | ||
129 | } | ||
130 | |||
91 | lis3_dev.pdata = pdata; | 131 | lis3_dev.pdata = pdata; |
92 | lis3_dev.bus_priv = client; | 132 | lis3_dev.bus_priv = client; |
93 | lis3_dev.init = lis3_i2c_init; | 133 | lis3_dev.init = lis3_i2c_init; |
@@ -98,21 +138,34 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, | |||
98 | lis3_dev.pm_dev = &client->dev; | 138 | lis3_dev.pm_dev = &client->dev; |
99 | 139 | ||
100 | i2c_set_clientdata(client, &lis3_dev); | 140 | i2c_set_clientdata(client, &lis3_dev); |
141 | |||
142 | /* Provide power over the init call */ | ||
143 | if (lis3_dev.reg_ctrl) | ||
144 | lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON); | ||
145 | |||
101 | ret = lis3lv02d_init_device(&lis3_dev); | 146 | ret = lis3lv02d_init_device(&lis3_dev); |
147 | |||
148 | if (lis3_dev.reg_ctrl) | ||
149 | lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF); | ||
102 | fail: | 150 | fail: |
103 | return ret; | 151 | return ret; |
104 | } | 152 | } |
105 | 153 | ||
106 | static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) | 154 | static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) |
107 | { | 155 | { |
156 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
108 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; | 157 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; |
109 | 158 | ||
110 | if (pdata && pdata->release_resources) | 159 | if (pdata && pdata->release_resources) |
111 | pdata->release_resources(); | 160 | pdata->release_resources(); |
112 | 161 | ||
113 | lis3lv02d_joystick_disable(); | 162 | lis3lv02d_joystick_disable(); |
163 | lis3lv02d_remove_fs(&lis3_dev); | ||
114 | 164 | ||
115 | return lis3lv02d_remove_fs(&lis3_dev); | 165 | if (lis3_dev.reg_ctrl) |
166 | regulator_bulk_free(ARRAY_SIZE(lis3->regulators), | ||
167 | lis3_dev.regulators); | ||
168 | return 0; | ||
116 | } | 169 | } |
117 | 170 | ||
118 | #ifdef CONFIG_PM | 171 | #ifdef CONFIG_PM |