aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s3c24xx/adc.c
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-07-18 05:12:27 -0400
committerBen Dooks <ben-linux@fluff.org>2009-07-18 05:15:53 -0400
commite170adcb406504b8acd35554c69830c11916be1f (patch)
tree75a8aeb283e39d1b9b82bebfe347eb6c64def65f /arch/arm/plat-s3c24xx/adc.c
parent885f9ebe7554628967b6e93b284dd3021e1bb280 (diff)
ARM: S3C: Add ADC synchronous read call.
To add HWMON support, we need a synchronous read() call that blocks until completion. Add the client that is being service to the select and convert callbacks to make the code easier. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'arch/arm/plat-s3c24xx/adc.c')
-rw-r--r--arch/arm/plat-s3c24xx/adc.c64
1 files changed, 53 insertions, 11 deletions
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
index ee1baf11ad9e..11117a7ba911 100644
--- a/arch/arm/plat-s3c24xx/adc.c
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -39,13 +39,16 @@
39struct s3c_adc_client { 39struct s3c_adc_client {
40 struct platform_device *pdev; 40 struct platform_device *pdev;
41 struct list_head pend; 41 struct list_head pend;
42 wait_queue_head_t *wait;
42 43
43 unsigned int nr_samples; 44 unsigned int nr_samples;
45 int result;
44 unsigned char is_ts; 46 unsigned char is_ts;
45 unsigned char channel; 47 unsigned char channel;
46 48
47 void (*select_cb)(unsigned selected); 49 void (*select_cb)(struct s3c_adc_client *c, unsigned selected);
48 void (*convert_cb)(unsigned val1, unsigned val2, 50 void (*convert_cb)(struct s3c_adc_client *c,
51 unsigned val1, unsigned val2,
49 unsigned *samples_left); 52 unsigned *samples_left);
50}; 53};
51 54
@@ -81,7 +84,7 @@ static inline void s3c_adc_select(struct adc_device *adc,
81{ 84{
82 unsigned con = readl(adc->regs + S3C2410_ADCCON); 85 unsigned con = readl(adc->regs + S3C2410_ADCCON);
83 86
84 client->select_cb(1); 87 client->select_cb(client, 1);
85 88
86 con &= ~S3C2410_ADCCON_MUXMASK; 89 con &= ~S3C2410_ADCCON_MUXMASK;
87 con &= ~S3C2410_ADCCON_STDBM; 90 con &= ~S3C2410_ADCCON_STDBM;
@@ -153,25 +156,61 @@ int s3c_adc_start(struct s3c_adc_client *client,
153} 156}
154EXPORT_SYMBOL_GPL(s3c_adc_start); 157EXPORT_SYMBOL_GPL(s3c_adc_start);
155 158
156static void s3c_adc_default_select(unsigned select) 159static void s3c_convert_done(struct s3c_adc_client *client,
160 unsigned v, unsigned u, unsigned *left)
161{
162 client->result = v;
163 wake_up(client->wait);
164}
165
166int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
167{
168 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
169 int ret;
170
171 client->convert_cb = s3c_convert_done;
172 client->wait = &wake;
173 client->result = -1;
174
175 ret = s3c_adc_start(client, ch, 1);
176 if (ret < 0)
177 goto err;
178
179 ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
180 if (client->result < 0) {
181 ret = -ETIMEDOUT;
182 goto err;
183 }
184
185 client->convert_cb = NULL;
186 return client->result;
187
188err:
189 return ret;
190}
191EXPORT_SYMBOL_GPL(s3c_adc_convert);
192
193static void s3c_adc_default_select(struct s3c_adc_client *client,
194 unsigned select)
157{ 195{
158} 196}
159 197
160struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, 198struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
161 void (*select)(unsigned int selected), 199 void (*select)(struct s3c_adc_client *client,
162 void (*conv)(unsigned d0, unsigned d1, 200 unsigned int selected),
201 void (*conv)(struct s3c_adc_client *client,
202 unsigned d0, unsigned d1,
163 unsigned *samples_left), 203 unsigned *samples_left),
164 unsigned int is_ts) 204 unsigned int is_ts)
165{ 205{
166 struct s3c_adc_client *client; 206 struct s3c_adc_client *client;
167 207
168 WARN_ON(!pdev); 208 WARN_ON(!pdev);
169 WARN_ON(!conv);
170 209
171 if (!select) 210 if (!select)
172 select = s3c_adc_default_select; 211 select = s3c_adc_default_select;
173 212
174 if (!conv || !pdev) 213 if (!pdev)
175 return ERR_PTR(-EINVAL); 214 return ERR_PTR(-EINVAL);
176 215
177 client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL); 216 client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
@@ -230,16 +269,19 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
230 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1); 269 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
231 270
232 client->nr_samples--; 271 client->nr_samples--;
233 (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff, &client->nr_samples); 272
273 if (client->convert_cb)
274 (client->convert_cb)(client, data0 & 0x3ff, data1 & 0x3ff,
275 &client->nr_samples);
234 276
235 if (client->nr_samples > 0) { 277 if (client->nr_samples > 0) {
236 /* fire another conversion for this */ 278 /* fire another conversion for this */
237 279
238 client->select_cb(1); 280 client->select_cb(client, 1);
239 s3c_adc_convert(adc); 281 s3c_adc_convert(adc);
240 } else { 282 } else {
241 local_irq_save(flags); 283 local_irq_save(flags);
242 (client->select_cb)(0); 284 (client->select_cb)(client, 0);
243 adc->cur = NULL; 285 adc->cur = NULL;
244 286
245 s3c_adc_try(adc); 287 s3c_adc_try(adc);