aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-samsung/adc.c
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2010-05-10 00:31:36 -0400
committerBen Dooks <ben-linux@fluff.org>2010-05-20 08:05:49 -0400
commit1f1f584c9a1dd234041573d2d1c42620b3966607 (patch)
treeb05881c9a1eb9d7adeba78e9b48ddd9536b733ef /arch/arm/plat-samsung/adc.c
parent6a399547242df3b12f13d637a95f63eaa82f9385 (diff)
ARM: SAMSUNG: Make ADC client SMP safe
Change local_irq disable calls to use spinlocks to ensure that the ADC driver data is protected against multiple access.. Note, this does not protect the client's data, and the client should ensure it does not make multiple calls to the ADC driver. Signed-off-by: Ben Dooks <ben-linux@fluff.org>
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);