aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/Kconfig7
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ab8500-gpadc.c296
-rw-r--r--include/linux/mfd/ab8500-gpadc.h28
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
537config 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
537config AB3550_CORE 544config 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
74obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o 74obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
75obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o 75obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
76obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o 76obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
77obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
77obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 78obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
78obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 79obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
79obj-$(CONFIG_LPC_SCH) += lpc_sch.o 80obj-$(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 */
58static 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 */
75int 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
171out:
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}
186EXPORT_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 */
198static 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
207static 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;
252fail:
253 kfree(gpadc);
254 gpadc = NULL;
255 return ret;
256}
257
258static 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
271static 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
280static int __init ab8500_gpadc_init(void)
281{
282 return platform_driver_register(&ab8500_gpadc_driver);
283}
284
285static void __exit ab8500_gpadc_exit(void)
286{
287 platform_driver_unregister(&ab8500_gpadc_driver);
288}
289
290subsys_initcall_sync(ab8500_gpadc_init);
291module_exit(ab8500_gpadc_exit);
292
293MODULE_LICENSE("GPL v2");
294MODULE_AUTHOR("Arun R Murthy");
295MODULE_ALIAS("platform:ab8500_gpadc");
296MODULE_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
26int ab8500_gpadc_convert(u8 input);
27
28#endif /* _AB8500_GPADC_H */