diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/regulator/max8925-regulator.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/regulator/max8925-regulator.c')
-rw-r--r-- | drivers/regulator/max8925-regulator.c | 216 |
1 files changed, 85 insertions, 131 deletions
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 446a8544555..e4dbd667c04 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c | |||
@@ -9,7 +9,6 @@ | |||
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
14 | #include <linux/err.h> | 13 | #include <linux/err.h> |
15 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
@@ -17,8 +16,6 @@ | |||
17 | #include <linux/regulator/driver.h> | 16 | #include <linux/regulator/driver.h> |
18 | #include <linux/regulator/machine.h> | 17 | #include <linux/regulator/machine.h> |
19 | #include <linux/mfd/max8925.h> | 18 | #include <linux/mfd/max8925.h> |
20 | #include <linux/of.h> | ||
21 | #include <linux/regulator/of_regulator.h> | ||
22 | 19 | ||
23 | #define SD1_DVM_VMIN 850000 | 20 | #define SD1_DVM_VMIN 850000 |
24 | #define SD1_DVM_VMAX 1000000 | 21 | #define SD1_DVM_VMAX 1000000 |
@@ -26,13 +23,9 @@ | |||
26 | #define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ | 23 | #define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ |
27 | #define SD1_DVM_EN 6 /* SDV1 bit 6 */ | 24 | #define SD1_DVM_EN 6 /* SDV1 bit 6 */ |
28 | 25 | ||
29 | /* bit definitions in LDO control registers */ | 26 | /* bit definitions in SD & LDO control registers */ |
30 | #define LDO_SEQ_I2C 0x7 /* Power U/D by i2c */ | 27 | #define OUT_ENABLE 0x1f /* Power U/D sequence as I2C */ |
31 | #define LDO_SEQ_MASK 0x7 /* Power U/D sequence mask */ | 28 | #define OUT_DISABLE 0x1e /* Power U/D sequence as I2C */ |
32 | #define LDO_SEQ_SHIFT 2 /* Power U/D sequence offset */ | ||
33 | #define LDO_I2C_EN 0x1 /* Enable by i2c */ | ||
34 | #define LDO_I2C_EN_MASK 0x1 /* Enable mask by i2c */ | ||
35 | #define LDO_I2C_EN_SHIFT 0 /* Enable offset by i2c */ | ||
36 | 29 | ||
37 | struct max8925_regulator_info { | 30 | struct max8925_regulator_info { |
38 | struct regulator_desc desc; | 31 | struct regulator_desc desc; |
@@ -40,20 +33,51 @@ struct max8925_regulator_info { | |||
40 | struct i2c_client *i2c; | 33 | struct i2c_client *i2c; |
41 | struct max8925_chip *chip; | 34 | struct max8925_chip *chip; |
42 | 35 | ||
36 | int min_uV; | ||
37 | int max_uV; | ||
38 | int step_uV; | ||
43 | int vol_reg; | 39 | int vol_reg; |
40 | int vol_shift; | ||
41 | int vol_nbits; | ||
42 | int enable_bit; | ||
44 | int enable_reg; | 43 | int enable_reg; |
45 | }; | 44 | }; |
46 | 45 | ||
47 | static int max8925_set_voltage_sel(struct regulator_dev *rdev, | 46 | static inline int check_range(struct max8925_regulator_info *info, |
48 | unsigned int selector) | 47 | int min_uV, int max_uV) |
48 | { | ||
49 | if (min_uV < info->min_uV || min_uV > info->max_uV) | ||
50 | return -EINVAL; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
49 | { | 56 | { |
50 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | 57 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); |
51 | unsigned char mask = rdev->desc->n_voltages - 1; | 58 | return info->min_uV + index * info->step_uV; |
59 | } | ||
52 | 60 | ||
53 | return max8925_set_bits(info->i2c, info->vol_reg, mask, selector); | 61 | static int max8925_set_voltage(struct regulator_dev *rdev, |
62 | int min_uV, int max_uV, unsigned int *selector) | ||
63 | { | ||
64 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | ||
65 | unsigned char data, mask; | ||
66 | |||
67 | if (check_range(info, min_uV, max_uV)) { | ||
68 | dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", | ||
69 | min_uV, max_uV); | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; | ||
73 | *selector = data; | ||
74 | data <<= info->vol_shift; | ||
75 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; | ||
76 | |||
77 | return max8925_set_bits(info->i2c, info->vol_reg, mask, data); | ||
54 | } | 78 | } |
55 | 79 | ||
56 | static int max8925_get_voltage_sel(struct regulator_dev *rdev) | 80 | static int max8925_get_voltage(struct regulator_dev *rdev) |
57 | { | 81 | { |
58 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | 82 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); |
59 | unsigned char data, mask; | 83 | unsigned char data, mask; |
@@ -62,10 +86,10 @@ static int max8925_get_voltage_sel(struct regulator_dev *rdev) | |||
62 | ret = max8925_reg_read(info->i2c, info->vol_reg); | 86 | ret = max8925_reg_read(info->i2c, info->vol_reg); |
63 | if (ret < 0) | 87 | if (ret < 0) |
64 | return ret; | 88 | return ret; |
65 | mask = rdev->desc->n_voltages - 1; | 89 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; |
66 | data = ret & mask; | 90 | data = (ret & mask) >> info->vol_shift; |
67 | 91 | ||
68 | return data; | 92 | return max8925_list_voltage(rdev, data); |
69 | } | 93 | } |
70 | 94 | ||
71 | static int max8925_enable(struct regulator_dev *rdev) | 95 | static int max8925_enable(struct regulator_dev *rdev) |
@@ -73,10 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev) | |||
73 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | 97 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); |
74 | 98 | ||
75 | return max8925_set_bits(info->i2c, info->enable_reg, | 99 | return max8925_set_bits(info->i2c, info->enable_reg, |
76 | LDO_SEQ_MASK << LDO_SEQ_SHIFT | | 100 | OUT_ENABLE << info->enable_bit, |
77 | LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT, | 101 | OUT_ENABLE << info->enable_bit); |
78 | LDO_SEQ_I2C << LDO_SEQ_SHIFT | | ||
79 | LDO_I2C_EN << LDO_I2C_EN_SHIFT); | ||
80 | } | 102 | } |
81 | 103 | ||
82 | static int max8925_disable(struct regulator_dev *rdev) | 104 | static int max8925_disable(struct regulator_dev *rdev) |
@@ -84,24 +106,20 @@ static int max8925_disable(struct regulator_dev *rdev) | |||
84 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | 106 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); |
85 | 107 | ||
86 | return max8925_set_bits(info->i2c, info->enable_reg, | 108 | return max8925_set_bits(info->i2c, info->enable_reg, |
87 | LDO_SEQ_MASK << LDO_SEQ_SHIFT | | 109 | OUT_ENABLE << info->enable_bit, |
88 | LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT, | 110 | OUT_DISABLE << info->enable_bit); |
89 | LDO_SEQ_I2C << LDO_SEQ_SHIFT); | ||
90 | } | 111 | } |
91 | 112 | ||
92 | static int max8925_is_enabled(struct regulator_dev *rdev) | 113 | static int max8925_is_enabled(struct regulator_dev *rdev) |
93 | { | 114 | { |
94 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); | 115 | struct max8925_regulator_info *info = rdev_get_drvdata(rdev); |
95 | int ldo_seq, ret; | 116 | int ret; |
96 | 117 | ||
97 | ret = max8925_reg_read(info->i2c, info->enable_reg); | 118 | ret = max8925_reg_read(info->i2c, info->enable_reg); |
98 | if (ret < 0) | 119 | if (ret < 0) |
99 | return ret; | 120 | return ret; |
100 | ldo_seq = (ret >> LDO_SEQ_SHIFT) & LDO_SEQ_MASK; | 121 | |
101 | if (ldo_seq != LDO_SEQ_I2C) | 122 | return ret & (1 << info->enable_bit); |
102 | return 1; | ||
103 | else | ||
104 | return ret & (LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT); | ||
105 | } | 123 | } |
106 | 124 | ||
107 | static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) | 125 | static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) |
@@ -112,7 +130,7 @@ static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) | |||
112 | if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX) | 130 | if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX) |
113 | return -EINVAL; | 131 | return -EINVAL; |
114 | 132 | ||
115 | data = DIV_ROUND_UP(uV - SD1_DVM_VMIN, SD1_DVM_STEP); | 133 | data = (uV - SD1_DVM_VMIN + SD1_DVM_STEP - 1) / SD1_DVM_STEP; |
116 | data <<= SD1_DVM_SHIFT; | 134 | data <<= SD1_DVM_SHIFT; |
117 | mask = 3 << SD1_DVM_SHIFT; | 135 | mask = 3 << SD1_DVM_SHIFT; |
118 | 136 | ||
@@ -135,10 +153,8 @@ static int max8925_set_dvm_disable(struct regulator_dev *rdev) | |||
135 | } | 153 | } |
136 | 154 | ||
137 | static struct regulator_ops max8925_regulator_sdv_ops = { | 155 | static struct regulator_ops max8925_regulator_sdv_ops = { |
138 | .map_voltage = regulator_map_voltage_linear, | 156 | .set_voltage = max8925_set_voltage, |
139 | .list_voltage = regulator_list_voltage_linear, | 157 | .get_voltage = max8925_get_voltage, |
140 | .set_voltage_sel = max8925_set_voltage_sel, | ||
141 | .get_voltage_sel = max8925_get_voltage_sel, | ||
142 | .enable = max8925_enable, | 158 | .enable = max8925_enable, |
143 | .disable = max8925_disable, | 159 | .disable = max8925_disable, |
144 | .is_enabled = max8925_is_enabled, | 160 | .is_enabled = max8925_is_enabled, |
@@ -148,10 +164,8 @@ static struct regulator_ops max8925_regulator_sdv_ops = { | |||
148 | }; | 164 | }; |
149 | 165 | ||
150 | static struct regulator_ops max8925_regulator_ldo_ops = { | 166 | static struct regulator_ops max8925_regulator_ldo_ops = { |
151 | .map_voltage = regulator_map_voltage_linear, | 167 | .set_voltage = max8925_set_voltage, |
152 | .list_voltage = regulator_list_voltage_linear, | 168 | .get_voltage = max8925_get_voltage, |
153 | .set_voltage_sel = max8925_set_voltage_sel, | ||
154 | .get_voltage_sel = max8925_get_voltage_sel, | ||
155 | .enable = max8925_enable, | 169 | .enable = max8925_enable, |
156 | .disable = max8925_disable, | 170 | .disable = max8925_disable, |
157 | .is_enabled = max8925_is_enabled, | 171 | .is_enabled = max8925_is_enabled, |
@@ -165,12 +179,15 @@ static struct regulator_ops max8925_regulator_ldo_ops = { | |||
165 | .type = REGULATOR_VOLTAGE, \ | 179 | .type = REGULATOR_VOLTAGE, \ |
166 | .id = MAX8925_ID_SD##_id, \ | 180 | .id = MAX8925_ID_SD##_id, \ |
167 | .owner = THIS_MODULE, \ | 181 | .owner = THIS_MODULE, \ |
168 | .n_voltages = 64, \ | ||
169 | .min_uV = min * 1000, \ | ||
170 | .uV_step = step * 1000, \ | ||
171 | }, \ | 182 | }, \ |
183 | .min_uV = min * 1000, \ | ||
184 | .max_uV = max * 1000, \ | ||
185 | .step_uV = step * 1000, \ | ||
172 | .vol_reg = MAX8925_SDV##_id, \ | 186 | .vol_reg = MAX8925_SDV##_id, \ |
187 | .vol_shift = 0, \ | ||
188 | .vol_nbits = 6, \ | ||
173 | .enable_reg = MAX8925_SDCTL##_id, \ | 189 | .enable_reg = MAX8925_SDCTL##_id, \ |
190 | .enable_bit = 0, \ | ||
174 | } | 191 | } |
175 | 192 | ||
176 | #define MAX8925_LDO(_id, min, max, step) \ | 193 | #define MAX8925_LDO(_id, min, max, step) \ |
@@ -181,42 +198,17 @@ static struct regulator_ops max8925_regulator_ldo_ops = { | |||
181 | .type = REGULATOR_VOLTAGE, \ | 198 | .type = REGULATOR_VOLTAGE, \ |
182 | .id = MAX8925_ID_LDO##_id, \ | 199 | .id = MAX8925_ID_LDO##_id, \ |
183 | .owner = THIS_MODULE, \ | 200 | .owner = THIS_MODULE, \ |
184 | .n_voltages = 64, \ | ||
185 | .min_uV = min * 1000, \ | ||
186 | .uV_step = step * 1000, \ | ||
187 | }, \ | 201 | }, \ |
202 | .min_uV = min * 1000, \ | ||
203 | .max_uV = max * 1000, \ | ||
204 | .step_uV = step * 1000, \ | ||
188 | .vol_reg = MAX8925_LDOVOUT##_id, \ | 205 | .vol_reg = MAX8925_LDOVOUT##_id, \ |
206 | .vol_shift = 0, \ | ||
207 | .vol_nbits = 6, \ | ||
189 | .enable_reg = MAX8925_LDOCTL##_id, \ | 208 | .enable_reg = MAX8925_LDOCTL##_id, \ |
209 | .enable_bit = 0, \ | ||
190 | } | 210 | } |
191 | 211 | ||
192 | #ifdef CONFIG_OF | ||
193 | static struct of_regulator_match max8925_regulator_matches[] = { | ||
194 | { .name = "SDV1",}, | ||
195 | { .name = "SDV2",}, | ||
196 | { .name = "SDV3",}, | ||
197 | { .name = "LDO1",}, | ||
198 | { .name = "LDO2",}, | ||
199 | { .name = "LDO3",}, | ||
200 | { .name = "LDO4",}, | ||
201 | { .name = "LDO5",}, | ||
202 | { .name = "LDO6",}, | ||
203 | { .name = "LDO7",}, | ||
204 | { .name = "LDO8",}, | ||
205 | { .name = "LDO9",}, | ||
206 | { .name = "LDO10",}, | ||
207 | { .name = "LDO11",}, | ||
208 | { .name = "LDO12",}, | ||
209 | { .name = "LDO13",}, | ||
210 | { .name = "LDO14",}, | ||
211 | { .name = "LDO15",}, | ||
212 | { .name = "LDO16",}, | ||
213 | { .name = "LDO17",}, | ||
214 | { .name = "LDO18",}, | ||
215 | { .name = "LDO19",}, | ||
216 | { .name = "LDO20",}, | ||
217 | }; | ||
218 | #endif | ||
219 | |||
220 | static struct max8925_regulator_info max8925_regulator_info[] = { | 212 | static struct max8925_regulator_info max8925_regulator_info[] = { |
221 | MAX8925_SDV(1, 637.5, 1425, 12.5), | 213 | MAX8925_SDV(1, 637.5, 1425, 12.5), |
222 | MAX8925_SDV(2, 650, 2225, 25), | 214 | MAX8925_SDV(2, 650, 2225, 25), |
@@ -244,75 +236,36 @@ static struct max8925_regulator_info max8925_regulator_info[] = { | |||
244 | MAX8925_LDO(20, 750, 3900, 50), | 236 | MAX8925_LDO(20, 750, 3900, 50), |
245 | }; | 237 | }; |
246 | 238 | ||
247 | #ifdef CONFIG_OF | 239 | static struct max8925_regulator_info * __devinit find_regulator_info(int id) |
248 | static int max8925_regulator_dt_init(struct platform_device *pdev, | ||
249 | struct max8925_regulator_info *info, | ||
250 | struct regulator_config *config, | ||
251 | int ridx) | ||
252 | { | 240 | { |
253 | struct device_node *nproot, *np; | 241 | struct max8925_regulator_info *ri; |
254 | int rcount; | 242 | int i; |
255 | nproot = pdev->dev.parent->of_node; | ||
256 | if (!nproot) | ||
257 | return -ENODEV; | ||
258 | np = of_find_node_by_name(nproot, "regulators"); | ||
259 | if (!np) { | ||
260 | dev_err(&pdev->dev, "failed to find regulators node\n"); | ||
261 | return -ENODEV; | ||
262 | } | ||
263 | |||
264 | rcount = of_regulator_match(&pdev->dev, np, | ||
265 | &max8925_regulator_matches[ridx], 1); | ||
266 | if (rcount < 0) | ||
267 | return -ENODEV; | ||
268 | config->init_data = max8925_regulator_matches[ridx].init_data; | ||
269 | config->of_node = max8925_regulator_matches[ridx].of_node; | ||
270 | 243 | ||
271 | return 0; | 244 | for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { |
245 | ri = &max8925_regulator_info[i]; | ||
246 | if (ri->desc.id == id) | ||
247 | return ri; | ||
248 | } | ||
249 | return NULL; | ||
272 | } | 250 | } |
273 | #else | ||
274 | #define max8925_regulator_dt_init(w, x, y, z) (-1) | ||
275 | #endif | ||
276 | 251 | ||
277 | static int max8925_regulator_probe(struct platform_device *pdev) | 252 | static int __devinit max8925_regulator_probe(struct platform_device *pdev) |
278 | { | 253 | { |
279 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); | 254 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); |
280 | struct regulator_init_data *pdata = pdev->dev.platform_data; | 255 | struct max8925_platform_data *pdata = chip->dev->platform_data; |
281 | struct regulator_config config = { }; | ||
282 | struct max8925_regulator_info *ri; | 256 | struct max8925_regulator_info *ri; |
283 | struct resource *res; | ||
284 | struct regulator_dev *rdev; | 257 | struct regulator_dev *rdev; |
285 | int i, regulator_idx; | ||
286 | 258 | ||
287 | res = platform_get_resource(pdev, IORESOURCE_REG, 0); | 259 | ri = find_regulator_info(pdev->id); |
288 | if (!res) { | 260 | if (ri == NULL) { |
289 | dev_err(&pdev->dev, "No REG resource!\n"); | 261 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); |
290 | return -EINVAL; | ||
291 | } | ||
292 | for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { | ||
293 | ri = &max8925_regulator_info[i]; | ||
294 | if (ri->vol_reg == res->start) { | ||
295 | regulator_idx = i; | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | if (i == ARRAY_SIZE(max8925_regulator_info)) { | ||
301 | dev_err(&pdev->dev, "Failed to find regulator %llu\n", | ||
302 | (unsigned long long)res->start); | ||
303 | return -EINVAL; | 262 | return -EINVAL; |
304 | } | 263 | } |
305 | ri->i2c = chip->i2c; | 264 | ri->i2c = chip->i2c; |
306 | ri->chip = chip; | 265 | ri->chip = chip; |
307 | 266 | ||
308 | config.dev = &pdev->dev; | 267 | rdev = regulator_register(&ri->desc, &pdev->dev, |
309 | config.driver_data = ri; | 268 | pdata->regulator[pdev->id], ri); |
310 | |||
311 | if (max8925_regulator_dt_init(pdev, ri, &config, regulator_idx)) | ||
312 | if (pdata) | ||
313 | config.init_data = pdata; | ||
314 | |||
315 | rdev = regulator_register(&ri->desc, &config); | ||
316 | if (IS_ERR(rdev)) { | 269 | if (IS_ERR(rdev)) { |
317 | dev_err(&pdev->dev, "failed to register regulator %s\n", | 270 | dev_err(&pdev->dev, "failed to register regulator %s\n", |
318 | ri->desc.name); | 271 | ri->desc.name); |
@@ -323,7 +276,7 @@ static int max8925_regulator_probe(struct platform_device *pdev) | |||
323 | return 0; | 276 | return 0; |
324 | } | 277 | } |
325 | 278 | ||
326 | static int max8925_regulator_remove(struct platform_device *pdev) | 279 | static int __devexit max8925_regulator_remove(struct platform_device *pdev) |
327 | { | 280 | { |
328 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 281 | struct regulator_dev *rdev = platform_get_drvdata(pdev); |
329 | 282 | ||
@@ -339,7 +292,7 @@ static struct platform_driver max8925_regulator_driver = { | |||
339 | .owner = THIS_MODULE, | 292 | .owner = THIS_MODULE, |
340 | }, | 293 | }, |
341 | .probe = max8925_regulator_probe, | 294 | .probe = max8925_regulator_probe, |
342 | .remove = max8925_regulator_remove, | 295 | .remove = __devexit_p(max8925_regulator_remove), |
343 | }; | 296 | }; |
344 | 297 | ||
345 | static int __init max8925_regulator_init(void) | 298 | static int __init max8925_regulator_init(void) |
@@ -358,3 +311,4 @@ MODULE_LICENSE("GPL"); | |||
358 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | 311 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); |
359 | MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC"); | 312 | MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC"); |
360 | MODULE_ALIAS("platform:max8925-regulator"); | 313 | MODULE_ALIAS("platform:max8925-regulator"); |
314 | |||