Immutable branch for IIO and Input
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSy79CAAoJEFGvii+H/Hdh3ZcQALTHjbU85CljM+tDsQUC3ugi uMQZxf2YEWDmLE1epcGbQ22EVdI2s59jFs8tEUBSOqbUXm+Oyuf8zdjenibnOoht epKvlRgUGXZA4A90YsJjVLSkn2Nl/QvyKhjU7n9KTH6rnPFGOw2Ja5n7cLy3DtNY vsSwHRtOrV5tWMSJQbGamz9cGujhAli5kHQ+hPUKNeaztSGFbpl02SsV8oJ/Dlbg juzjY9QDMnKjiSjA0ZtvUIJoyU5yJuRtrBM02SsvXAVPTZpMEaM5P7dO3lqPSXzK jUZuMszrB8gV0NxeSkdiWYUZ89rpoSVYv6EW/pg87OvTxukHyB4oi1+/3YXYdNgj 8kDVhL/BKPdqLw9vo7WbvnZJz99qNyh7R4ZOf90Yv+3BOAPue0WdDQjZw/5p41Ur 8+VRc1SvOSzXDuNIon97DmpKk477i3ylMiAeqi+b7ynzgvJqGayFf0KUHlUHmKjM ZNKHl2sd9qvft5WUX1P02ihc9/j8LMF5h8WX8Et1/a05SXn1LvfK5HJQk9ZHB94m ZaXwEOirbHAVyTlQre1zYncBWtlsLlOJT+c0G+HjFX99+79u0KxFyUTpXgfypJUe 5UGQjM/w+CcVpl6h58k65PjyGRRweVUkqnoAnOpVGCRvIx4sU1g5nF9usEb8omDA PODxF76LVgohEozCwGpq =Tc4K -----END PGP SIGNATURE----- Merge tag 'ib-iio-input-3.13-1' into for-mfd-next Immutable branch for IIO and Input
This commit is contained in:
commit
28b4c2948f
|
@ -60,6 +60,24 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
|
|||
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)
|
||||
{
|
||||
return 1 << adc_dev->channel_step[chan];
|
||||
|
@ -181,7 +199,7 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
|
|||
enb |= (get_adc_step_bit(adc_dev, bit) << 1);
|
||||
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
|
||||
| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
|
||||
|
@ -199,6 +217,7 @@ static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
|
|||
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
|
||||
IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
|
||||
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 */
|
||||
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
|
||||
|
@ -328,34 +347,43 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
|
|||
unsigned int fifo1count, read, stepid;
|
||||
bool found = false;
|
||||
u32 step_en;
|
||||
unsigned long timeout = jiffies + usecs_to_jiffies
|
||||
(IDLE_TIMEOUT * adc_dev->channels);
|
||||
unsigned long timeout;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
step_en = get_adc_step_mask(adc_dev);
|
||||
am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
|
||||
step_en = get_adc_chan_step_mask(adc_dev, chan);
|
||||
if (!step_en)
|
||||
return -EINVAL;
|
||||
|
||||
/* Wait for ADC sequencer to complete sampling */
|
||||
while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
|
||||
if (time_after(jiffies, timeout))
|
||||
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
|
||||
while (fifo1count--)
|
||||
tiadc_readl(adc_dev, REG_FIFO1);
|
||||
|
||||
am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
map_val = chan->channel + TOTAL_CHANNELS;
|
||||
|
||||
/*
|
||||
* When the sub-system is first enabled,
|
||||
* the sequencer will always start with the
|
||||
* lowest step (1) and continue until step (16).
|
||||
* For ex: If we have enabled 4 ADC channels and
|
||||
* currently use only 1 out of them, the
|
||||
* sequencer still configures all the 4 steps,
|
||||
* leading to 3 unwanted data.
|
||||
* Hence we need to flush out this data.
|
||||
* We check the complete FIFO. We programmed just one entry but in case
|
||||
* something went wrong we left empty handed (-EAGAIN previously) and
|
||||
* then the value apeared somehow in the FIFO we would have two entries.
|
||||
* Therefore we read every item and keep only the latest version of the
|
||||
* requested channel.
|
||||
*/
|
||||
|
||||
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
|
||||
for (i = 0; i < fifo1count; i++) {
|
||||
read = tiadc_readl(adc_dev, REG_FIFO1);
|
||||
stepid = read & FIFOREAD_CHNLID_MASK;
|
||||
|
@ -367,6 +395,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
|
|||
*val = (u16) read;
|
||||
}
|
||||
}
|
||||
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
|
||||
|
||||
if (found == false)
|
||||
return -EBUSY;
|
||||
|
@ -494,7 +523,8 @@ static int tiadc_resume(struct device *dev)
|
|||
tiadc_writel(adc_dev, REG_CTRL, restore);
|
||||
|
||||
tiadc_step_config(indio_dev);
|
||||
|
||||
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc,
|
||||
adc_dev->buffer_en_ch_steps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ static void titsc_step_config(struct titsc *ts_dev)
|
|||
/* The steps1 … end and bit 0 for TS_Charge */
|
||||
stepenable = (1 << (end_step + 2)) - 1;
|
||||
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,
|
||||
|
@ -322,7 +322,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
|
|||
|
||||
if (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_NONE;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(am335x_tsc_se_update);
|
||||
|
||||
void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val)
|
||||
void am335x_tsc_se_set_cache(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);
|
||||
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);
|
||||
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_set_once);
|
||||
|
||||
void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tsadc)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tsadc->reg_lock, flags);
|
||||
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_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));
|
||||
|
|
|
@ -159,6 +159,9 @@ struct ti_tscadc_dev {
|
|||
int adc_cell; /* -1 if not used */
|
||||
struct mfd_cell cells[TSCADC_CELLS];
|
||||
u32 reg_se_cache;
|
||||
bool adc_waiting;
|
||||
bool adc_in_use;
|
||||
wait_queue_head_t reg_se_wait;
|
||||
spinlock_t reg_lock;
|
||||
unsigned int clk_div;
|
||||
|
||||
|
@ -176,8 +179,9 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p)
|
|||
return *tscadc_dev;
|
||||
}
|
||||
|
||||
void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc);
|
||||
void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val);
|
||||
void am335x_tsc_se_set_cache(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_adc_done(struct ti_tscadc_dev *tsadc);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue