aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-samsung/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-samsung/adc.c')
-rw-r--r--arch/arm/plat-samsung/adc.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index 210030d5cfe1..04d9521ddc9f 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -66,6 +66,7 @@ struct adc_device {
66 struct s3c_adc_client *cur; 66 struct s3c_adc_client *cur;
67 struct s3c_adc_client *ts_pend; 67 struct s3c_adc_client *ts_pend;
68 void __iomem *regs; 68 void __iomem *regs;
69 spinlock_t lock;
69 70
70 unsigned int prescale; 71 unsigned int prescale;
71 72
@@ -74,7 +75,7 @@ struct adc_device {
74 75
75static struct adc_device *adc_dev; 76static struct adc_device *adc_dev;
76 77
77static LIST_HEAD(adc_pending); 78static LIST_HEAD(adc_pending); /* protected by adc_device.lock */
78 79
79#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg) 80#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
80 81
@@ -145,7 +146,7 @@ int s3c_adc_start(struct s3c_adc_client *client,
145 if (client->is_ts && adc->ts_pend) 146 if (client->is_ts && adc->ts_pend)
146 return -EAGAIN; 147 return -EAGAIN;
147 148
148 local_irq_save(flags); 149 spin_lock_irqsave(&adc->lock, flags);
149 150
150 client->channel = channel; 151 client->channel = channel;
151 client->nr_samples = nr_samples; 152 client->nr_samples = nr_samples;
@@ -157,7 +158,8 @@ int s3c_adc_start(struct s3c_adc_client *client,
157 158
158 if (!adc->cur) 159 if (!adc->cur)
159 s3c_adc_try(adc); 160 s3c_adc_try(adc);
160 local_irq_restore(flags); 161
162 spin_unlock_irqrestore(&adc->lock, flags);
161 163
162 return 0; 164 return 0;
163} 165}
@@ -237,6 +239,10 @@ EXPORT_SYMBOL_GPL(s3c_adc_register);
237 239
238void s3c_adc_release(struct s3c_adc_client *client) 240void s3c_adc_release(struct s3c_adc_client *client)
239{ 241{
242 unsigned long flags;
243
244 spin_lock_irqsave(&adc_dev->lock, flags);
245
240 /* We should really check that nothing is in progress. */ 246 /* We should really check that nothing is in progress. */
241 if (adc_dev->cur == client) 247 if (adc_dev->cur == client)
242 adc_dev->cur = NULL; 248 adc_dev->cur = NULL;
@@ -255,6 +261,8 @@ void s3c_adc_release(struct s3c_adc_client *client)
255 261
256 if (adc_dev->cur == NULL) 262 if (adc_dev->cur == NULL)
257 s3c_adc_try(adc_dev); 263 s3c_adc_try(adc_dev);
264
265 spin_unlock_irqrestore(&adc_dev->lock, flags);
258 kfree(client); 266 kfree(client);
259} 267}
260EXPORT_SYMBOL_GPL(s3c_adc_release); 268EXPORT_SYMBOL_GPL(s3c_adc_release);
@@ -264,7 +272,6 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
264 struct adc_device *adc = pw; 272 struct adc_device *adc = pw;
265 struct s3c_adc_client *client = adc->cur; 273 struct s3c_adc_client *client = adc->cur;
266 enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; 274 enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
267 unsigned long flags;
268 unsigned data0, data1; 275 unsigned data0, data1;
269 276
270 if (!client) { 277 if (!client) {
@@ -296,12 +303,12 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
296 client->select_cb(client, 1); 303 client->select_cb(client, 1);
297 s3c_adc_convert(adc); 304 s3c_adc_convert(adc);
298 } else { 305 } else {
299 local_irq_save(flags); 306 spin_lock(&adc->lock);
300 (client->select_cb)(client, 0); 307 (client->select_cb)(client, 0);
301 adc->cur = NULL; 308 adc->cur = NULL;
302 309
303 s3c_adc_try(adc); 310 s3c_adc_try(adc);
304 local_irq_restore(flags); 311 spin_unlock(&adc->lock);
305 } 312 }
306 313
307exit: 314exit:
@@ -326,6 +333,8 @@ static int s3c_adc_probe(struct platform_device *pdev)
326 return -ENOMEM; 333 return -ENOMEM;
327 } 334 }
328 335
336 spin_lock_init(&adc->lock);
337
329 adc->pdev = pdev; 338 adc->pdev = pdev;
330 adc->prescale = S3C2410_ADCCON_PRSCVL(49); 339 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
331 340
@@ -407,13 +416,17 @@ static int __devexit s3c_adc_remove(struct platform_device *pdev)
407static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state) 416static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
408{ 417{
409 struct adc_device *adc = platform_get_drvdata(pdev); 418 struct adc_device *adc = platform_get_drvdata(pdev);
419 unsigned long flags;
410 u32 con; 420 u32 con;
411 421
422 spin_lock_irqsave(&adc->lock, flags);
423
412 con = readl(adc->regs + S3C2410_ADCCON); 424 con = readl(adc->regs + S3C2410_ADCCON);
413 con |= S3C2410_ADCCON_STDBM; 425 con |= S3C2410_ADCCON_STDBM;
414 writel(con, adc->regs + S3C2410_ADCCON); 426 writel(con, adc->regs + S3C2410_ADCCON);
415 427
416 disable_irq(adc->irq); 428 disable_irq(adc->irq);
429 spin_unlock_irqrestore(&adc->lock, flags);
417 clk_disable(adc->clk); 430 clk_disable(adc->clk);
418 431
419 return 0; 432 return 0;
@@ -422,6 +435,7 @@ static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
422static int s3c_adc_resume(struct platform_device *pdev) 435static int s3c_adc_resume(struct platform_device *pdev)
423{ 436{
424 struct adc_device *adc = platform_get_drvdata(pdev); 437 struct adc_device *adc = platform_get_drvdata(pdev);
438 unsigned long flags;
425 439
426 clk_enable(adc->clk); 440 clk_enable(adc->clk);
427 enable_irq(adc->irq); 441 enable_irq(adc->irq);