aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2012-10-09 05:48:59 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-10-17 09:21:14 -0400
commit24282a1ca33b4a2cdfb907fb7a3ba4d0f6e93311 (patch)
tree2e100956e7d8ea132908fd2c9c92aea965e3c675
parentddffeb8c4d0331609ef2581d84de4d763607bd37 (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.c195
-rw-r--r--include/linux/mfd/tps65090.h28
-rw-r--r--include/linux/regulator/tps65090-regulator.h50
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
29struct tps65090_regulator { 28struct 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
38static struct regulator_ops tps65090_ops = { 34static 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
58static struct tps65090_regulator TPS65090_regulator[] = { 52static 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
71static inline struct tps65090_regulator *find_regulator_info(int id) 65static 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++) { 77static 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
93static 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
84static int __devinit tps65090_regulator_probe(struct platform_device *pdev) 116static 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
185scrub:
186 while (--num >= 0) {
187 ri = &pmic[num];
188 regulator_unregister(ri->rdev);
189 }
190 return ret;
117} 191}
118 192
119static int __devexit tps65090_regulator_remove(struct platform_device *pdev) 193static 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 */
28enum {
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
27struct tps65090 { 44struct 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
67struct tps65090_regulator_plat_data {
68 struct regulator_init_data *reg_init_data;
69};
70
44struct tps65090_platform_data { 71struct 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
26enum {
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
46struct tps65090_regulator_platform_data {
47 struct regulator_init_data regulator;
48};
49
50#endif /* __REGULATOR_TPS65090_H */