diff options
author | Lee Jones <lee.jones@linaro.org> | 2014-01-21 09:26:55 +0100 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2014-01-21 09:26:55 +0100 |
commit | 28b4c2948fe005da0f70d492f59593f862b3f773 (patch) | |
tree | f45d67d4dd230bdfffdb9fa93eea32913bf14c96 /drivers/mfd | |
parent | Merge tag 'ib-asoc-3.14.2' into for-mfd-next (diff) | |
parent | mfd: input: iio: ti_amm335x: Rework TSC/ADC synchronization (diff) | |
download | linux-28b4c2948fe005da0f70d492f59593f862b3f773.tar.xz linux-28b4c2948fe005da0f70d492f59593f862b3f773.zip |
Merge tag 'ib-iio-input-3.13-1' into for-mfd-next
Immutable branch for IIO and Input
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/ti_am335x_tscadc.c | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 88718abfb9ba..d4e860413bb5 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -24,6 +24,7 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/sched.h> #include <linux/mfd/ti_am335x_tscadc.h> @@ -48,32 +49,79 @@ static const struct regmap_config tscadc_regmap_config = { .val_bits = 32, }; -void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc) +void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) { - tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); + unsigned long flags; + + spin_lock_irqsave(&tsadc->reg_lock, flags); + tsadc->reg_se_cache = val; + if (tsadc->adc_waiting) + wake_up(&tsadc->reg_se_wait); + else if (!tsadc->adc_in_use) + tscadc_writel(tsadc, REG_SE, val); + + spin_unlock_irqrestore(&tsadc->reg_lock, flags); +} +EXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); + +static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tsadc) +{ + DEFINE_WAIT(wait); + u32 reg; + + /* + * disable TSC steps so it does not run while the ADC is using it. If + * write 0 while it is running (it just started or was already running) + * then it completes all steps that were enabled and stops then. + */ + tscadc_writel(tsadc, REG_SE, 0); + reg = tscadc_readl(tsadc, REG_ADCFSM); + if (reg & SEQ_STATUS) { + tsadc->adc_waiting = true; + prepare_to_wait(&tsadc->reg_se_wait, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&tsadc->reg_lock); + + schedule(); + + spin_lock_irq(&tsadc->reg_lock); + finish_wait(&tsadc->reg_se_wait, &wait); + + reg = tscadc_readl(tsadc, REG_ADCFSM); + WARN_ON(reg & SEQ_STATUS); + tsadc->adc_waiting = false; + } + tsadc->adc_in_use = true; +} + +void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) +{ + spin_lock_irq(&tsadc->reg_lock); + am335x_tscadc_need_adc(tsadc); + + tscadc_writel(tsadc, REG_SE, val); + spin_unlock_irq(&tsadc->reg_lock); } -EXPORT_SYMBOL_GPL(am335x_tsc_se_update); +EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); -void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val) +void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); - tsadc->reg_se_cache |= val; - am335x_tsc_se_update(tsadc); + tsadc->adc_in_use = false; + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } -EXPORT_SYMBOL_GPL(am335x_tsc_se_set); +EXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) { unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache &= ~val; - am335x_tsc_se_update(tsadc); + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); @@ -181,6 +229,8 @@ static int ti_tscadc_probe(struct platform_device *pdev) } spin_lock_init(&tscadc->reg_lock); + init_waitqueue_head(&tscadc->reg_se_wait); + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -302,7 +352,6 @@ static int tscadc_resume(struct device *dev) if (tscadc_dev->tsc_cell != -1) tscadc_idle_config(tscadc_dev); - am335x_tsc_se_update(tscadc_dev); restore = tscadc_readl(tscadc_dev, REG_CTRL); tscadc_writel(tscadc_dev, REG_CTRL, (restore | CNTRLREG_TSCSSENB)); |