diff options
| author | Tero Kristo <t-kristo@ti.com> | 2012-02-16 05:27:52 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-11 16:08:45 -0400 |
| commit | 63bfff4e20211b464cbea6e79e5fd36df227c154 (patch) | |
| tree | 4ea7a62c37820578be7ecbc943f6e62a017c64e4 | |
| parent | a33b6e5a8fb5fadeef206bacef13117e8a3080c4 (diff) | |
regulator: twl4030: add support for external voltage get/set
This is needed for SMPS regulators, which use the OMAP voltage
processor for voltage get/set functions instead of the normal I2C
channel. For this purpose, regulator_init_data->driver_data contents
are expanded, it is now a struct which contains function pointers
for the set/get voltage operations, a data pointer for these, and
the previously used features bitmask.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Samuel Ortiz <sameo@linux.intel.com> [for the MFD part]
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
| -rw-r--r-- | drivers/mfd/twl-core.c | 16 | ||||
| -rw-r--r-- | drivers/regulator/twl-regulator.c | 39 | ||||
| -rw-r--r-- | include/linux/i2c/twl.h | 7 |
3 files changed, 56 insertions, 6 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e04e04ddc15e..fae5f76d6ccb 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c | |||
| @@ -619,6 +619,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
| 619 | unsigned num_consumers, unsigned long features) | 619 | unsigned num_consumers, unsigned long features) |
| 620 | { | 620 | { |
| 621 | unsigned sub_chip_id; | 621 | unsigned sub_chip_id; |
| 622 | struct twl_regulator_driver_data drv_data; | ||
| 623 | |||
| 622 | /* regulator framework demands init_data ... */ | 624 | /* regulator framework demands init_data ... */ |
| 623 | if (!pdata) | 625 | if (!pdata) |
| 624 | return NULL; | 626 | return NULL; |
| @@ -628,7 +630,19 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, | |||
| 628 | pdata->num_consumer_supplies = num_consumers; | 630 | pdata->num_consumer_supplies = num_consumers; |
| 629 | } | 631 | } |
| 630 | 632 | ||
| 631 | pdata->driver_data = (void *)features; | 633 | if (pdata->driver_data) { |
| 634 | /* If we have existing drv_data, just add the flags */ | ||
| 635 | struct twl_regulator_driver_data *tmp; | ||
| 636 | tmp = pdata->driver_data; | ||
| 637 | tmp->features |= features; | ||
| 638 | } else { | ||
| 639 | /* add new driver data struct, used only during init */ | ||
| 640 | drv_data.features = features; | ||
| 641 | drv_data.set_voltage = NULL; | ||
| 642 | drv_data.get_voltage = NULL; | ||
| 643 | drv_data.data = NULL; | ||
| 644 | pdata->driver_data = &drv_data; | ||
| 645 | } | ||
| 632 | 646 | ||
| 633 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | 647 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ |
| 634 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; | 648 | sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; |
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index e5d222342157..7ff8bb22d569 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c | |||
| @@ -58,6 +58,16 @@ struct twlreg_info { | |||
| 58 | 58 | ||
| 59 | /* chip specific features */ | 59 | /* chip specific features */ |
| 60 | unsigned long features; | 60 | unsigned long features; |
| 61 | |||
| 62 | /* | ||
| 63 | * optional override functions for voltage set/get | ||
| 64 | * these are currently only used for SMPS regulators | ||
| 65 | */ | ||
| 66 | int (*get_voltage)(void *data); | ||
| 67 | int (*set_voltage)(void *data, int target_uV); | ||
| 68 | |||
| 69 | /* data passed from board for external get/set voltage */ | ||
| 70 | void *data; | ||
| 61 | }; | 71 | }; |
| 62 | 72 | ||
| 63 | 73 | ||
| @@ -522,15 +532,25 @@ twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, | |||
| 522 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 532 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 523 | int vsel = DIV_ROUND_UP(min_uV - 600000, 12500); | 533 | int vsel = DIV_ROUND_UP(min_uV - 600000, 12500); |
| 524 | 534 | ||
| 525 | twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030, | 535 | if (info->set_voltage) { |
| 526 | vsel); | 536 | return info->set_voltage(info->data, min_uV); |
| 537 | } else { | ||
| 538 | twlreg_write(info, TWL_MODULE_PM_RECEIVER, | ||
| 539 | VREG_VOLTAGE_SMPS_4030, vsel); | ||
| 540 | } | ||
| 541 | |||
| 527 | return 0; | 542 | return 0; |
| 528 | } | 543 | } |
| 529 | 544 | ||
| 530 | static int twl4030smps_get_voltage(struct regulator_dev *rdev) | 545 | static int twl4030smps_get_voltage(struct regulator_dev *rdev) |
| 531 | { | 546 | { |
| 532 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 547 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
| 533 | int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, | 548 | int vsel; |
| 549 | |||
| 550 | if (info->get_voltage) | ||
| 551 | return info->get_voltage(info->data); | ||
| 552 | |||
| 553 | vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, | ||
| 534 | VREG_VOLTAGE_SMPS_4030); | 554 | VREG_VOLTAGE_SMPS_4030); |
| 535 | 555 | ||
| 536 | return vsel * 12500 + 600000; | 556 | return vsel * 12500 + 600000; |
| @@ -1060,6 +1080,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1060 | struct regulator_init_data *initdata; | 1080 | struct regulator_init_data *initdata; |
| 1061 | struct regulation_constraints *c; | 1081 | struct regulation_constraints *c; |
| 1062 | struct regulator_dev *rdev; | 1082 | struct regulator_dev *rdev; |
| 1083 | struct twl_regulator_driver_data *drvdata; | ||
| 1063 | 1084 | ||
| 1064 | for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) { | 1085 | for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) { |
| 1065 | if (twl_regs[i].desc.id != pdev->id) | 1086 | if (twl_regs[i].desc.id != pdev->id) |
| @@ -1074,8 +1095,16 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
| 1074 | if (!initdata) | 1095 | if (!initdata) |
| 1075 | return -EINVAL; | 1096 | return -EINVAL; |
| 1076 | 1097 | ||
| 1077 | /* copy the features into regulator data */ | 1098 | drvdata = initdata->driver_data; |
| 1078 | info->features = (unsigned long)initdata->driver_data; | 1099 | |
| 1100 | if (!drvdata) | ||
| 1101 | return -EINVAL; | ||
| 1102 | |||
| 1103 | /* copy the driver data into regulator data */ | ||
| 1104 | info->features = drvdata->features; | ||
| 1105 | info->data = drvdata->data; | ||
| 1106 | info->set_voltage = drvdata->set_voltage; | ||
| 1107 | info->get_voltage = drvdata->get_voltage; | ||
| 1079 | 1108 | ||
| 1080 | /* Constrain board-specific capabilities according to what | 1109 | /* Constrain board-specific capabilities according to what |
| 1081 | * this driver and the chip itself can actually do. | 1110 | * this driver and the chip itself can actually do. |
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 78d3465251d6..08a82d314f24 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h | |||
| @@ -749,6 +749,13 @@ struct twl4030_platform_data { | |||
| 749 | struct regulator_init_data *vio6025; | 749 | struct regulator_init_data *vio6025; |
| 750 | }; | 750 | }; |
| 751 | 751 | ||
| 752 | struct twl_regulator_driver_data { | ||
| 753 | int (*set_voltage)(void *data, int target_uV); | ||
| 754 | int (*get_voltage)(void *data); | ||
| 755 | void *data; | ||
| 756 | unsigned long features; | ||
| 757 | }; | ||
| 758 | |||
| 752 | /*----------------------------------------------------------------------*/ | 759 | /*----------------------------------------------------------------------*/ |
| 753 | 760 | ||
| 754 | int twl4030_sih_setup(int module); | 761 | int twl4030_sih_setup(int module); |
