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

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

Immutable branch for IIO and Input
parents 09fd19da 7ca6740c
Loading
Loading
Loading
Loading
+49 −19
Original line number Diff line number Diff line
@@ -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;

	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
	while (fifo1count--)
		tiadc_readl(adc_dev, REG_FIFO1);

	/* Wait for ADC sequencer to complete sampling */
	while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
		if (time_after(jiffies, timeout))
	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;
}

+2 −2
Original line number Diff line number Diff line
@@ -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;
+60 −11
Original line number Diff line number Diff line
@@ -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));
+6 −2
Original line number Diff line number Diff line
@@ -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