diff options
Diffstat (limited to 'drivers/regulator/tps65090-regulator.c')
-rw-r--r-- | drivers/regulator/tps65090-regulator.c | 106 |
1 files changed, 101 insertions, 5 deletions
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 41c391789c97..c8e70451df38 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c | |||
@@ -19,11 +19,13 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
22 | #include <linux/of_gpio.h> | ||
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
23 | #include <linux/err.h> | 24 | #include <linux/err.h> |
24 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
25 | #include <linux/regulator/driver.h> | 26 | #include <linux/regulator/driver.h> |
26 | #include <linux/regulator/machine.h> | 27 | #include <linux/regulator/machine.h> |
28 | #include <linux/regulator/of_regulator.h> | ||
27 | #include <linux/mfd/tps65090.h> | 29 | #include <linux/mfd/tps65090.h> |
28 | 30 | ||
29 | struct tps65090_regulator { | 31 | struct tps65090_regulator { |
@@ -67,8 +69,8 @@ static struct regulator_desc tps65090_regulator_desc[] = { | |||
67 | tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), | 69 | tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), |
68 | tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), | 70 | tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), |
69 | tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), | 71 | tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), |
70 | tps65090_REG_DESC(LDO1, "vsys_l1", 0, tps65090_ldo_ops), | 72 | tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops), |
71 | tps65090_REG_DESC(LDO2, "vsys_l2", 0, tps65090_ldo_ops), | 73 | tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops), |
72 | }; | 74 | }; |
73 | 75 | ||
74 | static inline bool is_dcdc(int id) | 76 | static inline bool is_dcdc(int id) |
@@ -138,6 +140,92 @@ static void tps65090_configure_regulator_config( | |||
138 | } | 140 | } |
139 | } | 141 | } |
140 | 142 | ||
143 | #ifdef CONFIG_OF | ||
144 | static struct of_regulator_match tps65090_matches[] = { | ||
145 | { .name = "dcdc1", }, | ||
146 | { .name = "dcdc2", }, | ||
147 | { .name = "dcdc3", }, | ||
148 | { .name = "fet1", }, | ||
149 | { .name = "fet2", }, | ||
150 | { .name = "fet3", }, | ||
151 | { .name = "fet4", }, | ||
152 | { .name = "fet5", }, | ||
153 | { .name = "fet6", }, | ||
154 | { .name = "fet7", }, | ||
155 | { .name = "ldo1", }, | ||
156 | { .name = "ldo2", }, | ||
157 | }; | ||
158 | |||
159 | static struct tps65090_platform_data *tps65090_parse_dt_reg_data( | ||
160 | struct platform_device *pdev, | ||
161 | struct of_regulator_match **tps65090_reg_matches) | ||
162 | { | ||
163 | struct tps65090_platform_data *tps65090_pdata; | ||
164 | struct device_node *np = pdev->dev.parent->of_node; | ||
165 | struct device_node *regulators; | ||
166 | int idx = 0, ret; | ||
167 | struct tps65090_regulator_plat_data *reg_pdata; | ||
168 | |||
169 | tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), | ||
170 | GFP_KERNEL); | ||
171 | if (!tps65090_pdata) { | ||
172 | dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); | ||
173 | return ERR_PTR(-ENOMEM); | ||
174 | } | ||
175 | |||
176 | reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * | ||
177 | sizeof(*reg_pdata), GFP_KERNEL); | ||
178 | if (!reg_pdata) { | ||
179 | dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); | ||
180 | return ERR_PTR(-ENOMEM); | ||
181 | } | ||
182 | |||
183 | regulators = of_find_node_by_name(np, "regulators"); | ||
184 | if (!regulators) { | ||
185 | dev_err(&pdev->dev, "regulator node not found\n"); | ||
186 | return ERR_PTR(-ENODEV); | ||
187 | } | ||
188 | |||
189 | ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, | ||
190 | ARRAY_SIZE(tps65090_matches)); | ||
191 | if (ret < 0) { | ||
192 | dev_err(&pdev->dev, | ||
193 | "Error parsing regulator init data: %d\n", ret); | ||
194 | return ERR_PTR(ret); | ||
195 | } | ||
196 | |||
197 | *tps65090_reg_matches = tps65090_matches; | ||
198 | for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) { | ||
199 | struct regulator_init_data *ri_data; | ||
200 | struct tps65090_regulator_plat_data *rpdata; | ||
201 | |||
202 | rpdata = ®_pdata[idx]; | ||
203 | ri_data = tps65090_matches[idx].init_data; | ||
204 | if (!ri_data || !tps65090_matches[idx].of_node) | ||
205 | continue; | ||
206 | |||
207 | rpdata->reg_init_data = ri_data; | ||
208 | rpdata->enable_ext_control = of_property_read_bool( | ||
209 | tps65090_matches[idx].of_node, | ||
210 | "ti,enable-ext-control"); | ||
211 | if (rpdata->enable_ext_control) | ||
212 | rpdata->gpio = of_get_named_gpio(np, | ||
213 | "dcdc-ext-control-gpios", 0); | ||
214 | |||
215 | tps65090_pdata->reg_pdata[idx] = rpdata; | ||
216 | } | ||
217 | return tps65090_pdata; | ||
218 | } | ||
219 | #else | ||
220 | static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data( | ||
221 | struct platform_device *pdev, | ||
222 | struct of_regulator_match **tps65090_reg_matches) | ||
223 | { | ||
224 | *tps65090_reg_matches = NULL; | ||
225 | return NULL; | ||
226 | } | ||
227 | #endif | ||
228 | |||
141 | static int tps65090_regulator_probe(struct platform_device *pdev) | 229 | static int tps65090_regulator_probe(struct platform_device *pdev) |
142 | { | 230 | { |
143 | struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent); | 231 | struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent); |
@@ -147,15 +235,19 @@ static int tps65090_regulator_probe(struct platform_device *pdev) | |||
147 | struct tps65090_regulator_plat_data *tps_pdata; | 235 | struct tps65090_regulator_plat_data *tps_pdata; |
148 | struct tps65090_regulator *pmic; | 236 | struct tps65090_regulator *pmic; |
149 | struct tps65090_platform_data *tps65090_pdata; | 237 | struct tps65090_platform_data *tps65090_pdata; |
238 | struct of_regulator_match *tps65090_reg_matches = NULL; | ||
150 | int num; | 239 | int num; |
151 | int ret; | 240 | int ret; |
152 | 241 | ||
153 | dev_dbg(&pdev->dev, "Probing regulator\n"); | 242 | dev_dbg(&pdev->dev, "Probing regulator\n"); |
154 | 243 | ||
155 | tps65090_pdata = dev_get_platdata(pdev->dev.parent); | 244 | tps65090_pdata = dev_get_platdata(pdev->dev.parent); |
156 | if (!tps65090_pdata) { | 245 | if (!tps65090_pdata && tps65090_mfd->dev->of_node) |
246 | tps65090_pdata = tps65090_parse_dt_reg_data(pdev, | ||
247 | &tps65090_reg_matches); | ||
248 | if (IS_ERR_OR_NULL(tps65090_pdata)) { | ||
157 | dev_err(&pdev->dev, "Platform data missing\n"); | 249 | dev_err(&pdev->dev, "Platform data missing\n"); |
158 | return -EINVAL; | 250 | return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL; |
159 | } | 251 | } |
160 | 252 | ||
161 | pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), | 253 | pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), |
@@ -192,13 +284,17 @@ static int tps65090_regulator_probe(struct platform_device *pdev) | |||
192 | } | 284 | } |
193 | } | 285 | } |
194 | 286 | ||
195 | config.dev = &pdev->dev; | 287 | config.dev = pdev->dev.parent; |
196 | config.driver_data = ri; | 288 | config.driver_data = ri; |
197 | config.regmap = tps65090_mfd->rmap; | 289 | config.regmap = tps65090_mfd->rmap; |
198 | if (tps_pdata) | 290 | if (tps_pdata) |
199 | config.init_data = tps_pdata->reg_init_data; | 291 | config.init_data = tps_pdata->reg_init_data; |
200 | else | 292 | else |
201 | config.init_data = NULL; | 293 | config.init_data = NULL; |
294 | if (tps65090_reg_matches) | ||
295 | config.of_node = tps65090_reg_matches[num].of_node; | ||
296 | else | ||
297 | config.of_node = NULL; | ||
202 | 298 | ||
203 | rdev = regulator_register(ri->desc, &config); | 299 | rdev = regulator_register(ri->desc, &config); |
204 | if (IS_ERR(rdev)) { | 300 | if (IS_ERR(rdev)) { |