diff options
Diffstat (limited to 'arch/arm/plat-samsung/adc.c')
| -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); |
