aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/ab8500-gpadc.c
diff options
context:
space:
mode:
authorDaniel Willerud <daniel.willerud@stericsson.com>2011-03-05 05:46:13 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2011-03-23 05:42:04 -0400
commit6321992cd3c56bab6cc52e3384951e12616805a1 (patch)
tree9a5d028aeb44c0f061c1e5a49735b82a7c609f56 /drivers/mfd/ab8500-gpadc.c
parentcf16943947cef089c564d2be0ae9d96a285f495e (diff)
mfd: Reentrance and revamp ab8500 gpadc fetching interface
This revamps the interface so that AB8500 GPADCs are fetched by name. Probed GPADCs are added to a list and this list is searched for a matching GPADC. This makes it possible to have multiple AB8500 GPADC instances instead of it being a singleton, and rids the need to keep a GPADC pointer around in the core AB8500 MFD struct. Currently the match is made to the device name which is by default numbered from the device instance such as "ab8500-gpadc.0" but by using the .init_name field of the device a more intiutive naming for the GPADC blocks can be achieved if desired. Signed-off-by: Daniel Willerud <daniel.willerud@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/ab8500-gpadc.c')
-rw-r--r--drivers/mfd/ab8500-gpadc.c115
1 files changed, 70 insertions, 45 deletions
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index f60f71f4b473..178cbc55caea 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * License Terms: GNU General Public License v2 4 * License Terms: GNU General Public License v2
5 * Author: Arun R Murthy <arun.murthy@stericsson.com> 5 * Author: Arun R Murthy <arun.murthy@stericsson.com>
6 * Author: Daniel Willerud <daniel.willerud@stericsson.com>
6 */ 7 */
7#include <linux/init.h> 8#include <linux/init.h>
8#include <linux/module.h> 9#include <linux/module.h>
@@ -15,6 +16,7 @@
15#include <linux/regulator/consumer.h> 16#include <linux/regulator/consumer.h>
16#include <linux/err.h> 17#include <linux/err.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/list.h>
18#include <linux/mfd/ab8500.h> 20#include <linux/mfd/ab8500.h>
19#include <linux/mfd/abx500.h> 21#include <linux/mfd/abx500.h>
20#include <linux/mfd/ab8500/ab8500-gpadc.h> 22#include <linux/mfd/ab8500/ab8500-gpadc.h>
@@ -48,21 +50,41 @@
48/** 50/**
49 * struct ab8500_gpadc - ab8500 GPADC device information 51 * struct ab8500_gpadc - ab8500 GPADC device information
50 * @dev: pointer to the struct device 52 * @dev: pointer to the struct device
51 * @parent: pointer to the parent device structure ab8500 53 * @node: a list of AB8500 GPADCs, hence prepared for
54 reentrance
52 * @ab8500_gpadc_complete: pointer to the struct completion, to indicate 55 * @ab8500_gpadc_complete: pointer to the struct completion, to indicate
53 * the completion of gpadc conversion 56 * the completion of gpadc conversion
54 * @ab8500_gpadc_lock: structure of type mutex 57 * @ab8500_gpadc_lock: structure of type mutex
55 * @regu: pointer to the struct regulator 58 * @regu: pointer to the struct regulator
56 * @irq: interrupt number that is used by gpadc 59 * @irq: interrupt number that is used by gpadc
57 */ 60 */
58static struct ab8500_gpadc { 61struct ab8500_gpadc {
59 struct device *dev; 62 struct device *dev;
60 struct ab8500 *parent; 63 struct list_head node;
61 struct completion ab8500_gpadc_complete; 64 struct completion ab8500_gpadc_complete;
62 struct mutex ab8500_gpadc_lock; 65 struct mutex ab8500_gpadc_lock;
63 struct regulator *regu; 66 struct regulator *regu;
64 int irq; 67 int irq;
65} *di; 68};
69
70static LIST_HEAD(ab8500_gpadc_list);
71
72/**
73 * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC
74 * (i.e. the first GPADC in the instance list)
75 */
76struct ab8500_gpadc *ab8500_gpadc_get(char *name)
77{
78 struct ab8500_gpadc *gpadc;
79
80 list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
81 if (!strcmp(name, dev_name(gpadc->dev)))
82 return gpadc;
83 }
84
85 return ERR_PTR(-ENOENT);
86}
87EXPORT_SYMBOL(ab8500_gpadc_get);
66 88
67/** 89/**
68 * ab8500_gpadc_convert() - gpadc conversion 90 * ab8500_gpadc_convert() - gpadc conversion
@@ -72,24 +94,24 @@ static struct ab8500_gpadc {
72 * data. Thereafter calibration has to be made to obtain the 94 * data. Thereafter calibration has to be made to obtain the
73 * data in the required quantity measurement. 95 * data in the required quantity measurement.
74 */ 96 */
75int ab8500_gpadc_convert(u8 input) 97int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
76{ 98{
77 int ret; 99 int ret;
78 u16 data = 0; 100 u16 data = 0;
79 int looplimit = 0; 101 int looplimit = 0;
80 u8 val, low_data, high_data; 102 u8 val, low_data, high_data;
81 103
82 if (!di) 104 if (!gpadc)
83 return -ENODEV; 105 return -ENODEV;
84 106
85 mutex_lock(&di->ab8500_gpadc_lock); 107 mutex_lock(&gpadc->ab8500_gpadc_lock);
86 /* Enable VTVout LDO this is required for GPADC */ 108 /* Enable VTVout LDO this is required for GPADC */
87 regulator_enable(di->regu); 109 regulator_enable(gpadc->regu);
88 110
89 /* Check if ADC is not busy, lock and proceed */ 111 /* Check if ADC is not busy, lock and proceed */
90 do { 112 do {
91 ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, 113 ret = abx500_get_register_interruptible(gpadc->dev,
92 AB8500_GPADC_STAT_REG, &val); 114 AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
93 if (ret < 0) 115 if (ret < 0)
94 goto out; 116 goto out;
95 if (!(val & GPADC_BUSY)) 117 if (!(val & GPADC_BUSY))
@@ -97,75 +119,76 @@ int ab8500_gpadc_convert(u8 input)
97 msleep(10); 119 msleep(10);
98 } while (++looplimit < 10); 120 } while (++looplimit < 10);
99 if (looplimit >= 10 && (val & GPADC_BUSY)) { 121 if (looplimit >= 10 && (val & GPADC_BUSY)) {
100 dev_err(di->dev, "gpadc_conversion: GPADC busy"); 122 dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
101 ret = -EINVAL; 123 ret = -EINVAL;
102 goto out; 124 goto out;
103 } 125 }
104 126
105 /* Enable GPADC */ 127 /* Enable GPADC */
106 ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, 128 ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
107 AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); 129 AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
108 if (ret < 0) { 130 if (ret < 0) {
109 dev_err(di->dev, "gpadc_conversion: enable gpadc failed\n"); 131 dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
110 goto out; 132 goto out;
111 } 133 }
112 /* Select the input source and set average samples to 16 */ 134 /* Select the input source and set average samples to 16 */
113 ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, 135 ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
114 AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); 136 AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
115 if (ret < 0) { 137 if (ret < 0) {
116 dev_err(di->dev, 138 dev_err(gpadc->dev,
117 "gpadc_conversion: set avg samples failed\n"); 139 "gpadc_conversion: set avg samples failed\n");
118 goto out; 140 goto out;
119 } 141 }
120 /* Enable ADC, Buffering and select rising edge, start Conversion */ 142 /* Enable ADC, Buffering and select rising edge, start Conversion */
121 ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, 143 ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
122 AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); 144 AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
123 if (ret < 0) { 145 if (ret < 0) {
124 dev_err(di->dev, 146 dev_err(gpadc->dev,
125 "gpadc_conversion: select falling edge failed\n"); 147 "gpadc_conversion: select falling edge failed\n");
126 goto out; 148 goto out;
127 } 149 }
128 ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, 150 ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
129 AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); 151 AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
130 if (ret < 0) { 152 if (ret < 0) {
131 dev_err(di->dev, 153 dev_err(gpadc->dev,
132 "gpadc_conversion: start s/w conversion failed\n"); 154 "gpadc_conversion: start s/w conversion failed\n");
133 goto out; 155 goto out;
134 } 156 }
135 /* wait for completion of conversion */ 157 /* wait for completion of conversion */
136 if (!wait_for_completion_timeout(&di->ab8500_gpadc_complete, 2*HZ)) { 158 if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
137 dev_err(di->dev, 159 dev_err(gpadc->dev,
138 "timeout: didnt recieve GPADC conversion interrupt\n"); 160 "timeout: didnt recieve GPADC conversion interrupt\n");
139 ret = -EINVAL; 161 ret = -EINVAL;
140 goto out; 162 goto out;
141 } 163 }
142 164
143 /* Read the converted RAW data */ 165 /* Read the converted RAW data */
144 ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, 166 ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
145 AB8500_GPADC_MANDATAL_REG, &low_data); 167 AB8500_GPADC_MANDATAL_REG, &low_data);
146 if (ret < 0) { 168 if (ret < 0) {
147 dev_err(di->dev, "gpadc_conversion: read low data failed\n"); 169 dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
148 goto out; 170 goto out;
149 } 171 }
150 172
151 ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, 173 ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
152 AB8500_GPADC_MANDATAH_REG, &high_data); 174 AB8500_GPADC_MANDATAH_REG, &high_data);
153 if (ret < 0) { 175 if (ret < 0) {
154 dev_err(di->dev, "gpadc_conversion: read high data failed\n"); 176 dev_err(gpadc->dev,
177 "gpadc_conversion: read high data failed\n");
155 goto out; 178 goto out;
156 } 179 }
157 180
158 data = (high_data << 8) | low_data; 181 data = (high_data << 8) | low_data;
159 /* Disable GPADC */ 182 /* Disable GPADC */
160 ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, 183 ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
161 AB8500_GPADC_CTRL1_REG, DIS_GPADC); 184 AB8500_GPADC_CTRL1_REG, DIS_GPADC);
162 if (ret < 0) { 185 if (ret < 0) {
163 dev_err(di->dev, "gpadc_conversion: disable gpadc failed\n"); 186 dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
164 goto out; 187 goto out;
165 } 188 }
166 /* Disable VTVout LDO this is required for GPADC */ 189 /* Disable VTVout LDO this is required for GPADC */
167 regulator_disable(di->regu); 190 regulator_disable(gpadc->regu);
168 mutex_unlock(&di->ab8500_gpadc_lock); 191 mutex_unlock(&gpadc->ab8500_gpadc_lock);
169 return data; 192 return data;
170 193
171out: 194out:
@@ -175,12 +198,12 @@ out:
175 * GPADC status register to go low. In V1.1 there wait_for_completion 198 * 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 199 * seems to timeout when waiting for an interrupt.. Not seen in V2.0
177 */ 200 */
178 (void) abx500_set_register_interruptible(di->dev, AB8500_GPADC, 201 (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
179 AB8500_GPADC_CTRL1_REG, DIS_GPADC); 202 AB8500_GPADC_CTRL1_REG, DIS_GPADC);
180 regulator_disable(di->regu); 203 regulator_disable(gpadc->regu);
181 mutex_unlock(&di->ab8500_gpadc_lock); 204 mutex_unlock(&gpadc->ab8500_gpadc_lock);
182 dev_err(di->dev, "gpadc_conversion: Failed to AD convert channel %d\n", 205 dev_err(gpadc->dev,
183 input); 206 "gpadc_conversion: Failed to AD convert channel %d\n", input);
184 return ret; 207 return ret;
185} 208}
186EXPORT_SYMBOL(ab8500_gpadc_convert); 209EXPORT_SYMBOL(ab8500_gpadc_convert);
@@ -195,9 +218,9 @@ EXPORT_SYMBOL(ab8500_gpadc_convert);
195 * can be read from the registers. 218 * can be read from the registers.
196 * Returns IRQ status(IRQ_HANDLED) 219 * Returns IRQ status(IRQ_HANDLED)
197 */ 220 */
198static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_di) 221static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
199{ 222{
200 struct ab8500_gpadc *gpadc = _di; 223 struct ab8500_gpadc *gpadc = _gpadc;
201 224
202 complete(&gpadc->ab8500_gpadc_complete); 225 complete(&gpadc->ab8500_gpadc_complete);
203 226
@@ -215,16 +238,16 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
215 return -ENOMEM; 238 return -ENOMEM;
216 } 239 }
217 240
218 gpadc->parent = dev_get_drvdata(pdev->dev.parent);
219 gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); 241 gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
220 if (gpadc->irq < 0) { 242 if (gpadc->irq < 0) {
221 dev_err(gpadc->dev, "failed to get platform irq-%d\n", di->irq); 243 dev_err(gpadc->dev, "failed to get platform irq-%d\n",
244 gpadc->irq);
222 ret = gpadc->irq; 245 ret = gpadc->irq;
223 goto fail; 246 goto fail;
224 } 247 }
225 248
226 gpadc->dev = &pdev->dev; 249 gpadc->dev = &pdev->dev;
227 mutex_init(&di->ab8500_gpadc_lock); 250 mutex_init(&gpadc->ab8500_gpadc_lock);
228 251
229 /* Initialize completion used to notify completion of conversion */ 252 /* Initialize completion used to notify completion of conversion */
230 init_completion(&gpadc->ab8500_gpadc_complete); 253 init_completion(&gpadc->ab8500_gpadc_complete);
@@ -246,7 +269,7 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
246 dev_err(gpadc->dev, "failed to get vtvout LDO\n"); 269 dev_err(gpadc->dev, "failed to get vtvout LDO\n");
247 goto fail; 270 goto fail;
248 } 271 }
249 di = gpadc; 272 list_add_tail(&gpadc->node, &ab8500_gpadc_list);
250 dev_dbg(gpadc->dev, "probe success\n"); 273 dev_dbg(gpadc->dev, "probe success\n");
251 return 0; 274 return 0;
252fail: 275fail:
@@ -259,8 +282,10 @@ static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
259{ 282{
260 struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); 283 struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev);
261 284
285 /* remove this gpadc entry from the list */
286 list_del(&gpadc->node);
262 /* remove interrupt - completion of Sw ADC conversion */ 287 /* remove interrupt - completion of Sw ADC conversion */
263 free_irq(gpadc->irq, di); 288 free_irq(gpadc->irq, gpadc);
264 /* disable VTVout LDO that is being used by GPADC */ 289 /* disable VTVout LDO that is being used by GPADC */
265 regulator_put(gpadc->regu); 290 regulator_put(gpadc->regu);
266 kfree(gpadc); 291 kfree(gpadc);
@@ -291,6 +316,6 @@ subsys_initcall_sync(ab8500_gpadc_init);
291module_exit(ab8500_gpadc_exit); 316module_exit(ab8500_gpadc_exit);
292 317
293MODULE_LICENSE("GPL v2"); 318MODULE_LICENSE("GPL v2");
294MODULE_AUTHOR("Arun R Murthy"); 319MODULE_AUTHOR("Arun R Murthy, Daniel Willerud");
295MODULE_ALIAS("platform:ab8500_gpadc"); 320MODULE_ALIAS("platform:ab8500_gpadc");
296MODULE_DESCRIPTION("AB8500 GPADC driver"); 321MODULE_DESCRIPTION("AB8500 GPADC driver");