Commit 020501f1a0911af70873e4d3d122b2e1889ccd03
Committed by
Mark Brown
1 parent
1e4b545cdd
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
regulator: Remove NULL test before calling regulator_unregister()
It's safe to call regulator_unregister() with NULL, thus remove the NULL test before regulator_unregister() calls. Signed-off-by: Axel Lin <axel.lin@ingics.com> Signed-off-by: Mark Brown <broonie@sirena.org.uk>
Showing 5 changed files with 7 additions and 14 deletions Inline Diff
drivers/regulator/max1586.c
1 | /* | 1 | /* |
2 | * max1586.c -- Voltage and current regulation for the Maxim 1586 | 2 | * max1586.c -- Voltage and current regulation for the Maxim 1586 |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Robert Jarzmik | 4 | * Copyright (C) 2008 Robert Jarzmik |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/regulator/driver.h> | 24 | #include <linux/regulator/driver.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/regulator/max1586.h> | 26 | #include <linux/regulator/max1586.h> |
27 | 27 | ||
28 | #define MAX1586_V3_MAX_VSEL 31 | 28 | #define MAX1586_V3_MAX_VSEL 31 |
29 | #define MAX1586_V6_MAX_VSEL 3 | 29 | #define MAX1586_V6_MAX_VSEL 3 |
30 | 30 | ||
31 | #define MAX1586_V3_MIN_UV 700000 | 31 | #define MAX1586_V3_MIN_UV 700000 |
32 | #define MAX1586_V3_MAX_UV 1475000 | 32 | #define MAX1586_V3_MAX_UV 1475000 |
33 | 33 | ||
34 | #define MAX1586_V6_MIN_UV 0 | 34 | #define MAX1586_V6_MIN_UV 0 |
35 | #define MAX1586_V6_MAX_UV 3000000 | 35 | #define MAX1586_V6_MAX_UV 3000000 |
36 | 36 | ||
37 | #define I2C_V3_SELECT (0 << 5) | 37 | #define I2C_V3_SELECT (0 << 5) |
38 | #define I2C_V6_SELECT (1 << 5) | 38 | #define I2C_V6_SELECT (1 << 5) |
39 | 39 | ||
40 | struct max1586_data { | 40 | struct max1586_data { |
41 | struct i2c_client *client; | 41 | struct i2c_client *client; |
42 | 42 | ||
43 | /* min/max V3 voltage */ | 43 | /* min/max V3 voltage */ |
44 | unsigned int min_uV; | 44 | unsigned int min_uV; |
45 | unsigned int max_uV; | 45 | unsigned int max_uV; |
46 | 46 | ||
47 | unsigned int v3_curr_sel; | 47 | unsigned int v3_curr_sel; |
48 | unsigned int v6_curr_sel; | 48 | unsigned int v6_curr_sel; |
49 | 49 | ||
50 | struct regulator_dev *rdev[0]; | 50 | struct regulator_dev *rdev[0]; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * V6 voltage | 54 | * V6 voltage |
55 | * On I2C bus, sending a "x" byte to the max1586 means : | 55 | * On I2C bus, sending a "x" byte to the max1586 means : |
56 | * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) | 56 | * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) |
57 | * As regulator framework doesn't accept voltages to be 0V, we use 1uV. | 57 | * As regulator framework doesn't accept voltages to be 0V, we use 1uV. |
58 | */ | 58 | */ |
59 | static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; | 59 | static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * V3 voltage | 62 | * V3 voltage |
63 | * On I2C bus, sending a "x" byte to the max1586 means : | 63 | * On I2C bus, sending a "x" byte to the max1586 means : |
64 | * set V3 to 0.700V + (x & 0x1f) * 0.025V | 64 | * set V3 to 0.700V + (x & 0x1f) * 0.025V |
65 | * This voltage can be increased by external resistors | 65 | * This voltage can be increased by external resistors |
66 | * R24 and R25=100kOhm as described in the data sheet. | 66 | * R24 and R25=100kOhm as described in the data sheet. |
67 | * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm | 67 | * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm |
68 | */ | 68 | */ |
69 | static int max1586_v3_get_voltage_sel(struct regulator_dev *rdev) | 69 | static int max1586_v3_get_voltage_sel(struct regulator_dev *rdev) |
70 | { | 70 | { |
71 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); | 71 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); |
72 | 72 | ||
73 | return max1586->v3_curr_sel; | 73 | return max1586->v3_curr_sel; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, | 76 | static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, |
77 | unsigned selector) | 77 | unsigned selector) |
78 | { | 78 | { |
79 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); | 79 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); |
80 | struct i2c_client *client = max1586->client; | 80 | struct i2c_client *client = max1586->client; |
81 | int ret; | 81 | int ret; |
82 | u8 v3_prog; | 82 | u8 v3_prog; |
83 | 83 | ||
84 | dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", | 84 | dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", |
85 | regulator_list_voltage_linear(rdev, selector) / 1000); | 85 | regulator_list_voltage_linear(rdev, selector) / 1000); |
86 | 86 | ||
87 | v3_prog = I2C_V3_SELECT | (u8) selector; | 87 | v3_prog = I2C_V3_SELECT | (u8) selector; |
88 | ret = i2c_smbus_write_byte(client, v3_prog); | 88 | ret = i2c_smbus_write_byte(client, v3_prog); |
89 | if (ret) | 89 | if (ret) |
90 | return ret; | 90 | return ret; |
91 | 91 | ||
92 | max1586->v3_curr_sel = selector; | 92 | max1586->v3_curr_sel = selector; |
93 | 93 | ||
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
96 | 96 | ||
97 | static int max1586_v6_get_voltage_sel(struct regulator_dev *rdev) | 97 | static int max1586_v6_get_voltage_sel(struct regulator_dev *rdev) |
98 | { | 98 | { |
99 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); | 99 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); |
100 | 100 | ||
101 | return max1586->v6_curr_sel; | 101 | return max1586->v6_curr_sel; |
102 | } | 102 | } |
103 | 103 | ||
104 | static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, | 104 | static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, |
105 | unsigned int selector) | 105 | unsigned int selector) |
106 | { | 106 | { |
107 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); | 107 | struct max1586_data *max1586 = rdev_get_drvdata(rdev); |
108 | struct i2c_client *client = max1586->client; | 108 | struct i2c_client *client = max1586->client; |
109 | u8 v6_prog; | 109 | u8 v6_prog; |
110 | int ret; | 110 | int ret; |
111 | 111 | ||
112 | dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", | 112 | dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", |
113 | rdev->desc->volt_table[selector] / 1000); | 113 | rdev->desc->volt_table[selector] / 1000); |
114 | 114 | ||
115 | v6_prog = I2C_V6_SELECT | (u8) selector; | 115 | v6_prog = I2C_V6_SELECT | (u8) selector; |
116 | ret = i2c_smbus_write_byte(client, v6_prog); | 116 | ret = i2c_smbus_write_byte(client, v6_prog); |
117 | if (ret) | 117 | if (ret) |
118 | return ret; | 118 | return ret; |
119 | 119 | ||
120 | max1586->v6_curr_sel = selector; | 120 | max1586->v6_curr_sel = selector; |
121 | 121 | ||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back | 126 | * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back |
127 | * the set up value. | 127 | * the set up value. |
128 | */ | 128 | */ |
129 | static struct regulator_ops max1586_v3_ops = { | 129 | static struct regulator_ops max1586_v3_ops = { |
130 | .get_voltage_sel = max1586_v3_get_voltage_sel, | 130 | .get_voltage_sel = max1586_v3_get_voltage_sel, |
131 | .set_voltage_sel = max1586_v3_set_voltage_sel, | 131 | .set_voltage_sel = max1586_v3_set_voltage_sel, |
132 | .list_voltage = regulator_list_voltage_linear, | 132 | .list_voltage = regulator_list_voltage_linear, |
133 | .map_voltage = regulator_map_voltage_linear, | 133 | .map_voltage = regulator_map_voltage_linear, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static struct regulator_ops max1586_v6_ops = { | 136 | static struct regulator_ops max1586_v6_ops = { |
137 | .get_voltage_sel = max1586_v6_get_voltage_sel, | 137 | .get_voltage_sel = max1586_v6_get_voltage_sel, |
138 | .set_voltage_sel = max1586_v6_set_voltage_sel, | 138 | .set_voltage_sel = max1586_v6_set_voltage_sel, |
139 | .list_voltage = regulator_list_voltage_table, | 139 | .list_voltage = regulator_list_voltage_table, |
140 | }; | 140 | }; |
141 | 141 | ||
142 | static struct regulator_desc max1586_reg[] = { | 142 | static struct regulator_desc max1586_reg[] = { |
143 | { | 143 | { |
144 | .name = "Output_V3", | 144 | .name = "Output_V3", |
145 | .id = MAX1586_V3, | 145 | .id = MAX1586_V3, |
146 | .ops = &max1586_v3_ops, | 146 | .ops = &max1586_v3_ops, |
147 | .type = REGULATOR_VOLTAGE, | 147 | .type = REGULATOR_VOLTAGE, |
148 | .n_voltages = MAX1586_V3_MAX_VSEL + 1, | 148 | .n_voltages = MAX1586_V3_MAX_VSEL + 1, |
149 | .owner = THIS_MODULE, | 149 | .owner = THIS_MODULE, |
150 | }, | 150 | }, |
151 | { | 151 | { |
152 | .name = "Output_V6", | 152 | .name = "Output_V6", |
153 | .id = MAX1586_V6, | 153 | .id = MAX1586_V6, |
154 | .ops = &max1586_v6_ops, | 154 | .ops = &max1586_v6_ops, |
155 | .type = REGULATOR_VOLTAGE, | 155 | .type = REGULATOR_VOLTAGE, |
156 | .n_voltages = MAX1586_V6_MAX_VSEL + 1, | 156 | .n_voltages = MAX1586_V6_MAX_VSEL + 1, |
157 | .volt_table = v6_voltages_uv, | 157 | .volt_table = v6_voltages_uv, |
158 | .owner = THIS_MODULE, | 158 | .owner = THIS_MODULE, |
159 | }, | 159 | }, |
160 | }; | 160 | }; |
161 | 161 | ||
162 | static int max1586_pmic_probe(struct i2c_client *client, | 162 | static int max1586_pmic_probe(struct i2c_client *client, |
163 | const struct i2c_device_id *i2c_id) | 163 | const struct i2c_device_id *i2c_id) |
164 | { | 164 | { |
165 | struct regulator_dev **rdev; | 165 | struct regulator_dev **rdev; |
166 | struct max1586_platform_data *pdata = client->dev.platform_data; | 166 | struct max1586_platform_data *pdata = client->dev.platform_data; |
167 | struct regulator_config config = { }; | 167 | struct regulator_config config = { }; |
168 | struct max1586_data *max1586; | 168 | struct max1586_data *max1586; |
169 | int i, id, ret = -ENOMEM; | 169 | int i, id, ret = -ENOMEM; |
170 | 170 | ||
171 | max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + | 171 | max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + |
172 | sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), | 172 | sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), |
173 | GFP_KERNEL); | 173 | GFP_KERNEL); |
174 | if (!max1586) | 174 | if (!max1586) |
175 | return -ENOMEM; | 175 | return -ENOMEM; |
176 | 176 | ||
177 | max1586->client = client; | 177 | max1586->client = client; |
178 | 178 | ||
179 | if (!pdata->v3_gain) | 179 | if (!pdata->v3_gain) |
180 | return -EINVAL; | 180 | return -EINVAL; |
181 | 181 | ||
182 | max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; | 182 | max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; |
183 | max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; | 183 | max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; |
184 | 184 | ||
185 | /* Set curr_sel to default voltage on power-up */ | 185 | /* Set curr_sel to default voltage on power-up */ |
186 | max1586->v3_curr_sel = 24; /* 1.3V */ | 186 | max1586->v3_curr_sel = 24; /* 1.3V */ |
187 | max1586->v6_curr_sel = 0; | 187 | max1586->v6_curr_sel = 0; |
188 | 188 | ||
189 | rdev = max1586->rdev; | 189 | rdev = max1586->rdev; |
190 | for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { | 190 | for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { |
191 | id = pdata->subdevs[i].id; | 191 | id = pdata->subdevs[i].id; |
192 | if (!pdata->subdevs[i].platform_data) | 192 | if (!pdata->subdevs[i].platform_data) |
193 | continue; | 193 | continue; |
194 | if (id < MAX1586_V3 || id > MAX1586_V6) { | 194 | if (id < MAX1586_V3 || id > MAX1586_V6) { |
195 | dev_err(&client->dev, "invalid regulator id %d\n", id); | 195 | dev_err(&client->dev, "invalid regulator id %d\n", id); |
196 | goto err; | 196 | goto err; |
197 | } | 197 | } |
198 | 198 | ||
199 | if (id == MAX1586_V3) { | 199 | if (id == MAX1586_V3) { |
200 | max1586_reg[id].min_uV = max1586->min_uV; | 200 | max1586_reg[id].min_uV = max1586->min_uV; |
201 | max1586_reg[id].uV_step = | 201 | max1586_reg[id].uV_step = |
202 | (max1586->max_uV - max1586->min_uV) / | 202 | (max1586->max_uV - max1586->min_uV) / |
203 | MAX1586_V3_MAX_VSEL; | 203 | MAX1586_V3_MAX_VSEL; |
204 | } | 204 | } |
205 | 205 | ||
206 | config.dev = &client->dev; | 206 | config.dev = &client->dev; |
207 | config.init_data = pdata->subdevs[i].platform_data; | 207 | config.init_data = pdata->subdevs[i].platform_data; |
208 | config.driver_data = max1586; | 208 | config.driver_data = max1586; |
209 | 209 | ||
210 | rdev[i] = regulator_register(&max1586_reg[id], &config); | 210 | rdev[i] = regulator_register(&max1586_reg[id], &config); |
211 | if (IS_ERR(rdev[i])) { | 211 | if (IS_ERR(rdev[i])) { |
212 | ret = PTR_ERR(rdev[i]); | 212 | ret = PTR_ERR(rdev[i]); |
213 | dev_err(&client->dev, "failed to register %s\n", | 213 | dev_err(&client->dev, "failed to register %s\n", |
214 | max1586_reg[id].name); | 214 | max1586_reg[id].name); |
215 | goto err; | 215 | goto err; |
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | i2c_set_clientdata(client, max1586); | 219 | i2c_set_clientdata(client, max1586); |
220 | dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); | 220 | dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); |
221 | return 0; | 221 | return 0; |
222 | 222 | ||
223 | err: | 223 | err: |
224 | while (--i >= 0) | 224 | while (--i >= 0) |
225 | regulator_unregister(rdev[i]); | 225 | regulator_unregister(rdev[i]); |
226 | return ret; | 226 | return ret; |
227 | } | 227 | } |
228 | 228 | ||
229 | static int max1586_pmic_remove(struct i2c_client *client) | 229 | static int max1586_pmic_remove(struct i2c_client *client) |
230 | { | 230 | { |
231 | struct max1586_data *max1586 = i2c_get_clientdata(client); | 231 | struct max1586_data *max1586 = i2c_get_clientdata(client); |
232 | int i; | 232 | int i; |
233 | 233 | ||
234 | for (i = 0; i <= MAX1586_V6; i++) | 234 | for (i = 0; i <= MAX1586_V6; i++) |
235 | if (max1586->rdev[i]) | 235 | regulator_unregister(max1586->rdev[i]); |
236 | regulator_unregister(max1586->rdev[i]); | ||
237 | return 0; | 236 | return 0; |
238 | } | 237 | } |
239 | 238 | ||
240 | static const struct i2c_device_id max1586_id[] = { | 239 | static const struct i2c_device_id max1586_id[] = { |
241 | { "max1586", 0 }, | 240 | { "max1586", 0 }, |
242 | { } | 241 | { } |
243 | }; | 242 | }; |
244 | MODULE_DEVICE_TABLE(i2c, max1586_id); | 243 | MODULE_DEVICE_TABLE(i2c, max1586_id); |
245 | 244 | ||
246 | static struct i2c_driver max1586_pmic_driver = { | 245 | static struct i2c_driver max1586_pmic_driver = { |
247 | .probe = max1586_pmic_probe, | 246 | .probe = max1586_pmic_probe, |
248 | .remove = max1586_pmic_remove, | 247 | .remove = max1586_pmic_remove, |
249 | .driver = { | 248 | .driver = { |
250 | .name = "max1586", | 249 | .name = "max1586", |
251 | .owner = THIS_MODULE, | 250 | .owner = THIS_MODULE, |
252 | }, | 251 | }, |
253 | .id_table = max1586_id, | 252 | .id_table = max1586_id, |
254 | }; | 253 | }; |
255 | 254 | ||
256 | static int __init max1586_pmic_init(void) | 255 | static int __init max1586_pmic_init(void) |
257 | { | 256 | { |
258 | return i2c_add_driver(&max1586_pmic_driver); | 257 | return i2c_add_driver(&max1586_pmic_driver); |
259 | } | 258 | } |
260 | subsys_initcall(max1586_pmic_init); | 259 | subsys_initcall(max1586_pmic_init); |
261 | 260 | ||
262 | static void __exit max1586_pmic_exit(void) | 261 | static void __exit max1586_pmic_exit(void) |
263 | { | 262 | { |
264 | i2c_del_driver(&max1586_pmic_driver); | 263 | i2c_del_driver(&max1586_pmic_driver); |
265 | } | 264 | } |
266 | module_exit(max1586_pmic_exit); | 265 | module_exit(max1586_pmic_exit); |
267 | 266 | ||
268 | /* Module information */ | 267 | /* Module information */ |
269 | MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); | 268 | MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); |
270 | MODULE_AUTHOR("Robert Jarzmik"); | 269 | MODULE_AUTHOR("Robert Jarzmik"); |
271 | MODULE_LICENSE("GPL"); | 270 | MODULE_LICENSE("GPL"); |
272 | 271 |
drivers/regulator/max8649.c
1 | /* | 1 | /* |
2 | * Regulators driver for Maxim max8649 | 2 | * Regulators driver for Maxim max8649 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Marvell International Ltd. | 4 | * Copyright (C) 2009-2010 Marvell International Ltd. |
5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
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> | 12 | #include <linux/module.h> |
13 | #include <linux/err.h> | 13 | #include <linux/err.h> |
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/regulator/driver.h> | 16 | #include <linux/regulator/driver.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/regulator/max8649.h> | 18 | #include <linux/regulator/max8649.h> |
19 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
20 | 20 | ||
21 | #define MAX8649_DCDC_VMIN 750000 /* uV */ | 21 | #define MAX8649_DCDC_VMIN 750000 /* uV */ |
22 | #define MAX8649_DCDC_VMAX 1380000 /* uV */ | 22 | #define MAX8649_DCDC_VMAX 1380000 /* uV */ |
23 | #define MAX8649_DCDC_STEP 10000 /* uV */ | 23 | #define MAX8649_DCDC_STEP 10000 /* uV */ |
24 | #define MAX8649_VOL_MASK 0x3f | 24 | #define MAX8649_VOL_MASK 0x3f |
25 | 25 | ||
26 | /* Registers */ | 26 | /* Registers */ |
27 | #define MAX8649_MODE0 0x00 | 27 | #define MAX8649_MODE0 0x00 |
28 | #define MAX8649_MODE1 0x01 | 28 | #define MAX8649_MODE1 0x01 |
29 | #define MAX8649_MODE2 0x02 | 29 | #define MAX8649_MODE2 0x02 |
30 | #define MAX8649_MODE3 0x03 | 30 | #define MAX8649_MODE3 0x03 |
31 | #define MAX8649_CONTROL 0x04 | 31 | #define MAX8649_CONTROL 0x04 |
32 | #define MAX8649_SYNC 0x05 | 32 | #define MAX8649_SYNC 0x05 |
33 | #define MAX8649_RAMP 0x06 | 33 | #define MAX8649_RAMP 0x06 |
34 | #define MAX8649_CHIP_ID1 0x08 | 34 | #define MAX8649_CHIP_ID1 0x08 |
35 | #define MAX8649_CHIP_ID2 0x09 | 35 | #define MAX8649_CHIP_ID2 0x09 |
36 | 36 | ||
37 | /* Bits */ | 37 | /* Bits */ |
38 | #define MAX8649_EN_PD (1 << 7) | 38 | #define MAX8649_EN_PD (1 << 7) |
39 | #define MAX8649_VID0_PD (1 << 6) | 39 | #define MAX8649_VID0_PD (1 << 6) |
40 | #define MAX8649_VID1_PD (1 << 5) | 40 | #define MAX8649_VID1_PD (1 << 5) |
41 | #define MAX8649_VID_MASK (3 << 5) | 41 | #define MAX8649_VID_MASK (3 << 5) |
42 | 42 | ||
43 | #define MAX8649_FORCE_PWM (1 << 7) | 43 | #define MAX8649_FORCE_PWM (1 << 7) |
44 | #define MAX8649_SYNC_EXTCLK (1 << 6) | 44 | #define MAX8649_SYNC_EXTCLK (1 << 6) |
45 | 45 | ||
46 | #define MAX8649_EXT_MASK (3 << 6) | 46 | #define MAX8649_EXT_MASK (3 << 6) |
47 | 47 | ||
48 | #define MAX8649_RAMP_MASK (7 << 5) | 48 | #define MAX8649_RAMP_MASK (7 << 5) |
49 | #define MAX8649_RAMP_DOWN (1 << 1) | 49 | #define MAX8649_RAMP_DOWN (1 << 1) |
50 | 50 | ||
51 | struct max8649_regulator_info { | 51 | struct max8649_regulator_info { |
52 | struct regulator_dev *regulator; | 52 | struct regulator_dev *regulator; |
53 | struct device *dev; | 53 | struct device *dev; |
54 | struct regmap *regmap; | 54 | struct regmap *regmap; |
55 | 55 | ||
56 | unsigned mode:2; /* bit[1:0] = VID1, VID0 */ | 56 | unsigned mode:2; /* bit[1:0] = VID1, VID0 */ |
57 | unsigned extclk_freq:2; | 57 | unsigned extclk_freq:2; |
58 | unsigned extclk:1; | 58 | unsigned extclk:1; |
59 | unsigned ramp_timing:3; | 59 | unsigned ramp_timing:3; |
60 | unsigned ramp_down:1; | 60 | unsigned ramp_down:1; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | /* EN_PD means pulldown on EN input */ | 63 | /* EN_PD means pulldown on EN input */ |
64 | static int max8649_enable(struct regulator_dev *rdev) | 64 | static int max8649_enable(struct regulator_dev *rdev) |
65 | { | 65 | { |
66 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 66 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
67 | return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0); | 67 | return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0); |
68 | } | 68 | } |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Applied internal pulldown resistor on EN input pin. | 71 | * Applied internal pulldown resistor on EN input pin. |
72 | * If pulldown EN pin outside, it would be better. | 72 | * If pulldown EN pin outside, it would be better. |
73 | */ | 73 | */ |
74 | static int max8649_disable(struct regulator_dev *rdev) | 74 | static int max8649_disable(struct regulator_dev *rdev) |
75 | { | 75 | { |
76 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 76 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
77 | return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, | 77 | return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, |
78 | MAX8649_EN_PD); | 78 | MAX8649_EN_PD); |
79 | } | 79 | } |
80 | 80 | ||
81 | static int max8649_is_enabled(struct regulator_dev *rdev) | 81 | static int max8649_is_enabled(struct regulator_dev *rdev) |
82 | { | 82 | { |
83 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 83 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
84 | unsigned int val; | 84 | unsigned int val; |
85 | int ret; | 85 | int ret; |
86 | 86 | ||
87 | ret = regmap_read(info->regmap, MAX8649_CONTROL, &val); | 87 | ret = regmap_read(info->regmap, MAX8649_CONTROL, &val); |
88 | if (ret != 0) | 88 | if (ret != 0) |
89 | return ret; | 89 | return ret; |
90 | return !((unsigned char)val & MAX8649_EN_PD); | 90 | return !((unsigned char)val & MAX8649_EN_PD); |
91 | } | 91 | } |
92 | 92 | ||
93 | static int max8649_enable_time(struct regulator_dev *rdev) | 93 | static int max8649_enable_time(struct regulator_dev *rdev) |
94 | { | 94 | { |
95 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 95 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
96 | int voltage, rate, ret; | 96 | int voltage, rate, ret; |
97 | unsigned int val; | 97 | unsigned int val; |
98 | 98 | ||
99 | /* get voltage */ | 99 | /* get voltage */ |
100 | ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); | 100 | ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); |
101 | if (ret != 0) | 101 | if (ret != 0) |
102 | return ret; | 102 | return ret; |
103 | val &= MAX8649_VOL_MASK; | 103 | val &= MAX8649_VOL_MASK; |
104 | voltage = regulator_list_voltage_linear(rdev, (unsigned char)val); | 104 | voltage = regulator_list_voltage_linear(rdev, (unsigned char)val); |
105 | 105 | ||
106 | /* get rate */ | 106 | /* get rate */ |
107 | ret = regmap_read(info->regmap, MAX8649_RAMP, &val); | 107 | ret = regmap_read(info->regmap, MAX8649_RAMP, &val); |
108 | if (ret != 0) | 108 | if (ret != 0) |
109 | return ret; | 109 | return ret; |
110 | ret = (val & MAX8649_RAMP_MASK) >> 5; | 110 | ret = (val & MAX8649_RAMP_MASK) >> 5; |
111 | rate = (32 * 1000) >> ret; /* uV/uS */ | 111 | rate = (32 * 1000) >> ret; /* uV/uS */ |
112 | 112 | ||
113 | return DIV_ROUND_UP(voltage, rate); | 113 | return DIV_ROUND_UP(voltage, rate); |
114 | } | 114 | } |
115 | 115 | ||
116 | static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) | 116 | static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) |
117 | { | 117 | { |
118 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 118 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
119 | 119 | ||
120 | switch (mode) { | 120 | switch (mode) { |
121 | case REGULATOR_MODE_FAST: | 121 | case REGULATOR_MODE_FAST: |
122 | regmap_update_bits(info->regmap, rdev->desc->vsel_reg, | 122 | regmap_update_bits(info->regmap, rdev->desc->vsel_reg, |
123 | MAX8649_FORCE_PWM, MAX8649_FORCE_PWM); | 123 | MAX8649_FORCE_PWM, MAX8649_FORCE_PWM); |
124 | break; | 124 | break; |
125 | case REGULATOR_MODE_NORMAL: | 125 | case REGULATOR_MODE_NORMAL: |
126 | regmap_update_bits(info->regmap, rdev->desc->vsel_reg, | 126 | regmap_update_bits(info->regmap, rdev->desc->vsel_reg, |
127 | MAX8649_FORCE_PWM, 0); | 127 | MAX8649_FORCE_PWM, 0); |
128 | break; | 128 | break; |
129 | default: | 129 | default: |
130 | return -EINVAL; | 130 | return -EINVAL; |
131 | } | 131 | } |
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | 134 | ||
135 | static unsigned int max8649_get_mode(struct regulator_dev *rdev) | 135 | static unsigned int max8649_get_mode(struct regulator_dev *rdev) |
136 | { | 136 | { |
137 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); | 137 | struct max8649_regulator_info *info = rdev_get_drvdata(rdev); |
138 | unsigned int val; | 138 | unsigned int val; |
139 | int ret; | 139 | int ret; |
140 | 140 | ||
141 | ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); | 141 | ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); |
142 | if (ret != 0) | 142 | if (ret != 0) |
143 | return ret; | 143 | return ret; |
144 | if (val & MAX8649_FORCE_PWM) | 144 | if (val & MAX8649_FORCE_PWM) |
145 | return REGULATOR_MODE_FAST; | 145 | return REGULATOR_MODE_FAST; |
146 | return REGULATOR_MODE_NORMAL; | 146 | return REGULATOR_MODE_NORMAL; |
147 | } | 147 | } |
148 | 148 | ||
149 | static struct regulator_ops max8649_dcdc_ops = { | 149 | static struct regulator_ops max8649_dcdc_ops = { |
150 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | 150 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
151 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 151 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
152 | .list_voltage = regulator_list_voltage_linear, | 152 | .list_voltage = regulator_list_voltage_linear, |
153 | .map_voltage = regulator_map_voltage_linear, | 153 | .map_voltage = regulator_map_voltage_linear, |
154 | .enable = max8649_enable, | 154 | .enable = max8649_enable, |
155 | .disable = max8649_disable, | 155 | .disable = max8649_disable, |
156 | .is_enabled = max8649_is_enabled, | 156 | .is_enabled = max8649_is_enabled, |
157 | .enable_time = max8649_enable_time, | 157 | .enable_time = max8649_enable_time, |
158 | .set_mode = max8649_set_mode, | 158 | .set_mode = max8649_set_mode, |
159 | .get_mode = max8649_get_mode, | 159 | .get_mode = max8649_get_mode, |
160 | 160 | ||
161 | }; | 161 | }; |
162 | 162 | ||
163 | static struct regulator_desc dcdc_desc = { | 163 | static struct regulator_desc dcdc_desc = { |
164 | .name = "max8649", | 164 | .name = "max8649", |
165 | .ops = &max8649_dcdc_ops, | 165 | .ops = &max8649_dcdc_ops, |
166 | .type = REGULATOR_VOLTAGE, | 166 | .type = REGULATOR_VOLTAGE, |
167 | .n_voltages = 1 << 6, | 167 | .n_voltages = 1 << 6, |
168 | .owner = THIS_MODULE, | 168 | .owner = THIS_MODULE, |
169 | .vsel_mask = MAX8649_VOL_MASK, | 169 | .vsel_mask = MAX8649_VOL_MASK, |
170 | .min_uV = MAX8649_DCDC_VMIN, | 170 | .min_uV = MAX8649_DCDC_VMIN, |
171 | .uV_step = MAX8649_DCDC_STEP, | 171 | .uV_step = MAX8649_DCDC_STEP, |
172 | }; | 172 | }; |
173 | 173 | ||
174 | static struct regmap_config max8649_regmap_config = { | 174 | static struct regmap_config max8649_regmap_config = { |
175 | .reg_bits = 8, | 175 | .reg_bits = 8, |
176 | .val_bits = 8, | 176 | .val_bits = 8, |
177 | }; | 177 | }; |
178 | 178 | ||
179 | static int max8649_regulator_probe(struct i2c_client *client, | 179 | static int max8649_regulator_probe(struct i2c_client *client, |
180 | const struct i2c_device_id *id) | 180 | const struct i2c_device_id *id) |
181 | { | 181 | { |
182 | struct max8649_platform_data *pdata = client->dev.platform_data; | 182 | struct max8649_platform_data *pdata = client->dev.platform_data; |
183 | struct max8649_regulator_info *info = NULL; | 183 | struct max8649_regulator_info *info = NULL; |
184 | struct regulator_config config = { }; | 184 | struct regulator_config config = { }; |
185 | unsigned int val; | 185 | unsigned int val; |
186 | unsigned char data; | 186 | unsigned char data; |
187 | int ret; | 187 | int ret; |
188 | 188 | ||
189 | info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info), | 189 | info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info), |
190 | GFP_KERNEL); | 190 | GFP_KERNEL); |
191 | if (!info) { | 191 | if (!info) { |
192 | dev_err(&client->dev, "No enough memory\n"); | 192 | dev_err(&client->dev, "No enough memory\n"); |
193 | return -ENOMEM; | 193 | return -ENOMEM; |
194 | } | 194 | } |
195 | 195 | ||
196 | info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config); | 196 | info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config); |
197 | if (IS_ERR(info->regmap)) { | 197 | if (IS_ERR(info->regmap)) { |
198 | ret = PTR_ERR(info->regmap); | 198 | ret = PTR_ERR(info->regmap); |
199 | dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); | 199 | dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); |
200 | return ret; | 200 | return ret; |
201 | } | 201 | } |
202 | 202 | ||
203 | info->dev = &client->dev; | 203 | info->dev = &client->dev; |
204 | i2c_set_clientdata(client, info); | 204 | i2c_set_clientdata(client, info); |
205 | 205 | ||
206 | info->mode = pdata->mode; | 206 | info->mode = pdata->mode; |
207 | switch (info->mode) { | 207 | switch (info->mode) { |
208 | case 0: | 208 | case 0: |
209 | dcdc_desc.vsel_reg = MAX8649_MODE0; | 209 | dcdc_desc.vsel_reg = MAX8649_MODE0; |
210 | break; | 210 | break; |
211 | case 1: | 211 | case 1: |
212 | dcdc_desc.vsel_reg = MAX8649_MODE1; | 212 | dcdc_desc.vsel_reg = MAX8649_MODE1; |
213 | break; | 213 | break; |
214 | case 2: | 214 | case 2: |
215 | dcdc_desc.vsel_reg = MAX8649_MODE2; | 215 | dcdc_desc.vsel_reg = MAX8649_MODE2; |
216 | break; | 216 | break; |
217 | case 3: | 217 | case 3: |
218 | dcdc_desc.vsel_reg = MAX8649_MODE3; | 218 | dcdc_desc.vsel_reg = MAX8649_MODE3; |
219 | break; | 219 | break; |
220 | default: | 220 | default: |
221 | break; | 221 | break; |
222 | } | 222 | } |
223 | 223 | ||
224 | ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val); | 224 | ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val); |
225 | if (ret != 0) { | 225 | if (ret != 0) { |
226 | dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n", | 226 | dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n", |
227 | ret); | 227 | ret); |
228 | return ret; | 228 | return ret; |
229 | } | 229 | } |
230 | dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val); | 230 | dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val); |
231 | 231 | ||
232 | /* enable VID0 & VID1 */ | 232 | /* enable VID0 & VID1 */ |
233 | regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0); | 233 | regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0); |
234 | 234 | ||
235 | /* enable/disable external clock synchronization */ | 235 | /* enable/disable external clock synchronization */ |
236 | info->extclk = pdata->extclk; | 236 | info->extclk = pdata->extclk; |
237 | data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; | 237 | data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; |
238 | regmap_update_bits(info->regmap, dcdc_desc.vsel_reg, | 238 | regmap_update_bits(info->regmap, dcdc_desc.vsel_reg, |
239 | MAX8649_SYNC_EXTCLK, data); | 239 | MAX8649_SYNC_EXTCLK, data); |
240 | if (info->extclk) { | 240 | if (info->extclk) { |
241 | /* set external clock frequency */ | 241 | /* set external clock frequency */ |
242 | info->extclk_freq = pdata->extclk_freq; | 242 | info->extclk_freq = pdata->extclk_freq; |
243 | regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK, | 243 | regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK, |
244 | info->extclk_freq << 6); | 244 | info->extclk_freq << 6); |
245 | } | 245 | } |
246 | 246 | ||
247 | if (pdata->ramp_timing) { | 247 | if (pdata->ramp_timing) { |
248 | info->ramp_timing = pdata->ramp_timing; | 248 | info->ramp_timing = pdata->ramp_timing; |
249 | regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK, | 249 | regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK, |
250 | info->ramp_timing << 5); | 250 | info->ramp_timing << 5); |
251 | } | 251 | } |
252 | 252 | ||
253 | info->ramp_down = pdata->ramp_down; | 253 | info->ramp_down = pdata->ramp_down; |
254 | if (info->ramp_down) { | 254 | if (info->ramp_down) { |
255 | regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN, | 255 | regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN, |
256 | MAX8649_RAMP_DOWN); | 256 | MAX8649_RAMP_DOWN); |
257 | } | 257 | } |
258 | 258 | ||
259 | config.dev = &client->dev; | 259 | config.dev = &client->dev; |
260 | config.init_data = pdata->regulator; | 260 | config.init_data = pdata->regulator; |
261 | config.driver_data = info; | 261 | config.driver_data = info; |
262 | config.regmap = info->regmap; | 262 | config.regmap = info->regmap; |
263 | 263 | ||
264 | info->regulator = regulator_register(&dcdc_desc, &config); | 264 | info->regulator = regulator_register(&dcdc_desc, &config); |
265 | if (IS_ERR(info->regulator)) { | 265 | if (IS_ERR(info->regulator)) { |
266 | dev_err(info->dev, "failed to register regulator %s\n", | 266 | dev_err(info->dev, "failed to register regulator %s\n", |
267 | dcdc_desc.name); | 267 | dcdc_desc.name); |
268 | return PTR_ERR(info->regulator); | 268 | return PTR_ERR(info->regulator); |
269 | } | 269 | } |
270 | 270 | ||
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | 273 | ||
274 | static int max8649_regulator_remove(struct i2c_client *client) | 274 | static int max8649_regulator_remove(struct i2c_client *client) |
275 | { | 275 | { |
276 | struct max8649_regulator_info *info = i2c_get_clientdata(client); | 276 | struct max8649_regulator_info *info = i2c_get_clientdata(client); |
277 | 277 | ||
278 | if (info) { | 278 | if (info) |
279 | if (info->regulator) | 279 | regulator_unregister(info->regulator); |
280 | regulator_unregister(info->regulator); | ||
281 | } | ||
282 | 280 | ||
283 | return 0; | 281 | return 0; |
284 | } | 282 | } |
285 | 283 | ||
286 | static const struct i2c_device_id max8649_id[] = { | 284 | static const struct i2c_device_id max8649_id[] = { |
287 | { "max8649", 0 }, | 285 | { "max8649", 0 }, |
288 | { } | 286 | { } |
289 | }; | 287 | }; |
290 | MODULE_DEVICE_TABLE(i2c, max8649_id); | 288 | MODULE_DEVICE_TABLE(i2c, max8649_id); |
291 | 289 | ||
292 | static struct i2c_driver max8649_driver = { | 290 | static struct i2c_driver max8649_driver = { |
293 | .probe = max8649_regulator_probe, | 291 | .probe = max8649_regulator_probe, |
294 | .remove = max8649_regulator_remove, | 292 | .remove = max8649_regulator_remove, |
295 | .driver = { | 293 | .driver = { |
296 | .name = "max8649", | 294 | .name = "max8649", |
297 | }, | 295 | }, |
298 | .id_table = max8649_id, | 296 | .id_table = max8649_id, |
299 | }; | 297 | }; |
300 | 298 | ||
301 | static int __init max8649_init(void) | 299 | static int __init max8649_init(void) |
302 | { | 300 | { |
303 | return i2c_add_driver(&max8649_driver); | 301 | return i2c_add_driver(&max8649_driver); |
304 | } | 302 | } |
305 | subsys_initcall(max8649_init); | 303 | subsys_initcall(max8649_init); |
306 | 304 | ||
307 | static void __exit max8649_exit(void) | 305 | static void __exit max8649_exit(void) |
308 | { | 306 | { |
309 | i2c_del_driver(&max8649_driver); | 307 | i2c_del_driver(&max8649_driver); |
310 | } | 308 | } |
311 | module_exit(max8649_exit); | 309 | module_exit(max8649_exit); |
312 | 310 | ||
313 | /* Module information */ | 311 | /* Module information */ |
314 | MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver"); | 312 | MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver"); |
315 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | 313 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); |
316 | MODULE_LICENSE("GPL"); | 314 | MODULE_LICENSE("GPL"); |
317 | 315 |
drivers/regulator/max8660.c
1 | /* | 1 | /* |
2 | * max8660.c -- Voltage regulation for the Maxim 8660/8661 | 2 | * max8660.c -- Voltage regulation for the Maxim 8660/8661 |
3 | * | 3 | * |
4 | * based on max1586.c and wm8400-regulator.c | 4 | * based on max1586.c and wm8400-regulator.c |
5 | * | 5 | * |
6 | * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K. | 6 | * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the Free | 9 | * under the terms of the GNU General Public License as published by the Free |
10 | * Software Foundation; version 2 of the License. | 10 | * Software Foundation; version 2 of the License. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | 12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | * more details. | 15 | * more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License along with | 17 | * You should have received a copy of the GNU General Public License along with |
18 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 18 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
19 | * Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Place, Suite 330, Boston, MA 02111-1307 USA |
20 | * | 20 | * |
21 | * Some info: | 21 | * Some info: |
22 | * | 22 | * |
23 | * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf | 23 | * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf |
24 | * | 24 | * |
25 | * This chip is a bit nasty because it is a write-only device. Thus, the driver | 25 | * This chip is a bit nasty because it is a write-only device. Thus, the driver |
26 | * uses shadow registers to keep track of its values. The main problem appears | 26 | * uses shadow registers to keep track of its values. The main problem appears |
27 | * to be the initialization: When Linux boots up, we cannot know if the chip is | 27 | * to be the initialization: When Linux boots up, we cannot know if the chip is |
28 | * in the default state or not, so we would have to pass such information in | 28 | * in the default state or not, so we would have to pass such information in |
29 | * platform_data. As this adds a bit of complexity to the driver, this is left | 29 | * platform_data. As this adds a bit of complexity to the driver, this is left |
30 | * out for now until it is really needed. | 30 | * out for now until it is really needed. |
31 | * | 31 | * |
32 | * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2. | 32 | * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2. |
33 | * | 33 | * |
34 | * If the driver is feature complete, it might be worth to check if one set of | 34 | * If the driver is feature complete, it might be worth to check if one set of |
35 | * functions for V3-V7 is sufficient. For maximum flexibility during | 35 | * functions for V3-V7 is sufficient. For maximum flexibility during |
36 | * development, they are separated for now. | 36 | * development, they are separated for now. |
37 | * | 37 | * |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/module.h> | 40 | #include <linux/module.h> |
41 | #include <linux/err.h> | 41 | #include <linux/err.h> |
42 | #include <linux/i2c.h> | 42 | #include <linux/i2c.h> |
43 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
44 | #include <linux/regulator/driver.h> | 44 | #include <linux/regulator/driver.h> |
45 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
46 | #include <linux/regulator/max8660.h> | 46 | #include <linux/regulator/max8660.h> |
47 | 47 | ||
48 | #define MAX8660_DCDC_MIN_UV 725000 | 48 | #define MAX8660_DCDC_MIN_UV 725000 |
49 | #define MAX8660_DCDC_MAX_UV 1800000 | 49 | #define MAX8660_DCDC_MAX_UV 1800000 |
50 | #define MAX8660_DCDC_STEP 25000 | 50 | #define MAX8660_DCDC_STEP 25000 |
51 | #define MAX8660_DCDC_MAX_SEL 0x2b | 51 | #define MAX8660_DCDC_MAX_SEL 0x2b |
52 | 52 | ||
53 | #define MAX8660_LDO5_MIN_UV 1700000 | 53 | #define MAX8660_LDO5_MIN_UV 1700000 |
54 | #define MAX8660_LDO5_MAX_UV 2000000 | 54 | #define MAX8660_LDO5_MAX_UV 2000000 |
55 | #define MAX8660_LDO5_STEP 25000 | 55 | #define MAX8660_LDO5_STEP 25000 |
56 | #define MAX8660_LDO5_MAX_SEL 0x0c | 56 | #define MAX8660_LDO5_MAX_SEL 0x0c |
57 | 57 | ||
58 | #define MAX8660_LDO67_MIN_UV 1800000 | 58 | #define MAX8660_LDO67_MIN_UV 1800000 |
59 | #define MAX8660_LDO67_MAX_UV 3300000 | 59 | #define MAX8660_LDO67_MAX_UV 3300000 |
60 | #define MAX8660_LDO67_STEP 100000 | 60 | #define MAX8660_LDO67_STEP 100000 |
61 | #define MAX8660_LDO67_MAX_SEL 0x0f | 61 | #define MAX8660_LDO67_MAX_SEL 0x0f |
62 | 62 | ||
63 | enum { | 63 | enum { |
64 | MAX8660_OVER1, | 64 | MAX8660_OVER1, |
65 | MAX8660_OVER2, | 65 | MAX8660_OVER2, |
66 | MAX8660_VCC1, | 66 | MAX8660_VCC1, |
67 | MAX8660_ADTV1, | 67 | MAX8660_ADTV1, |
68 | MAX8660_ADTV2, | 68 | MAX8660_ADTV2, |
69 | MAX8660_SDTV1, | 69 | MAX8660_SDTV1, |
70 | MAX8660_SDTV2, | 70 | MAX8660_SDTV2, |
71 | MAX8660_MDTV1, | 71 | MAX8660_MDTV1, |
72 | MAX8660_MDTV2, | 72 | MAX8660_MDTV2, |
73 | MAX8660_L12VCR, | 73 | MAX8660_L12VCR, |
74 | MAX8660_FPWM, | 74 | MAX8660_FPWM, |
75 | MAX8660_N_REGS, /* not a real register */ | 75 | MAX8660_N_REGS, /* not a real register */ |
76 | }; | 76 | }; |
77 | 77 | ||
78 | struct max8660 { | 78 | struct max8660 { |
79 | struct i2c_client *client; | 79 | struct i2c_client *client; |
80 | u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */ | 80 | u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */ |
81 | struct regulator_dev *rdev[]; | 81 | struct regulator_dev *rdev[]; |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val) | 84 | static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val) |
85 | { | 85 | { |
86 | static const u8 max8660_addresses[MAX8660_N_REGS] = | 86 | static const u8 max8660_addresses[MAX8660_N_REGS] = |
87 | { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 }; | 87 | { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 }; |
88 | 88 | ||
89 | int ret; | 89 | int ret; |
90 | u8 reg_val = (max8660->shadow_regs[reg] & mask) | val; | 90 | u8 reg_val = (max8660->shadow_regs[reg] & mask) | val; |
91 | dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n", | 91 | dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n", |
92 | max8660_addresses[reg], reg_val); | 92 | max8660_addresses[reg], reg_val); |
93 | 93 | ||
94 | ret = i2c_smbus_write_byte_data(max8660->client, | 94 | ret = i2c_smbus_write_byte_data(max8660->client, |
95 | max8660_addresses[reg], reg_val); | 95 | max8660_addresses[reg], reg_val); |
96 | if (ret == 0) | 96 | if (ret == 0) |
97 | max8660->shadow_regs[reg] = reg_val; | 97 | max8660->shadow_regs[reg] = reg_val; |
98 | 98 | ||
99 | return ret; | 99 | return ret; |
100 | } | 100 | } |
101 | 101 | ||
102 | 102 | ||
103 | /* | 103 | /* |
104 | * DCDC functions | 104 | * DCDC functions |
105 | */ | 105 | */ |
106 | 106 | ||
107 | static int max8660_dcdc_is_enabled(struct regulator_dev *rdev) | 107 | static int max8660_dcdc_is_enabled(struct regulator_dev *rdev) |
108 | { | 108 | { |
109 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 109 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
110 | u8 val = max8660->shadow_regs[MAX8660_OVER1]; | 110 | u8 val = max8660->shadow_regs[MAX8660_OVER1]; |
111 | u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; | 111 | u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; |
112 | return !!(val & mask); | 112 | return !!(val & mask); |
113 | } | 113 | } |
114 | 114 | ||
115 | static int max8660_dcdc_enable(struct regulator_dev *rdev) | 115 | static int max8660_dcdc_enable(struct regulator_dev *rdev) |
116 | { | 116 | { |
117 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 117 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
118 | u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; | 118 | u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; |
119 | return max8660_write(max8660, MAX8660_OVER1, 0xff, bit); | 119 | return max8660_write(max8660, MAX8660_OVER1, 0xff, bit); |
120 | } | 120 | } |
121 | 121 | ||
122 | static int max8660_dcdc_disable(struct regulator_dev *rdev) | 122 | static int max8660_dcdc_disable(struct regulator_dev *rdev) |
123 | { | 123 | { |
124 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 124 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
125 | u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4; | 125 | u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4; |
126 | return max8660_write(max8660, MAX8660_OVER1, mask, 0); | 126 | return max8660_write(max8660, MAX8660_OVER1, mask, 0); |
127 | } | 127 | } |
128 | 128 | ||
129 | static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev) | 129 | static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev) |
130 | { | 130 | { |
131 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 131 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
132 | 132 | ||
133 | u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; | 133 | u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; |
134 | u8 selector = max8660->shadow_regs[reg]; | 134 | u8 selector = max8660->shadow_regs[reg]; |
135 | return selector; | 135 | return selector; |
136 | } | 136 | } |
137 | 137 | ||
138 | static int max8660_dcdc_set_voltage_sel(struct regulator_dev *rdev, | 138 | static int max8660_dcdc_set_voltage_sel(struct regulator_dev *rdev, |
139 | unsigned int selector) | 139 | unsigned int selector) |
140 | { | 140 | { |
141 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 141 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
142 | u8 reg, bits; | 142 | u8 reg, bits; |
143 | int ret; | 143 | int ret; |
144 | 144 | ||
145 | reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; | 145 | reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; |
146 | ret = max8660_write(max8660, reg, 0, selector); | 146 | ret = max8660_write(max8660, reg, 0, selector); |
147 | if (ret) | 147 | if (ret) |
148 | return ret; | 148 | return ret; |
149 | 149 | ||
150 | /* Select target voltage register and activate regulation */ | 150 | /* Select target voltage register and activate regulation */ |
151 | bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30; | 151 | bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30; |
152 | return max8660_write(max8660, MAX8660_VCC1, 0xff, bits); | 152 | return max8660_write(max8660, MAX8660_VCC1, 0xff, bits); |
153 | } | 153 | } |
154 | 154 | ||
155 | static struct regulator_ops max8660_dcdc_ops = { | 155 | static struct regulator_ops max8660_dcdc_ops = { |
156 | .is_enabled = max8660_dcdc_is_enabled, | 156 | .is_enabled = max8660_dcdc_is_enabled, |
157 | .list_voltage = regulator_list_voltage_linear, | 157 | .list_voltage = regulator_list_voltage_linear, |
158 | .map_voltage = regulator_map_voltage_linear, | 158 | .map_voltage = regulator_map_voltage_linear, |
159 | .set_voltage_sel = max8660_dcdc_set_voltage_sel, | 159 | .set_voltage_sel = max8660_dcdc_set_voltage_sel, |
160 | .get_voltage_sel = max8660_dcdc_get_voltage_sel, | 160 | .get_voltage_sel = max8660_dcdc_get_voltage_sel, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | 163 | ||
164 | /* | 164 | /* |
165 | * LDO5 functions | 165 | * LDO5 functions |
166 | */ | 166 | */ |
167 | 167 | ||
168 | static int max8660_ldo5_get_voltage_sel(struct regulator_dev *rdev) | 168 | static int max8660_ldo5_get_voltage_sel(struct regulator_dev *rdev) |
169 | { | 169 | { |
170 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 170 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
171 | 171 | ||
172 | u8 selector = max8660->shadow_regs[MAX8660_MDTV2]; | 172 | u8 selector = max8660->shadow_regs[MAX8660_MDTV2]; |
173 | return selector; | 173 | return selector; |
174 | } | 174 | } |
175 | 175 | ||
176 | static int max8660_ldo5_set_voltage_sel(struct regulator_dev *rdev, | 176 | static int max8660_ldo5_set_voltage_sel(struct regulator_dev *rdev, |
177 | unsigned int selector) | 177 | unsigned int selector) |
178 | { | 178 | { |
179 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 179 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
180 | int ret; | 180 | int ret; |
181 | 181 | ||
182 | ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); | 182 | ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); |
183 | if (ret) | 183 | if (ret) |
184 | return ret; | 184 | return ret; |
185 | 185 | ||
186 | /* Select target voltage register and activate regulation */ | 186 | /* Select target voltage register and activate regulation */ |
187 | return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0); | 187 | return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0); |
188 | } | 188 | } |
189 | 189 | ||
190 | static struct regulator_ops max8660_ldo5_ops = { | 190 | static struct regulator_ops max8660_ldo5_ops = { |
191 | .list_voltage = regulator_list_voltage_linear, | 191 | .list_voltage = regulator_list_voltage_linear, |
192 | .map_voltage = regulator_map_voltage_linear, | 192 | .map_voltage = regulator_map_voltage_linear, |
193 | .set_voltage_sel = max8660_ldo5_set_voltage_sel, | 193 | .set_voltage_sel = max8660_ldo5_set_voltage_sel, |
194 | .get_voltage_sel = max8660_ldo5_get_voltage_sel, | 194 | .get_voltage_sel = max8660_ldo5_get_voltage_sel, |
195 | }; | 195 | }; |
196 | 196 | ||
197 | 197 | ||
198 | /* | 198 | /* |
199 | * LDO67 functions | 199 | * LDO67 functions |
200 | */ | 200 | */ |
201 | 201 | ||
202 | static int max8660_ldo67_is_enabled(struct regulator_dev *rdev) | 202 | static int max8660_ldo67_is_enabled(struct regulator_dev *rdev) |
203 | { | 203 | { |
204 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 204 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
205 | u8 val = max8660->shadow_regs[MAX8660_OVER2]; | 205 | u8 val = max8660->shadow_regs[MAX8660_OVER2]; |
206 | u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; | 206 | u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; |
207 | return !!(val & mask); | 207 | return !!(val & mask); |
208 | } | 208 | } |
209 | 209 | ||
210 | static int max8660_ldo67_enable(struct regulator_dev *rdev) | 210 | static int max8660_ldo67_enable(struct regulator_dev *rdev) |
211 | { | 211 | { |
212 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 212 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
213 | u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; | 213 | u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; |
214 | return max8660_write(max8660, MAX8660_OVER2, 0xff, bit); | 214 | return max8660_write(max8660, MAX8660_OVER2, 0xff, bit); |
215 | } | 215 | } |
216 | 216 | ||
217 | static int max8660_ldo67_disable(struct regulator_dev *rdev) | 217 | static int max8660_ldo67_disable(struct regulator_dev *rdev) |
218 | { | 218 | { |
219 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 219 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
220 | u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4; | 220 | u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4; |
221 | return max8660_write(max8660, MAX8660_OVER2, mask, 0); | 221 | return max8660_write(max8660, MAX8660_OVER2, mask, 0); |
222 | } | 222 | } |
223 | 223 | ||
224 | static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev) | 224 | static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev) |
225 | { | 225 | { |
226 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 226 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
227 | 227 | ||
228 | u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4; | 228 | u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4; |
229 | u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf; | 229 | u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf; |
230 | return selector; | 230 | return selector; |
231 | } | 231 | } |
232 | 232 | ||
233 | static int max8660_ldo67_set_voltage_sel(struct regulator_dev *rdev, | 233 | static int max8660_ldo67_set_voltage_sel(struct regulator_dev *rdev, |
234 | unsigned int selector) | 234 | unsigned int selector) |
235 | { | 235 | { |
236 | struct max8660 *max8660 = rdev_get_drvdata(rdev); | 236 | struct max8660 *max8660 = rdev_get_drvdata(rdev); |
237 | 237 | ||
238 | if (rdev_get_id(rdev) == MAX8660_V6) | 238 | if (rdev_get_id(rdev) == MAX8660_V6) |
239 | return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); | 239 | return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); |
240 | else | 240 | else |
241 | return max8660_write(max8660, MAX8660_L12VCR, 0x0f, | 241 | return max8660_write(max8660, MAX8660_L12VCR, 0x0f, |
242 | selector << 4); | 242 | selector << 4); |
243 | } | 243 | } |
244 | 244 | ||
245 | static struct regulator_ops max8660_ldo67_ops = { | 245 | static struct regulator_ops max8660_ldo67_ops = { |
246 | .is_enabled = max8660_ldo67_is_enabled, | 246 | .is_enabled = max8660_ldo67_is_enabled, |
247 | .enable = max8660_ldo67_enable, | 247 | .enable = max8660_ldo67_enable, |
248 | .disable = max8660_ldo67_disable, | 248 | .disable = max8660_ldo67_disable, |
249 | .list_voltage = regulator_list_voltage_linear, | 249 | .list_voltage = regulator_list_voltage_linear, |
250 | .map_voltage = regulator_map_voltage_linear, | 250 | .map_voltage = regulator_map_voltage_linear, |
251 | .get_voltage_sel = max8660_ldo67_get_voltage_sel, | 251 | .get_voltage_sel = max8660_ldo67_get_voltage_sel, |
252 | .set_voltage_sel = max8660_ldo67_set_voltage_sel, | 252 | .set_voltage_sel = max8660_ldo67_set_voltage_sel, |
253 | }; | 253 | }; |
254 | 254 | ||
255 | static const struct regulator_desc max8660_reg[] = { | 255 | static const struct regulator_desc max8660_reg[] = { |
256 | { | 256 | { |
257 | .name = "V3(DCDC)", | 257 | .name = "V3(DCDC)", |
258 | .id = MAX8660_V3, | 258 | .id = MAX8660_V3, |
259 | .ops = &max8660_dcdc_ops, | 259 | .ops = &max8660_dcdc_ops, |
260 | .type = REGULATOR_VOLTAGE, | 260 | .type = REGULATOR_VOLTAGE, |
261 | .n_voltages = MAX8660_DCDC_MAX_SEL + 1, | 261 | .n_voltages = MAX8660_DCDC_MAX_SEL + 1, |
262 | .owner = THIS_MODULE, | 262 | .owner = THIS_MODULE, |
263 | .min_uV = MAX8660_DCDC_MIN_UV, | 263 | .min_uV = MAX8660_DCDC_MIN_UV, |
264 | .uV_step = MAX8660_DCDC_STEP, | 264 | .uV_step = MAX8660_DCDC_STEP, |
265 | }, | 265 | }, |
266 | { | 266 | { |
267 | .name = "V4(DCDC)", | 267 | .name = "V4(DCDC)", |
268 | .id = MAX8660_V4, | 268 | .id = MAX8660_V4, |
269 | .ops = &max8660_dcdc_ops, | 269 | .ops = &max8660_dcdc_ops, |
270 | .type = REGULATOR_VOLTAGE, | 270 | .type = REGULATOR_VOLTAGE, |
271 | .n_voltages = MAX8660_DCDC_MAX_SEL + 1, | 271 | .n_voltages = MAX8660_DCDC_MAX_SEL + 1, |
272 | .owner = THIS_MODULE, | 272 | .owner = THIS_MODULE, |
273 | .min_uV = MAX8660_DCDC_MIN_UV, | 273 | .min_uV = MAX8660_DCDC_MIN_UV, |
274 | .uV_step = MAX8660_DCDC_STEP, | 274 | .uV_step = MAX8660_DCDC_STEP, |
275 | }, | 275 | }, |
276 | { | 276 | { |
277 | .name = "V5(LDO)", | 277 | .name = "V5(LDO)", |
278 | .id = MAX8660_V5, | 278 | .id = MAX8660_V5, |
279 | .ops = &max8660_ldo5_ops, | 279 | .ops = &max8660_ldo5_ops, |
280 | .type = REGULATOR_VOLTAGE, | 280 | .type = REGULATOR_VOLTAGE, |
281 | .n_voltages = MAX8660_LDO5_MAX_SEL + 1, | 281 | .n_voltages = MAX8660_LDO5_MAX_SEL + 1, |
282 | .owner = THIS_MODULE, | 282 | .owner = THIS_MODULE, |
283 | .min_uV = MAX8660_LDO5_MIN_UV, | 283 | .min_uV = MAX8660_LDO5_MIN_UV, |
284 | .uV_step = MAX8660_LDO5_STEP, | 284 | .uV_step = MAX8660_LDO5_STEP, |
285 | }, | 285 | }, |
286 | { | 286 | { |
287 | .name = "V6(LDO)", | 287 | .name = "V6(LDO)", |
288 | .id = MAX8660_V6, | 288 | .id = MAX8660_V6, |
289 | .ops = &max8660_ldo67_ops, | 289 | .ops = &max8660_ldo67_ops, |
290 | .type = REGULATOR_VOLTAGE, | 290 | .type = REGULATOR_VOLTAGE, |
291 | .n_voltages = MAX8660_LDO67_MAX_SEL + 1, | 291 | .n_voltages = MAX8660_LDO67_MAX_SEL + 1, |
292 | .owner = THIS_MODULE, | 292 | .owner = THIS_MODULE, |
293 | .min_uV = MAX8660_LDO67_MIN_UV, | 293 | .min_uV = MAX8660_LDO67_MIN_UV, |
294 | .uV_step = MAX8660_LDO67_STEP, | 294 | .uV_step = MAX8660_LDO67_STEP, |
295 | }, | 295 | }, |
296 | { | 296 | { |
297 | .name = "V7(LDO)", | 297 | .name = "V7(LDO)", |
298 | .id = MAX8660_V7, | 298 | .id = MAX8660_V7, |
299 | .ops = &max8660_ldo67_ops, | 299 | .ops = &max8660_ldo67_ops, |
300 | .type = REGULATOR_VOLTAGE, | 300 | .type = REGULATOR_VOLTAGE, |
301 | .n_voltages = MAX8660_LDO67_MAX_SEL + 1, | 301 | .n_voltages = MAX8660_LDO67_MAX_SEL + 1, |
302 | .owner = THIS_MODULE, | 302 | .owner = THIS_MODULE, |
303 | .min_uV = MAX8660_LDO67_MIN_UV, | 303 | .min_uV = MAX8660_LDO67_MIN_UV, |
304 | .uV_step = MAX8660_LDO67_STEP, | 304 | .uV_step = MAX8660_LDO67_STEP, |
305 | }, | 305 | }, |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static int max8660_probe(struct i2c_client *client, | 308 | static int max8660_probe(struct i2c_client *client, |
309 | const struct i2c_device_id *i2c_id) | 309 | const struct i2c_device_id *i2c_id) |
310 | { | 310 | { |
311 | struct regulator_dev **rdev; | 311 | struct regulator_dev **rdev; |
312 | struct max8660_platform_data *pdata = client->dev.platform_data; | 312 | struct max8660_platform_data *pdata = client->dev.platform_data; |
313 | struct regulator_config config = { }; | 313 | struct regulator_config config = { }; |
314 | struct max8660 *max8660; | 314 | struct max8660 *max8660; |
315 | int boot_on, i, id, ret = -EINVAL; | 315 | int boot_on, i, id, ret = -EINVAL; |
316 | 316 | ||
317 | if (pdata->num_subdevs > MAX8660_V_END) { | 317 | if (pdata->num_subdevs > MAX8660_V_END) { |
318 | dev_err(&client->dev, "Too many regulators found!\n"); | 318 | dev_err(&client->dev, "Too many regulators found!\n"); |
319 | return -EINVAL; | 319 | return -EINVAL; |
320 | } | 320 | } |
321 | 321 | ||
322 | max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) + | 322 | max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) + |
323 | sizeof(struct regulator_dev *) * MAX8660_V_END, | 323 | sizeof(struct regulator_dev *) * MAX8660_V_END, |
324 | GFP_KERNEL); | 324 | GFP_KERNEL); |
325 | if (!max8660) | 325 | if (!max8660) |
326 | return -ENOMEM; | 326 | return -ENOMEM; |
327 | 327 | ||
328 | max8660->client = client; | 328 | max8660->client = client; |
329 | rdev = max8660->rdev; | 329 | rdev = max8660->rdev; |
330 | 330 | ||
331 | if (pdata->en34_is_high) { | 331 | if (pdata->en34_is_high) { |
332 | /* Simulate always on */ | 332 | /* Simulate always on */ |
333 | max8660->shadow_regs[MAX8660_OVER1] = 5; | 333 | max8660->shadow_regs[MAX8660_OVER1] = 5; |
334 | } else { | 334 | } else { |
335 | /* Otherwise devices can be toggled via software */ | 335 | /* Otherwise devices can be toggled via software */ |
336 | max8660_dcdc_ops.enable = max8660_dcdc_enable; | 336 | max8660_dcdc_ops.enable = max8660_dcdc_enable; |
337 | max8660_dcdc_ops.disable = max8660_dcdc_disable; | 337 | max8660_dcdc_ops.disable = max8660_dcdc_disable; |
338 | } | 338 | } |
339 | 339 | ||
340 | /* | 340 | /* |
341 | * First, set up shadow registers to prevent glitches. As some | 341 | * First, set up shadow registers to prevent glitches. As some |
342 | * registers are shared between regulators, everything must be properly | 342 | * registers are shared between regulators, everything must be properly |
343 | * set up for all regulators in advance. | 343 | * set up for all regulators in advance. |
344 | */ | 344 | */ |
345 | max8660->shadow_regs[MAX8660_ADTV1] = | 345 | max8660->shadow_regs[MAX8660_ADTV1] = |
346 | max8660->shadow_regs[MAX8660_ADTV2] = | 346 | max8660->shadow_regs[MAX8660_ADTV2] = |
347 | max8660->shadow_regs[MAX8660_SDTV1] = | 347 | max8660->shadow_regs[MAX8660_SDTV1] = |
348 | max8660->shadow_regs[MAX8660_SDTV2] = 0x1b; | 348 | max8660->shadow_regs[MAX8660_SDTV2] = 0x1b; |
349 | max8660->shadow_regs[MAX8660_MDTV1] = | 349 | max8660->shadow_regs[MAX8660_MDTV1] = |
350 | max8660->shadow_regs[MAX8660_MDTV2] = 0x04; | 350 | max8660->shadow_regs[MAX8660_MDTV2] = 0x04; |
351 | 351 | ||
352 | for (i = 0; i < pdata->num_subdevs; i++) { | 352 | for (i = 0; i < pdata->num_subdevs; i++) { |
353 | 353 | ||
354 | if (!pdata->subdevs[i].platform_data) | 354 | if (!pdata->subdevs[i].platform_data) |
355 | goto err_out; | 355 | goto err_out; |
356 | 356 | ||
357 | boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; | 357 | boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; |
358 | 358 | ||
359 | switch (pdata->subdevs[i].id) { | 359 | switch (pdata->subdevs[i].id) { |
360 | case MAX8660_V3: | 360 | case MAX8660_V3: |
361 | if (boot_on) | 361 | if (boot_on) |
362 | max8660->shadow_regs[MAX8660_OVER1] |= 1; | 362 | max8660->shadow_regs[MAX8660_OVER1] |= 1; |
363 | break; | 363 | break; |
364 | 364 | ||
365 | case MAX8660_V4: | 365 | case MAX8660_V4: |
366 | if (boot_on) | 366 | if (boot_on) |
367 | max8660->shadow_regs[MAX8660_OVER1] |= 4; | 367 | max8660->shadow_regs[MAX8660_OVER1] |= 4; |
368 | break; | 368 | break; |
369 | 369 | ||
370 | case MAX8660_V5: | 370 | case MAX8660_V5: |
371 | break; | 371 | break; |
372 | 372 | ||
373 | case MAX8660_V6: | 373 | case MAX8660_V6: |
374 | if (boot_on) | 374 | if (boot_on) |
375 | max8660->shadow_regs[MAX8660_OVER2] |= 2; | 375 | max8660->shadow_regs[MAX8660_OVER2] |= 2; |
376 | break; | 376 | break; |
377 | 377 | ||
378 | case MAX8660_V7: | 378 | case MAX8660_V7: |
379 | if (!strcmp(i2c_id->name, "max8661")) { | 379 | if (!strcmp(i2c_id->name, "max8661")) { |
380 | dev_err(&client->dev, "Regulator not on this chip!\n"); | 380 | dev_err(&client->dev, "Regulator not on this chip!\n"); |
381 | goto err_out; | 381 | goto err_out; |
382 | } | 382 | } |
383 | 383 | ||
384 | if (boot_on) | 384 | if (boot_on) |
385 | max8660->shadow_regs[MAX8660_OVER2] |= 4; | 385 | max8660->shadow_regs[MAX8660_OVER2] |= 4; |
386 | break; | 386 | break; |
387 | 387 | ||
388 | default: | 388 | default: |
389 | dev_err(&client->dev, "invalid regulator %s\n", | 389 | dev_err(&client->dev, "invalid regulator %s\n", |
390 | pdata->subdevs[i].name); | 390 | pdata->subdevs[i].name); |
391 | goto err_out; | 391 | goto err_out; |
392 | } | 392 | } |
393 | } | 393 | } |
394 | 394 | ||
395 | /* Finally register devices */ | 395 | /* Finally register devices */ |
396 | for (i = 0; i < pdata->num_subdevs; i++) { | 396 | for (i = 0; i < pdata->num_subdevs; i++) { |
397 | 397 | ||
398 | id = pdata->subdevs[i].id; | 398 | id = pdata->subdevs[i].id; |
399 | 399 | ||
400 | config.dev = &client->dev; | 400 | config.dev = &client->dev; |
401 | config.init_data = pdata->subdevs[i].platform_data; | 401 | config.init_data = pdata->subdevs[i].platform_data; |
402 | config.driver_data = max8660; | 402 | config.driver_data = max8660; |
403 | 403 | ||
404 | rdev[i] = regulator_register(&max8660_reg[id], &config); | 404 | rdev[i] = regulator_register(&max8660_reg[id], &config); |
405 | if (IS_ERR(rdev[i])) { | 405 | if (IS_ERR(rdev[i])) { |
406 | ret = PTR_ERR(rdev[i]); | 406 | ret = PTR_ERR(rdev[i]); |
407 | dev_err(&client->dev, "failed to register %s\n", | 407 | dev_err(&client->dev, "failed to register %s\n", |
408 | max8660_reg[id].name); | 408 | max8660_reg[id].name); |
409 | goto err_unregister; | 409 | goto err_unregister; |
410 | } | 410 | } |
411 | } | 411 | } |
412 | 412 | ||
413 | i2c_set_clientdata(client, max8660); | 413 | i2c_set_clientdata(client, max8660); |
414 | return 0; | 414 | return 0; |
415 | 415 | ||
416 | err_unregister: | 416 | err_unregister: |
417 | while (--i >= 0) | 417 | while (--i >= 0) |
418 | regulator_unregister(rdev[i]); | 418 | regulator_unregister(rdev[i]); |
419 | err_out: | 419 | err_out: |
420 | return ret; | 420 | return ret; |
421 | } | 421 | } |
422 | 422 | ||
423 | static int max8660_remove(struct i2c_client *client) | 423 | static int max8660_remove(struct i2c_client *client) |
424 | { | 424 | { |
425 | struct max8660 *max8660 = i2c_get_clientdata(client); | 425 | struct max8660 *max8660 = i2c_get_clientdata(client); |
426 | int i; | 426 | int i; |
427 | 427 | ||
428 | for (i = 0; i < MAX8660_V_END; i++) | 428 | for (i = 0; i < MAX8660_V_END; i++) |
429 | if (max8660->rdev[i]) | 429 | regulator_unregister(max8660->rdev[i]); |
430 | regulator_unregister(max8660->rdev[i]); | ||
431 | return 0; | 430 | return 0; |
432 | } | 431 | } |
433 | 432 | ||
434 | static const struct i2c_device_id max8660_id[] = { | 433 | static const struct i2c_device_id max8660_id[] = { |
435 | { "max8660", 0 }, | 434 | { "max8660", 0 }, |
436 | { "max8661", 0 }, | 435 | { "max8661", 0 }, |
437 | { } | 436 | { } |
438 | }; | 437 | }; |
439 | MODULE_DEVICE_TABLE(i2c, max8660_id); | 438 | MODULE_DEVICE_TABLE(i2c, max8660_id); |
440 | 439 | ||
441 | static struct i2c_driver max8660_driver = { | 440 | static struct i2c_driver max8660_driver = { |
442 | .probe = max8660_probe, | 441 | .probe = max8660_probe, |
443 | .remove = max8660_remove, | 442 | .remove = max8660_remove, |
444 | .driver = { | 443 | .driver = { |
445 | .name = "max8660", | 444 | .name = "max8660", |
446 | .owner = THIS_MODULE, | 445 | .owner = THIS_MODULE, |
447 | }, | 446 | }, |
448 | .id_table = max8660_id, | 447 | .id_table = max8660_id, |
449 | }; | 448 | }; |
450 | 449 | ||
451 | static int __init max8660_init(void) | 450 | static int __init max8660_init(void) |
452 | { | 451 | { |
453 | return i2c_add_driver(&max8660_driver); | 452 | return i2c_add_driver(&max8660_driver); |
454 | } | 453 | } |
455 | subsys_initcall(max8660_init); | 454 | subsys_initcall(max8660_init); |
456 | 455 | ||
457 | static void __exit max8660_exit(void) | 456 | static void __exit max8660_exit(void) |
458 | { | 457 | { |
459 | i2c_del_driver(&max8660_driver); | 458 | i2c_del_driver(&max8660_driver); |
460 | } | 459 | } |
461 | module_exit(max8660_exit); | 460 | module_exit(max8660_exit); |
462 | 461 | ||
463 | /* Module information */ | 462 | /* Module information */ |
464 | MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver"); | 463 | MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver"); |
465 | MODULE_AUTHOR("Wolfram Sang"); | 464 | MODULE_AUTHOR("Wolfram Sang"); |
466 | MODULE_LICENSE("GPL v2"); | 465 | MODULE_LICENSE("GPL v2"); |
467 | 466 |
drivers/regulator/s5m8767.c
1 | /* | 1 | /* |
2 | * s5m8767.c | 2 | * s5m8767.c |
3 | * | 3 | * |
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd | 4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd |
5 | * http://www.samsung.com | 5 | * http://www.samsung.com |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
9 | * Free Software Foundation; either version 2 of the License, or (at your | 9 | * Free Software Foundation; either version 2 of the License, or (at your |
10 | * option) any later version. | 10 | * option) any later version. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
17 | #include <linux/of_gpio.h> | 17 | #include <linux/of_gpio.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/regulator/driver.h> | 21 | #include <linux/regulator/driver.h> |
22 | #include <linux/regulator/machine.h> | 22 | #include <linux/regulator/machine.h> |
23 | #include <linux/mfd/samsung/core.h> | 23 | #include <linux/mfd/samsung/core.h> |
24 | #include <linux/mfd/samsung/s5m8767.h> | 24 | #include <linux/mfd/samsung/s5m8767.h> |
25 | #include <linux/regulator/of_regulator.h> | 25 | #include <linux/regulator/of_regulator.h> |
26 | 26 | ||
27 | #define S5M8767_OPMODE_NORMAL_MODE 0x1 | 27 | #define S5M8767_OPMODE_NORMAL_MODE 0x1 |
28 | 28 | ||
29 | struct s5m8767_info { | 29 | struct s5m8767_info { |
30 | struct device *dev; | 30 | struct device *dev; |
31 | struct sec_pmic_dev *iodev; | 31 | struct sec_pmic_dev *iodev; |
32 | int num_regulators; | 32 | int num_regulators; |
33 | struct regulator_dev **rdev; | 33 | struct regulator_dev **rdev; |
34 | struct sec_opmode_data *opmode; | 34 | struct sec_opmode_data *opmode; |
35 | 35 | ||
36 | int ramp_delay; | 36 | int ramp_delay; |
37 | bool buck2_ramp; | 37 | bool buck2_ramp; |
38 | bool buck3_ramp; | 38 | bool buck3_ramp; |
39 | bool buck4_ramp; | 39 | bool buck4_ramp; |
40 | 40 | ||
41 | bool buck2_gpiodvs; | 41 | bool buck2_gpiodvs; |
42 | bool buck3_gpiodvs; | 42 | bool buck3_gpiodvs; |
43 | bool buck4_gpiodvs; | 43 | bool buck4_gpiodvs; |
44 | u8 buck2_vol[8]; | 44 | u8 buck2_vol[8]; |
45 | u8 buck3_vol[8]; | 45 | u8 buck3_vol[8]; |
46 | u8 buck4_vol[8]; | 46 | u8 buck4_vol[8]; |
47 | int buck_gpios[3]; | 47 | int buck_gpios[3]; |
48 | int buck_ds[3]; | 48 | int buck_ds[3]; |
49 | int buck_gpioindex; | 49 | int buck_gpioindex; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct sec_voltage_desc { | 52 | struct sec_voltage_desc { |
53 | int max; | 53 | int max; |
54 | int min; | 54 | int min; |
55 | int step; | 55 | int step; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static const struct sec_voltage_desc buck_voltage_val1 = { | 58 | static const struct sec_voltage_desc buck_voltage_val1 = { |
59 | .max = 2225000, | 59 | .max = 2225000, |
60 | .min = 650000, | 60 | .min = 650000, |
61 | .step = 6250, | 61 | .step = 6250, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static const struct sec_voltage_desc buck_voltage_val2 = { | 64 | static const struct sec_voltage_desc buck_voltage_val2 = { |
65 | .max = 1600000, | 65 | .max = 1600000, |
66 | .min = 600000, | 66 | .min = 600000, |
67 | .step = 6250, | 67 | .step = 6250, |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static const struct sec_voltage_desc buck_voltage_val3 = { | 70 | static const struct sec_voltage_desc buck_voltage_val3 = { |
71 | .max = 3000000, | 71 | .max = 3000000, |
72 | .min = 750000, | 72 | .min = 750000, |
73 | .step = 12500, | 73 | .step = 12500, |
74 | }; | 74 | }; |
75 | 75 | ||
76 | static const struct sec_voltage_desc ldo_voltage_val1 = { | 76 | static const struct sec_voltage_desc ldo_voltage_val1 = { |
77 | .max = 3950000, | 77 | .max = 3950000, |
78 | .min = 800000, | 78 | .min = 800000, |
79 | .step = 50000, | 79 | .step = 50000, |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static const struct sec_voltage_desc ldo_voltage_val2 = { | 82 | static const struct sec_voltage_desc ldo_voltage_val2 = { |
83 | .max = 2375000, | 83 | .max = 2375000, |
84 | .min = 800000, | 84 | .min = 800000, |
85 | .step = 25000, | 85 | .step = 25000, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static const struct sec_voltage_desc *reg_voltage_map[] = { | 88 | static const struct sec_voltage_desc *reg_voltage_map[] = { |
89 | [S5M8767_LDO1] = &ldo_voltage_val2, | 89 | [S5M8767_LDO1] = &ldo_voltage_val2, |
90 | [S5M8767_LDO2] = &ldo_voltage_val2, | 90 | [S5M8767_LDO2] = &ldo_voltage_val2, |
91 | [S5M8767_LDO3] = &ldo_voltage_val1, | 91 | [S5M8767_LDO3] = &ldo_voltage_val1, |
92 | [S5M8767_LDO4] = &ldo_voltage_val1, | 92 | [S5M8767_LDO4] = &ldo_voltage_val1, |
93 | [S5M8767_LDO5] = &ldo_voltage_val1, | 93 | [S5M8767_LDO5] = &ldo_voltage_val1, |
94 | [S5M8767_LDO6] = &ldo_voltage_val2, | 94 | [S5M8767_LDO6] = &ldo_voltage_val2, |
95 | [S5M8767_LDO7] = &ldo_voltage_val2, | 95 | [S5M8767_LDO7] = &ldo_voltage_val2, |
96 | [S5M8767_LDO8] = &ldo_voltage_val2, | 96 | [S5M8767_LDO8] = &ldo_voltage_val2, |
97 | [S5M8767_LDO9] = &ldo_voltage_val1, | 97 | [S5M8767_LDO9] = &ldo_voltage_val1, |
98 | [S5M8767_LDO10] = &ldo_voltage_val1, | 98 | [S5M8767_LDO10] = &ldo_voltage_val1, |
99 | [S5M8767_LDO11] = &ldo_voltage_val1, | 99 | [S5M8767_LDO11] = &ldo_voltage_val1, |
100 | [S5M8767_LDO12] = &ldo_voltage_val1, | 100 | [S5M8767_LDO12] = &ldo_voltage_val1, |
101 | [S5M8767_LDO13] = &ldo_voltage_val1, | 101 | [S5M8767_LDO13] = &ldo_voltage_val1, |
102 | [S5M8767_LDO14] = &ldo_voltage_val1, | 102 | [S5M8767_LDO14] = &ldo_voltage_val1, |
103 | [S5M8767_LDO15] = &ldo_voltage_val2, | 103 | [S5M8767_LDO15] = &ldo_voltage_val2, |
104 | [S5M8767_LDO16] = &ldo_voltage_val1, | 104 | [S5M8767_LDO16] = &ldo_voltage_val1, |
105 | [S5M8767_LDO17] = &ldo_voltage_val1, | 105 | [S5M8767_LDO17] = &ldo_voltage_val1, |
106 | [S5M8767_LDO18] = &ldo_voltage_val1, | 106 | [S5M8767_LDO18] = &ldo_voltage_val1, |
107 | [S5M8767_LDO19] = &ldo_voltage_val1, | 107 | [S5M8767_LDO19] = &ldo_voltage_val1, |
108 | [S5M8767_LDO20] = &ldo_voltage_val1, | 108 | [S5M8767_LDO20] = &ldo_voltage_val1, |
109 | [S5M8767_LDO21] = &ldo_voltage_val1, | 109 | [S5M8767_LDO21] = &ldo_voltage_val1, |
110 | [S5M8767_LDO22] = &ldo_voltage_val1, | 110 | [S5M8767_LDO22] = &ldo_voltage_val1, |
111 | [S5M8767_LDO23] = &ldo_voltage_val1, | 111 | [S5M8767_LDO23] = &ldo_voltage_val1, |
112 | [S5M8767_LDO24] = &ldo_voltage_val1, | 112 | [S5M8767_LDO24] = &ldo_voltage_val1, |
113 | [S5M8767_LDO25] = &ldo_voltage_val1, | 113 | [S5M8767_LDO25] = &ldo_voltage_val1, |
114 | [S5M8767_LDO26] = &ldo_voltage_val1, | 114 | [S5M8767_LDO26] = &ldo_voltage_val1, |
115 | [S5M8767_LDO27] = &ldo_voltage_val1, | 115 | [S5M8767_LDO27] = &ldo_voltage_val1, |
116 | [S5M8767_LDO28] = &ldo_voltage_val1, | 116 | [S5M8767_LDO28] = &ldo_voltage_val1, |
117 | [S5M8767_BUCK1] = &buck_voltage_val1, | 117 | [S5M8767_BUCK1] = &buck_voltage_val1, |
118 | [S5M8767_BUCK2] = &buck_voltage_val2, | 118 | [S5M8767_BUCK2] = &buck_voltage_val2, |
119 | [S5M8767_BUCK3] = &buck_voltage_val2, | 119 | [S5M8767_BUCK3] = &buck_voltage_val2, |
120 | [S5M8767_BUCK4] = &buck_voltage_val2, | 120 | [S5M8767_BUCK4] = &buck_voltage_val2, |
121 | [S5M8767_BUCK5] = &buck_voltage_val1, | 121 | [S5M8767_BUCK5] = &buck_voltage_val1, |
122 | [S5M8767_BUCK6] = &buck_voltage_val1, | 122 | [S5M8767_BUCK6] = &buck_voltage_val1, |
123 | [S5M8767_BUCK7] = NULL, | 123 | [S5M8767_BUCK7] = NULL, |
124 | [S5M8767_BUCK8] = NULL, | 124 | [S5M8767_BUCK8] = NULL, |
125 | [S5M8767_BUCK9] = &buck_voltage_val3, | 125 | [S5M8767_BUCK9] = &buck_voltage_val3, |
126 | }; | 126 | }; |
127 | 127 | ||
128 | static unsigned int s5m8767_opmode_reg[][4] = { | 128 | static unsigned int s5m8767_opmode_reg[][4] = { |
129 | /* {OFF, ON, LOWPOWER, SUSPEND} */ | 129 | /* {OFF, ON, LOWPOWER, SUSPEND} */ |
130 | /* LDO1 ... LDO28 */ | 130 | /* LDO1 ... LDO28 */ |
131 | {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ | 131 | {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ |
132 | {0x0, 0x3, 0x2, 0x1}, | 132 | {0x0, 0x3, 0x2, 0x1}, |
133 | {0x0, 0x3, 0x2, 0x1}, | 133 | {0x0, 0x3, 0x2, 0x1}, |
134 | {0x0, 0x0, 0x0, 0x0}, | 134 | {0x0, 0x0, 0x0, 0x0}, |
135 | {0x0, 0x3, 0x2, 0x1}, /* LDO5 */ | 135 | {0x0, 0x3, 0x2, 0x1}, /* LDO5 */ |
136 | {0x0, 0x3, 0x2, 0x1}, | 136 | {0x0, 0x3, 0x2, 0x1}, |
137 | {0x0, 0x3, 0x2, 0x1}, | 137 | {0x0, 0x3, 0x2, 0x1}, |
138 | {0x0, 0x3, 0x2, 0x1}, | 138 | {0x0, 0x3, 0x2, 0x1}, |
139 | {0x0, 0x3, 0x2, 0x1}, | 139 | {0x0, 0x3, 0x2, 0x1}, |
140 | {0x0, 0x3, 0x2, 0x1}, /* LDO10 */ | 140 | {0x0, 0x3, 0x2, 0x1}, /* LDO10 */ |
141 | {0x0, 0x3, 0x2, 0x1}, | 141 | {0x0, 0x3, 0x2, 0x1}, |
142 | {0x0, 0x3, 0x2, 0x1}, | 142 | {0x0, 0x3, 0x2, 0x1}, |
143 | {0x0, 0x3, 0x2, 0x1}, | 143 | {0x0, 0x3, 0x2, 0x1}, |
144 | {0x0, 0x3, 0x2, 0x1}, | 144 | {0x0, 0x3, 0x2, 0x1}, |
145 | {0x0, 0x3, 0x2, 0x1}, /* LDO15 */ | 145 | {0x0, 0x3, 0x2, 0x1}, /* LDO15 */ |
146 | {0x0, 0x3, 0x2, 0x1}, | 146 | {0x0, 0x3, 0x2, 0x1}, |
147 | {0x0, 0x3, 0x2, 0x1}, | 147 | {0x0, 0x3, 0x2, 0x1}, |
148 | {0x0, 0x0, 0x0, 0x0}, | 148 | {0x0, 0x0, 0x0, 0x0}, |
149 | {0x0, 0x3, 0x2, 0x1}, | 149 | {0x0, 0x3, 0x2, 0x1}, |
150 | {0x0, 0x3, 0x2, 0x1}, /* LDO20 */ | 150 | {0x0, 0x3, 0x2, 0x1}, /* LDO20 */ |
151 | {0x0, 0x3, 0x2, 0x1}, | 151 | {0x0, 0x3, 0x2, 0x1}, |
152 | {0x0, 0x3, 0x2, 0x1}, | 152 | {0x0, 0x3, 0x2, 0x1}, |
153 | {0x0, 0x0, 0x0, 0x0}, | 153 | {0x0, 0x0, 0x0, 0x0}, |
154 | {0x0, 0x3, 0x2, 0x1}, | 154 | {0x0, 0x3, 0x2, 0x1}, |
155 | {0x0, 0x3, 0x2, 0x1}, /* LDO25 */ | 155 | {0x0, 0x3, 0x2, 0x1}, /* LDO25 */ |
156 | {0x0, 0x3, 0x2, 0x1}, | 156 | {0x0, 0x3, 0x2, 0x1}, |
157 | {0x0, 0x3, 0x2, 0x1}, | 157 | {0x0, 0x3, 0x2, 0x1}, |
158 | {0x0, 0x3, 0x2, 0x1}, /* LDO28 */ | 158 | {0x0, 0x3, 0x2, 0x1}, /* LDO28 */ |
159 | 159 | ||
160 | /* BUCK1 ... BUCK9 */ | 160 | /* BUCK1 ... BUCK9 */ |
161 | {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */ | 161 | {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */ |
162 | {0x0, 0x3, 0x1, 0x1}, | 162 | {0x0, 0x3, 0x1, 0x1}, |
163 | {0x0, 0x3, 0x1, 0x1}, | 163 | {0x0, 0x3, 0x1, 0x1}, |
164 | {0x0, 0x3, 0x1, 0x1}, | 164 | {0x0, 0x3, 0x1, 0x1}, |
165 | {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */ | 165 | {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */ |
166 | {0x0, 0x3, 0x1, 0x1}, | 166 | {0x0, 0x3, 0x1, 0x1}, |
167 | {0x0, 0x3, 0x1, 0x1}, | 167 | {0x0, 0x3, 0x1, 0x1}, |
168 | {0x0, 0x3, 0x1, 0x1}, | 168 | {0x0, 0x3, 0x1, 0x1}, |
169 | {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ | 169 | {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ |
170 | }; | 170 | }; |
171 | 171 | ||
172 | static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, | 172 | static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, |
173 | int *enable_ctrl) | 173 | int *enable_ctrl) |
174 | { | 174 | { |
175 | int i, reg_id = rdev_get_id(rdev); | 175 | int i, reg_id = rdev_get_id(rdev); |
176 | unsigned int mode; | 176 | unsigned int mode; |
177 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 177 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
178 | 178 | ||
179 | switch (reg_id) { | 179 | switch (reg_id) { |
180 | case S5M8767_LDO1 ... S5M8767_LDO2: | 180 | case S5M8767_LDO1 ... S5M8767_LDO2: |
181 | *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | 181 | *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); |
182 | break; | 182 | break; |
183 | case S5M8767_LDO3 ... S5M8767_LDO28: | 183 | case S5M8767_LDO3 ... S5M8767_LDO28: |
184 | *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | 184 | *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); |
185 | break; | 185 | break; |
186 | case S5M8767_BUCK1: | 186 | case S5M8767_BUCK1: |
187 | *reg = S5M8767_REG_BUCK1CTRL1; | 187 | *reg = S5M8767_REG_BUCK1CTRL1; |
188 | break; | 188 | break; |
189 | case S5M8767_BUCK2 ... S5M8767_BUCK4: | 189 | case S5M8767_BUCK2 ... S5M8767_BUCK4: |
190 | *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9; | 190 | *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9; |
191 | break; | 191 | break; |
192 | case S5M8767_BUCK5: | 192 | case S5M8767_BUCK5: |
193 | *reg = S5M8767_REG_BUCK5CTRL1; | 193 | *reg = S5M8767_REG_BUCK5CTRL1; |
194 | break; | 194 | break; |
195 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | 195 | case S5M8767_BUCK6 ... S5M8767_BUCK9: |
196 | *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2; | 196 | *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2; |
197 | break; | 197 | break; |
198 | default: | 198 | default: |
199 | return -EINVAL; | 199 | return -EINVAL; |
200 | } | 200 | } |
201 | 201 | ||
202 | for (i = 0; i < s5m8767->num_regulators; i++) { | 202 | for (i = 0; i < s5m8767->num_regulators; i++) { |
203 | if (s5m8767->opmode[i].id == reg_id) { | 203 | if (s5m8767->opmode[i].id == reg_id) { |
204 | mode = s5m8767->opmode[i].mode; | 204 | mode = s5m8767->opmode[i].mode; |
205 | break; | 205 | break; |
206 | } | 206 | } |
207 | } | 207 | } |
208 | 208 | ||
209 | if (i < s5m8767->num_regulators) | 209 | if (i < s5m8767->num_regulators) |
210 | *enable_ctrl = | 210 | *enable_ctrl = |
211 | s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; | 211 | s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; |
212 | 212 | ||
213 | return 0; | 213 | return 0; |
214 | } | 214 | } |
215 | 215 | ||
216 | static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) | 216 | static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) |
217 | { | 217 | { |
218 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 218 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
219 | int ret, reg; | 219 | int ret, reg; |
220 | int mask = 0xc0, enable_ctrl; | 220 | int mask = 0xc0, enable_ctrl; |
221 | unsigned int val; | 221 | unsigned int val; |
222 | 222 | ||
223 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | 223 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); |
224 | if (ret == -EINVAL) | 224 | if (ret == -EINVAL) |
225 | return 1; | 225 | return 1; |
226 | else if (ret) | 226 | else if (ret) |
227 | return ret; | 227 | return ret; |
228 | 228 | ||
229 | ret = sec_reg_read(s5m8767->iodev, reg, &val); | 229 | ret = sec_reg_read(s5m8767->iodev, reg, &val); |
230 | if (ret) | 230 | if (ret) |
231 | return ret; | 231 | return ret; |
232 | 232 | ||
233 | return (val & mask) == enable_ctrl; | 233 | return (val & mask) == enable_ctrl; |
234 | } | 234 | } |
235 | 235 | ||
236 | static int s5m8767_reg_enable(struct regulator_dev *rdev) | 236 | static int s5m8767_reg_enable(struct regulator_dev *rdev) |
237 | { | 237 | { |
238 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 238 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
239 | int ret, reg; | 239 | int ret, reg; |
240 | int mask = 0xc0, enable_ctrl; | 240 | int mask = 0xc0, enable_ctrl; |
241 | 241 | ||
242 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | 242 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); |
243 | if (ret) | 243 | if (ret) |
244 | return ret; | 244 | return ret; |
245 | 245 | ||
246 | return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); | 246 | return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); |
247 | } | 247 | } |
248 | 248 | ||
249 | static int s5m8767_reg_disable(struct regulator_dev *rdev) | 249 | static int s5m8767_reg_disable(struct regulator_dev *rdev) |
250 | { | 250 | { |
251 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 251 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
252 | int ret, reg; | 252 | int ret, reg; |
253 | int mask = 0xc0, enable_ctrl; | 253 | int mask = 0xc0, enable_ctrl; |
254 | 254 | ||
255 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | 255 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); |
256 | if (ret) | 256 | if (ret) |
257 | return ret; | 257 | return ret; |
258 | 258 | ||
259 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); | 259 | return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); |
260 | } | 260 | } |
261 | 261 | ||
262 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) | 262 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) |
263 | { | 263 | { |
264 | int reg; | 264 | int reg; |
265 | 265 | ||
266 | switch (reg_id) { | 266 | switch (reg_id) { |
267 | case S5M8767_LDO1 ... S5M8767_LDO2: | 267 | case S5M8767_LDO1 ... S5M8767_LDO2: |
268 | reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | 268 | reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); |
269 | break; | 269 | break; |
270 | case S5M8767_LDO3 ... S5M8767_LDO28: | 270 | case S5M8767_LDO3 ... S5M8767_LDO28: |
271 | reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | 271 | reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); |
272 | break; | 272 | break; |
273 | case S5M8767_BUCK1: | 273 | case S5M8767_BUCK1: |
274 | reg = S5M8767_REG_BUCK1CTRL2; | 274 | reg = S5M8767_REG_BUCK1CTRL2; |
275 | break; | 275 | break; |
276 | case S5M8767_BUCK2: | 276 | case S5M8767_BUCK2: |
277 | reg = S5M8767_REG_BUCK2DVS1; | 277 | reg = S5M8767_REG_BUCK2DVS1; |
278 | if (s5m8767->buck2_gpiodvs) | 278 | if (s5m8767->buck2_gpiodvs) |
279 | reg += s5m8767->buck_gpioindex; | 279 | reg += s5m8767->buck_gpioindex; |
280 | break; | 280 | break; |
281 | case S5M8767_BUCK3: | 281 | case S5M8767_BUCK3: |
282 | reg = S5M8767_REG_BUCK3DVS1; | 282 | reg = S5M8767_REG_BUCK3DVS1; |
283 | if (s5m8767->buck3_gpiodvs) | 283 | if (s5m8767->buck3_gpiodvs) |
284 | reg += s5m8767->buck_gpioindex; | 284 | reg += s5m8767->buck_gpioindex; |
285 | break; | 285 | break; |
286 | case S5M8767_BUCK4: | 286 | case S5M8767_BUCK4: |
287 | reg = S5M8767_REG_BUCK4DVS1; | 287 | reg = S5M8767_REG_BUCK4DVS1; |
288 | if (s5m8767->buck4_gpiodvs) | 288 | if (s5m8767->buck4_gpiodvs) |
289 | reg += s5m8767->buck_gpioindex; | 289 | reg += s5m8767->buck_gpioindex; |
290 | break; | 290 | break; |
291 | case S5M8767_BUCK5: | 291 | case S5M8767_BUCK5: |
292 | reg = S5M8767_REG_BUCK5CTRL2; | 292 | reg = S5M8767_REG_BUCK5CTRL2; |
293 | break; | 293 | break; |
294 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | 294 | case S5M8767_BUCK6 ... S5M8767_BUCK9: |
295 | reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2; | 295 | reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2; |
296 | break; | 296 | break; |
297 | default: | 297 | default: |
298 | return -EINVAL; | 298 | return -EINVAL; |
299 | } | 299 | } |
300 | 300 | ||
301 | return reg; | 301 | return reg; |
302 | } | 302 | } |
303 | 303 | ||
304 | static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, | 304 | static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, |
305 | int min_vol) | 305 | int min_vol) |
306 | { | 306 | { |
307 | int selector = 0; | 307 | int selector = 0; |
308 | 308 | ||
309 | if (desc == NULL) | 309 | if (desc == NULL) |
310 | return -EINVAL; | 310 | return -EINVAL; |
311 | 311 | ||
312 | if (min_vol > desc->max) | 312 | if (min_vol > desc->max) |
313 | return -EINVAL; | 313 | return -EINVAL; |
314 | 314 | ||
315 | if (min_vol < desc->min) | 315 | if (min_vol < desc->min) |
316 | min_vol = desc->min; | 316 | min_vol = desc->min; |
317 | 317 | ||
318 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); | 318 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); |
319 | 319 | ||
320 | if (desc->min + desc->step * selector > desc->max) | 320 | if (desc->min + desc->step * selector > desc->max) |
321 | return -EINVAL; | 321 | return -EINVAL; |
322 | 322 | ||
323 | return selector; | 323 | return selector; |
324 | } | 324 | } |
325 | 325 | ||
326 | static inline int s5m8767_set_high(struct s5m8767_info *s5m8767) | 326 | static inline int s5m8767_set_high(struct s5m8767_info *s5m8767) |
327 | { | 327 | { |
328 | int temp_index = s5m8767->buck_gpioindex; | 328 | int temp_index = s5m8767->buck_gpioindex; |
329 | 329 | ||
330 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | 330 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); |
331 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | 331 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); |
332 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | 332 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); |
333 | 333 | ||
334 | return 0; | 334 | return 0; |
335 | } | 335 | } |
336 | 336 | ||
337 | static inline int s5m8767_set_low(struct s5m8767_info *s5m8767) | 337 | static inline int s5m8767_set_low(struct s5m8767_info *s5m8767) |
338 | { | 338 | { |
339 | int temp_index = s5m8767->buck_gpioindex; | 339 | int temp_index = s5m8767->buck_gpioindex; |
340 | 340 | ||
341 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | 341 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); |
342 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | 342 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); |
343 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | 343 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); |
344 | 344 | ||
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
347 | 347 | ||
348 | static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | 348 | static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, |
349 | unsigned selector) | 349 | unsigned selector) |
350 | { | 350 | { |
351 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 351 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
352 | int reg_id = rdev_get_id(rdev); | 352 | int reg_id = rdev_get_id(rdev); |
353 | int old_index, index = 0; | 353 | int old_index, index = 0; |
354 | u8 *buck234_vol = NULL; | 354 | u8 *buck234_vol = NULL; |
355 | 355 | ||
356 | switch (reg_id) { | 356 | switch (reg_id) { |
357 | case S5M8767_LDO1 ... S5M8767_LDO28: | 357 | case S5M8767_LDO1 ... S5M8767_LDO28: |
358 | break; | 358 | break; |
359 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | 359 | case S5M8767_BUCK1 ... S5M8767_BUCK6: |
360 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) | 360 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) |
361 | buck234_vol = &s5m8767->buck2_vol[0]; | 361 | buck234_vol = &s5m8767->buck2_vol[0]; |
362 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) | 362 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) |
363 | buck234_vol = &s5m8767->buck3_vol[0]; | 363 | buck234_vol = &s5m8767->buck3_vol[0]; |
364 | else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs) | 364 | else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs) |
365 | buck234_vol = &s5m8767->buck4_vol[0]; | 365 | buck234_vol = &s5m8767->buck4_vol[0]; |
366 | break; | 366 | break; |
367 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | 367 | case S5M8767_BUCK7 ... S5M8767_BUCK8: |
368 | return -EINVAL; | 368 | return -EINVAL; |
369 | case S5M8767_BUCK9: | 369 | case S5M8767_BUCK9: |
370 | break; | 370 | break; |
371 | default: | 371 | default: |
372 | return -EINVAL; | 372 | return -EINVAL; |
373 | } | 373 | } |
374 | 374 | ||
375 | /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */ | 375 | /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */ |
376 | if (buck234_vol) { | 376 | if (buck234_vol) { |
377 | while (*buck234_vol != selector) { | 377 | while (*buck234_vol != selector) { |
378 | buck234_vol++; | 378 | buck234_vol++; |
379 | index++; | 379 | index++; |
380 | } | 380 | } |
381 | old_index = s5m8767->buck_gpioindex; | 381 | old_index = s5m8767->buck_gpioindex; |
382 | s5m8767->buck_gpioindex = index; | 382 | s5m8767->buck_gpioindex = index; |
383 | 383 | ||
384 | if (index > old_index) | 384 | if (index > old_index) |
385 | return s5m8767_set_high(s5m8767); | 385 | return s5m8767_set_high(s5m8767); |
386 | else | 386 | else |
387 | return s5m8767_set_low(s5m8767); | 387 | return s5m8767_set_low(s5m8767); |
388 | } else { | 388 | } else { |
389 | return regulator_set_voltage_sel_regmap(rdev, selector); | 389 | return regulator_set_voltage_sel_regmap(rdev, selector); |
390 | } | 390 | } |
391 | } | 391 | } |
392 | 392 | ||
393 | static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, | 393 | static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, |
394 | unsigned int old_sel, | 394 | unsigned int old_sel, |
395 | unsigned int new_sel) | 395 | unsigned int new_sel) |
396 | { | 396 | { |
397 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 397 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
398 | const struct sec_voltage_desc *desc; | 398 | const struct sec_voltage_desc *desc; |
399 | int reg_id = rdev_get_id(rdev); | 399 | int reg_id = rdev_get_id(rdev); |
400 | 400 | ||
401 | desc = reg_voltage_map[reg_id]; | 401 | desc = reg_voltage_map[reg_id]; |
402 | 402 | ||
403 | if ((old_sel < new_sel) && s5m8767->ramp_delay) | 403 | if ((old_sel < new_sel) && s5m8767->ramp_delay) |
404 | return DIV_ROUND_UP(desc->step * (new_sel - old_sel), | 404 | return DIV_ROUND_UP(desc->step * (new_sel - old_sel), |
405 | s5m8767->ramp_delay * 1000); | 405 | s5m8767->ramp_delay * 1000); |
406 | return 0; | 406 | return 0; |
407 | } | 407 | } |
408 | 408 | ||
409 | static struct regulator_ops s5m8767_ops = { | 409 | static struct regulator_ops s5m8767_ops = { |
410 | .list_voltage = regulator_list_voltage_linear, | 410 | .list_voltage = regulator_list_voltage_linear, |
411 | .is_enabled = s5m8767_reg_is_enabled, | 411 | .is_enabled = s5m8767_reg_is_enabled, |
412 | .enable = s5m8767_reg_enable, | 412 | .enable = s5m8767_reg_enable, |
413 | .disable = s5m8767_reg_disable, | 413 | .disable = s5m8767_reg_disable, |
414 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | 414 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
415 | .set_voltage_sel = s5m8767_set_voltage_sel, | 415 | .set_voltage_sel = s5m8767_set_voltage_sel, |
416 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, | 416 | .set_voltage_time_sel = s5m8767_set_voltage_time_sel, |
417 | }; | 417 | }; |
418 | 418 | ||
419 | static struct regulator_ops s5m8767_buck78_ops = { | 419 | static struct regulator_ops s5m8767_buck78_ops = { |
420 | .is_enabled = s5m8767_reg_is_enabled, | 420 | .is_enabled = s5m8767_reg_is_enabled, |
421 | .enable = s5m8767_reg_enable, | 421 | .enable = s5m8767_reg_enable, |
422 | .disable = s5m8767_reg_disable, | 422 | .disable = s5m8767_reg_disable, |
423 | }; | 423 | }; |
424 | 424 | ||
425 | #define s5m8767_regulator_desc(_name) { \ | 425 | #define s5m8767_regulator_desc(_name) { \ |
426 | .name = #_name, \ | 426 | .name = #_name, \ |
427 | .id = S5M8767_##_name, \ | 427 | .id = S5M8767_##_name, \ |
428 | .ops = &s5m8767_ops, \ | 428 | .ops = &s5m8767_ops, \ |
429 | .type = REGULATOR_VOLTAGE, \ | 429 | .type = REGULATOR_VOLTAGE, \ |
430 | .owner = THIS_MODULE, \ | 430 | .owner = THIS_MODULE, \ |
431 | } | 431 | } |
432 | 432 | ||
433 | #define s5m8767_regulator_buck78_desc(_name) { \ | 433 | #define s5m8767_regulator_buck78_desc(_name) { \ |
434 | .name = #_name, \ | 434 | .name = #_name, \ |
435 | .id = S5M8767_##_name, \ | 435 | .id = S5M8767_##_name, \ |
436 | .ops = &s5m8767_buck78_ops, \ | 436 | .ops = &s5m8767_buck78_ops, \ |
437 | .type = REGULATOR_VOLTAGE, \ | 437 | .type = REGULATOR_VOLTAGE, \ |
438 | .owner = THIS_MODULE, \ | 438 | .owner = THIS_MODULE, \ |
439 | } | 439 | } |
440 | 440 | ||
441 | static struct regulator_desc regulators[] = { | 441 | static struct regulator_desc regulators[] = { |
442 | s5m8767_regulator_desc(LDO1), | 442 | s5m8767_regulator_desc(LDO1), |
443 | s5m8767_regulator_desc(LDO2), | 443 | s5m8767_regulator_desc(LDO2), |
444 | s5m8767_regulator_desc(LDO3), | 444 | s5m8767_regulator_desc(LDO3), |
445 | s5m8767_regulator_desc(LDO4), | 445 | s5m8767_regulator_desc(LDO4), |
446 | s5m8767_regulator_desc(LDO5), | 446 | s5m8767_regulator_desc(LDO5), |
447 | s5m8767_regulator_desc(LDO6), | 447 | s5m8767_regulator_desc(LDO6), |
448 | s5m8767_regulator_desc(LDO7), | 448 | s5m8767_regulator_desc(LDO7), |
449 | s5m8767_regulator_desc(LDO8), | 449 | s5m8767_regulator_desc(LDO8), |
450 | s5m8767_regulator_desc(LDO9), | 450 | s5m8767_regulator_desc(LDO9), |
451 | s5m8767_regulator_desc(LDO10), | 451 | s5m8767_regulator_desc(LDO10), |
452 | s5m8767_regulator_desc(LDO11), | 452 | s5m8767_regulator_desc(LDO11), |
453 | s5m8767_regulator_desc(LDO12), | 453 | s5m8767_regulator_desc(LDO12), |
454 | s5m8767_regulator_desc(LDO13), | 454 | s5m8767_regulator_desc(LDO13), |
455 | s5m8767_regulator_desc(LDO14), | 455 | s5m8767_regulator_desc(LDO14), |
456 | s5m8767_regulator_desc(LDO15), | 456 | s5m8767_regulator_desc(LDO15), |
457 | s5m8767_regulator_desc(LDO16), | 457 | s5m8767_regulator_desc(LDO16), |
458 | s5m8767_regulator_desc(LDO17), | 458 | s5m8767_regulator_desc(LDO17), |
459 | s5m8767_regulator_desc(LDO18), | 459 | s5m8767_regulator_desc(LDO18), |
460 | s5m8767_regulator_desc(LDO19), | 460 | s5m8767_regulator_desc(LDO19), |
461 | s5m8767_regulator_desc(LDO20), | 461 | s5m8767_regulator_desc(LDO20), |
462 | s5m8767_regulator_desc(LDO21), | 462 | s5m8767_regulator_desc(LDO21), |
463 | s5m8767_regulator_desc(LDO22), | 463 | s5m8767_regulator_desc(LDO22), |
464 | s5m8767_regulator_desc(LDO23), | 464 | s5m8767_regulator_desc(LDO23), |
465 | s5m8767_regulator_desc(LDO24), | 465 | s5m8767_regulator_desc(LDO24), |
466 | s5m8767_regulator_desc(LDO25), | 466 | s5m8767_regulator_desc(LDO25), |
467 | s5m8767_regulator_desc(LDO26), | 467 | s5m8767_regulator_desc(LDO26), |
468 | s5m8767_regulator_desc(LDO27), | 468 | s5m8767_regulator_desc(LDO27), |
469 | s5m8767_regulator_desc(LDO28), | 469 | s5m8767_regulator_desc(LDO28), |
470 | s5m8767_regulator_desc(BUCK1), | 470 | s5m8767_regulator_desc(BUCK1), |
471 | s5m8767_regulator_desc(BUCK2), | 471 | s5m8767_regulator_desc(BUCK2), |
472 | s5m8767_regulator_desc(BUCK3), | 472 | s5m8767_regulator_desc(BUCK3), |
473 | s5m8767_regulator_desc(BUCK4), | 473 | s5m8767_regulator_desc(BUCK4), |
474 | s5m8767_regulator_desc(BUCK5), | 474 | s5m8767_regulator_desc(BUCK5), |
475 | s5m8767_regulator_desc(BUCK6), | 475 | s5m8767_regulator_desc(BUCK6), |
476 | s5m8767_regulator_buck78_desc(BUCK7), | 476 | s5m8767_regulator_buck78_desc(BUCK7), |
477 | s5m8767_regulator_buck78_desc(BUCK8), | 477 | s5m8767_regulator_buck78_desc(BUCK8), |
478 | s5m8767_regulator_desc(BUCK9), | 478 | s5m8767_regulator_desc(BUCK9), |
479 | }; | 479 | }; |
480 | 480 | ||
481 | #ifdef CONFIG_OF | 481 | #ifdef CONFIG_OF |
482 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, | 482 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, |
483 | struct sec_platform_data *pdata, | 483 | struct sec_platform_data *pdata, |
484 | struct device_node *pmic_np) | 484 | struct device_node *pmic_np) |
485 | { | 485 | { |
486 | int i, gpio; | 486 | int i, gpio; |
487 | 487 | ||
488 | for (i = 0; i < 3; i++) { | 488 | for (i = 0; i < 3; i++) { |
489 | gpio = of_get_named_gpio(pmic_np, | 489 | gpio = of_get_named_gpio(pmic_np, |
490 | "s5m8767,pmic-buck-dvs-gpios", i); | 490 | "s5m8767,pmic-buck-dvs-gpios", i); |
491 | if (!gpio_is_valid(gpio)) { | 491 | if (!gpio_is_valid(gpio)) { |
492 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | 492 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); |
493 | return -EINVAL; | 493 | return -EINVAL; |
494 | } | 494 | } |
495 | pdata->buck_gpios[i] = gpio; | 495 | pdata->buck_gpios[i] = gpio; |
496 | } | 496 | } |
497 | return 0; | 497 | return 0; |
498 | } | 498 | } |
499 | 499 | ||
500 | static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, | 500 | static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, |
501 | struct sec_platform_data *pdata, | 501 | struct sec_platform_data *pdata, |
502 | struct device_node *pmic_np) | 502 | struct device_node *pmic_np) |
503 | { | 503 | { |
504 | int i, gpio; | 504 | int i, gpio; |
505 | 505 | ||
506 | for (i = 0; i < 3; i++) { | 506 | for (i = 0; i < 3; i++) { |
507 | gpio = of_get_named_gpio(pmic_np, | 507 | gpio = of_get_named_gpio(pmic_np, |
508 | "s5m8767,pmic-buck-ds-gpios", i); | 508 | "s5m8767,pmic-buck-ds-gpios", i); |
509 | if (!gpio_is_valid(gpio)) { | 509 | if (!gpio_is_valid(gpio)) { |
510 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | 510 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); |
511 | return -EINVAL; | 511 | return -EINVAL; |
512 | } | 512 | } |
513 | pdata->buck_ds[i] = gpio; | 513 | pdata->buck_ds[i] = gpio; |
514 | } | 514 | } |
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | 518 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, |
519 | struct sec_platform_data *pdata) | 519 | struct sec_platform_data *pdata) |
520 | { | 520 | { |
521 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 521 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
522 | struct device_node *pmic_np, *regulators_np, *reg_np; | 522 | struct device_node *pmic_np, *regulators_np, *reg_np; |
523 | struct sec_regulator_data *rdata; | 523 | struct sec_regulator_data *rdata; |
524 | struct sec_opmode_data *rmode; | 524 | struct sec_opmode_data *rmode; |
525 | unsigned int i, dvs_voltage_nr = 1, ret; | 525 | unsigned int i, dvs_voltage_nr = 1, ret; |
526 | 526 | ||
527 | pmic_np = iodev->dev->of_node; | 527 | pmic_np = iodev->dev->of_node; |
528 | if (!pmic_np) { | 528 | if (!pmic_np) { |
529 | dev_err(iodev->dev, "could not find pmic sub-node\n"); | 529 | dev_err(iodev->dev, "could not find pmic sub-node\n"); |
530 | return -ENODEV; | 530 | return -ENODEV; |
531 | } | 531 | } |
532 | 532 | ||
533 | regulators_np = of_find_node_by_name(pmic_np, "regulators"); | 533 | regulators_np = of_find_node_by_name(pmic_np, "regulators"); |
534 | if (!regulators_np) { | 534 | if (!regulators_np) { |
535 | dev_err(iodev->dev, "could not find regulators sub-node\n"); | 535 | dev_err(iodev->dev, "could not find regulators sub-node\n"); |
536 | return -EINVAL; | 536 | return -EINVAL; |
537 | } | 537 | } |
538 | 538 | ||
539 | /* count the number of regulators to be supported in pmic */ | 539 | /* count the number of regulators to be supported in pmic */ |
540 | pdata->num_regulators = of_get_child_count(regulators_np); | 540 | pdata->num_regulators = of_get_child_count(regulators_np); |
541 | 541 | ||
542 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * | 542 | rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * |
543 | pdata->num_regulators, GFP_KERNEL); | 543 | pdata->num_regulators, GFP_KERNEL); |
544 | if (!rdata) { | 544 | if (!rdata) { |
545 | dev_err(iodev->dev, | 545 | dev_err(iodev->dev, |
546 | "could not allocate memory for regulator data\n"); | 546 | "could not allocate memory for regulator data\n"); |
547 | return -ENOMEM; | 547 | return -ENOMEM; |
548 | } | 548 | } |
549 | 549 | ||
550 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * | 550 | rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * |
551 | pdata->num_regulators, GFP_KERNEL); | 551 | pdata->num_regulators, GFP_KERNEL); |
552 | if (!rdata) { | 552 | if (!rdata) { |
553 | dev_err(iodev->dev, | 553 | dev_err(iodev->dev, |
554 | "could not allocate memory for regulator mode\n"); | 554 | "could not allocate memory for regulator mode\n"); |
555 | return -ENOMEM; | 555 | return -ENOMEM; |
556 | } | 556 | } |
557 | 557 | ||
558 | pdata->regulators = rdata; | 558 | pdata->regulators = rdata; |
559 | pdata->opmode = rmode; | 559 | pdata->opmode = rmode; |
560 | for_each_child_of_node(regulators_np, reg_np) { | 560 | for_each_child_of_node(regulators_np, reg_np) { |
561 | for (i = 0; i < ARRAY_SIZE(regulators); i++) | 561 | for (i = 0; i < ARRAY_SIZE(regulators); i++) |
562 | if (!of_node_cmp(reg_np->name, regulators[i].name)) | 562 | if (!of_node_cmp(reg_np->name, regulators[i].name)) |
563 | break; | 563 | break; |
564 | 564 | ||
565 | if (i == ARRAY_SIZE(regulators)) { | 565 | if (i == ARRAY_SIZE(regulators)) { |
566 | dev_warn(iodev->dev, | 566 | dev_warn(iodev->dev, |
567 | "don't know how to configure regulator %s\n", | 567 | "don't know how to configure regulator %s\n", |
568 | reg_np->name); | 568 | reg_np->name); |
569 | continue; | 569 | continue; |
570 | } | 570 | } |
571 | 571 | ||
572 | rdata->id = i; | 572 | rdata->id = i; |
573 | rdata->initdata = of_get_regulator_init_data( | 573 | rdata->initdata = of_get_regulator_init_data( |
574 | &pdev->dev, reg_np); | 574 | &pdev->dev, reg_np); |
575 | rdata->reg_node = reg_np; | 575 | rdata->reg_node = reg_np; |
576 | rdata++; | 576 | rdata++; |
577 | rmode->id = i; | 577 | rmode->id = i; |
578 | if (of_property_read_u32(reg_np, "op_mode", | 578 | if (of_property_read_u32(reg_np, "op_mode", |
579 | &rmode->mode)) { | 579 | &rmode->mode)) { |
580 | dev_warn(iodev->dev, | 580 | dev_warn(iodev->dev, |
581 | "no op_mode property property at %s\n", | 581 | "no op_mode property property at %s\n", |
582 | reg_np->full_name); | 582 | reg_np->full_name); |
583 | 583 | ||
584 | rmode->mode = S5M8767_OPMODE_NORMAL_MODE; | 584 | rmode->mode = S5M8767_OPMODE_NORMAL_MODE; |
585 | } | 585 | } |
586 | rmode++; | 586 | rmode++; |
587 | } | 587 | } |
588 | 588 | ||
589 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) | 589 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) |
590 | pdata->buck2_gpiodvs = true; | 590 | pdata->buck2_gpiodvs = true; |
591 | 591 | ||
592 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) | 592 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) |
593 | pdata->buck3_gpiodvs = true; | 593 | pdata->buck3_gpiodvs = true; |
594 | 594 | ||
595 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) | 595 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) |
596 | pdata->buck4_gpiodvs = true; | 596 | pdata->buck4_gpiodvs = true; |
597 | 597 | ||
598 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 598 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || |
599 | pdata->buck4_gpiodvs) { | 599 | pdata->buck4_gpiodvs) { |
600 | ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); | 600 | ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); |
601 | if (ret) | 601 | if (ret) |
602 | return -EINVAL; | 602 | return -EINVAL; |
603 | 603 | ||
604 | if (of_property_read_u32(pmic_np, | 604 | if (of_property_read_u32(pmic_np, |
605 | "s5m8767,pmic-buck-default-dvs-idx", | 605 | "s5m8767,pmic-buck-default-dvs-idx", |
606 | &pdata->buck_default_idx)) { | 606 | &pdata->buck_default_idx)) { |
607 | pdata->buck_default_idx = 0; | 607 | pdata->buck_default_idx = 0; |
608 | } else { | 608 | } else { |
609 | if (pdata->buck_default_idx >= 8) { | 609 | if (pdata->buck_default_idx >= 8) { |
610 | pdata->buck_default_idx = 0; | 610 | pdata->buck_default_idx = 0; |
611 | dev_info(iodev->dev, | 611 | dev_info(iodev->dev, |
612 | "invalid value for default dvs index, use 0\n"); | 612 | "invalid value for default dvs index, use 0\n"); |
613 | } | 613 | } |
614 | } | 614 | } |
615 | dvs_voltage_nr = 8; | 615 | dvs_voltage_nr = 8; |
616 | } | 616 | } |
617 | 617 | ||
618 | ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); | 618 | ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); |
619 | if (ret) | 619 | if (ret) |
620 | return -EINVAL; | 620 | return -EINVAL; |
621 | 621 | ||
622 | if (of_property_read_u32_array(pmic_np, | 622 | if (of_property_read_u32_array(pmic_np, |
623 | "s5m8767,pmic-buck2-dvs-voltage", | 623 | "s5m8767,pmic-buck2-dvs-voltage", |
624 | pdata->buck2_voltage, dvs_voltage_nr)) { | 624 | pdata->buck2_voltage, dvs_voltage_nr)) { |
625 | dev_err(iodev->dev, "buck2 voltages not specified\n"); | 625 | dev_err(iodev->dev, "buck2 voltages not specified\n"); |
626 | return -EINVAL; | 626 | return -EINVAL; |
627 | } | 627 | } |
628 | 628 | ||
629 | if (of_property_read_u32_array(pmic_np, | 629 | if (of_property_read_u32_array(pmic_np, |
630 | "s5m8767,pmic-buck3-dvs-voltage", | 630 | "s5m8767,pmic-buck3-dvs-voltage", |
631 | pdata->buck3_voltage, dvs_voltage_nr)) { | 631 | pdata->buck3_voltage, dvs_voltage_nr)) { |
632 | dev_err(iodev->dev, "buck3 voltages not specified\n"); | 632 | dev_err(iodev->dev, "buck3 voltages not specified\n"); |
633 | return -EINVAL; | 633 | return -EINVAL; |
634 | } | 634 | } |
635 | 635 | ||
636 | if (of_property_read_u32_array(pmic_np, | 636 | if (of_property_read_u32_array(pmic_np, |
637 | "s5m8767,pmic-buck4-dvs-voltage", | 637 | "s5m8767,pmic-buck4-dvs-voltage", |
638 | pdata->buck4_voltage, dvs_voltage_nr)) { | 638 | pdata->buck4_voltage, dvs_voltage_nr)) { |
639 | dev_err(iodev->dev, "buck4 voltages not specified\n"); | 639 | dev_err(iodev->dev, "buck4 voltages not specified\n"); |
640 | return -EINVAL; | 640 | return -EINVAL; |
641 | } | 641 | } |
642 | 642 | ||
643 | return 0; | 643 | return 0; |
644 | } | 644 | } |
645 | #else | 645 | #else |
646 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | 646 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, |
647 | struct sec_platform_data *pdata) | 647 | struct sec_platform_data *pdata) |
648 | { | 648 | { |
649 | return 0; | 649 | return 0; |
650 | } | 650 | } |
651 | #endif /* CONFIG_OF */ | 651 | #endif /* CONFIG_OF */ |
652 | 652 | ||
653 | static int s5m8767_pmic_probe(struct platform_device *pdev) | 653 | static int s5m8767_pmic_probe(struct platform_device *pdev) |
654 | { | 654 | { |
655 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 655 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
656 | struct sec_platform_data *pdata = iodev->pdata; | 656 | struct sec_platform_data *pdata = iodev->pdata; |
657 | struct regulator_config config = { }; | 657 | struct regulator_config config = { }; |
658 | struct regulator_dev **rdev; | 658 | struct regulator_dev **rdev; |
659 | struct s5m8767_info *s5m8767; | 659 | struct s5m8767_info *s5m8767; |
660 | int i, ret, size, buck_init; | 660 | int i, ret, size, buck_init; |
661 | 661 | ||
662 | if (!pdata) { | 662 | if (!pdata) { |
663 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); | 663 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); |
664 | return -ENODEV; | 664 | return -ENODEV; |
665 | } | 665 | } |
666 | 666 | ||
667 | if (iodev->dev->of_node) { | 667 | if (iodev->dev->of_node) { |
668 | ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); | 668 | ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); |
669 | if (ret) | 669 | if (ret) |
670 | return ret; | 670 | return ret; |
671 | } | 671 | } |
672 | 672 | ||
673 | if (pdata->buck2_gpiodvs) { | 673 | if (pdata->buck2_gpiodvs) { |
674 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { | 674 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { |
675 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 675 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); |
676 | return -EINVAL; | 676 | return -EINVAL; |
677 | } | 677 | } |
678 | } | 678 | } |
679 | 679 | ||
680 | if (pdata->buck3_gpiodvs) { | 680 | if (pdata->buck3_gpiodvs) { |
681 | if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) { | 681 | if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) { |
682 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 682 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); |
683 | return -EINVAL; | 683 | return -EINVAL; |
684 | } | 684 | } |
685 | } | 685 | } |
686 | 686 | ||
687 | if (pdata->buck4_gpiodvs) { | 687 | if (pdata->buck4_gpiodvs) { |
688 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) { | 688 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) { |
689 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 689 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); |
690 | return -EINVAL; | 690 | return -EINVAL; |
691 | } | 691 | } |
692 | } | 692 | } |
693 | 693 | ||
694 | s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info), | 694 | s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info), |
695 | GFP_KERNEL); | 695 | GFP_KERNEL); |
696 | if (!s5m8767) | 696 | if (!s5m8767) |
697 | return -ENOMEM; | 697 | return -ENOMEM; |
698 | 698 | ||
699 | size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); | 699 | size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); |
700 | s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | 700 | s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); |
701 | if (!s5m8767->rdev) | 701 | if (!s5m8767->rdev) |
702 | return -ENOMEM; | 702 | return -ENOMEM; |
703 | 703 | ||
704 | rdev = s5m8767->rdev; | 704 | rdev = s5m8767->rdev; |
705 | s5m8767->dev = &pdev->dev; | 705 | s5m8767->dev = &pdev->dev; |
706 | s5m8767->iodev = iodev; | 706 | s5m8767->iodev = iodev; |
707 | s5m8767->num_regulators = pdata->num_regulators; | 707 | s5m8767->num_regulators = pdata->num_regulators; |
708 | platform_set_drvdata(pdev, s5m8767); | 708 | platform_set_drvdata(pdev, s5m8767); |
709 | 709 | ||
710 | s5m8767->buck_gpioindex = pdata->buck_default_idx; | 710 | s5m8767->buck_gpioindex = pdata->buck_default_idx; |
711 | s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; | 711 | s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; |
712 | s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; | 712 | s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; |
713 | s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; | 713 | s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; |
714 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; | 714 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; |
715 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; | 715 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; |
716 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; | 716 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; |
717 | s5m8767->buck_ds[0] = pdata->buck_ds[0]; | 717 | s5m8767->buck_ds[0] = pdata->buck_ds[0]; |
718 | s5m8767->buck_ds[1] = pdata->buck_ds[1]; | 718 | s5m8767->buck_ds[1] = pdata->buck_ds[1]; |
719 | s5m8767->buck_ds[2] = pdata->buck_ds[2]; | 719 | s5m8767->buck_ds[2] = pdata->buck_ds[2]; |
720 | 720 | ||
721 | s5m8767->ramp_delay = pdata->buck_ramp_delay; | 721 | s5m8767->ramp_delay = pdata->buck_ramp_delay; |
722 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; | 722 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; |
723 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; | 723 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; |
724 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; | 724 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; |
725 | s5m8767->opmode = pdata->opmode; | 725 | s5m8767->opmode = pdata->opmode; |
726 | 726 | ||
727 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 727 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
728 | pdata->buck2_init); | 728 | pdata->buck2_init); |
729 | 729 | ||
730 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); | 730 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); |
731 | 731 | ||
732 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 732 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
733 | pdata->buck3_init); | 733 | pdata->buck3_init); |
734 | 734 | ||
735 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); | 735 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); |
736 | 736 | ||
737 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 737 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, |
738 | pdata->buck4_init); | 738 | pdata->buck4_init); |
739 | 739 | ||
740 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); | 740 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); |
741 | 741 | ||
742 | for (i = 0; i < 8; i++) { | 742 | for (i = 0; i < 8; i++) { |
743 | if (s5m8767->buck2_gpiodvs) { | 743 | if (s5m8767->buck2_gpiodvs) { |
744 | s5m8767->buck2_vol[i] = | 744 | s5m8767->buck2_vol[i] = |
745 | s5m8767_convert_voltage_to_sel( | 745 | s5m8767_convert_voltage_to_sel( |
746 | &buck_voltage_val2, | 746 | &buck_voltage_val2, |
747 | pdata->buck2_voltage[i]); | 747 | pdata->buck2_voltage[i]); |
748 | } | 748 | } |
749 | 749 | ||
750 | if (s5m8767->buck3_gpiodvs) { | 750 | if (s5m8767->buck3_gpiodvs) { |
751 | s5m8767->buck3_vol[i] = | 751 | s5m8767->buck3_vol[i] = |
752 | s5m8767_convert_voltage_to_sel( | 752 | s5m8767_convert_voltage_to_sel( |
753 | &buck_voltage_val2, | 753 | &buck_voltage_val2, |
754 | pdata->buck3_voltage[i]); | 754 | pdata->buck3_voltage[i]); |
755 | } | 755 | } |
756 | 756 | ||
757 | if (s5m8767->buck4_gpiodvs) { | 757 | if (s5m8767->buck4_gpiodvs) { |
758 | s5m8767->buck4_vol[i] = | 758 | s5m8767->buck4_vol[i] = |
759 | s5m8767_convert_voltage_to_sel( | 759 | s5m8767_convert_voltage_to_sel( |
760 | &buck_voltage_val2, | 760 | &buck_voltage_val2, |
761 | pdata->buck4_voltage[i]); | 761 | pdata->buck4_voltage[i]); |
762 | } | 762 | } |
763 | } | 763 | } |
764 | 764 | ||
765 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 765 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || |
766 | pdata->buck4_gpiodvs) { | 766 | pdata->buck4_gpiodvs) { |
767 | 767 | ||
768 | if (!gpio_is_valid(pdata->buck_gpios[0]) || | 768 | if (!gpio_is_valid(pdata->buck_gpios[0]) || |
769 | !gpio_is_valid(pdata->buck_gpios[1]) || | 769 | !gpio_is_valid(pdata->buck_gpios[1]) || |
770 | !gpio_is_valid(pdata->buck_gpios[2])) { | 770 | !gpio_is_valid(pdata->buck_gpios[2])) { |
771 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); | 771 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); |
772 | return -EINVAL; | 772 | return -EINVAL; |
773 | } | 773 | } |
774 | 774 | ||
775 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], | 775 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], |
776 | "S5M8767 SET1"); | 776 | "S5M8767 SET1"); |
777 | if (ret) | 777 | if (ret) |
778 | return ret; | 778 | return ret; |
779 | 779 | ||
780 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1], | 780 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1], |
781 | "S5M8767 SET2"); | 781 | "S5M8767 SET2"); |
782 | if (ret) | 782 | if (ret) |
783 | return ret; | 783 | return ret; |
784 | 784 | ||
785 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2], | 785 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2], |
786 | "S5M8767 SET3"); | 786 | "S5M8767 SET3"); |
787 | if (ret) | 787 | if (ret) |
788 | return ret; | 788 | return ret; |
789 | 789 | ||
790 | /* SET1 GPIO */ | 790 | /* SET1 GPIO */ |
791 | gpio_direction_output(pdata->buck_gpios[0], | 791 | gpio_direction_output(pdata->buck_gpios[0], |
792 | (s5m8767->buck_gpioindex >> 2) & 0x1); | 792 | (s5m8767->buck_gpioindex >> 2) & 0x1); |
793 | /* SET2 GPIO */ | 793 | /* SET2 GPIO */ |
794 | gpio_direction_output(pdata->buck_gpios[1], | 794 | gpio_direction_output(pdata->buck_gpios[1], |
795 | (s5m8767->buck_gpioindex >> 1) & 0x1); | 795 | (s5m8767->buck_gpioindex >> 1) & 0x1); |
796 | /* SET3 GPIO */ | 796 | /* SET3 GPIO */ |
797 | gpio_direction_output(pdata->buck_gpios[2], | 797 | gpio_direction_output(pdata->buck_gpios[2], |
798 | (s5m8767->buck_gpioindex >> 0) & 0x1); | 798 | (s5m8767->buck_gpioindex >> 0) & 0x1); |
799 | } | 799 | } |
800 | 800 | ||
801 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); | 801 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); |
802 | if (ret) | 802 | if (ret) |
803 | return ret; | 803 | return ret; |
804 | 804 | ||
805 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3"); | 805 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3"); |
806 | if (ret) | 806 | if (ret) |
807 | return ret; | 807 | return ret; |
808 | 808 | ||
809 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4"); | 809 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4"); |
810 | if (ret) | 810 | if (ret) |
811 | return ret; | 811 | return ret; |
812 | 812 | ||
813 | /* DS2 GPIO */ | 813 | /* DS2 GPIO */ |
814 | gpio_direction_output(pdata->buck_ds[0], 0x0); | 814 | gpio_direction_output(pdata->buck_ds[0], 0x0); |
815 | /* DS3 GPIO */ | 815 | /* DS3 GPIO */ |
816 | gpio_direction_output(pdata->buck_ds[1], 0x0); | 816 | gpio_direction_output(pdata->buck_ds[1], 0x0); |
817 | /* DS4 GPIO */ | 817 | /* DS4 GPIO */ |
818 | gpio_direction_output(pdata->buck_ds[2], 0x0); | 818 | gpio_direction_output(pdata->buck_ds[2], 0x0); |
819 | 819 | ||
820 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 820 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || |
821 | pdata->buck4_gpiodvs) { | 821 | pdata->buck4_gpiodvs) { |
822 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, | 822 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, |
823 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), | 823 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), |
824 | 1 << 1); | 824 | 1 << 1); |
825 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, | 825 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, |
826 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), | 826 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), |
827 | 1 << 1); | 827 | 1 << 1); |
828 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, | 828 | sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, |
829 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), | 829 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), |
830 | 1 << 1); | 830 | 1 << 1); |
831 | } | 831 | } |
832 | 832 | ||
833 | /* Initialize GPIO DVS registers */ | 833 | /* Initialize GPIO DVS registers */ |
834 | for (i = 0; i < 8; i++) { | 834 | for (i = 0; i < 8; i++) { |
835 | if (s5m8767->buck2_gpiodvs) { | 835 | if (s5m8767->buck2_gpiodvs) { |
836 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, | 836 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, |
837 | s5m8767->buck2_vol[i]); | 837 | s5m8767->buck2_vol[i]); |
838 | } | 838 | } |
839 | 839 | ||
840 | if (s5m8767->buck3_gpiodvs) { | 840 | if (s5m8767->buck3_gpiodvs) { |
841 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, | 841 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, |
842 | s5m8767->buck3_vol[i]); | 842 | s5m8767->buck3_vol[i]); |
843 | } | 843 | } |
844 | 844 | ||
845 | if (s5m8767->buck4_gpiodvs) { | 845 | if (s5m8767->buck4_gpiodvs) { |
846 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, | 846 | sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, |
847 | s5m8767->buck4_vol[i]); | 847 | s5m8767->buck4_vol[i]); |
848 | } | 848 | } |
849 | } | 849 | } |
850 | 850 | ||
851 | if (s5m8767->buck2_ramp) | 851 | if (s5m8767->buck2_ramp) |
852 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); | 852 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); |
853 | 853 | ||
854 | if (s5m8767->buck3_ramp) | 854 | if (s5m8767->buck3_ramp) |
855 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); | 855 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); |
856 | 856 | ||
857 | if (s5m8767->buck4_ramp) | 857 | if (s5m8767->buck4_ramp) |
858 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); | 858 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); |
859 | 859 | ||
860 | if (s5m8767->buck2_ramp || s5m8767->buck3_ramp | 860 | if (s5m8767->buck2_ramp || s5m8767->buck3_ramp |
861 | || s5m8767->buck4_ramp) { | 861 | || s5m8767->buck4_ramp) { |
862 | switch (s5m8767->ramp_delay) { | 862 | switch (s5m8767->ramp_delay) { |
863 | case 5: | 863 | case 5: |
864 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 864 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
865 | 0x40, 0xf0); | 865 | 0x40, 0xf0); |
866 | break; | 866 | break; |
867 | case 10: | 867 | case 10: |
868 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 868 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
869 | 0x90, 0xf0); | 869 | 0x90, 0xf0); |
870 | break; | 870 | break; |
871 | case 25: | 871 | case 25: |
872 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 872 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
873 | 0xd0, 0xf0); | 873 | 0xd0, 0xf0); |
874 | break; | 874 | break; |
875 | case 50: | 875 | case 50: |
876 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 876 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
877 | 0xe0, 0xf0); | 877 | 0xe0, 0xf0); |
878 | break; | 878 | break; |
879 | case 100: | 879 | case 100: |
880 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 880 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
881 | 0xf0, 0xf0); | 881 | 0xf0, 0xf0); |
882 | break; | 882 | break; |
883 | default: | 883 | default: |
884 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, | 884 | sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, |
885 | 0x90, 0xf0); | 885 | 0x90, 0xf0); |
886 | } | 886 | } |
887 | } | 887 | } |
888 | 888 | ||
889 | for (i = 0; i < pdata->num_regulators; i++) { | 889 | for (i = 0; i < pdata->num_regulators; i++) { |
890 | const struct sec_voltage_desc *desc; | 890 | const struct sec_voltage_desc *desc; |
891 | int id = pdata->regulators[i].id; | 891 | int id = pdata->regulators[i].id; |
892 | 892 | ||
893 | desc = reg_voltage_map[id]; | 893 | desc = reg_voltage_map[id]; |
894 | if (desc) { | 894 | if (desc) { |
895 | regulators[id].n_voltages = | 895 | regulators[id].n_voltages = |
896 | (desc->max - desc->min) / desc->step + 1; | 896 | (desc->max - desc->min) / desc->step + 1; |
897 | regulators[id].min_uV = desc->min; | 897 | regulators[id].min_uV = desc->min; |
898 | regulators[id].uV_step = desc->step; | 898 | regulators[id].uV_step = desc->step; |
899 | regulators[id].vsel_reg = | 899 | regulators[id].vsel_reg = |
900 | s5m8767_get_vsel_reg(id, s5m8767); | 900 | s5m8767_get_vsel_reg(id, s5m8767); |
901 | if (id < S5M8767_BUCK1) | 901 | if (id < S5M8767_BUCK1) |
902 | regulators[id].vsel_mask = 0x3f; | 902 | regulators[id].vsel_mask = 0x3f; |
903 | else | 903 | else |
904 | regulators[id].vsel_mask = 0xff; | 904 | regulators[id].vsel_mask = 0xff; |
905 | } | 905 | } |
906 | 906 | ||
907 | config.dev = s5m8767->dev; | 907 | config.dev = s5m8767->dev; |
908 | config.init_data = pdata->regulators[i].initdata; | 908 | config.init_data = pdata->regulators[i].initdata; |
909 | config.driver_data = s5m8767; | 909 | config.driver_data = s5m8767; |
910 | config.regmap = iodev->regmap; | 910 | config.regmap = iodev->regmap; |
911 | config.of_node = pdata->regulators[i].reg_node; | 911 | config.of_node = pdata->regulators[i].reg_node; |
912 | 912 | ||
913 | rdev[i] = regulator_register(®ulators[id], &config); | 913 | rdev[i] = regulator_register(®ulators[id], &config); |
914 | if (IS_ERR(rdev[i])) { | 914 | if (IS_ERR(rdev[i])) { |
915 | ret = PTR_ERR(rdev[i]); | 915 | ret = PTR_ERR(rdev[i]); |
916 | dev_err(s5m8767->dev, "regulator init failed for %d\n", | 916 | dev_err(s5m8767->dev, "regulator init failed for %d\n", |
917 | id); | 917 | id); |
918 | rdev[i] = NULL; | 918 | rdev[i] = NULL; |
919 | goto err; | 919 | goto err; |
920 | } | 920 | } |
921 | } | 921 | } |
922 | 922 | ||
923 | return 0; | 923 | return 0; |
924 | err: | 924 | err: |
925 | for (i = 0; i < s5m8767->num_regulators; i++) | 925 | for (i = 0; i < s5m8767->num_regulators; i++) |
926 | if (rdev[i]) | 926 | regulator_unregister(rdev[i]); |
927 | regulator_unregister(rdev[i]); | ||
928 | 927 | ||
929 | return ret; | 928 | return ret; |
930 | } | 929 | } |
931 | 930 | ||
932 | static int s5m8767_pmic_remove(struct platform_device *pdev) | 931 | static int s5m8767_pmic_remove(struct platform_device *pdev) |
933 | { | 932 | { |
934 | struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); | 933 | struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); |
935 | struct regulator_dev **rdev = s5m8767->rdev; | 934 | struct regulator_dev **rdev = s5m8767->rdev; |
936 | int i; | 935 | int i; |
937 | 936 | ||
938 | for (i = 0; i < s5m8767->num_regulators; i++) | 937 | for (i = 0; i < s5m8767->num_regulators; i++) |
939 | if (rdev[i]) | 938 | regulator_unregister(rdev[i]); |
940 | regulator_unregister(rdev[i]); | ||
941 | 939 | ||
942 | return 0; | 940 | return 0; |
943 | } | 941 | } |
944 | 942 | ||
945 | static const struct platform_device_id s5m8767_pmic_id[] = { | 943 | static const struct platform_device_id s5m8767_pmic_id[] = { |
946 | { "s5m8767-pmic", 0}, | 944 | { "s5m8767-pmic", 0}, |
947 | { }, | 945 | { }, |
948 | }; | 946 | }; |
949 | MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); | 947 | MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); |
950 | 948 | ||
951 | static struct platform_driver s5m8767_pmic_driver = { | 949 | static struct platform_driver s5m8767_pmic_driver = { |
952 | .driver = { | 950 | .driver = { |
953 | .name = "s5m8767-pmic", | 951 | .name = "s5m8767-pmic", |
954 | .owner = THIS_MODULE, | 952 | .owner = THIS_MODULE, |
955 | }, | 953 | }, |
956 | .probe = s5m8767_pmic_probe, | 954 | .probe = s5m8767_pmic_probe, |
957 | .remove = s5m8767_pmic_remove, | 955 | .remove = s5m8767_pmic_remove, |
958 | .id_table = s5m8767_pmic_id, | 956 | .id_table = s5m8767_pmic_id, |
959 | }; | 957 | }; |
960 | 958 | ||
961 | static int __init s5m8767_pmic_init(void) | 959 | static int __init s5m8767_pmic_init(void) |
962 | { | 960 | { |
963 | return platform_driver_register(&s5m8767_pmic_driver); | 961 | return platform_driver_register(&s5m8767_pmic_driver); |
964 | } | 962 | } |
965 | subsys_initcall(s5m8767_pmic_init); | 963 | subsys_initcall(s5m8767_pmic_init); |
966 | 964 | ||
967 | static void __exit s5m8767_pmic_exit(void) | 965 | static void __exit s5m8767_pmic_exit(void) |
968 | { | 966 | { |
969 | platform_driver_unregister(&s5m8767_pmic_driver); | 967 | platform_driver_unregister(&s5m8767_pmic_driver); |
970 | } | 968 | } |
971 | module_exit(s5m8767_pmic_exit); | 969 | module_exit(s5m8767_pmic_exit); |
972 | 970 | ||
973 | /* Module information */ | 971 | /* Module information */ |
974 | MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); | 972 | MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); |
975 | MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); | 973 | MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); |
976 | MODULE_LICENSE("GPL"); | 974 | MODULE_LICENSE("GPL"); |
977 | 975 |
drivers/regulator/tps6524x-regulator.c
1 | /* | 1 | /* |
2 | * Regulator driver for TPS6524x PMIC | 2 | * Regulator driver for TPS6524x PMIC |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Texas Instruments | 4 | * Copyright (C) 2010 Texas Instruments |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation version 2. | 8 | * published by the Free Software Foundation version 2. |
9 | * | 9 | * |
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | 10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, |
11 | * whether express or implied; without even the implied warranty of | 11 | * whether express or implied; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * General Public License for more details. | 13 | * General Public License for more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/regulator/driver.h> | 22 | #include <linux/regulator/driver.h> |
23 | #include <linux/regulator/machine.h> | 23 | #include <linux/regulator/machine.h> |
24 | 24 | ||
25 | #define REG_LDO_SET 0x0 | 25 | #define REG_LDO_SET 0x0 |
26 | #define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ | 26 | #define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ |
27 | #define LDO_VSEL_MASK 0x0f | 27 | #define LDO_VSEL_MASK 0x0f |
28 | #define LDO2_ILIM_SHIFT 12 | 28 | #define LDO2_ILIM_SHIFT 12 |
29 | #define LDO2_VSEL_SHIFT 4 | 29 | #define LDO2_VSEL_SHIFT 4 |
30 | #define LDO1_ILIM_SHIFT 8 | 30 | #define LDO1_ILIM_SHIFT 8 |
31 | #define LDO1_VSEL_SHIFT 0 | 31 | #define LDO1_VSEL_SHIFT 0 |
32 | 32 | ||
33 | #define REG_BLOCK_EN 0x1 | 33 | #define REG_BLOCK_EN 0x1 |
34 | #define BLOCK_MASK 1 | 34 | #define BLOCK_MASK 1 |
35 | #define BLOCK_LDO1_SHIFT 0 | 35 | #define BLOCK_LDO1_SHIFT 0 |
36 | #define BLOCK_LDO2_SHIFT 1 | 36 | #define BLOCK_LDO2_SHIFT 1 |
37 | #define BLOCK_LCD_SHIFT 2 | 37 | #define BLOCK_LCD_SHIFT 2 |
38 | #define BLOCK_USB_SHIFT 3 | 38 | #define BLOCK_USB_SHIFT 3 |
39 | 39 | ||
40 | #define REG_DCDC_SET 0x2 | 40 | #define REG_DCDC_SET 0x2 |
41 | #define DCDC_VDCDC_MASK 0x1f | 41 | #define DCDC_VDCDC_MASK 0x1f |
42 | #define DCDC_VDCDC1_SHIFT 0 | 42 | #define DCDC_VDCDC1_SHIFT 0 |
43 | #define DCDC_VDCDC2_SHIFT 5 | 43 | #define DCDC_VDCDC2_SHIFT 5 |
44 | #define DCDC_VDCDC3_SHIFT 10 | 44 | #define DCDC_VDCDC3_SHIFT 10 |
45 | 45 | ||
46 | #define REG_DCDC_EN 0x3 | 46 | #define REG_DCDC_EN 0x3 |
47 | #define DCDCDCDC_EN_MASK 0x1 | 47 | #define DCDCDCDC_EN_MASK 0x1 |
48 | #define DCDCDCDC1_EN_SHIFT 0 | 48 | #define DCDCDCDC1_EN_SHIFT 0 |
49 | #define DCDCDCDC1_PG_MSK BIT(1) | 49 | #define DCDCDCDC1_PG_MSK BIT(1) |
50 | #define DCDCDCDC2_EN_SHIFT 2 | 50 | #define DCDCDCDC2_EN_SHIFT 2 |
51 | #define DCDCDCDC2_PG_MSK BIT(3) | 51 | #define DCDCDCDC2_PG_MSK BIT(3) |
52 | #define DCDCDCDC3_EN_SHIFT 4 | 52 | #define DCDCDCDC3_EN_SHIFT 4 |
53 | #define DCDCDCDC3_PG_MSK BIT(5) | 53 | #define DCDCDCDC3_PG_MSK BIT(5) |
54 | 54 | ||
55 | #define REG_USB 0x4 | 55 | #define REG_USB 0x4 |
56 | #define USB_ILIM_SHIFT 0 | 56 | #define USB_ILIM_SHIFT 0 |
57 | #define USB_ILIM_MASK 0x3 | 57 | #define USB_ILIM_MASK 0x3 |
58 | #define USB_TSD_SHIFT 2 | 58 | #define USB_TSD_SHIFT 2 |
59 | #define USB_TSD_MASK 0x3 | 59 | #define USB_TSD_MASK 0x3 |
60 | #define USB_TWARN_SHIFT 4 | 60 | #define USB_TWARN_SHIFT 4 |
61 | #define USB_TWARN_MASK 0x3 | 61 | #define USB_TWARN_MASK 0x3 |
62 | #define USB_IWARN_SD BIT(6) | 62 | #define USB_IWARN_SD BIT(6) |
63 | #define USB_FAST_LOOP BIT(7) | 63 | #define USB_FAST_LOOP BIT(7) |
64 | 64 | ||
65 | #define REG_ALARM 0x5 | 65 | #define REG_ALARM 0x5 |
66 | #define ALARM_LDO1 BIT(0) | 66 | #define ALARM_LDO1 BIT(0) |
67 | #define ALARM_DCDC1 BIT(1) | 67 | #define ALARM_DCDC1 BIT(1) |
68 | #define ALARM_DCDC2 BIT(2) | 68 | #define ALARM_DCDC2 BIT(2) |
69 | #define ALARM_DCDC3 BIT(3) | 69 | #define ALARM_DCDC3 BIT(3) |
70 | #define ALARM_LDO2 BIT(4) | 70 | #define ALARM_LDO2 BIT(4) |
71 | #define ALARM_USB_WARN BIT(5) | 71 | #define ALARM_USB_WARN BIT(5) |
72 | #define ALARM_USB_ALARM BIT(6) | 72 | #define ALARM_USB_ALARM BIT(6) |
73 | #define ALARM_LCD BIT(9) | 73 | #define ALARM_LCD BIT(9) |
74 | #define ALARM_TEMP_WARM BIT(10) | 74 | #define ALARM_TEMP_WARM BIT(10) |
75 | #define ALARM_TEMP_HOT BIT(11) | 75 | #define ALARM_TEMP_HOT BIT(11) |
76 | #define ALARM_NRST BIT(14) | 76 | #define ALARM_NRST BIT(14) |
77 | #define ALARM_POWERUP BIT(15) | 77 | #define ALARM_POWERUP BIT(15) |
78 | 78 | ||
79 | #define REG_INT_ENABLE 0x6 | 79 | #define REG_INT_ENABLE 0x6 |
80 | #define INT_LDO1 BIT(0) | 80 | #define INT_LDO1 BIT(0) |
81 | #define INT_DCDC1 BIT(1) | 81 | #define INT_DCDC1 BIT(1) |
82 | #define INT_DCDC2 BIT(2) | 82 | #define INT_DCDC2 BIT(2) |
83 | #define INT_DCDC3 BIT(3) | 83 | #define INT_DCDC3 BIT(3) |
84 | #define INT_LDO2 BIT(4) | 84 | #define INT_LDO2 BIT(4) |
85 | #define INT_USB_WARN BIT(5) | 85 | #define INT_USB_WARN BIT(5) |
86 | #define INT_USB_ALARM BIT(6) | 86 | #define INT_USB_ALARM BIT(6) |
87 | #define INT_LCD BIT(9) | 87 | #define INT_LCD BIT(9) |
88 | #define INT_TEMP_WARM BIT(10) | 88 | #define INT_TEMP_WARM BIT(10) |
89 | #define INT_TEMP_HOT BIT(11) | 89 | #define INT_TEMP_HOT BIT(11) |
90 | #define INT_GLOBAL_EN BIT(15) | 90 | #define INT_GLOBAL_EN BIT(15) |
91 | 91 | ||
92 | #define REG_INT_STATUS 0x7 | 92 | #define REG_INT_STATUS 0x7 |
93 | #define STATUS_LDO1 BIT(0) | 93 | #define STATUS_LDO1 BIT(0) |
94 | #define STATUS_DCDC1 BIT(1) | 94 | #define STATUS_DCDC1 BIT(1) |
95 | #define STATUS_DCDC2 BIT(2) | 95 | #define STATUS_DCDC2 BIT(2) |
96 | #define STATUS_DCDC3 BIT(3) | 96 | #define STATUS_DCDC3 BIT(3) |
97 | #define STATUS_LDO2 BIT(4) | 97 | #define STATUS_LDO2 BIT(4) |
98 | #define STATUS_USB_WARN BIT(5) | 98 | #define STATUS_USB_WARN BIT(5) |
99 | #define STATUS_USB_ALARM BIT(6) | 99 | #define STATUS_USB_ALARM BIT(6) |
100 | #define STATUS_LCD BIT(9) | 100 | #define STATUS_LCD BIT(9) |
101 | #define STATUS_TEMP_WARM BIT(10) | 101 | #define STATUS_TEMP_WARM BIT(10) |
102 | #define STATUS_TEMP_HOT BIT(11) | 102 | #define STATUS_TEMP_HOT BIT(11) |
103 | 103 | ||
104 | #define REG_SOFTWARE_RESET 0xb | 104 | #define REG_SOFTWARE_RESET 0xb |
105 | #define REG_WRITE_ENABLE 0xd | 105 | #define REG_WRITE_ENABLE 0xd |
106 | #define REG_REV_ID 0xf | 106 | #define REG_REV_ID 0xf |
107 | 107 | ||
108 | #define N_DCDC 3 | 108 | #define N_DCDC 3 |
109 | #define N_LDO 2 | 109 | #define N_LDO 2 |
110 | #define N_SWITCH 2 | 110 | #define N_SWITCH 2 |
111 | #define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH) | 111 | #define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH) |
112 | 112 | ||
113 | #define CMD_READ(reg) ((reg) << 6) | 113 | #define CMD_READ(reg) ((reg) << 6) |
114 | #define CMD_WRITE(reg) (BIT(5) | (reg) << 6) | 114 | #define CMD_WRITE(reg) (BIT(5) | (reg) << 6) |
115 | #define STAT_CLK BIT(3) | 115 | #define STAT_CLK BIT(3) |
116 | #define STAT_WRITE BIT(2) | 116 | #define STAT_WRITE BIT(2) |
117 | #define STAT_INVALID BIT(1) | 117 | #define STAT_INVALID BIT(1) |
118 | #define STAT_WP BIT(0) | 118 | #define STAT_WP BIT(0) |
119 | 119 | ||
120 | struct field { | 120 | struct field { |
121 | int reg; | 121 | int reg; |
122 | int shift; | 122 | int shift; |
123 | int mask; | 123 | int mask; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct supply_info { | 126 | struct supply_info { |
127 | const char *name; | 127 | const char *name; |
128 | int n_voltages; | 128 | int n_voltages; |
129 | const unsigned int *voltages; | 129 | const unsigned int *voltages; |
130 | int n_ilimsels; | 130 | int n_ilimsels; |
131 | const unsigned int *ilimsels; | 131 | const unsigned int *ilimsels; |
132 | struct field enable, voltage, ilimsel; | 132 | struct field enable, voltage, ilimsel; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | struct tps6524x { | 135 | struct tps6524x { |
136 | struct device *dev; | 136 | struct device *dev; |
137 | struct spi_device *spi; | 137 | struct spi_device *spi; |
138 | struct mutex lock; | 138 | struct mutex lock; |
139 | struct regulator_desc desc[N_REGULATORS]; | 139 | struct regulator_desc desc[N_REGULATORS]; |
140 | struct regulator_dev *rdev[N_REGULATORS]; | 140 | struct regulator_dev *rdev[N_REGULATORS]; |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static int __read_reg(struct tps6524x *hw, int reg) | 143 | static int __read_reg(struct tps6524x *hw, int reg) |
144 | { | 144 | { |
145 | int error = 0; | 145 | int error = 0; |
146 | u16 cmd = CMD_READ(reg), in; | 146 | u16 cmd = CMD_READ(reg), in; |
147 | u8 status; | 147 | u8 status; |
148 | struct spi_message m; | 148 | struct spi_message m; |
149 | struct spi_transfer t[3]; | 149 | struct spi_transfer t[3]; |
150 | 150 | ||
151 | spi_message_init(&m); | 151 | spi_message_init(&m); |
152 | memset(t, 0, sizeof(t)); | 152 | memset(t, 0, sizeof(t)); |
153 | 153 | ||
154 | t[0].tx_buf = &cmd; | 154 | t[0].tx_buf = &cmd; |
155 | t[0].len = 2; | 155 | t[0].len = 2; |
156 | t[0].bits_per_word = 12; | 156 | t[0].bits_per_word = 12; |
157 | spi_message_add_tail(&t[0], &m); | 157 | spi_message_add_tail(&t[0], &m); |
158 | 158 | ||
159 | t[1].rx_buf = ∈ | 159 | t[1].rx_buf = ∈ |
160 | t[1].len = 2; | 160 | t[1].len = 2; |
161 | t[1].bits_per_word = 16; | 161 | t[1].bits_per_word = 16; |
162 | spi_message_add_tail(&t[1], &m); | 162 | spi_message_add_tail(&t[1], &m); |
163 | 163 | ||
164 | t[2].rx_buf = &status; | 164 | t[2].rx_buf = &status; |
165 | t[2].len = 1; | 165 | t[2].len = 1; |
166 | t[2].bits_per_word = 4; | 166 | t[2].bits_per_word = 4; |
167 | spi_message_add_tail(&t[2], &m); | 167 | spi_message_add_tail(&t[2], &m); |
168 | 168 | ||
169 | error = spi_sync(hw->spi, &m); | 169 | error = spi_sync(hw->spi, &m); |
170 | if (error < 0) | 170 | if (error < 0) |
171 | return error; | 171 | return error; |
172 | 172 | ||
173 | dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", | 173 | dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", |
174 | reg, in, status); | 174 | reg, in, status); |
175 | 175 | ||
176 | if (!(status & STAT_CLK) || (status & STAT_WRITE)) | 176 | if (!(status & STAT_CLK) || (status & STAT_WRITE)) |
177 | return -EIO; | 177 | return -EIO; |
178 | 178 | ||
179 | if (status & STAT_INVALID) | 179 | if (status & STAT_INVALID) |
180 | return -EINVAL; | 180 | return -EINVAL; |
181 | 181 | ||
182 | return in; | 182 | return in; |
183 | } | 183 | } |
184 | 184 | ||
185 | static int read_reg(struct tps6524x *hw, int reg) | 185 | static int read_reg(struct tps6524x *hw, int reg) |
186 | { | 186 | { |
187 | int ret; | 187 | int ret; |
188 | 188 | ||
189 | mutex_lock(&hw->lock); | 189 | mutex_lock(&hw->lock); |
190 | ret = __read_reg(hw, reg); | 190 | ret = __read_reg(hw, reg); |
191 | mutex_unlock(&hw->lock); | 191 | mutex_unlock(&hw->lock); |
192 | 192 | ||
193 | return ret; | 193 | return ret; |
194 | } | 194 | } |
195 | 195 | ||
196 | static int __write_reg(struct tps6524x *hw, int reg, int val) | 196 | static int __write_reg(struct tps6524x *hw, int reg, int val) |
197 | { | 197 | { |
198 | int error = 0; | 198 | int error = 0; |
199 | u16 cmd = CMD_WRITE(reg), out = val; | 199 | u16 cmd = CMD_WRITE(reg), out = val; |
200 | u8 status; | 200 | u8 status; |
201 | struct spi_message m; | 201 | struct spi_message m; |
202 | struct spi_transfer t[3]; | 202 | struct spi_transfer t[3]; |
203 | 203 | ||
204 | spi_message_init(&m); | 204 | spi_message_init(&m); |
205 | memset(t, 0, sizeof(t)); | 205 | memset(t, 0, sizeof(t)); |
206 | 206 | ||
207 | t[0].tx_buf = &cmd; | 207 | t[0].tx_buf = &cmd; |
208 | t[0].len = 2; | 208 | t[0].len = 2; |
209 | t[0].bits_per_word = 12; | 209 | t[0].bits_per_word = 12; |
210 | spi_message_add_tail(&t[0], &m); | 210 | spi_message_add_tail(&t[0], &m); |
211 | 211 | ||
212 | t[1].tx_buf = &out; | 212 | t[1].tx_buf = &out; |
213 | t[1].len = 2; | 213 | t[1].len = 2; |
214 | t[1].bits_per_word = 16; | 214 | t[1].bits_per_word = 16; |
215 | spi_message_add_tail(&t[1], &m); | 215 | spi_message_add_tail(&t[1], &m); |
216 | 216 | ||
217 | t[2].rx_buf = &status; | 217 | t[2].rx_buf = &status; |
218 | t[2].len = 1; | 218 | t[2].len = 1; |
219 | t[2].bits_per_word = 4; | 219 | t[2].bits_per_word = 4; |
220 | spi_message_add_tail(&t[2], &m); | 220 | spi_message_add_tail(&t[2], &m); |
221 | 221 | ||
222 | error = spi_sync(hw->spi, &m); | 222 | error = spi_sync(hw->spi, &m); |
223 | if (error < 0) | 223 | if (error < 0) |
224 | return error; | 224 | return error; |
225 | 225 | ||
226 | dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", | 226 | dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", |
227 | reg, out, status); | 227 | reg, out, status); |
228 | 228 | ||
229 | if (!(status & STAT_CLK) || !(status & STAT_WRITE)) | 229 | if (!(status & STAT_CLK) || !(status & STAT_WRITE)) |
230 | return -EIO; | 230 | return -EIO; |
231 | 231 | ||
232 | if (status & (STAT_INVALID | STAT_WP)) | 232 | if (status & (STAT_INVALID | STAT_WP)) |
233 | return -EINVAL; | 233 | return -EINVAL; |
234 | 234 | ||
235 | return error; | 235 | return error; |
236 | } | 236 | } |
237 | 237 | ||
238 | static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) | 238 | static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) |
239 | { | 239 | { |
240 | int ret; | 240 | int ret; |
241 | 241 | ||
242 | ret = __read_reg(hw, reg); | 242 | ret = __read_reg(hw, reg); |
243 | if (ret < 0) | 243 | if (ret < 0) |
244 | return ret; | 244 | return ret; |
245 | 245 | ||
246 | ret &= ~mask; | 246 | ret &= ~mask; |
247 | ret |= val; | 247 | ret |= val; |
248 | 248 | ||
249 | ret = __write_reg(hw, reg, ret); | 249 | ret = __write_reg(hw, reg, ret); |
250 | 250 | ||
251 | return (ret < 0) ? ret : 0; | 251 | return (ret < 0) ? ret : 0; |
252 | } | 252 | } |
253 | 253 | ||
254 | static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) | 254 | static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) |
255 | { | 255 | { |
256 | int ret; | 256 | int ret; |
257 | 257 | ||
258 | mutex_lock(&hw->lock); | 258 | mutex_lock(&hw->lock); |
259 | 259 | ||
260 | ret = __write_reg(hw, REG_WRITE_ENABLE, 1); | 260 | ret = __write_reg(hw, REG_WRITE_ENABLE, 1); |
261 | if (ret) { | 261 | if (ret) { |
262 | dev_err(hw->dev, "failed to set write enable\n"); | 262 | dev_err(hw->dev, "failed to set write enable\n"); |
263 | goto error; | 263 | goto error; |
264 | } | 264 | } |
265 | 265 | ||
266 | ret = __rmw_reg(hw, reg, mask, val); | 266 | ret = __rmw_reg(hw, reg, mask, val); |
267 | if (ret) | 267 | if (ret) |
268 | dev_err(hw->dev, "failed to rmw register %d\n", reg); | 268 | dev_err(hw->dev, "failed to rmw register %d\n", reg); |
269 | 269 | ||
270 | ret = __write_reg(hw, REG_WRITE_ENABLE, 0); | 270 | ret = __write_reg(hw, REG_WRITE_ENABLE, 0); |
271 | if (ret) { | 271 | if (ret) { |
272 | dev_err(hw->dev, "failed to clear write enable\n"); | 272 | dev_err(hw->dev, "failed to clear write enable\n"); |
273 | goto error; | 273 | goto error; |
274 | } | 274 | } |
275 | 275 | ||
276 | error: | 276 | error: |
277 | mutex_unlock(&hw->lock); | 277 | mutex_unlock(&hw->lock); |
278 | 278 | ||
279 | return ret; | 279 | return ret; |
280 | } | 280 | } |
281 | 281 | ||
282 | static int read_field(struct tps6524x *hw, const struct field *field) | 282 | static int read_field(struct tps6524x *hw, const struct field *field) |
283 | { | 283 | { |
284 | int tmp; | 284 | int tmp; |
285 | 285 | ||
286 | tmp = read_reg(hw, field->reg); | 286 | tmp = read_reg(hw, field->reg); |
287 | if (tmp < 0) | 287 | if (tmp < 0) |
288 | return tmp; | 288 | return tmp; |
289 | 289 | ||
290 | return (tmp >> field->shift) & field->mask; | 290 | return (tmp >> field->shift) & field->mask; |
291 | } | 291 | } |
292 | 292 | ||
293 | static int write_field(struct tps6524x *hw, const struct field *field, | 293 | static int write_field(struct tps6524x *hw, const struct field *field, |
294 | int val) | 294 | int val) |
295 | { | 295 | { |
296 | if (val & ~field->mask) | 296 | if (val & ~field->mask) |
297 | return -EOVERFLOW; | 297 | return -EOVERFLOW; |
298 | 298 | ||
299 | return rmw_protect(hw, field->reg, | 299 | return rmw_protect(hw, field->reg, |
300 | field->mask << field->shift, | 300 | field->mask << field->shift, |
301 | val << field->shift); | 301 | val << field->shift); |
302 | } | 302 | } |
303 | 303 | ||
304 | static const unsigned int dcdc1_voltages[] = { | 304 | static const unsigned int dcdc1_voltages[] = { |
305 | 800000, 825000, 850000, 875000, | 305 | 800000, 825000, 850000, 875000, |
306 | 900000, 925000, 950000, 975000, | 306 | 900000, 925000, 950000, 975000, |
307 | 1000000, 1025000, 1050000, 1075000, | 307 | 1000000, 1025000, 1050000, 1075000, |
308 | 1100000, 1125000, 1150000, 1175000, | 308 | 1100000, 1125000, 1150000, 1175000, |
309 | 1200000, 1225000, 1250000, 1275000, | 309 | 1200000, 1225000, 1250000, 1275000, |
310 | 1300000, 1325000, 1350000, 1375000, | 310 | 1300000, 1325000, 1350000, 1375000, |
311 | 1400000, 1425000, 1450000, 1475000, | 311 | 1400000, 1425000, 1450000, 1475000, |
312 | 1500000, 1525000, 1550000, 1575000, | 312 | 1500000, 1525000, 1550000, 1575000, |
313 | }; | 313 | }; |
314 | 314 | ||
315 | static const unsigned int dcdc2_voltages[] = { | 315 | static const unsigned int dcdc2_voltages[] = { |
316 | 1400000, 1450000, 1500000, 1550000, | 316 | 1400000, 1450000, 1500000, 1550000, |
317 | 1600000, 1650000, 1700000, 1750000, | 317 | 1600000, 1650000, 1700000, 1750000, |
318 | 1800000, 1850000, 1900000, 1950000, | 318 | 1800000, 1850000, 1900000, 1950000, |
319 | 2000000, 2050000, 2100000, 2150000, | 319 | 2000000, 2050000, 2100000, 2150000, |
320 | 2200000, 2250000, 2300000, 2350000, | 320 | 2200000, 2250000, 2300000, 2350000, |
321 | 2400000, 2450000, 2500000, 2550000, | 321 | 2400000, 2450000, 2500000, 2550000, |
322 | 2600000, 2650000, 2700000, 2750000, | 322 | 2600000, 2650000, 2700000, 2750000, |
323 | 2800000, 2850000, 2900000, 2950000, | 323 | 2800000, 2850000, 2900000, 2950000, |
324 | }; | 324 | }; |
325 | 325 | ||
326 | static const unsigned int dcdc3_voltages[] = { | 326 | static const unsigned int dcdc3_voltages[] = { |
327 | 2400000, 2450000, 2500000, 2550000, 2600000, | 327 | 2400000, 2450000, 2500000, 2550000, 2600000, |
328 | 2650000, 2700000, 2750000, 2800000, 2850000, | 328 | 2650000, 2700000, 2750000, 2800000, 2850000, |
329 | 2900000, 2950000, 3000000, 3050000, 3100000, | 329 | 2900000, 2950000, 3000000, 3050000, 3100000, |
330 | 3150000, 3200000, 3250000, 3300000, 3350000, | 330 | 3150000, 3200000, 3250000, 3300000, 3350000, |
331 | 3400000, 3450000, 3500000, 3550000, 3600000, | 331 | 3400000, 3450000, 3500000, 3550000, 3600000, |
332 | }; | 332 | }; |
333 | 333 | ||
334 | static const unsigned int ldo1_voltages[] = { | 334 | static const unsigned int ldo1_voltages[] = { |
335 | 4300000, 4350000, 4400000, 4450000, | 335 | 4300000, 4350000, 4400000, 4450000, |
336 | 4500000, 4550000, 4600000, 4650000, | 336 | 4500000, 4550000, 4600000, 4650000, |
337 | 4700000, 4750000, 4800000, 4850000, | 337 | 4700000, 4750000, 4800000, 4850000, |
338 | 4900000, 4950000, 5000000, 5050000, | 338 | 4900000, 4950000, 5000000, 5050000, |
339 | }; | 339 | }; |
340 | 340 | ||
341 | static const unsigned int ldo2_voltages[] = { | 341 | static const unsigned int ldo2_voltages[] = { |
342 | 1100000, 1150000, 1200000, 1250000, | 342 | 1100000, 1150000, 1200000, 1250000, |
343 | 1300000, 1700000, 1750000, 1800000, | 343 | 1300000, 1700000, 1750000, 1800000, |
344 | 1850000, 1900000, 3150000, 3200000, | 344 | 1850000, 1900000, 3150000, 3200000, |
345 | 3250000, 3300000, 3350000, 3400000, | 345 | 3250000, 3300000, 3350000, 3400000, |
346 | }; | 346 | }; |
347 | 347 | ||
348 | static const unsigned int fixed_5000000_voltage[] = { | 348 | static const unsigned int fixed_5000000_voltage[] = { |
349 | 5000000 | 349 | 5000000 |
350 | }; | 350 | }; |
351 | 351 | ||
352 | static const unsigned int ldo_ilimsel[] = { | 352 | static const unsigned int ldo_ilimsel[] = { |
353 | 400000, 1500000 | 353 | 400000, 1500000 |
354 | }; | 354 | }; |
355 | 355 | ||
356 | static const unsigned int usb_ilimsel[] = { | 356 | static const unsigned int usb_ilimsel[] = { |
357 | 200000, 400000, 800000, 1000000 | 357 | 200000, 400000, 800000, 1000000 |
358 | }; | 358 | }; |
359 | 359 | ||
360 | static const unsigned int fixed_2400000_ilimsel[] = { | 360 | static const unsigned int fixed_2400000_ilimsel[] = { |
361 | 2400000 | 361 | 2400000 |
362 | }; | 362 | }; |
363 | 363 | ||
364 | static const unsigned int fixed_1200000_ilimsel[] = { | 364 | static const unsigned int fixed_1200000_ilimsel[] = { |
365 | 1200000 | 365 | 1200000 |
366 | }; | 366 | }; |
367 | 367 | ||
368 | static const unsigned int fixed_400000_ilimsel[] = { | 368 | static const unsigned int fixed_400000_ilimsel[] = { |
369 | 400000 | 369 | 400000 |
370 | }; | 370 | }; |
371 | 371 | ||
372 | #define __MK_FIELD(_reg, _mask, _shift) \ | 372 | #define __MK_FIELD(_reg, _mask, _shift) \ |
373 | { .reg = (_reg), .mask = (_mask), .shift = (_shift), } | 373 | { .reg = (_reg), .mask = (_mask), .shift = (_shift), } |
374 | 374 | ||
375 | static const struct supply_info supply_info[N_REGULATORS] = { | 375 | static const struct supply_info supply_info[N_REGULATORS] = { |
376 | { | 376 | { |
377 | .name = "DCDC1", | 377 | .name = "DCDC1", |
378 | .n_voltages = ARRAY_SIZE(dcdc1_voltages), | 378 | .n_voltages = ARRAY_SIZE(dcdc1_voltages), |
379 | .voltages = dcdc1_voltages, | 379 | .voltages = dcdc1_voltages, |
380 | .n_ilimsels = ARRAY_SIZE(fixed_2400000_ilimsel), | 380 | .n_ilimsels = ARRAY_SIZE(fixed_2400000_ilimsel), |
381 | .ilimsels = fixed_2400000_ilimsel, | 381 | .ilimsels = fixed_2400000_ilimsel, |
382 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, | 382 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, |
383 | DCDCDCDC1_EN_SHIFT), | 383 | DCDCDCDC1_EN_SHIFT), |
384 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, | 384 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, |
385 | DCDC_VDCDC1_SHIFT), | 385 | DCDC_VDCDC1_SHIFT), |
386 | }, | 386 | }, |
387 | { | 387 | { |
388 | .name = "DCDC2", | 388 | .name = "DCDC2", |
389 | .n_voltages = ARRAY_SIZE(dcdc2_voltages), | 389 | .n_voltages = ARRAY_SIZE(dcdc2_voltages), |
390 | .voltages = dcdc2_voltages, | 390 | .voltages = dcdc2_voltages, |
391 | .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), | 391 | .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), |
392 | .ilimsels = fixed_1200000_ilimsel, | 392 | .ilimsels = fixed_1200000_ilimsel, |
393 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, | 393 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, |
394 | DCDCDCDC2_EN_SHIFT), | 394 | DCDCDCDC2_EN_SHIFT), |
395 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, | 395 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, |
396 | DCDC_VDCDC2_SHIFT), | 396 | DCDC_VDCDC2_SHIFT), |
397 | }, | 397 | }, |
398 | { | 398 | { |
399 | .name = "DCDC3", | 399 | .name = "DCDC3", |
400 | .n_voltages = ARRAY_SIZE(dcdc3_voltages), | 400 | .n_voltages = ARRAY_SIZE(dcdc3_voltages), |
401 | .voltages = dcdc3_voltages, | 401 | .voltages = dcdc3_voltages, |
402 | .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), | 402 | .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), |
403 | .ilimsels = fixed_1200000_ilimsel, | 403 | .ilimsels = fixed_1200000_ilimsel, |
404 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, | 404 | .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, |
405 | DCDCDCDC3_EN_SHIFT), | 405 | DCDCDCDC3_EN_SHIFT), |
406 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, | 406 | .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, |
407 | DCDC_VDCDC3_SHIFT), | 407 | DCDC_VDCDC3_SHIFT), |
408 | }, | 408 | }, |
409 | { | 409 | { |
410 | .name = "LDO1", | 410 | .name = "LDO1", |
411 | .n_voltages = ARRAY_SIZE(ldo1_voltages), | 411 | .n_voltages = ARRAY_SIZE(ldo1_voltages), |
412 | .voltages = ldo1_voltages, | 412 | .voltages = ldo1_voltages, |
413 | .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), | 413 | .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), |
414 | .ilimsels = ldo_ilimsel, | 414 | .ilimsels = ldo_ilimsel, |
415 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, | 415 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, |
416 | BLOCK_LDO1_SHIFT), | 416 | BLOCK_LDO1_SHIFT), |
417 | .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, | 417 | .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, |
418 | LDO1_VSEL_SHIFT), | 418 | LDO1_VSEL_SHIFT), |
419 | .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, | 419 | .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, |
420 | LDO1_ILIM_SHIFT), | 420 | LDO1_ILIM_SHIFT), |
421 | }, | 421 | }, |
422 | { | 422 | { |
423 | .name = "LDO2", | 423 | .name = "LDO2", |
424 | .n_voltages = ARRAY_SIZE(ldo2_voltages), | 424 | .n_voltages = ARRAY_SIZE(ldo2_voltages), |
425 | .voltages = ldo2_voltages, | 425 | .voltages = ldo2_voltages, |
426 | .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), | 426 | .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), |
427 | .ilimsels = ldo_ilimsel, | 427 | .ilimsels = ldo_ilimsel, |
428 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, | 428 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, |
429 | BLOCK_LDO2_SHIFT), | 429 | BLOCK_LDO2_SHIFT), |
430 | .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, | 430 | .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, |
431 | LDO2_VSEL_SHIFT), | 431 | LDO2_VSEL_SHIFT), |
432 | .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, | 432 | .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, |
433 | LDO2_ILIM_SHIFT), | 433 | LDO2_ILIM_SHIFT), |
434 | }, | 434 | }, |
435 | { | 435 | { |
436 | .name = "USB", | 436 | .name = "USB", |
437 | .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), | 437 | .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), |
438 | .voltages = fixed_5000000_voltage, | 438 | .voltages = fixed_5000000_voltage, |
439 | .n_ilimsels = ARRAY_SIZE(usb_ilimsel), | 439 | .n_ilimsels = ARRAY_SIZE(usb_ilimsel), |
440 | .ilimsels = usb_ilimsel, | 440 | .ilimsels = usb_ilimsel, |
441 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, | 441 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, |
442 | BLOCK_USB_SHIFT), | 442 | BLOCK_USB_SHIFT), |
443 | .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, | 443 | .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, |
444 | USB_ILIM_SHIFT), | 444 | USB_ILIM_SHIFT), |
445 | }, | 445 | }, |
446 | { | 446 | { |
447 | .name = "LCD", | 447 | .name = "LCD", |
448 | .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), | 448 | .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), |
449 | .voltages = fixed_5000000_voltage, | 449 | .voltages = fixed_5000000_voltage, |
450 | .n_ilimsels = ARRAY_SIZE(fixed_400000_ilimsel), | 450 | .n_ilimsels = ARRAY_SIZE(fixed_400000_ilimsel), |
451 | .ilimsels = fixed_400000_ilimsel, | 451 | .ilimsels = fixed_400000_ilimsel, |
452 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, | 452 | .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, |
453 | BLOCK_LCD_SHIFT), | 453 | BLOCK_LCD_SHIFT), |
454 | }, | 454 | }, |
455 | }; | 455 | }; |
456 | 456 | ||
457 | static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) | 457 | static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) |
458 | { | 458 | { |
459 | const struct supply_info *info; | 459 | const struct supply_info *info; |
460 | struct tps6524x *hw; | 460 | struct tps6524x *hw; |
461 | 461 | ||
462 | hw = rdev_get_drvdata(rdev); | 462 | hw = rdev_get_drvdata(rdev); |
463 | info = &supply_info[rdev_get_id(rdev)]; | 463 | info = &supply_info[rdev_get_id(rdev)]; |
464 | 464 | ||
465 | if (rdev->desc->n_voltages == 1) | 465 | if (rdev->desc->n_voltages == 1) |
466 | return -EINVAL; | 466 | return -EINVAL; |
467 | 467 | ||
468 | return write_field(hw, &info->voltage, selector); | 468 | return write_field(hw, &info->voltage, selector); |
469 | } | 469 | } |
470 | 470 | ||
471 | static int get_voltage_sel(struct regulator_dev *rdev) | 471 | static int get_voltage_sel(struct regulator_dev *rdev) |
472 | { | 472 | { |
473 | const struct supply_info *info; | 473 | const struct supply_info *info; |
474 | struct tps6524x *hw; | 474 | struct tps6524x *hw; |
475 | int ret; | 475 | int ret; |
476 | 476 | ||
477 | hw = rdev_get_drvdata(rdev); | 477 | hw = rdev_get_drvdata(rdev); |
478 | info = &supply_info[rdev_get_id(rdev)]; | 478 | info = &supply_info[rdev_get_id(rdev)]; |
479 | 479 | ||
480 | if (rdev->desc->n_voltages == 1) | 480 | if (rdev->desc->n_voltages == 1) |
481 | return 0; | 481 | return 0; |
482 | 482 | ||
483 | ret = read_field(hw, &info->voltage); | 483 | ret = read_field(hw, &info->voltage); |
484 | if (ret < 0) | 484 | if (ret < 0) |
485 | return ret; | 485 | return ret; |
486 | if (WARN_ON(ret >= info->n_voltages)) | 486 | if (WARN_ON(ret >= info->n_voltages)) |
487 | return -EIO; | 487 | return -EIO; |
488 | 488 | ||
489 | return ret; | 489 | return ret; |
490 | } | 490 | } |
491 | 491 | ||
492 | static int set_current_limit(struct regulator_dev *rdev, int min_uA, | 492 | static int set_current_limit(struct regulator_dev *rdev, int min_uA, |
493 | int max_uA) | 493 | int max_uA) |
494 | { | 494 | { |
495 | const struct supply_info *info; | 495 | const struct supply_info *info; |
496 | struct tps6524x *hw; | 496 | struct tps6524x *hw; |
497 | int i; | 497 | int i; |
498 | 498 | ||
499 | hw = rdev_get_drvdata(rdev); | 499 | hw = rdev_get_drvdata(rdev); |
500 | info = &supply_info[rdev_get_id(rdev)]; | 500 | info = &supply_info[rdev_get_id(rdev)]; |
501 | 501 | ||
502 | if (info->n_ilimsels == 1) | 502 | if (info->n_ilimsels == 1) |
503 | return -EINVAL; | 503 | return -EINVAL; |
504 | 504 | ||
505 | for (i = info->n_ilimsels - 1; i >= 0; i--) { | 505 | for (i = info->n_ilimsels - 1; i >= 0; i--) { |
506 | if (min_uA <= info->ilimsels[i] && | 506 | if (min_uA <= info->ilimsels[i] && |
507 | max_uA >= info->ilimsels[i]) | 507 | max_uA >= info->ilimsels[i]) |
508 | return write_field(hw, &info->ilimsel, i); | 508 | return write_field(hw, &info->ilimsel, i); |
509 | } | 509 | } |
510 | 510 | ||
511 | return -EINVAL; | 511 | return -EINVAL; |
512 | } | 512 | } |
513 | 513 | ||
514 | static int get_current_limit(struct regulator_dev *rdev) | 514 | static int get_current_limit(struct regulator_dev *rdev) |
515 | { | 515 | { |
516 | const struct supply_info *info; | 516 | const struct supply_info *info; |
517 | struct tps6524x *hw; | 517 | struct tps6524x *hw; |
518 | int ret; | 518 | int ret; |
519 | 519 | ||
520 | hw = rdev_get_drvdata(rdev); | 520 | hw = rdev_get_drvdata(rdev); |
521 | info = &supply_info[rdev_get_id(rdev)]; | 521 | info = &supply_info[rdev_get_id(rdev)]; |
522 | 522 | ||
523 | if (info->n_ilimsels == 1) | 523 | if (info->n_ilimsels == 1) |
524 | return info->ilimsels[0]; | 524 | return info->ilimsels[0]; |
525 | 525 | ||
526 | ret = read_field(hw, &info->ilimsel); | 526 | ret = read_field(hw, &info->ilimsel); |
527 | if (ret < 0) | 527 | if (ret < 0) |
528 | return ret; | 528 | return ret; |
529 | if (WARN_ON(ret >= info->n_ilimsels)) | 529 | if (WARN_ON(ret >= info->n_ilimsels)) |
530 | return -EIO; | 530 | return -EIO; |
531 | 531 | ||
532 | return info->ilimsels[ret]; | 532 | return info->ilimsels[ret]; |
533 | } | 533 | } |
534 | 534 | ||
535 | static int enable_supply(struct regulator_dev *rdev) | 535 | static int enable_supply(struct regulator_dev *rdev) |
536 | { | 536 | { |
537 | const struct supply_info *info; | 537 | const struct supply_info *info; |
538 | struct tps6524x *hw; | 538 | struct tps6524x *hw; |
539 | 539 | ||
540 | hw = rdev_get_drvdata(rdev); | 540 | hw = rdev_get_drvdata(rdev); |
541 | info = &supply_info[rdev_get_id(rdev)]; | 541 | info = &supply_info[rdev_get_id(rdev)]; |
542 | 542 | ||
543 | return write_field(hw, &info->enable, 1); | 543 | return write_field(hw, &info->enable, 1); |
544 | } | 544 | } |
545 | 545 | ||
546 | static int disable_supply(struct regulator_dev *rdev) | 546 | static int disable_supply(struct regulator_dev *rdev) |
547 | { | 547 | { |
548 | const struct supply_info *info; | 548 | const struct supply_info *info; |
549 | struct tps6524x *hw; | 549 | struct tps6524x *hw; |
550 | 550 | ||
551 | hw = rdev_get_drvdata(rdev); | 551 | hw = rdev_get_drvdata(rdev); |
552 | info = &supply_info[rdev_get_id(rdev)]; | 552 | info = &supply_info[rdev_get_id(rdev)]; |
553 | 553 | ||
554 | return write_field(hw, &info->enable, 0); | 554 | return write_field(hw, &info->enable, 0); |
555 | } | 555 | } |
556 | 556 | ||
557 | static int is_supply_enabled(struct regulator_dev *rdev) | 557 | static int is_supply_enabled(struct regulator_dev *rdev) |
558 | { | 558 | { |
559 | const struct supply_info *info; | 559 | const struct supply_info *info; |
560 | struct tps6524x *hw; | 560 | struct tps6524x *hw; |
561 | 561 | ||
562 | hw = rdev_get_drvdata(rdev); | 562 | hw = rdev_get_drvdata(rdev); |
563 | info = &supply_info[rdev_get_id(rdev)]; | 563 | info = &supply_info[rdev_get_id(rdev)]; |
564 | 564 | ||
565 | return read_field(hw, &info->enable); | 565 | return read_field(hw, &info->enable); |
566 | } | 566 | } |
567 | 567 | ||
568 | static struct regulator_ops regulator_ops = { | 568 | static struct regulator_ops regulator_ops = { |
569 | .is_enabled = is_supply_enabled, | 569 | .is_enabled = is_supply_enabled, |
570 | .enable = enable_supply, | 570 | .enable = enable_supply, |
571 | .disable = disable_supply, | 571 | .disable = disable_supply, |
572 | .get_voltage_sel = get_voltage_sel, | 572 | .get_voltage_sel = get_voltage_sel, |
573 | .set_voltage_sel = set_voltage_sel, | 573 | .set_voltage_sel = set_voltage_sel, |
574 | .list_voltage = regulator_list_voltage_table, | 574 | .list_voltage = regulator_list_voltage_table, |
575 | .set_current_limit = set_current_limit, | 575 | .set_current_limit = set_current_limit, |
576 | .get_current_limit = get_current_limit, | 576 | .get_current_limit = get_current_limit, |
577 | }; | 577 | }; |
578 | 578 | ||
579 | static int pmic_remove(struct spi_device *spi) | 579 | static int pmic_remove(struct spi_device *spi) |
580 | { | 580 | { |
581 | struct tps6524x *hw = spi_get_drvdata(spi); | 581 | struct tps6524x *hw = spi_get_drvdata(spi); |
582 | int i; | 582 | int i; |
583 | 583 | ||
584 | if (!hw) | 584 | if (!hw) |
585 | return 0; | 585 | return 0; |
586 | for (i = 0; i < N_REGULATORS; i++) { | 586 | for (i = 0; i < N_REGULATORS; i++) { |
587 | if (hw->rdev[i]) | 587 | regulator_unregister(hw->rdev[i]); |
588 | regulator_unregister(hw->rdev[i]); | ||
589 | hw->rdev[i] = NULL; | 588 | hw->rdev[i] = NULL; |
590 | } | 589 | } |
591 | spi_set_drvdata(spi, NULL); | 590 | spi_set_drvdata(spi, NULL); |
592 | return 0; | 591 | return 0; |
593 | } | 592 | } |
594 | 593 | ||
595 | static int pmic_probe(struct spi_device *spi) | 594 | static int pmic_probe(struct spi_device *spi) |
596 | { | 595 | { |
597 | struct tps6524x *hw; | 596 | struct tps6524x *hw; |
598 | struct device *dev = &spi->dev; | 597 | struct device *dev = &spi->dev; |
599 | const struct supply_info *info = supply_info; | 598 | const struct supply_info *info = supply_info; |
600 | struct regulator_init_data *init_data; | 599 | struct regulator_init_data *init_data; |
601 | struct regulator_config config = { }; | 600 | struct regulator_config config = { }; |
602 | int ret = 0, i; | 601 | int ret = 0, i; |
603 | 602 | ||
604 | init_data = dev->platform_data; | 603 | init_data = dev->platform_data; |
605 | if (!init_data) { | 604 | if (!init_data) { |
606 | dev_err(dev, "could not find regulator platform data\n"); | 605 | dev_err(dev, "could not find regulator platform data\n"); |
607 | return -EINVAL; | 606 | return -EINVAL; |
608 | } | 607 | } |
609 | 608 | ||
610 | hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); | 609 | hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); |
611 | if (!hw) { | 610 | if (!hw) { |
612 | dev_err(dev, "cannot allocate regulator private data\n"); | 611 | dev_err(dev, "cannot allocate regulator private data\n"); |
613 | return -ENOMEM; | 612 | return -ENOMEM; |
614 | } | 613 | } |
615 | spi_set_drvdata(spi, hw); | 614 | spi_set_drvdata(spi, hw); |
616 | 615 | ||
617 | memset(hw, 0, sizeof(struct tps6524x)); | 616 | memset(hw, 0, sizeof(struct tps6524x)); |
618 | hw->dev = dev; | 617 | hw->dev = dev; |
619 | hw->spi = spi_dev_get(spi); | 618 | hw->spi = spi_dev_get(spi); |
620 | mutex_init(&hw->lock); | 619 | mutex_init(&hw->lock); |
621 | 620 | ||
622 | for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { | 621 | for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { |
623 | hw->desc[i].name = info->name; | 622 | hw->desc[i].name = info->name; |
624 | hw->desc[i].id = i; | 623 | hw->desc[i].id = i; |
625 | hw->desc[i].n_voltages = info->n_voltages; | 624 | hw->desc[i].n_voltages = info->n_voltages; |
626 | hw->desc[i].volt_table = info->voltages; | 625 | hw->desc[i].volt_table = info->voltages; |
627 | hw->desc[i].ops = ®ulator_ops; | 626 | hw->desc[i].ops = ®ulator_ops; |
628 | hw->desc[i].type = REGULATOR_VOLTAGE; | 627 | hw->desc[i].type = REGULATOR_VOLTAGE; |
629 | hw->desc[i].owner = THIS_MODULE; | 628 | hw->desc[i].owner = THIS_MODULE; |
630 | 629 | ||
631 | config.dev = dev; | 630 | config.dev = dev; |
632 | config.init_data = init_data; | 631 | config.init_data = init_data; |
633 | config.driver_data = hw; | 632 | config.driver_data = hw; |
634 | 633 | ||
635 | hw->rdev[i] = regulator_register(&hw->desc[i], &config); | 634 | hw->rdev[i] = regulator_register(&hw->desc[i], &config); |
636 | if (IS_ERR(hw->rdev[i])) { | 635 | if (IS_ERR(hw->rdev[i])) { |
637 | ret = PTR_ERR(hw->rdev[i]); | 636 | ret = PTR_ERR(hw->rdev[i]); |
638 | hw->rdev[i] = NULL; | 637 | hw->rdev[i] = NULL; |
639 | goto fail; | 638 | goto fail; |
640 | } | 639 | } |
641 | } | 640 | } |
642 | 641 | ||
643 | return 0; | 642 | return 0; |
644 | 643 | ||
645 | fail: | 644 | fail: |
646 | pmic_remove(spi); | 645 | pmic_remove(spi); |
647 | return ret; | 646 | return ret; |
648 | } | 647 | } |
649 | 648 | ||
650 | static struct spi_driver pmic_driver = { | 649 | static struct spi_driver pmic_driver = { |
651 | .probe = pmic_probe, | 650 | .probe = pmic_probe, |
652 | .remove = pmic_remove, | 651 | .remove = pmic_remove, |
653 | .driver = { | 652 | .driver = { |
654 | .name = "tps6524x", | 653 | .name = "tps6524x", |
655 | .owner = THIS_MODULE, | 654 | .owner = THIS_MODULE, |
656 | }, | 655 | }, |
657 | }; | 656 | }; |
658 | 657 | ||
659 | module_spi_driver(pmic_driver); | 658 | module_spi_driver(pmic_driver); |
660 | 659 | ||
661 | MODULE_DESCRIPTION("TPS6524X PMIC Driver"); | 660 | MODULE_DESCRIPTION("TPS6524X PMIC Driver"); |
662 | MODULE_AUTHOR("Cyril Chemparathy"); | 661 | MODULE_AUTHOR("Cyril Chemparathy"); |
663 | MODULE_LICENSE("GPL"); | 662 | MODULE_LICENSE("GPL"); |
664 | MODULE_ALIAS("spi:tps6524x"); | 663 | MODULE_ALIAS("spi:tps6524x"); |
665 | 664 |