Commit 28b4c294 authored by Lee Jones's avatar Lee Jones

Merge tag 'ib-iio-input-3.13-1' into for-mfd-next

Immutable branch for IIO and Input
parents 09fd19da 7ca6740c
...@@ -60,6 +60,24 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) ...@@ -60,6 +60,24 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
return step_en; return step_en;
} }
static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev,
struct iio_chan_spec const *chan)
{
int i;
for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
if (chan->channel == adc_dev->channel_line[i]) {
u32 step;
step = adc_dev->channel_step[i];
/* +1 for the charger */
return 1 << (step + 1);
}
}
WARN_ON(1);
return 0;
}
static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
{ {
return 1 << adc_dev->channel_step[chan]; return 1 << adc_dev->channel_step[chan];
...@@ -181,7 +199,7 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev) ...@@ -181,7 +199,7 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
enb |= (get_adc_step_bit(adc_dev, bit) << 1); enb |= (get_adc_step_bit(adc_dev, bit) << 1);
adc_dev->buffer_en_ch_steps = enb; adc_dev->buffer_en_ch_steps = enb;
am335x_tsc_se_set(adc_dev->mfd_tscadc, enb); am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES
| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
...@@ -199,6 +217,7 @@ static int tiadc_buffer_predisable(struct iio_dev *indio_dev) ...@@ -199,6 +217,7 @@ static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps);
adc_dev->buffer_en_ch_steps = 0;
/* Flush FIFO of leftover data in the time it takes to disable adc */ /* Flush FIFO of leftover data in the time it takes to disable adc */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
...@@ -328,34 +347,43 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, ...@@ -328,34 +347,43 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
unsigned int fifo1count, read, stepid; unsigned int fifo1count, read, stepid;
bool found = false; bool found = false;
u32 step_en; u32 step_en;
unsigned long timeout = jiffies + usecs_to_jiffies unsigned long timeout;
(IDLE_TIMEOUT * adc_dev->channels);
if (iio_buffer_enabled(indio_dev)) if (iio_buffer_enabled(indio_dev))
return -EBUSY; return -EBUSY;
step_en = get_adc_step_mask(adc_dev); step_en = get_adc_chan_step_mask(adc_dev, chan);
am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); if (!step_en)
return -EINVAL;
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
while (fifo1count--)
tiadc_readl(adc_dev, REG_FIFO1);
/* Wait for ADC sequencer to complete sampling */ am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
if (time_after(jiffies, timeout)) timeout = jiffies + usecs_to_jiffies
(IDLE_TIMEOUT * adc_dev->channels);
/* Wait for Fifo threshold interrupt */
while (1) {
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
if (fifo1count)
break;
if (time_after(jiffies, timeout)) {
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
return -EAGAIN; return -EAGAIN;
} }
}
map_val = chan->channel + TOTAL_CHANNELS; map_val = chan->channel + TOTAL_CHANNELS;
/* /*
* When the sub-system is first enabled, * We check the complete FIFO. We programmed just one entry but in case
* the sequencer will always start with the * something went wrong we left empty handed (-EAGAIN previously) and
* lowest step (1) and continue until step (16). * then the value apeared somehow in the FIFO we would have two entries.
* For ex: If we have enabled 4 ADC channels and * Therefore we read every item and keep only the latest version of the
* currently use only 1 out of them, the * requested channel.
* sequencer still configures all the 4 steps,
* leading to 3 unwanted data.
* Hence we need to flush out this data.
*/ */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++) { for (i = 0; i < fifo1count; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1); read = tiadc_readl(adc_dev, REG_FIFO1);
stepid = read & FIFOREAD_CHNLID_MASK; stepid = read & FIFOREAD_CHNLID_MASK;
...@@ -367,6 +395,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, ...@@ -367,6 +395,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
*val = (u16) read; *val = (u16) read;
} }
} }
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
if (found == false) if (found == false)
return -EBUSY; return -EBUSY;
...@@ -494,7 +523,8 @@ static int tiadc_resume(struct device *dev) ...@@ -494,7 +523,8 @@ static int tiadc_resume(struct device *dev)
tiadc_writel(adc_dev, REG_CTRL, restore); tiadc_writel(adc_dev, REG_CTRL, restore);
tiadc_step_config(indio_dev); tiadc_step_config(indio_dev);
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc,
adc_dev->buffer_en_ch_steps);
return 0; return 0;
} }
......
...@@ -198,7 +198,7 @@ static void titsc_step_config(struct titsc *ts_dev) ...@@ -198,7 +198,7 @@ static void titsc_step_config(struct titsc *ts_dev)
/* The steps1 … end and bit 0 for TS_Charge */ /* The steps1 … end and bit 0 for TS_Charge */
stepenable = (1 << (end_step + 2)) - 1; stepenable = (1 << (end_step + 2)) - 1;
ts_dev->step_mask = stepenable; ts_dev->step_mask = stepenable;
am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
} }
static void titsc_read_coordinates(struct titsc *ts_dev, static void titsc_read_coordinates(struct titsc *ts_dev,
...@@ -322,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) ...@@ -322,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
if (irqclr) { if (irqclr) {
titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask); am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
return IRQ_NONE; return IRQ_NONE;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/sched.h>
#include <linux/mfd/ti_am335x_tscadc.h> #include <linux/mfd/ti_am335x_tscadc.h>
...@@ -48,32 +49,79 @@ static const struct regmap_config tscadc_regmap_config = { ...@@ -48,32 +49,79 @@ static const struct regmap_config tscadc_regmap_config = {
.val_bits = 32, .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; unsigned long flags;
spin_lock_irqsave(&tsadc->reg_lock, flags); spin_lock_irqsave(&tsadc->reg_lock, flags);
tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->adc_in_use = false;
tsadc->reg_se_cache |= val; tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache);
am335x_tsc_se_update(tsadc);
spin_unlock_irqrestore(&tsadc->reg_lock, flags); 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) void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&tsadc->reg_lock, flags); spin_lock_irqsave(&tsadc->reg_lock, flags);
tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE);
tsadc->reg_se_cache &= ~val; 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); spin_unlock_irqrestore(&tsadc->reg_lock, flags);
} }
EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
...@@ -181,6 +229,8 @@ static int ti_tscadc_probe(struct platform_device *pdev) ...@@ -181,6 +229,8 @@ static int ti_tscadc_probe(struct platform_device *pdev)
} }
spin_lock_init(&tscadc->reg_lock); spin_lock_init(&tscadc->reg_lock);
init_waitqueue_head(&tscadc->reg_se_wait);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
...@@ -302,7 +352,6 @@ static int tscadc_resume(struct device *dev) ...@@ -302,7 +352,6 @@ static int tscadc_resume(struct device *dev)
if (tscadc_dev->tsc_cell != -1) if (tscadc_dev->tsc_cell != -1)
tscadc_idle_config(tscadc_dev); tscadc_idle_config(tscadc_dev);
am335x_tsc_se_update(tscadc_dev);
restore = tscadc_readl(tscadc_dev, REG_CTRL); restore = tscadc_readl(tscadc_dev, REG_CTRL);
tscadc_writel(tscadc_dev, REG_CTRL, tscadc_writel(tscadc_dev, REG_CTRL,
(restore | CNTRLREG_TSCSSENB)); (restore | CNTRLREG_TSCSSENB));
......
...@@ -159,6 +159,9 @@ struct ti_tscadc_dev { ...@@ -159,6 +159,9 @@ struct ti_tscadc_dev {
int adc_cell; /* -1 if not used */ int adc_cell; /* -1 if not used */
struct mfd_cell cells[TSCADC_CELLS]; struct mfd_cell cells[TSCADC_CELLS];
u32 reg_se_cache; u32 reg_se_cache;
bool adc_waiting;
bool adc_in_use;
wait_queue_head_t reg_se_wait;
spinlock_t reg_lock; spinlock_t reg_lock;
unsigned int clk_div; unsigned int clk_div;
...@@ -176,8 +179,9 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) ...@@ -176,8 +179,9 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p)
return *tscadc_dev; return *tscadc_dev;
} }
void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc); void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val);
void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val);
void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val);
void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment