diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2012-10-09 05:48:59 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-10-17 09:21:14 -0400 |
commit | 24282a1ca33b4a2cdfb907fb7a3ba4d0f6e93311 (patch) | |
tree | 2e100956e7d8ea132908fd2c9c92aea965e3c675 | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
regulator: tps65090: Register all regulators in single probe call
MFD driver registers the regulator driver once per device and
hence it is require to register all regulators in single probe
call.
Following are details of changes done to achieve this:
- Move the regulator enums to mfd header and remove the
tps65090-regulator.h as it does not contain more info.
- Add max regulator and register all regulators even if there
is no regulator init data from platform.
- Convert regulator init data to pointer type in platform data.
- Add input supply name in regulator desc to provide input supply.
- Separate desc information from driver information.
- Disable external control bit to have control through register write.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | drivers/regulator/tps65090-regulator.c | 195 | ||||
-rw-r--r-- | include/linux/mfd/tps65090.h | 28 | ||||
-rw-r--r-- | include/linux/regulator/tps65090-regulator.h | 50 |
3 files changed, 165 insertions, 108 deletions
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 001ad554ac62..5f7f9311024e 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c | |||
@@ -24,15 +24,11 @@ | |||
24 | #include <linux/regulator/driver.h> | 24 | #include <linux/regulator/driver.h> |
25 | #include <linux/regulator/machine.h> | 25 | #include <linux/regulator/machine.h> |
26 | #include <linux/mfd/tps65090.h> | 26 | #include <linux/mfd/tps65090.h> |
27 | #include <linux/regulator/tps65090-regulator.h> | ||
28 | 27 | ||
29 | struct tps65090_regulator { | 28 | struct tps65090_regulator { |
30 | int id; | ||
31 | /* used by regulator core */ | ||
32 | struct regulator_desc desc; | ||
33 | |||
34 | /* Device */ | ||
35 | struct device *dev; | 29 | struct device *dev; |
30 | struct regulator_desc *desc; | ||
31 | struct regulator_dev *rdev; | ||
36 | }; | 32 | }; |
37 | 33 | ||
38 | static struct regulator_ops tps65090_ops = { | 34 | static struct regulator_ops tps65090_ops = { |
@@ -41,44 +37,80 @@ static struct regulator_ops tps65090_ops = { | |||
41 | .is_enabled = regulator_is_enabled_regmap, | 37 | .is_enabled = regulator_is_enabled_regmap, |
42 | }; | 38 | }; |
43 | 39 | ||
44 | #define tps65090_REG(_id) \ | 40 | #define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ |
45 | { \ | 41 | { \ |
46 | .id = TPS65090_ID_##_id, \ | 42 | .name = "TPS65090_RAILS"#_id, \ |
47 | .desc = { \ | 43 | .supply_name = _sname, \ |
48 | .name = tps65090_rails(_id), \ | 44 | .id = TPS65090_ID_##_id, \ |
49 | .id = TPS65090_ID_##_id, \ | 45 | .ops = &_ops, \ |
50 | .ops = &tps65090_ops, \ | 46 | .enable_reg = _en_reg, \ |
51 | .type = REGULATOR_VOLTAGE, \ | 47 | .enable_mask = BIT(0), \ |
52 | .owner = THIS_MODULE, \ | 48 | .type = REGULATOR_VOLTAGE, \ |
53 | .enable_reg = (TPS65090_ID_##_id) + 12, \ | 49 | .owner = THIS_MODULE, \ |
54 | .enable_mask = BIT(0), \ | ||
55 | }, \ | ||
56 | } | 50 | } |
57 | 51 | ||
58 | static struct tps65090_regulator TPS65090_regulator[] = { | 52 | static struct regulator_desc tps65090_regulator_desc[] = { |
59 | tps65090_REG(DCDC1), | 53 | tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_ops), |
60 | tps65090_REG(DCDC2), | 54 | tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_ops), |
61 | tps65090_REG(DCDC3), | 55 | tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_ops), |
62 | tps65090_REG(FET1), | 56 | tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_ops), |
63 | tps65090_REG(FET2), | 57 | tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_ops), |
64 | tps65090_REG(FET3), | 58 | tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_ops), |
65 | tps65090_REG(FET4), | 59 | tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_ops), |
66 | tps65090_REG(FET5), | 60 | tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_ops), |
67 | tps65090_REG(FET6), | 61 | tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_ops), |
68 | tps65090_REG(FET7), | 62 | tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_ops), |
69 | }; | 63 | }; |
70 | 64 | ||
71 | static inline struct tps65090_regulator *find_regulator_info(int id) | 65 | static inline bool is_dcdc(int id) |
72 | { | 66 | { |
73 | struct tps65090_regulator *ri; | 67 | switch (id) { |
74 | int i; | 68 | case TPS65090_ID_DCDC1: |
69 | case TPS65090_ID_DCDC2: | ||
70 | case TPS65090_ID_DCDC3: | ||
71 | return true; | ||
72 | default: | ||
73 | return false; | ||
74 | } | ||
75 | } | ||
75 | 76 | ||
76 | for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) { | 77 | static int __devinit tps65090_config_ext_control( |
77 | ri = &TPS65090_regulator[i]; | 78 | struct tps65090_regulator *ri, bool enable) |
78 | if (ri->desc.id == id) | 79 | { |
79 | return ri; | 80 | int ret; |
81 | struct device *parent = ri->dev->parent; | ||
82 | unsigned int reg_en_reg = ri->desc->enable_reg; | ||
83 | |||
84 | if (enable) | ||
85 | ret = tps65090_set_bits(parent, reg_en_reg, 1); | ||
86 | else | ||
87 | ret = tps65090_clr_bits(parent, reg_en_reg, 1); | ||
88 | if (ret < 0) | ||
89 | dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static int __devinit tps65090_regulator_disable_ext_control( | ||
94 | struct tps65090_regulator *ri, | ||
95 | struct tps65090_regulator_plat_data *tps_pdata) | ||
96 | { | ||
97 | int ret = 0; | ||
98 | struct device *parent = ri->dev->parent; | ||
99 | unsigned int reg_en_reg = ri->desc->enable_reg; | ||
100 | |||
101 | /* | ||
102 | * First enable output for internal control if require. | ||
103 | * And then disable external control. | ||
104 | */ | ||
105 | if (tps_pdata->reg_init_data->constraints.always_on || | ||
106 | tps_pdata->reg_init_data->constraints.boot_on) { | ||
107 | ret = tps65090_set_bits(parent, reg_en_reg, 0); | ||
108 | if (ret < 0) { | ||
109 | dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg); | ||
110 | return ret; | ||
111 | } | ||
80 | } | 112 | } |
81 | return NULL; | 113 | return tps65090_config_ext_control(ri, false); |
82 | } | 114 | } |
83 | 115 | ||
84 | static int __devinit tps65090_regulator_probe(struct platform_device *pdev) | 116 | static int __devinit tps65090_regulator_probe(struct platform_device *pdev) |
@@ -87,40 +119,87 @@ static int __devinit tps65090_regulator_probe(struct platform_device *pdev) | |||
87 | struct tps65090_regulator *ri = NULL; | 119 | struct tps65090_regulator *ri = NULL; |
88 | struct regulator_config config = { }; | 120 | struct regulator_config config = { }; |
89 | struct regulator_dev *rdev; | 121 | struct regulator_dev *rdev; |
90 | struct tps65090_regulator_platform_data *tps_pdata; | 122 | struct tps65090_regulator_plat_data *tps_pdata; |
91 | int id = pdev->id; | 123 | struct tps65090_regulator *pmic; |
124 | struct tps65090_platform_data *tps65090_pdata; | ||
125 | int num; | ||
126 | int ret; | ||
92 | 127 | ||
93 | dev_dbg(&pdev->dev, "Probing regulator %d\n", id); | 128 | dev_dbg(&pdev->dev, "Probing regulator\n"); |
94 | 129 | ||
95 | ri = find_regulator_info(id); | 130 | tps65090_pdata = dev_get_platdata(pdev->dev.parent); |
96 | if (ri == NULL) { | 131 | if (!tps65090_pdata) { |
97 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | 132 | dev_err(&pdev->dev, "Platform data missing\n"); |
98 | return -EINVAL; | 133 | return -EINVAL; |
99 | } | 134 | } |
100 | tps_pdata = pdev->dev.platform_data; | 135 | |
101 | ri->dev = &pdev->dev; | 136 | pmic = devm_kzalloc(&pdev->dev, TPS65090_ID_MAX * sizeof(*pmic), |
102 | 137 | GFP_KERNEL); | |
103 | config.dev = &pdev->dev; | 138 | if (!pmic) { |
104 | config.init_data = &tps_pdata->regulator; | 139 | dev_err(&pdev->dev, "mem alloc for pmic failed\n"); |
105 | config.driver_data = ri; | 140 | return -ENOMEM; |
106 | config.regmap = tps65090_mfd->rmap; | 141 | } |
107 | 142 | ||
108 | rdev = regulator_register(&ri->desc, &config); | 143 | for (num = 0; num < TPS65090_ID_MAX; num++) { |
109 | if (IS_ERR(rdev)) { | 144 | tps_pdata = tps65090_pdata->reg_pdata[num]; |
110 | dev_err(&pdev->dev, "failed to register regulator %s\n", | 145 | |
111 | ri->desc.name); | 146 | ri = &pmic[num]; |
112 | return PTR_ERR(rdev); | 147 | ri->dev = &pdev->dev; |
148 | ri->desc = &tps65090_regulator_desc[num]; | ||
149 | |||
150 | /* | ||
151 | * TPS5090 DCDC support the control from external digital input. | ||
152 | * It may be possible that during boot, the external control is | ||
153 | * enabled. Disabling external control for DCDC. | ||
154 | */ | ||
155 | if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) { | ||
156 | ret = tps65090_regulator_disable_ext_control( | ||
157 | ri, tps_pdata); | ||
158 | if (ret < 0) { | ||
159 | dev_err(&pdev->dev, | ||
160 | "failed disable ext control\n"); | ||
161 | goto scrub; | ||
162 | } | ||
163 | } | ||
164 | config.dev = &pdev->dev; | ||
165 | config.driver_data = ri; | ||
166 | config.regmap = tps65090_mfd->rmap; | ||
167 | if (tps_pdata) | ||
168 | config.init_data = tps_pdata->reg_init_data; | ||
169 | else | ||
170 | config.init_data = NULL; | ||
171 | |||
172 | rdev = regulator_register(ri->desc, &config); | ||
173 | if (IS_ERR(rdev)) { | ||
174 | dev_err(&pdev->dev, "failed to register regulator %s\n", | ||
175 | ri->desc->name); | ||
176 | ret = PTR_ERR(rdev); | ||
177 | goto scrub; | ||
178 | } | ||
179 | ri->rdev = rdev; | ||
113 | } | 180 | } |
114 | 181 | ||
115 | platform_set_drvdata(pdev, rdev); | 182 | platform_set_drvdata(pdev, pmic); |
116 | return 0; | 183 | return 0; |
184 | |||
185 | scrub: | ||
186 | while (--num >= 0) { | ||
187 | ri = &pmic[num]; | ||
188 | regulator_unregister(ri->rdev); | ||
189 | } | ||
190 | return ret; | ||
117 | } | 191 | } |
118 | 192 | ||
119 | static int __devexit tps65090_regulator_remove(struct platform_device *pdev) | 193 | static int __devexit tps65090_regulator_remove(struct platform_device *pdev) |
120 | { | 194 | { |
121 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 195 | struct tps65090_regulator *pmic = platform_get_drvdata(pdev); |
196 | struct tps65090_regulator *ri; | ||
197 | int num; | ||
122 | 198 | ||
123 | regulator_unregister(rdev); | 199 | for (num = 0; num < TPS65090_ID_MAX; ++num) { |
200 | ri = &pmic[num]; | ||
201 | regulator_unregister(ri->rdev); | ||
202 | } | ||
124 | return 0; | 203 | return 0; |
125 | } | 204 | } |
126 | 205 | ||
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h index 6bc31d854626..d06c63335a2a 100644 --- a/include/linux/mfd/tps65090.h +++ b/include/linux/mfd/tps65090.h | |||
@@ -24,6 +24,23 @@ | |||
24 | 24 | ||
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | 26 | ||
27 | /* TPS65090 Regulator ID */ | ||
28 | enum { | ||
29 | TPS65090_ID_DCDC1, | ||
30 | TPS65090_ID_DCDC2, | ||
31 | TPS65090_ID_DCDC3, | ||
32 | TPS65090_ID_FET1, | ||
33 | TPS65090_ID_FET2, | ||
34 | TPS65090_ID_FET3, | ||
35 | TPS65090_ID_FET4, | ||
36 | TPS65090_ID_FET5, | ||
37 | TPS65090_ID_FET6, | ||
38 | TPS65090_ID_FET7, | ||
39 | |||
40 | /* Last entry for maximum ID */ | ||
41 | TPS65090_ID_MAX, | ||
42 | }; | ||
43 | |||
27 | struct tps65090 { | 44 | struct tps65090 { |
28 | struct mutex lock; | 45 | struct mutex lock; |
29 | struct device *dev; | 46 | struct device *dev; |
@@ -41,10 +58,21 @@ struct tps65090_subdev_info { | |||
41 | void *platform_data; | 58 | void *platform_data; |
42 | }; | 59 | }; |
43 | 60 | ||
61 | /* | ||
62 | * struct tps65090_regulator_plat_data | ||
63 | * | ||
64 | * @reg_init_data: The regulator init data. | ||
65 | */ | ||
66 | |||
67 | struct tps65090_regulator_plat_data { | ||
68 | struct regulator_init_data *reg_init_data; | ||
69 | }; | ||
70 | |||
44 | struct tps65090_platform_data { | 71 | struct tps65090_platform_data { |
45 | int irq_base; | 72 | int irq_base; |
46 | int num_subdevs; | 73 | int num_subdevs; |
47 | struct tps65090_subdev_info *subdevs; | 74 | struct tps65090_subdev_info *subdevs; |
75 | struct tps65090_regulator_plat_data *reg_pdata[TPS65090_ID_MAX]; | ||
48 | }; | 76 | }; |
49 | 77 | ||
50 | /* | 78 | /* |
diff --git a/include/linux/regulator/tps65090-regulator.h b/include/linux/regulator/tps65090-regulator.h deleted file mode 100644 index 0fa04b64db3e..000000000000 --- a/include/linux/regulator/tps65090-regulator.h +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * Regulator driver interface for TI TPS65090 PMIC family | ||
3 | * | ||
4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
5 | |||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | |||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __REGULATOR_TPS65090_H | ||
20 | #define __REGULATOR_TPS65090_H | ||
21 | |||
22 | #include <linux/regulator/machine.h> | ||
23 | |||
24 | #define tps65090_rails(_name) "tps65090_"#_name | ||
25 | |||
26 | enum { | ||
27 | TPS65090_ID_DCDC1, | ||
28 | TPS65090_ID_DCDC2, | ||
29 | TPS65090_ID_DCDC3, | ||
30 | TPS65090_ID_FET1, | ||
31 | TPS65090_ID_FET2, | ||
32 | TPS65090_ID_FET3, | ||
33 | TPS65090_ID_FET4, | ||
34 | TPS65090_ID_FET5, | ||
35 | TPS65090_ID_FET6, | ||
36 | TPS65090_ID_FET7, | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * struct tps65090_regulator_platform_data | ||
41 | * | ||
42 | * @regulator: The regulator init data. | ||
43 | * @slew_rate_uV_per_us: Slew rate microvolt per microsec. | ||
44 | */ | ||
45 | |||
46 | struct tps65090_regulator_platform_data { | ||
47 | struct regulator_init_data regulator; | ||
48 | }; | ||
49 | |||
50 | #endif /* __REGULATOR_TPS65090_H */ | ||