diff options
Diffstat (limited to 'drivers/regulator/88pm8607.c')
-rw-r--r-- | drivers/regulator/88pm8607.c | 136 |
1 files changed, 120 insertions, 16 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index c3482b954cb7..1c5ab0172ea2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/err.h> | 13 | #include <linux/err.h> |
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/of.h> | ||
16 | #include <linux/regulator/of_regulator.h> | ||
15 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
16 | #include <linux/regulator/driver.h> | 18 | #include <linux/regulator/driver.h> |
17 | #include <linux/regulator/machine.h> | 19 | #include <linux/regulator/machine.h> |
@@ -23,6 +25,7 @@ struct pm8607_regulator_info { | |||
23 | struct pm860x_chip *chip; | 25 | struct pm860x_chip *chip; |
24 | struct regulator_dev *regulator; | 26 | struct regulator_dev *regulator; |
25 | struct i2c_client *i2c; | 27 | struct i2c_client *i2c; |
28 | struct i2c_client *i2c_8606; | ||
26 | 29 | ||
27 | unsigned int *vol_table; | 30 | unsigned int *vol_table; |
28 | unsigned int *vol_suspend; | 31 | unsigned int *vol_suspend; |
@@ -242,6 +245,35 @@ static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) | |||
242 | return ret; | 245 | return ret; |
243 | } | 246 | } |
244 | 247 | ||
248 | static int pm8606_preg_enable(struct regulator_dev *rdev) | ||
249 | { | ||
250 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
251 | |||
252 | return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, | ||
253 | 1 << rdev->desc->enable_mask, 0); | ||
254 | } | ||
255 | |||
256 | static int pm8606_preg_disable(struct regulator_dev *rdev) | ||
257 | { | ||
258 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
259 | |||
260 | return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, | ||
261 | 1 << rdev->desc->enable_mask, | ||
262 | 1 << rdev->desc->enable_mask); | ||
263 | } | ||
264 | |||
265 | static int pm8606_preg_is_enabled(struct regulator_dev *rdev) | ||
266 | { | ||
267 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
268 | int ret; | ||
269 | |||
270 | ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | |||
274 | return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); | ||
275 | } | ||
276 | |||
245 | static struct regulator_ops pm8607_regulator_ops = { | 277 | static struct regulator_ops pm8607_regulator_ops = { |
246 | .list_voltage = pm8607_list_voltage, | 278 | .list_voltage = pm8607_list_voltage, |
247 | .set_voltage_sel = pm8607_set_voltage_sel, | 279 | .set_voltage_sel = pm8607_set_voltage_sel, |
@@ -251,6 +283,25 @@ static struct regulator_ops pm8607_regulator_ops = { | |||
251 | .is_enabled = regulator_is_enabled_regmap, | 283 | .is_enabled = regulator_is_enabled_regmap, |
252 | }; | 284 | }; |
253 | 285 | ||
286 | static struct regulator_ops pm8606_preg_ops = { | ||
287 | .enable = pm8606_preg_enable, | ||
288 | .disable = pm8606_preg_disable, | ||
289 | .is_enabled = pm8606_preg_is_enabled, | ||
290 | }; | ||
291 | |||
292 | #define PM8606_PREG(ereg, ebit) \ | ||
293 | { \ | ||
294 | .desc = { \ | ||
295 | .name = "PREG", \ | ||
296 | .ops = &pm8606_preg_ops, \ | ||
297 | .type = REGULATOR_CURRENT, \ | ||
298 | .id = PM8606_ID_PREG, \ | ||
299 | .owner = THIS_MODULE, \ | ||
300 | .enable_reg = PM8606_##ereg, \ | ||
301 | .enable_mask = (ebit), \ | ||
302 | }, \ | ||
303 | } | ||
304 | |||
254 | #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ | 305 | #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ |
255 | { \ | 306 | { \ |
256 | .desc = { \ | 307 | .desc = { \ |
@@ -311,6 +362,38 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { | |||
311 | PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), | 362 | PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), |
312 | }; | 363 | }; |
313 | 364 | ||
365 | static struct pm8607_regulator_info pm8606_regulator_info[] = { | ||
366 | PM8606_PREG(PREREGULATORB, 5), | ||
367 | }; | ||
368 | |||
369 | #ifdef CONFIG_OF | ||
370 | static int pm8607_regulator_dt_init(struct platform_device *pdev, | ||
371 | struct pm8607_regulator_info *info, | ||
372 | struct regulator_config *config) | ||
373 | { | ||
374 | struct device_node *nproot, *np; | ||
375 | nproot = pdev->dev.parent->of_node; | ||
376 | if (!nproot) | ||
377 | return -ENODEV; | ||
378 | nproot = of_find_node_by_name(nproot, "regulators"); | ||
379 | if (!nproot) { | ||
380 | dev_err(&pdev->dev, "failed to find regulators node\n"); | ||
381 | return -ENODEV; | ||
382 | } | ||
383 | for_each_child_of_node(nproot, np) { | ||
384 | if (!of_node_cmp(np->name, info->desc.name)) { | ||
385 | config->init_data = | ||
386 | of_get_regulator_init_data(&pdev->dev, np); | ||
387 | config->of_node = np; | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | #else | ||
394 | #define pm8607_regulator_dt_init(x, y, z) (-1) | ||
395 | #endif | ||
396 | |||
314 | static int __devinit pm8607_regulator_probe(struct platform_device *pdev) | 397 | static int __devinit pm8607_regulator_probe(struct platform_device *pdev) |
315 | { | 398 | { |
316 | struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); | 399 | struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); |
@@ -320,22 +403,28 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) | |||
320 | struct resource *res; | 403 | struct resource *res; |
321 | int i; | 404 | int i; |
322 | 405 | ||
323 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 406 | res = platform_get_resource(pdev, IORESOURCE_REG, 0); |
324 | if (res == NULL) { | 407 | if (res) { |
325 | dev_err(&pdev->dev, "No I/O resource!\n"); | 408 | /* There're resources in 88PM8607 regulator driver */ |
326 | return -EINVAL; | 409 | for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { |
327 | } | 410 | info = &pm8607_regulator_info[i]; |
328 | for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { | 411 | if (info->desc.vsel_reg == res->start) |
329 | info = &pm8607_regulator_info[i]; | 412 | break; |
330 | if (info->desc.id == res->start) | 413 | } |
331 | break; | 414 | if (i == ARRAY_SIZE(pm8607_regulator_info)) { |
332 | } | 415 | dev_err(&pdev->dev, "Failed to find regulator %llu\n", |
333 | if (i == ARRAY_SIZE(pm8607_regulator_info)) { | 416 | (unsigned long long)res->start); |
334 | dev_err(&pdev->dev, "Failed to find regulator %llu\n", | 417 | return -EINVAL; |
335 | (unsigned long long)res->start); | 418 | } |
336 | return -EINVAL; | 419 | } else { |
420 | /* There's no resource in 88PM8606 PREG regulator driver */ | ||
421 | info = &pm8606_regulator_info[0]; | ||
422 | /* i is used to check regulator ID */ | ||
423 | i = -1; | ||
337 | } | 424 | } |
338 | info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; | 425 | info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; |
426 | info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : | ||
427 | chip->client; | ||
339 | info->chip = chip; | 428 | info->chip = chip; |
340 | 429 | ||
341 | /* check DVC ramp slope double */ | 430 | /* check DVC ramp slope double */ |
@@ -343,15 +432,17 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) | |||
343 | info->slope_double = 1; | 432 | info->slope_double = 1; |
344 | 433 | ||
345 | config.dev = &pdev->dev; | 434 | config.dev = &pdev->dev; |
346 | config.init_data = pdata; | ||
347 | config.driver_data = info; | 435 | config.driver_data = info; |
348 | 436 | ||
437 | if (pm8607_regulator_dt_init(pdev, info, &config)) | ||
438 | if (pdata) | ||
439 | config.init_data = pdata; | ||
440 | |||
349 | if (chip->id == CHIP_PM8607) | 441 | if (chip->id == CHIP_PM8607) |
350 | config.regmap = chip->regmap; | 442 | config.regmap = chip->regmap; |
351 | else | 443 | else |
352 | config.regmap = chip->regmap_companion; | 444 | config.regmap = chip->regmap_companion; |
353 | 445 | ||
354 | /* replace driver_data with info */ | ||
355 | info->regulator = regulator_register(&info->desc, &config); | 446 | info->regulator = regulator_register(&info->desc, &config); |
356 | if (IS_ERR(info->regulator)) { | 447 | if (IS_ERR(info->regulator)) { |
357 | dev_err(&pdev->dev, "failed to register regulator %s\n", | 448 | dev_err(&pdev->dev, "failed to register regulator %s\n", |
@@ -372,6 +463,18 @@ static int __devexit pm8607_regulator_remove(struct platform_device *pdev) | |||
372 | return 0; | 463 | return 0; |
373 | } | 464 | } |
374 | 465 | ||
466 | static struct platform_device_id pm8607_regulator_driver_ids[] = { | ||
467 | { | ||
468 | .name = "88pm860x-regulator", | ||
469 | .driver_data = 0, | ||
470 | }, { | ||
471 | .name = "88pm860x-preg", | ||
472 | .driver_data = 0, | ||
473 | }, | ||
474 | { }, | ||
475 | }; | ||
476 | MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); | ||
477 | |||
375 | static struct platform_driver pm8607_regulator_driver = { | 478 | static struct platform_driver pm8607_regulator_driver = { |
376 | .driver = { | 479 | .driver = { |
377 | .name = "88pm860x-regulator", | 480 | .name = "88pm860x-regulator", |
@@ -379,6 +482,7 @@ static struct platform_driver pm8607_regulator_driver = { | |||
379 | }, | 482 | }, |
380 | .probe = pm8607_regulator_probe, | 483 | .probe = pm8607_regulator_probe, |
381 | .remove = __devexit_p(pm8607_regulator_remove), | 484 | .remove = __devexit_p(pm8607_regulator_remove), |
485 | .id_table = pm8607_regulator_driver_ids, | ||
382 | }; | 486 | }; |
383 | 487 | ||
384 | static int __init pm8607_regulator_init(void) | 488 | static int __init pm8607_regulator_init(void) |