diff options
-rw-r--r-- | drivers/mfd/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/ab8500-gpadc.c | 296 | ||||
-rw-r--r-- | include/linux/mfd/ab8500-gpadc.h | 28 |
4 files changed, 332 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fdca643249e1..d71af4531b14 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -534,6 +534,13 @@ config AB8500_DEBUG | |||
534 | Select this option if you want debug information using the debug | 534 | Select this option if you want debug information using the debug |
535 | filesystem, debugfs. | 535 | filesystem, debugfs. |
536 | 536 | ||
537 | config AB8500_GPADC | ||
538 | bool "AB8500 GPADC driver" | ||
539 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
540 | default y | ||
541 | help | ||
542 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
543 | |||
537 | config AB3550_CORE | 544 | config AB3550_CORE |
538 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" | 545 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" |
539 | select MFD_CORE | 546 | select MFD_CORE |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 61a0b0f901a2..ad71bd59345f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -74,6 +74,7 @@ obj-$(CONFIG_AB3550_CORE) += ab3550-core.o | |||
74 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o | 74 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o |
75 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o | 75 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o |
76 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | 76 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o |
77 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o | ||
77 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 78 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
78 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 79 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
79 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 80 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c new file mode 100644 index 000000000000..19339bc439ca --- /dev/null +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/completion.h> | ||
15 | #include <linux/regulator/consumer.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/mfd/ab8500.h> | ||
19 | #include <linux/mfd/abx500.h> | ||
20 | #include <linux/mfd/ab8500-gpadc.h> | ||
21 | |||
22 | /* | ||
23 | * GPADC register offsets | ||
24 | * Bank : 0x0A | ||
25 | */ | ||
26 | #define AB8500_GPADC_CTRL1_REG 0x00 | ||
27 | #define AB8500_GPADC_CTRL2_REG 0x01 | ||
28 | #define AB8500_GPADC_CTRL3_REG 0x02 | ||
29 | #define AB8500_GPADC_AUTO_TIMER_REG 0x03 | ||
30 | #define AB8500_GPADC_STAT_REG 0x04 | ||
31 | #define AB8500_GPADC_MANDATAL_REG 0x05 | ||
32 | #define AB8500_GPADC_MANDATAH_REG 0x06 | ||
33 | #define AB8500_GPADC_AUTODATAL_REG 0x07 | ||
34 | #define AB8500_GPADC_AUTODATAH_REG 0x08 | ||
35 | #define AB8500_GPADC_MUX_CTRL_REG 0x09 | ||
36 | |||
37 | /* gpadc constants */ | ||
38 | #define EN_VINTCORE12 0x04 | ||
39 | #define EN_VTVOUT 0x02 | ||
40 | #define EN_GPADC 0x01 | ||
41 | #define DIS_GPADC 0x00 | ||
42 | #define SW_AVG_16 0x60 | ||
43 | #define ADC_SW_CONV 0x04 | ||
44 | #define EN_BUF 0x40 | ||
45 | #define DIS_ZERO 0x00 | ||
46 | #define GPADC_BUSY 0x01 | ||
47 | |||
48 | /** | ||
49 | * struct ab8500_gpadc - ab8500 GPADC device information | ||
50 | * @dev: pointer to the struct device | ||
51 | * @parent: pointer to the parent device structure ab8500 | ||
52 | * @ab8500_gpadc_complete: pointer to the struct completion, to indicate | ||
53 | * the completion of gpadc conversion | ||
54 | * @ab8500_gpadc_lock: structure of type mutex | ||
55 | * @regu: pointer to the struct regulator | ||
56 | * @irq: interrupt number that is used by gpadc | ||
57 | */ | ||
58 | static struct ab8500_gpadc { | ||
59 | struct device *dev; | ||
60 | struct ab8500 *parent; | ||
61 | struct completion ab8500_gpadc_complete; | ||
62 | struct mutex ab8500_gpadc_lock; | ||
63 | struct regulator *regu; | ||
64 | int irq; | ||
65 | } *di; | ||
66 | |||
67 | /** | ||
68 | * ab8500_gpadc_convert() - gpadc conversion | ||
69 | * @input: analog input to be converted to digital data | ||
70 | * | ||
71 | * This function converts the selected analog i/p to digital | ||
72 | * data. Thereafter calibration has to be made to obtain the | ||
73 | * data in the required quantity measurement. | ||
74 | */ | ||
75 | int ab8500_gpadc_convert(u8 input) | ||
76 | { | ||
77 | int ret; | ||
78 | u16 data = 0; | ||
79 | int looplimit = 0; | ||
80 | u8 val, low_data, high_data; | ||
81 | |||
82 | if (!di) | ||
83 | return -ENODEV; | ||
84 | |||
85 | mutex_lock(&di->ab8500_gpadc_lock); | ||
86 | /* Enable VTVout LDO this is required for GPADC */ | ||
87 | regulator_enable(di->regu); | ||
88 | |||
89 | /* Check if ADC is not busy, lock and proceed */ | ||
90 | do { | ||
91 | ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, | ||
92 | AB8500_GPADC_STAT_REG, &val); | ||
93 | if (ret < 0) | ||
94 | goto out; | ||
95 | if (!(val & GPADC_BUSY)) | ||
96 | break; | ||
97 | msleep(10); | ||
98 | } while (++looplimit < 10); | ||
99 | if (looplimit >= 10 && (val & GPADC_BUSY)) { | ||
100 | dev_err(di->dev, "gpadc_conversion: GPADC busy"); | ||
101 | ret = -EINVAL; | ||
102 | goto out; | ||
103 | } | ||
104 | |||
105 | /* Enable GPADC */ | ||
106 | ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, | ||
107 | AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); | ||
108 | if (ret < 0) { | ||
109 | dev_err(di->dev, "gpadc_conversion: enable gpadc failed\n"); | ||
110 | goto out; | ||
111 | } | ||
112 | /* Select the input source and set average samples to 16 */ | ||
113 | ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, | ||
114 | AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); | ||
115 | if (ret < 0) { | ||
116 | dev_err(di->dev, | ||
117 | "gpadc_conversion: set avg samples failed\n"); | ||
118 | goto out; | ||
119 | } | ||
120 | /* Enable ADC, Buffering and select rising edge, start Conversion */ | ||
121 | ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, | ||
122 | AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); | ||
123 | if (ret < 0) { | ||
124 | dev_err(di->dev, | ||
125 | "gpadc_conversion: select falling edge failed\n"); | ||
126 | goto out; | ||
127 | } | ||
128 | ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, | ||
129 | AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); | ||
130 | if (ret < 0) { | ||
131 | dev_err(di->dev, | ||
132 | "gpadc_conversion: start s/w conversion failed\n"); | ||
133 | goto out; | ||
134 | } | ||
135 | /* wait for completion of conversion */ | ||
136 | if (!wait_for_completion_timeout(&di->ab8500_gpadc_complete, 2*HZ)) { | ||
137 | dev_err(di->dev, | ||
138 | "timeout: didnt recieve GPADC conversion interrupt\n"); | ||
139 | ret = -EINVAL; | ||
140 | goto out; | ||
141 | } | ||
142 | |||
143 | /* Read the converted RAW data */ | ||
144 | ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, | ||
145 | AB8500_GPADC_MANDATAL_REG, &low_data); | ||
146 | if (ret < 0) { | ||
147 | dev_err(di->dev, "gpadc_conversion: read low data failed\n"); | ||
148 | goto out; | ||
149 | } | ||
150 | |||
151 | ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, | ||
152 | AB8500_GPADC_MANDATAH_REG, &high_data); | ||
153 | if (ret < 0) { | ||
154 | dev_err(di->dev, "gpadc_conversion: read high data failed\n"); | ||
155 | goto out; | ||
156 | } | ||
157 | |||
158 | data = (high_data << 8) | low_data; | ||
159 | /* Disable GPADC */ | ||
160 | ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, | ||
161 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
162 | if (ret < 0) { | ||
163 | dev_err(di->dev, "gpadc_conversion: disable gpadc failed\n"); | ||
164 | goto out; | ||
165 | } | ||
166 | /* Disable VTVout LDO this is required for GPADC */ | ||
167 | regulator_disable(di->regu); | ||
168 | mutex_unlock(&di->ab8500_gpadc_lock); | ||
169 | return data; | ||
170 | |||
171 | out: | ||
172 | /* | ||
173 | * It has shown to be needed to turn off the GPADC if an error occurs, | ||
174 | * otherwise we might have problem when waiting for the busy bit in the | ||
175 | * GPADC status register to go low. In V1.1 there wait_for_completion | ||
176 | * seems to timeout when waiting for an interrupt.. Not seen in V2.0 | ||
177 | */ | ||
178 | (void) abx500_set_register_interruptible(di->dev, AB8500_GPADC, | ||
179 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | ||
180 | regulator_disable(di->regu); | ||
181 | mutex_unlock(&di->ab8500_gpadc_lock); | ||
182 | dev_err(di->dev, "gpadc_conversion: Failed to AD convert channel %d\n", | ||
183 | input); | ||
184 | return ret; | ||
185 | } | ||
186 | EXPORT_SYMBOL(ab8500_gpadc_convert); | ||
187 | |||
188 | /** | ||
189 | * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion | ||
190 | * @irq: irq number | ||
191 | * @data: pointer to the data passed during request irq | ||
192 | * | ||
193 | * This is a interrupt service routine for s/w gpadc conversion completion. | ||
194 | * Notifies the gpadc completion is completed and the converted raw value | ||
195 | * can be read from the registers. | ||
196 | * Returns IRQ status(IRQ_HANDLED) | ||
197 | */ | ||
198 | static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_di) | ||
199 | { | ||
200 | struct ab8500_gpadc *gpadc = _di; | ||
201 | |||
202 | complete(&gpadc->ab8500_gpadc_complete); | ||
203 | |||
204 | return IRQ_HANDLED; | ||
205 | } | ||
206 | |||
207 | static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) | ||
208 | { | ||
209 | int ret = 0; | ||
210 | struct ab8500_gpadc *gpadc; | ||
211 | |||
212 | gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL); | ||
213 | if (!gpadc) { | ||
214 | dev_err(&pdev->dev, "Error: No memory\n"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | gpadc->parent = dev_get_drvdata(pdev->dev.parent); | ||
219 | gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); | ||
220 | if (gpadc->irq < 0) { | ||
221 | dev_err(gpadc->dev, "failed to get platform irq-%d\n", di->irq); | ||
222 | ret = gpadc->irq; | ||
223 | goto fail; | ||
224 | } | ||
225 | |||
226 | gpadc->dev = &pdev->dev; | ||
227 | mutex_init(&di->ab8500_gpadc_lock); | ||
228 | |||
229 | /* Initialize completion used to notify completion of conversion */ | ||
230 | init_completion(&gpadc->ab8500_gpadc_complete); | ||
231 | |||
232 | /* Register interrupt - SwAdcComplete */ | ||
233 | ret = request_threaded_irq(gpadc->irq, NULL, | ||
234 | ab8500_bm_gpswadcconvend_handler, | ||
235 | IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc); | ||
236 | if (ret < 0) { | ||
237 | dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n", | ||
238 | gpadc->irq); | ||
239 | goto fail; | ||
240 | } | ||
241 | |||
242 | /* VTVout LDO used to power up ab8500-GPADC */ | ||
243 | gpadc->regu = regulator_get(&pdev->dev, "vddadc"); | ||
244 | if (IS_ERR(gpadc->regu)) { | ||
245 | ret = PTR_ERR(gpadc->regu); | ||
246 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); | ||
247 | goto fail; | ||
248 | } | ||
249 | di = gpadc; | ||
250 | dev_dbg(gpadc->dev, "probe success\n"); | ||
251 | return 0; | ||
252 | fail: | ||
253 | kfree(gpadc); | ||
254 | gpadc = NULL; | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) | ||
259 | { | ||
260 | struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); | ||
261 | |||
262 | /* remove interrupt - completion of Sw ADC conversion */ | ||
263 | free_irq(gpadc->irq, di); | ||
264 | /* disable VTVout LDO that is being used by GPADC */ | ||
265 | regulator_put(gpadc->regu); | ||
266 | kfree(gpadc); | ||
267 | gpadc = NULL; | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static struct platform_driver ab8500_gpadc_driver = { | ||
272 | .probe = ab8500_gpadc_probe, | ||
273 | .remove = __devexit_p(ab8500_gpadc_remove), | ||
274 | .driver = { | ||
275 | .name = "ab8500-gpadc", | ||
276 | .owner = THIS_MODULE, | ||
277 | }, | ||
278 | }; | ||
279 | |||
280 | static int __init ab8500_gpadc_init(void) | ||
281 | { | ||
282 | return platform_driver_register(&ab8500_gpadc_driver); | ||
283 | } | ||
284 | |||
285 | static void __exit ab8500_gpadc_exit(void) | ||
286 | { | ||
287 | platform_driver_unregister(&ab8500_gpadc_driver); | ||
288 | } | ||
289 | |||
290 | subsys_initcall_sync(ab8500_gpadc_init); | ||
291 | module_exit(ab8500_gpadc_exit); | ||
292 | |||
293 | MODULE_LICENSE("GPL v2"); | ||
294 | MODULE_AUTHOR("Arun R Murthy"); | ||
295 | MODULE_ALIAS("platform:ab8500_gpadc"); | ||
296 | MODULE_DESCRIPTION("AB8500 GPADC driver"); | ||
diff --git a/include/linux/mfd/ab8500-gpadc.h b/include/linux/mfd/ab8500-gpadc.h new file mode 100644 index 000000000000..9f6cc26bc734 --- /dev/null +++ b/include/linux/mfd/ab8500-gpadc.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 ST-Ericsson SA | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef _AB8500_GPADC_H | ||
9 | #define _AB8500_GPADC_H | ||
10 | |||
11 | /* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */ | ||
12 | #define BAT_CTRL 0x01 | ||
13 | #define BTEMP_BALL 0x02 | ||
14 | #define MAIN_CHARGER_V 0x03 | ||
15 | #define ACC_DETECT1 0x04 | ||
16 | #define ACC_DETECT2 0x05 | ||
17 | #define ADC_AUX1 0x06 | ||
18 | #define ADC_AUX2 0x07 | ||
19 | #define MAIN_BAT_V 0x08 | ||
20 | #define VBUS_V 0x09 | ||
21 | #define MAIN_CHARGER_C 0x0A | ||
22 | #define USB_CHARGER_C 0x0B | ||
23 | #define BK_BAT_V 0x0C | ||
24 | #define DIE_TEMP 0x0D | ||
25 | |||
26 | int ab8500_gpadc_convert(u8 input); | ||
27 | |||
28 | #endif /* _AB8500_GPADC_H */ | ||