1 /*
2  * linux/drivers/regulator/aat2870-regulator.c
3  *
4  * Copyright (c) 2011, NVIDIA Corporation.
5  * Author: Jin Park <jinyoungp@nvidia.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/err.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/delay.h>
28 #include <linux/platform_device.h>
29 #include <linux/regulator/driver.h>
30 #include <linux/regulator/machine.h>
31 #include <linux/mfd/aat2870.h>
32 
33 struct aat2870_regulator {
34 	struct aat2870_data *aat2870;
35 	struct regulator_desc desc;
36 
37 	const int *voltages; /* uV */
38 
39 	int min_uV;
40 	int max_uV;
41 
42 	u8 enable_addr;
43 	u8 enable_shift;
44 	u8 enable_mask;
45 
46 	u8 voltage_addr;
47 	u8 voltage_shift;
48 	u8 voltage_mask;
49 };
50 
51 static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
52 				    unsigned selector)
53 {
54 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
55 
56 	return ri->voltages[selector];
57 }
58 
59 static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
60 				       unsigned selector)
61 {
62 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
63 	struct aat2870_data *aat2870 = ri->aat2870;
64 
65 	return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
66 			       selector << ri->voltage_shift);
67 }
68 
69 static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
70 {
71 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
72 	struct aat2870_data *aat2870 = ri->aat2870;
73 	u8 val;
74 	int ret;
75 
76 	ret = aat2870->read(aat2870, ri->voltage_addr, &val);
77 	if (ret)
78 		return ret;
79 
80 	return (val & ri->voltage_mask) >> ri->voltage_shift;
81 }
82 
83 static int aat2870_ldo_enable(struct regulator_dev *rdev)
84 {
85 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
86 	struct aat2870_data *aat2870 = ri->aat2870;
87 
88 	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
89 			       ri->enable_mask);
90 }
91 
92 static int aat2870_ldo_disable(struct regulator_dev *rdev)
93 {
94 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
95 	struct aat2870_data *aat2870 = ri->aat2870;
96 
97 	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
98 }
99 
100 static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
101 {
102 	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
103 	struct aat2870_data *aat2870 = ri->aat2870;
104 	u8 val;
105 	int ret;
106 
107 	ret = aat2870->read(aat2870, ri->enable_addr, &val);
108 	if (ret)
109 		return ret;
110 
111 	return val & ri->enable_mask ? 1 : 0;
112 }
113 
114 static struct regulator_ops aat2870_ldo_ops = {
115 	.list_voltage = aat2870_ldo_list_voltage,
116 	.set_voltage_sel = aat2870_ldo_set_voltage_sel,
117 	.get_voltage_sel = aat2870_ldo_get_voltage_sel,
118 	.enable = aat2870_ldo_enable,
119 	.disable = aat2870_ldo_disable,
120 	.is_enabled = aat2870_ldo_is_enabled,
121 };
122 
123 static const int aat2870_ldo_voltages[] = {
124 	1200000, 1300000, 1500000, 1600000,
125 	1800000, 2000000, 2200000, 2500000,
126 	2600000, 2700000, 2800000, 2900000,
127 	3000000, 3100000, 3200000, 3300000,
128 };
129 
130 #define AAT2870_LDO(ids)				\
131 	{						\
132 		.desc = {				\
133 			.name = #ids,			\
134 			.id = AAT2870_ID_##ids,		\
135 			.n_voltages = ARRAY_SIZE(aat2870_ldo_voltages),	\
136 			.ops = &aat2870_ldo_ops,	\
137 			.type = REGULATOR_VOLTAGE,	\
138 			.owner = THIS_MODULE,		\
139 		},					\
140 		.voltages = aat2870_ldo_voltages,	\
141 		.min_uV = 1200000,			\
142 		.max_uV = 3300000,			\
143 	}
144 
145 static struct aat2870_regulator aat2870_regulators[] = {
146 	AAT2870_LDO(LDOA),
147 	AAT2870_LDO(LDOB),
148 	AAT2870_LDO(LDOC),
149 	AAT2870_LDO(LDOD),
150 };
151 
152 static struct aat2870_regulator *aat2870_get_regulator(int id)
153 {
154 	struct aat2870_regulator *ri = NULL;
155 	int i;
156 
157 	for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
158 		ri = &aat2870_regulators[i];
159 		if (ri->desc.id == id)
160 			break;
161 	}
162 
163 	if (i == ARRAY_SIZE(aat2870_regulators))
164 		return NULL;
165 
166 	ri->enable_addr = AAT2870_LDO_EN;
167 	ri->enable_shift = id - AAT2870_ID_LDOA;
168 	ri->enable_mask = 0x1 << ri->enable_shift;
169 
170 	ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
171 			   AAT2870_LDO_CD : AAT2870_LDO_AB;
172 	ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
173 	ri->voltage_mask = 0xF << ri->voltage_shift;
174 
175 	return ri;
176 }
177 
178 static int aat2870_regulator_probe(struct platform_device *pdev)
179 {
180 	struct aat2870_regulator *ri;
181 	struct regulator_dev *rdev;
182 
183 	ri = aat2870_get_regulator(pdev->id);
184 	if (!ri) {
185 		dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
186 		return -EINVAL;
187 	}
188 	ri->aat2870 = dev_get_drvdata(pdev->dev.parent);
189 
190 	rdev = regulator_register(&ri->desc, &pdev->dev,
191 				  pdev->dev.platform_data, ri, NULL);
192 	if (IS_ERR(rdev)) {
193 		dev_err(&pdev->dev, "Failed to register regulator %s\n",
194 			ri->desc.name);
195 		return PTR_ERR(rdev);
196 	}
197 	platform_set_drvdata(pdev, rdev);
198 
199 	return 0;
200 }
201 
202 static int __devexit aat2870_regulator_remove(struct platform_device *pdev)
203 {
204 	struct regulator_dev *rdev = platform_get_drvdata(pdev);
205 
206 	regulator_unregister(rdev);
207 	return 0;
208 }
209 
210 static struct platform_driver aat2870_regulator_driver = {
211 	.driver = {
212 		.name	= "aat2870-regulator",
213 		.owner	= THIS_MODULE,
214 	},
215 	.probe	= aat2870_regulator_probe,
216 	.remove	= __devexit_p(aat2870_regulator_remove),
217 };
218 
219 static int __init aat2870_regulator_init(void)
220 {
221 	return platform_driver_register(&aat2870_regulator_driver);
222 }
223 subsys_initcall(aat2870_regulator_init);
224 
225 static void __exit aat2870_regulator_exit(void)
226 {
227 	platform_driver_unregister(&aat2870_regulator_driver);
228 }
229 module_exit(aat2870_regulator_exit);
230 
231 MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
232 MODULE_LICENSE("GPL");
233 MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
234