aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */