diff options
-rw-r--r-- | arch/arm/plat-samsung/adc.c | 26 |
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 | ||
75 | static struct adc_device *adc_dev; | 76 | static struct adc_device *adc_dev; |
76 | 77 | ||
77 | static LIST_HEAD(adc_pending); | 78 | static 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 | ||
238 | void s3c_adc_release(struct s3c_adc_client *client) | 240 | void 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 | } |
260 | EXPORT_SYMBOL_GPL(s3c_adc_release); | 268 | EXPORT_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 | ||
307 | exit: | 314 | exit: |
@@ -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) | |||
407 | static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state) | 416 | static 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) | |||
422 | static int s3c_adc_resume(struct platform_device *pdev) | 435 | static 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); |