aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/lis3lv02d_i2c.c
diff options
context:
space:
mode:
authorSamu Onkalo <samu.p.onkalo@nokia.com>2010-10-22 07:57:24 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2010-10-25 17:11:38 -0400
commitf9deb41f91c41d9d91a24c84a555ec7fe82620da (patch)
treec301a8324c3bbc779b752cdf47236575a87a26d2 /drivers/hwmon/lis3lv02d_i2c.c
parent2a346996626ecbb4269c239e9ff7372a182907e9 (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.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
index d52095603e0..ec35c87819c 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
38static const char reg_vdd[] = "Vdd";
39static const char reg_vdd_io[] = "Vdd_IO";
40
41static 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
37static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) 56static 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, &reg);
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, &reg); 82 ret = lis3->read(lis3, CTRL_REG1, &reg);
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);
102fail: 150fail:
103 return ret; 151 return ret;
104} 152}
105 153
106static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) 154static 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