diff options
-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 */ | ||