diff options
| -rw-r--r-- | drivers/iio/adc/ti_am335x_adc.c | 64 | ||||
| -rw-r--r-- | drivers/mfd/ti_am335x_tscadc.c | 63 | ||||
| -rw-r--r-- | include/linux/mfd/ti_am335x_tscadc.h | 4 |
3 files changed, 103 insertions, 28 deletions
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index e0dc2d0e7590..dff7343405e2 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c | |||
| @@ -60,6 +60,24 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) | |||
| 60 | return step_en; | 60 | return step_en; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev, | ||
| 64 | struct iio_chan_spec const *chan) | ||
| 65 | { | ||
| 66 | int i; | ||
| 67 | |||
| 68 | for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) { | ||
| 69 | if (chan->channel == adc_dev->channel_line[i]) { | ||
| 70 | u32 step; | ||
| 71 | |||
| 72 | step = adc_dev->channel_step[i]; | ||
| 73 | /* +1 for the charger */ | ||
| 74 | return 1 << (step + 1); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | WARN_ON(1); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 63 | static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) | 81 | static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) |
| 64 | { | 82 | { |
| 65 | return 1 << adc_dev->channel_step[chan]; | 83 | return 1 << adc_dev->channel_step[chan]; |
| @@ -326,34 +344,43 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, | |||
| 326 | unsigned int fifo1count, read, stepid; | 344 | unsigned int fifo1count, read, stepid; |
| 327 | bool found = false; | 345 | bool found = false; |
| 328 | u32 step_en; | 346 | u32 step_en; |
| 329 | unsigned long timeout = jiffies + usecs_to_jiffies | 347 | unsigned long timeout; |
| 330 | (IDLE_TIMEOUT * adc_dev->channels); | ||
| 331 | 348 | ||
| 332 | if (iio_buffer_enabled(indio_dev)) | 349 | if (iio_buffer_enabled(indio_dev)) |
| 333 | return -EBUSY; | 350 | return -EBUSY; |
| 334 | 351 | ||
| 335 | step_en = get_adc_step_mask(adc_dev); | 352 | step_en = get_adc_chan_step_mask(adc_dev, chan); |
| 353 | if (!step_en) | ||
| 354 | return -EINVAL; | ||
| 355 | |||
| 356 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | ||
| 357 | while (fifo1count--) | ||
| 358 | tiadc_readl(adc_dev, REG_FIFO1); | ||
| 359 | |||
| 336 | am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); | 360 | am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); |
| 337 | 361 | ||
| 338 | /* Wait for ADC sequencer to complete sampling */ | 362 | timeout = jiffies + usecs_to_jiffies |
| 339 | while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) { | 363 | (IDLE_TIMEOUT * adc_dev->channels); |
| 340 | if (time_after(jiffies, timeout)) | 364 | /* Wait for Fifo threshold interrupt */ |
| 365 | while (1) { | ||
| 366 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | ||
| 367 | if (fifo1count) | ||
| 368 | break; | ||
| 369 | |||
| 370 | if (time_after(jiffies, timeout)) { | ||
| 371 | am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); | ||
| 341 | return -EAGAIN; | 372 | return -EAGAIN; |
| 373 | } | ||
| 342 | } | 374 | } |
| 343 | map_val = chan->channel + TOTAL_CHANNELS; | 375 | map_val = chan->channel + TOTAL_CHANNELS; |
| 344 | 376 | ||
| 345 | /* | 377 | /* |
| 346 | * When the sub-system is first enabled, | 378 | * We check the complete FIFO. We programmed just one entry but in case |
| 347 | * the sequencer will always start with the | 379 | * something went wrong we left empty handed (-EAGAIN previously) and |
| 348 | * lowest step (1) and continue until step (16). | 380 | * then the value apeared somehow in the FIFO we would have two entries. |
| 349 | * For ex: If we have enabled 4 ADC channels and | 381 | * Therefore we read every item and keep only the latest version of the |
| 350 | * currently use only 1 out of them, the | 382 | * requested channel. |
| 351 | * sequencer still configures all the 4 steps, | ||
| 352 | * leading to 3 unwanted data. | ||
| 353 | * Hence we need to flush out this data. | ||
| 354 | */ | 383 | */ |
| 355 | |||
| 356 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | ||
| 357 | for (i = 0; i < fifo1count; i++) { | 384 | for (i = 0; i < fifo1count; i++) { |
| 358 | read = tiadc_readl(adc_dev, REG_FIFO1); | 385 | read = tiadc_readl(adc_dev, REG_FIFO1); |
| 359 | stepid = read & FIFOREAD_CHNLID_MASK; | 386 | stepid = read & FIFOREAD_CHNLID_MASK; |
| @@ -365,6 +392,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, | |||
| 365 | *val = (u16) read; | 392 | *val = (u16) read; |
| 366 | } | 393 | } |
| 367 | } | 394 | } |
| 395 | am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); | ||
| 368 | 396 | ||
| 369 | if (found == false) | 397 | if (found == false) |
| 370 | return -EBUSY; | 398 | return -EBUSY; |
| @@ -492,8 +520,8 @@ static int tiadc_resume(struct device *dev) | |||
| 492 | tiadc_writel(adc_dev, REG_CTRL, restore); | 520 | tiadc_writel(adc_dev, REG_CTRL, restore); |
| 493 | 521 | ||
| 494 | tiadc_step_config(indio_dev); | 522 | tiadc_step_config(indio_dev); |
| 495 | am335x_tsc_se_set(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); | 523 | am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, |
| 496 | 524 | adc_dev->buffer_en_ch_steps); | |
| 497 | return 0; | 525 | return 0; |
| 498 | } | 526 | } |
| 499 | 527 | ||
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 157f5699a33c..d4e860413bb5 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/pm_runtime.h> | 24 | #include <linux/pm_runtime.h> |
| 25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
| 26 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
| 27 | #include <linux/sched.h> | ||
| 27 | 28 | ||
| 28 | #include <linux/mfd/ti_am335x_tscadc.h> | 29 | #include <linux/mfd/ti_am335x_tscadc.h> |
| 29 | 30 | ||
| @@ -48,31 +49,71 @@ static const struct regmap_config tscadc_regmap_config = { | |||
| 48 | .val_bits = 32, | 49 | .val_bits = 32, |
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| 51 | static void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc) | ||
| 52 | { | ||
| 53 | tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); | ||
| 54 | } | ||
| 55 | |||
| 56 | void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) | 52 | void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) |
| 57 | { | 53 | { |
| 58 | unsigned long flags; | 54 | unsigned long flags; |
| 59 | 55 | ||
| 60 | spin_lock_irqsave(&tsadc->reg_lock, flags); | 56 | spin_lock_irqsave(&tsadc->reg_lock, flags); |
| 61 | tsadc->reg_se_cache |= val; | 57 | tsadc->reg_se_cache = val; |
| 62 | am335x_tsc_se_update(tsadc); | 58 | if (tsadc->adc_waiting) |
| 59 | wake_up(&tsadc->reg_se_wait); | ||
| 60 | else if (!tsadc->adc_in_use) | ||
| 61 | tscadc_writel(tsadc, REG_SE, val); | ||
| 62 | |||
| 63 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); | 63 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); |
| 64 | } | 64 | } |
| 65 | EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); | 65 | EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); |
| 66 | 66 | ||
| 67 | static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tsadc) | ||
| 68 | { | ||
| 69 | DEFINE_WAIT(wait); | ||
| 70 | u32 reg; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * disable TSC steps so it does not run while the ADC is using it. If | ||
| 74 | * write 0 while it is running (it just started or was already running) | ||
| 75 | * then it completes all steps that were enabled and stops then. | ||
| 76 | */ | ||
| 77 | tscadc_writel(tsadc, REG_SE, 0); | ||
| 78 | reg = tscadc_readl(tsadc, REG_ADCFSM); | ||
| 79 | if (reg & SEQ_STATUS) { | ||
| 80 | tsadc->adc_waiting = true; | ||
| 81 | prepare_to_wait(&tsadc->reg_se_wait, &wait, | ||
| 82 | TASK_UNINTERRUPTIBLE); | ||
| 83 | spin_unlock_irq(&tsadc->reg_lock); | ||
| 84 | |||
| 85 | schedule(); | ||
| 86 | |||
| 87 | spin_lock_irq(&tsadc->reg_lock); | ||
| 88 | finish_wait(&tsadc->reg_se_wait, &wait); | ||
| 89 | |||
| 90 | reg = tscadc_readl(tsadc, REG_ADCFSM); | ||
| 91 | WARN_ON(reg & SEQ_STATUS); | ||
| 92 | tsadc->adc_waiting = false; | ||
| 93 | } | ||
| 94 | tsadc->adc_in_use = true; | ||
| 95 | } | ||
| 96 | |||
| 67 | void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) | 97 | void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) |
| 68 | { | 98 | { |
| 99 | spin_lock_irq(&tsadc->reg_lock); | ||
| 100 | am335x_tscadc_need_adc(tsadc); | ||
| 101 | |||
| 102 | tscadc_writel(tsadc, REG_SE, val); | ||
| 103 | spin_unlock_irq(&tsadc->reg_lock); | ||
| 104 | } | ||
| 105 | EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); | ||
| 106 | |||
| 107 | void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc) | ||
| 108 | { | ||
| 69 | unsigned long flags; | 109 | unsigned long flags; |
| 70 | 110 | ||
| 71 | spin_lock_irqsave(&tsadc->reg_lock, flags); | 111 | spin_lock_irqsave(&tsadc->reg_lock, flags); |
| 72 | tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache | val); | 112 | tsadc->adc_in_use = false; |
| 113 | tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); | ||
| 73 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); | 114 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); |
| 74 | } | 115 | } |
| 75 | EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); | 116 | EXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done); |
| 76 | 117 | ||
| 77 | void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) | 118 | void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) |
| 78 | { | 119 | { |
| @@ -80,7 +121,7 @@ void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) | |||
| 80 | 121 | ||
| 81 | spin_lock_irqsave(&tsadc->reg_lock, flags); | 122 | spin_lock_irqsave(&tsadc->reg_lock, flags); |
| 82 | tsadc->reg_se_cache &= ~val; | 123 | tsadc->reg_se_cache &= ~val; |
| 83 | am335x_tsc_se_update(tsadc); | 124 | tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); |
| 84 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); | 125 | spin_unlock_irqrestore(&tsadc->reg_lock, flags); |
| 85 | } | 126 | } |
| 86 | EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); | 127 | EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); |
| @@ -188,6 +229,8 @@ static int ti_tscadc_probe(struct platform_device *pdev) | |||
| 188 | } | 229 | } |
| 189 | 230 | ||
| 190 | spin_lock_init(&tscadc->reg_lock); | 231 | spin_lock_init(&tscadc->reg_lock); |
| 232 | init_waitqueue_head(&tscadc->reg_se_wait); | ||
| 233 | |||
| 191 | pm_runtime_enable(&pdev->dev); | 234 | pm_runtime_enable(&pdev->dev); |
| 192 | pm_runtime_get_sync(&pdev->dev); | 235 | pm_runtime_get_sync(&pdev->dev); |
| 193 | 236 | ||
diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 2fa9c0613da4..fb96c84dada5 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h | |||
| @@ -159,6 +159,9 @@ struct ti_tscadc_dev { | |||
| 159 | int adc_cell; /* -1 if not used */ | 159 | int adc_cell; /* -1 if not used */ |
| 160 | struct mfd_cell cells[TSCADC_CELLS]; | 160 | struct mfd_cell cells[TSCADC_CELLS]; |
| 161 | u32 reg_se_cache; | 161 | u32 reg_se_cache; |
| 162 | bool adc_waiting; | ||
| 163 | bool adc_in_use; | ||
| 164 | wait_queue_head_t reg_se_wait; | ||
| 162 | spinlock_t reg_lock; | 165 | spinlock_t reg_lock; |
| 163 | unsigned int clk_div; | 166 | unsigned int clk_div; |
| 164 | 167 | ||
| @@ -179,5 +182,6 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) | |||
| 179 | void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val); | 182 | void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val); |
| 180 | void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val); | 183 | void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val); |
| 181 | void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); | 184 | void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); |
| 185 | void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc); | ||
| 182 | 186 | ||
| 183 | #endif | 187 | #endif |
