162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2016 Broadcom
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1162306a36Sopenharmony_ci#include <linux/regmap.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/iio/iio.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Below Register's are common to IPROC ADC and Touchscreen IP */
1962306a36Sopenharmony_ci#define IPROC_REGCTL1			0x00
2062306a36Sopenharmony_ci#define IPROC_REGCTL2			0x04
2162306a36Sopenharmony_ci#define IPROC_INTERRUPT_THRES		0x08
2262306a36Sopenharmony_ci#define IPROC_INTERRUPT_MASK		0x0c
2362306a36Sopenharmony_ci#define IPROC_INTERRUPT_STATUS		0x10
2462306a36Sopenharmony_ci#define IPROC_ANALOG_CONTROL		0x1c
2562306a36Sopenharmony_ci#define IPROC_CONTROLLER_STATUS		0x14
2662306a36Sopenharmony_ci#define IPROC_AUX_DATA			0x20
2762306a36Sopenharmony_ci#define IPROC_SOFT_BYPASS_CONTROL	0x38
2862306a36Sopenharmony_ci#define IPROC_SOFT_BYPASS_DATA		0x3C
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* IPROC ADC Channel register offsets */
3162306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_REGCTL1		0x800
3262306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_REGCTL2		0x804
3362306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_STATUS		0x808
3462306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_INTERRUPT_STATUS	0x80c
3562306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_INTERRUPT_MASK	0x810
3662306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_DATA			0x814
3762306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_OFFSET		0x20
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Bit definitions for IPROC_REGCTL2 */
4062306a36Sopenharmony_ci#define IPROC_ADC_AUXIN_SCAN_ENA	BIT(0)
4162306a36Sopenharmony_ci#define IPROC_ADC_PWR_LDO		BIT(5)
4262306a36Sopenharmony_ci#define IPROC_ADC_PWR_ADC		BIT(4)
4362306a36Sopenharmony_ci#define IPROC_ADC_PWR_BG		BIT(3)
4462306a36Sopenharmony_ci#define IPROC_ADC_CONTROLLER_EN		BIT(17)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* Bit definitions for IPROC_INTERRUPT_MASK and IPROC_INTERRUPT_STATUS */
4762306a36Sopenharmony_ci#define IPROC_ADC_AUXDATA_RDY_INTR	BIT(3)
4862306a36Sopenharmony_ci#define IPROC_ADC_INTR			9
4962306a36Sopenharmony_ci#define IPROC_ADC_INTR_MASK		(0xFF << IPROC_ADC_INTR)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Bit definitions for IPROC_ANALOG_CONTROL */
5262306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_SEL		11
5362306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_SEL_MASK	(0x7 << IPROC_ADC_CHANNEL_SEL)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL1 */
5662306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_ROUNDS	0x2
5762306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_ROUNDS_MASK	(0x3F << IPROC_ADC_CHANNEL_ROUNDS)
5862306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_MODE		0x1
5962306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_MODE_MASK	(0x1 << IPROC_ADC_CHANNEL_MODE)
6062306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_MODE_TDM	0x1
6162306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_MODE_SNAPSHOT 0x0
6262306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_ENABLE	0x0
6362306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_ENABLE_MASK	0x1
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL2 */
6662306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_WATERMARK	0x0
6762306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_WATERMARK_MASK \
6862306a36Sopenharmony_ci		(0x3F << IPROC_ADC_CHANNEL_WATERMARK)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define IPROC_ADC_WATER_MARK_LEVEL	0x1
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Bit definitions for IPROC_ADC_CHANNEL_STATUS */
7362306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_DATA_LOST		0x0
7462306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_DATA_LOST_MASK	\
7562306a36Sopenharmony_ci		(0x0 << IPROC_ADC_CHANNEL_DATA_LOST)
7662306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_VALID_ENTERIES	0x1
7762306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK	\
7862306a36Sopenharmony_ci		(0xFF << IPROC_ADC_CHANNEL_VALID_ENTERIES)
7962306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES	0x9
8062306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES_MASK	\
8162306a36Sopenharmony_ci		(0xFF << IPROC_ADC_CHANNEL_TOTAL_ENTERIES)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* Bit definitions for IPROC_ADC_CHANNEL_INTERRUPT_MASK */
8462306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_WTRMRK_INTR			0x0
8562306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK		\
8662306a36Sopenharmony_ci		(0x1 << IPROC_ADC_CHANNEL_WTRMRK_INTR)
8762306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_FULL_INTR			0x1
8862306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_FULL_INTR_MASK		\
8962306a36Sopenharmony_ci		(0x1 << IPROC_ADC_IPROC_ADC_CHANNEL_FULL_INTR)
9062306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_EMPTY_INTR			0x2
9162306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL_EMPTY_INTR_MASK		\
9262306a36Sopenharmony_ci		(0x1 << IPROC_ADC_CHANNEL_EMPTY_INTR)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define IPROC_ADC_WATER_MARK_INTR_ENABLE		0x1
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Number of time to retry a set of the interrupt mask reg */
9762306a36Sopenharmony_ci#define IPROC_ADC_INTMASK_RETRY_ATTEMPTS		10
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define IPROC_ADC_READ_TIMEOUT        (HZ*2)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define iproc_adc_dbg_reg(dev, priv, reg) \
10262306a36Sopenharmony_cido { \
10362306a36Sopenharmony_ci	u32 val; \
10462306a36Sopenharmony_ci	regmap_read(priv->regmap, reg, &val); \
10562306a36Sopenharmony_ci	dev_dbg(dev, "%20s= 0x%08x\n", #reg, val); \
10662306a36Sopenharmony_ci} while (0)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistruct iproc_adc_priv {
10962306a36Sopenharmony_ci	struct regmap *regmap;
11062306a36Sopenharmony_ci	struct clk *adc_clk;
11162306a36Sopenharmony_ci	struct mutex mutex;
11262306a36Sopenharmony_ci	int  irqno;
11362306a36Sopenharmony_ci	int chan_val;
11462306a36Sopenharmony_ci	int chan_id;
11562306a36Sopenharmony_ci	struct completion completion;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void iproc_adc_reg_dump(struct iio_dev *indio_dev)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct device *dev = &indio_dev->dev;
12162306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL1);
12462306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL2);
12562306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_THRES);
12662306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_MASK);
12762306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_STATUS);
12862306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_CONTROLLER_STATUS);
12962306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_ANALOG_CONTROL);
13062306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_AUX_DATA);
13162306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_CONTROL);
13262306a36Sopenharmony_ci	iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_DATA);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic irqreturn_t iproc_adc_interrupt_thread(int irq, void *data)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	u32 channel_intr_status;
13862306a36Sopenharmony_ci	u32 intr_status;
13962306a36Sopenharmony_ci	u32 intr_mask;
14062306a36Sopenharmony_ci	struct iio_dev *indio_dev = data;
14162306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * This interrupt is shared with the touchscreen driver.
14562306a36Sopenharmony_ci	 * Make sure this interrupt is intended for us.
14662306a36Sopenharmony_ci	 * Handle only ADC channel specific interrupts.
14762306a36Sopenharmony_ci	 */
14862306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
14962306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &intr_mask);
15062306a36Sopenharmony_ci	intr_status = intr_status & intr_mask;
15162306a36Sopenharmony_ci	channel_intr_status = (intr_status & IPROC_ADC_INTR_MASK) >>
15262306a36Sopenharmony_ci				IPROC_ADC_INTR;
15362306a36Sopenharmony_ci	if (channel_intr_status)
15462306a36Sopenharmony_ci		return IRQ_WAKE_THREAD;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return IRQ_NONE;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic irqreturn_t iproc_adc_interrupt_handler(int irq, void *data)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	irqreturn_t retval = IRQ_NONE;
16262306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv;
16362306a36Sopenharmony_ci	struct iio_dev *indio_dev = data;
16462306a36Sopenharmony_ci	unsigned int valid_entries;
16562306a36Sopenharmony_ci	u32 intr_status;
16662306a36Sopenharmony_ci	u32 intr_channels;
16762306a36Sopenharmony_ci	u32 channel_status;
16862306a36Sopenharmony_ci	u32 ch_intr_status;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	adc_priv = iio_priv(indio_dev);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
17362306a36Sopenharmony_ci	dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_handler(),INTRPT_STS:%x\n",
17462306a36Sopenharmony_ci			intr_status);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	intr_channels = (intr_status & IPROC_ADC_INTR_MASK) >> IPROC_ADC_INTR;
17762306a36Sopenharmony_ci	if (intr_channels) {
17862306a36Sopenharmony_ci		regmap_read(adc_priv->regmap,
17962306a36Sopenharmony_ci			    IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
18062306a36Sopenharmony_ci			    IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
18162306a36Sopenharmony_ci			    &ch_intr_status);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci		if (ch_intr_status & IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK) {
18462306a36Sopenharmony_ci			regmap_read(adc_priv->regmap,
18562306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_STATUS +
18662306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_OFFSET *
18762306a36Sopenharmony_ci					adc_priv->chan_id,
18862306a36Sopenharmony_ci					&channel_status);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci			valid_entries = ((channel_status &
19162306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK) >>
19262306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_VALID_ENTERIES);
19362306a36Sopenharmony_ci			if (valid_entries >= 1) {
19462306a36Sopenharmony_ci				regmap_read(adc_priv->regmap,
19562306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_DATA +
19662306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_OFFSET *
19762306a36Sopenharmony_ci					adc_priv->chan_id,
19862306a36Sopenharmony_ci					&adc_priv->chan_val);
19962306a36Sopenharmony_ci				complete(&adc_priv->completion);
20062306a36Sopenharmony_ci			} else {
20162306a36Sopenharmony_ci				dev_err(&indio_dev->dev,
20262306a36Sopenharmony_ci					"No data rcvd on channel %d\n",
20362306a36Sopenharmony_ci					adc_priv->chan_id);
20462306a36Sopenharmony_ci			}
20562306a36Sopenharmony_ci			regmap_write(adc_priv->regmap,
20662306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_INTERRUPT_MASK +
20762306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_OFFSET *
20862306a36Sopenharmony_ci					adc_priv->chan_id,
20962306a36Sopenharmony_ci					(ch_intr_status &
21062306a36Sopenharmony_ci					~(IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK)));
21162306a36Sopenharmony_ci		}
21262306a36Sopenharmony_ci		regmap_write(adc_priv->regmap,
21362306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
21462306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
21562306a36Sopenharmony_ci				ch_intr_status);
21662306a36Sopenharmony_ci		regmap_write(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
21762306a36Sopenharmony_ci				intr_channels);
21862306a36Sopenharmony_ci		retval = IRQ_HANDLED;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return retval;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int iproc_adc_do_read(struct iio_dev *indio_dev,
22562306a36Sopenharmony_ci			   int channel,
22662306a36Sopenharmony_ci			   u16 *p_adc_data)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	int read_len = 0;
22962306a36Sopenharmony_ci	u32 val;
23062306a36Sopenharmony_ci	u32 mask;
23162306a36Sopenharmony_ci	u32 val_check;
23262306a36Sopenharmony_ci	int failed_cnt = 0;
23362306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	mutex_lock(&adc_priv->mutex);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/*
23862306a36Sopenharmony_ci	 * After a read is complete the ADC interrupts will be disabled so
23962306a36Sopenharmony_ci	 * we can assume this section of code is safe from interrupts.
24062306a36Sopenharmony_ci	 */
24162306a36Sopenharmony_ci	adc_priv->chan_val = -1;
24262306a36Sopenharmony_ci	adc_priv->chan_id = channel;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	reinit_completion(&adc_priv->completion);
24562306a36Sopenharmony_ci	/* Clear any pending interrupt */
24662306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
24762306a36Sopenharmony_ci			IPROC_ADC_INTR_MASK | IPROC_ADC_AUXDATA_RDY_INTR,
24862306a36Sopenharmony_ci			((0x0 << channel) << IPROC_ADC_INTR) |
24962306a36Sopenharmony_ci			IPROC_ADC_AUXDATA_RDY_INTR);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Configure channel for snapshot mode and enable  */
25262306a36Sopenharmony_ci	val = (BIT(IPROC_ADC_CHANNEL_ROUNDS) |
25362306a36Sopenharmony_ci		(IPROC_ADC_CHANNEL_MODE_SNAPSHOT << IPROC_ADC_CHANNEL_MODE) |
25462306a36Sopenharmony_ci		(0x1 << IPROC_ADC_CHANNEL_ENABLE));
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	mask = IPROC_ADC_CHANNEL_ROUNDS_MASK | IPROC_ADC_CHANNEL_MODE_MASK |
25762306a36Sopenharmony_ci		IPROC_ADC_CHANNEL_ENABLE_MASK;
25862306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL1 +
25962306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_OFFSET * channel),
26062306a36Sopenharmony_ci				mask, val);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Set the Watermark for a channel */
26362306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL2 +
26462306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_OFFSET * channel),
26562306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_WATERMARK_MASK,
26662306a36Sopenharmony_ci					0x1);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Enable water mark interrupt */
26962306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_INTERRUPT_MASK +
27062306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_OFFSET *
27162306a36Sopenharmony_ci					channel),
27262306a36Sopenharmony_ci					IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK,
27362306a36Sopenharmony_ci					IPROC_ADC_WATER_MARK_INTR_ENABLE);
27462306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* Enable ADC interrupt for a channel */
27762306a36Sopenharmony_ci	val |= (BIT(channel) << IPROC_ADC_INTR);
27862306a36Sopenharmony_ci	regmap_write(adc_priv->regmap, IPROC_INTERRUPT_MASK, val);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/*
28162306a36Sopenharmony_ci	 * There seems to be a very rare issue where writing to this register
28262306a36Sopenharmony_ci	 * does not take effect.  To work around the issue we will try multiple
28362306a36Sopenharmony_ci	 * writes.  In total we will spend about 10*10 = 100 us attempting this.
28462306a36Sopenharmony_ci	 * Testing has shown that this may loop a few time, but we have never
28562306a36Sopenharmony_ci	 * hit the full count.
28662306a36Sopenharmony_ci	 */
28762306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
28862306a36Sopenharmony_ci	while (val_check != val) {
28962306a36Sopenharmony_ci		failed_cnt++;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS)
29262306a36Sopenharmony_ci			break;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		udelay(10);
29562306a36Sopenharmony_ci		regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
29662306a36Sopenharmony_ci				IPROC_ADC_INTR_MASK,
29762306a36Sopenharmony_ci				((0x1 << channel) <<
29862306a36Sopenharmony_ci				IPROC_ADC_INTR));
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (failed_cnt) {
30462306a36Sopenharmony_ci		dev_dbg(&indio_dev->dev,
30562306a36Sopenharmony_ci			"IntMask failed (%d times)", failed_cnt);
30662306a36Sopenharmony_ci		if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS) {
30762306a36Sopenharmony_ci			dev_err(&indio_dev->dev,
30862306a36Sopenharmony_ci				"IntMask set failed. Read will likely fail.");
30962306a36Sopenharmony_ci			read_len = -EIO;
31062306a36Sopenharmony_ci			goto adc_err;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (wait_for_completion_timeout(&adc_priv->completion,
31662306a36Sopenharmony_ci		IPROC_ADC_READ_TIMEOUT) > 0) {
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		/* Only the lower 16 bits are relevant */
31962306a36Sopenharmony_ci		*p_adc_data = adc_priv->chan_val & 0xFFFF;
32062306a36Sopenharmony_ci		read_len = sizeof(*p_adc_data);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	} else {
32362306a36Sopenharmony_ci		/*
32462306a36Sopenharmony_ci		 * We never got the interrupt, something went wrong.
32562306a36Sopenharmony_ci		 * Perhaps the interrupt may still be coming, we do not want
32662306a36Sopenharmony_ci		 * that now.  Lets disable the ADC interrupt, and clear the
32762306a36Sopenharmony_ci		 * status to put it back in to normal state.
32862306a36Sopenharmony_ci		 */
32962306a36Sopenharmony_ci		read_len = -ETIMEDOUT;
33062306a36Sopenharmony_ci		goto adc_err;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	mutex_unlock(&adc_priv->mutex);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return read_len;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciadc_err:
33762306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
33862306a36Sopenharmony_ci			   IPROC_ADC_INTR_MASK,
33962306a36Sopenharmony_ci			   ((0x0 << channel) << IPROC_ADC_INTR));
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
34262306a36Sopenharmony_ci			   IPROC_ADC_INTR_MASK,
34362306a36Sopenharmony_ci			   ((0x0 << channel) << IPROC_ADC_INTR));
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	dev_err(&indio_dev->dev, "Timed out waiting for ADC data!\n");
34662306a36Sopenharmony_ci	iproc_adc_reg_dump(indio_dev);
34762306a36Sopenharmony_ci	mutex_unlock(&adc_priv->mutex);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return read_len;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int iproc_adc_enable(struct iio_dev *indio_dev)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	u32 val;
35562306a36Sopenharmony_ci	u32 channel_id;
35662306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
35762306a36Sopenharmony_ci	int ret;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* Set i_amux = 3b'000, select channel 0 */
36062306a36Sopenharmony_ci	ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
36162306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_SEL_MASK, 0);
36262306a36Sopenharmony_ci	if (ret) {
36362306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
36462306a36Sopenharmony_ci			"failed to write IPROC_ANALOG_CONTROL %d\n", ret);
36562306a36Sopenharmony_ci		return ret;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	adc_priv->chan_val = -1;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/*
37062306a36Sopenharmony_ci	 * PWR up LDO, ADC, and Band Gap (0 to enable)
37162306a36Sopenharmony_ci	 * Also enable ADC controller (set high)
37262306a36Sopenharmony_ci	 */
37362306a36Sopenharmony_ci	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
37462306a36Sopenharmony_ci	if (ret) {
37562306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
37662306a36Sopenharmony_ci			"failed to read IPROC_REGCTL2 %d\n", ret);
37762306a36Sopenharmony_ci		return ret;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	val &= ~(IPROC_ADC_PWR_LDO | IPROC_ADC_PWR_ADC | IPROC_ADC_PWR_BG);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
38362306a36Sopenharmony_ci	if (ret) {
38462306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
38562306a36Sopenharmony_ci			"failed to write IPROC_REGCTL2 %d\n", ret);
38662306a36Sopenharmony_ci		return ret;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
39062306a36Sopenharmony_ci	if (ret) {
39162306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
39262306a36Sopenharmony_ci			"failed to read IPROC_REGCTL2 %d\n", ret);
39362306a36Sopenharmony_ci		return ret;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	val |= IPROC_ADC_CONTROLLER_EN;
39762306a36Sopenharmony_ci	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
39862306a36Sopenharmony_ci	if (ret) {
39962306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
40062306a36Sopenharmony_ci			"failed to write IPROC_REGCTL2 %d\n", ret);
40162306a36Sopenharmony_ci		return ret;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	for (channel_id = 0; channel_id < indio_dev->num_channels;
40562306a36Sopenharmony_ci		channel_id++) {
40662306a36Sopenharmony_ci		ret = regmap_write(adc_priv->regmap,
40762306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_INTERRUPT_MASK +
40862306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
40962306a36Sopenharmony_ci		if (ret) {
41062306a36Sopenharmony_ci			dev_err(&indio_dev->dev,
41162306a36Sopenharmony_ci			    "failed to write ADC_CHANNEL_INTERRUPT_MASK %d\n",
41262306a36Sopenharmony_ci			    ret);
41362306a36Sopenharmony_ci			return ret;
41462306a36Sopenharmony_ci		}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		ret = regmap_write(adc_priv->regmap,
41762306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
41862306a36Sopenharmony_ci				IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
41962306a36Sopenharmony_ci		if (ret) {
42062306a36Sopenharmony_ci			dev_err(&indio_dev->dev,
42162306a36Sopenharmony_ci			    "failed to write ADC_CHANNEL_INTERRUPT_STATUS %d\n",
42262306a36Sopenharmony_ci			    ret);
42362306a36Sopenharmony_ci			return ret;
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void iproc_adc_disable(struct iio_dev *indio_dev)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	u32 val;
43362306a36Sopenharmony_ci	int ret;
43462306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
43762306a36Sopenharmony_ci	if (ret) {
43862306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
43962306a36Sopenharmony_ci			"failed to read IPROC_REGCTL2 %d\n", ret);
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	val &= ~IPROC_ADC_CONTROLLER_EN;
44462306a36Sopenharmony_ci	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
44562306a36Sopenharmony_ci	if (ret) {
44662306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
44762306a36Sopenharmony_ci			"failed to write IPROC_REGCTL2 %d\n", ret);
44862306a36Sopenharmony_ci		return;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic int iproc_adc_read_raw(struct iio_dev *indio_dev,
45362306a36Sopenharmony_ci			  struct iio_chan_spec const *chan,
45462306a36Sopenharmony_ci			  int *val,
45562306a36Sopenharmony_ci			  int *val2,
45662306a36Sopenharmony_ci			  long mask)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	u16 adc_data;
45962306a36Sopenharmony_ci	int err;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	switch (mask) {
46262306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
46362306a36Sopenharmony_ci		err =  iproc_adc_do_read(indio_dev, chan->channel, &adc_data);
46462306a36Sopenharmony_ci		if (err < 0)
46562306a36Sopenharmony_ci			return err;
46662306a36Sopenharmony_ci		*val = adc_data;
46762306a36Sopenharmony_ci		return IIO_VAL_INT;
46862306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
46962306a36Sopenharmony_ci		switch (chan->type) {
47062306a36Sopenharmony_ci		case IIO_VOLTAGE:
47162306a36Sopenharmony_ci			*val = 1800;
47262306a36Sopenharmony_ci			*val2 = 10;
47362306a36Sopenharmony_ci			return IIO_VAL_FRACTIONAL_LOG2;
47462306a36Sopenharmony_ci		default:
47562306a36Sopenharmony_ci			return -EINVAL;
47662306a36Sopenharmony_ci		}
47762306a36Sopenharmony_ci	default:
47862306a36Sopenharmony_ci		return -EINVAL;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic const struct iio_info iproc_adc_iio_info = {
48362306a36Sopenharmony_ci	.read_raw = &iproc_adc_read_raw,
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci#define IPROC_ADC_CHANNEL(_index, _id) {                \
48762306a36Sopenharmony_ci	.type = IIO_VOLTAGE,                            \
48862306a36Sopenharmony_ci	.indexed = 1,                                   \
48962306a36Sopenharmony_ci	.channel = _index,                              \
49062306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
49162306a36Sopenharmony_ci	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
49262306a36Sopenharmony_ci	.datasheet_name = _id,                          \
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic const struct iio_chan_spec iproc_adc_iio_channels[] = {
49662306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(0, "adc0"),
49762306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(1, "adc1"),
49862306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(2, "adc2"),
49962306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(3, "adc3"),
50062306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(4, "adc4"),
50162306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(5, "adc5"),
50262306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(6, "adc6"),
50362306a36Sopenharmony_ci	IPROC_ADC_CHANNEL(7, "adc7"),
50462306a36Sopenharmony_ci};
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int iproc_adc_probe(struct platform_device *pdev)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv;
50962306a36Sopenharmony_ci	struct iio_dev *indio_dev = NULL;
51062306a36Sopenharmony_ci	int ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&pdev->dev,
51362306a36Sopenharmony_ci					sizeof(*adc_priv));
51462306a36Sopenharmony_ci	if (!indio_dev) {
51562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to allocate iio device\n");
51662306a36Sopenharmony_ci		return -ENOMEM;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	adc_priv = iio_priv(indio_dev);
52062306a36Sopenharmony_ci	platform_set_drvdata(pdev, indio_dev);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	mutex_init(&adc_priv->mutex);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	init_completion(&adc_priv->completion);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	adc_priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
52762306a36Sopenharmony_ci			   "adc-syscon");
52862306a36Sopenharmony_ci	if (IS_ERR(adc_priv->regmap)) {
52962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get handle for tsc syscon\n");
53062306a36Sopenharmony_ci		ret = PTR_ERR(adc_priv->regmap);
53162306a36Sopenharmony_ci		return ret;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	adc_priv->adc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
53562306a36Sopenharmony_ci	if (IS_ERR(adc_priv->adc_clk)) {
53662306a36Sopenharmony_ci		dev_err(&pdev->dev,
53762306a36Sopenharmony_ci			"failed getting clock tsc_clk\n");
53862306a36Sopenharmony_ci		ret = PTR_ERR(adc_priv->adc_clk);
53962306a36Sopenharmony_ci		return ret;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	adc_priv->irqno = platform_get_irq(pdev, 0);
54362306a36Sopenharmony_ci	if (adc_priv->irqno < 0)
54462306a36Sopenharmony_ci		return adc_priv->irqno;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
54762306a36Sopenharmony_ci				IPROC_ADC_AUXIN_SCAN_ENA, 0);
54862306a36Sopenharmony_ci	if (ret) {
54962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret);
55062306a36Sopenharmony_ci		return ret;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno,
55462306a36Sopenharmony_ci				iproc_adc_interrupt_handler,
55562306a36Sopenharmony_ci				iproc_adc_interrupt_thread,
55662306a36Sopenharmony_ci				IRQF_SHARED, "iproc-adc", indio_dev);
55762306a36Sopenharmony_ci	if (ret) {
55862306a36Sopenharmony_ci		dev_err(&pdev->dev, "request_irq error %d\n", ret);
55962306a36Sopenharmony_ci		return ret;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ret = clk_prepare_enable(adc_priv->adc_clk);
56362306a36Sopenharmony_ci	if (ret) {
56462306a36Sopenharmony_ci		dev_err(&pdev->dev,
56562306a36Sopenharmony_ci			"clk_prepare_enable failed %d\n", ret);
56662306a36Sopenharmony_ci		return ret;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	ret = iproc_adc_enable(indio_dev);
57062306a36Sopenharmony_ci	if (ret) {
57162306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to enable adc %d\n", ret);
57262306a36Sopenharmony_ci		goto err_adc_enable;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	indio_dev->name = "iproc-static-adc";
57662306a36Sopenharmony_ci	indio_dev->info = &iproc_adc_iio_info;
57762306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
57862306a36Sopenharmony_ci	indio_dev->channels = iproc_adc_iio_channels;
57962306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(iproc_adc_iio_channels);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
58262306a36Sopenharmony_ci	if (ret) {
58362306a36Sopenharmony_ci		dev_err(&pdev->dev, "iio_device_register failed:err %d\n", ret);
58462306a36Sopenharmony_ci		goto err_clk;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	return 0;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cierr_clk:
59062306a36Sopenharmony_ci	iproc_adc_disable(indio_dev);
59162306a36Sopenharmony_cierr_adc_enable:
59262306a36Sopenharmony_ci	clk_disable_unprepare(adc_priv->adc_clk);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return ret;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int iproc_adc_remove(struct platform_device *pdev)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
60062306a36Sopenharmony_ci	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
60362306a36Sopenharmony_ci	iproc_adc_disable(indio_dev);
60462306a36Sopenharmony_ci	clk_disable_unprepare(adc_priv->adc_clk);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic const struct of_device_id iproc_adc_of_match[] = {
61062306a36Sopenharmony_ci	{.compatible = "brcm,iproc-static-adc", },
61162306a36Sopenharmony_ci	{ },
61262306a36Sopenharmony_ci};
61362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, iproc_adc_of_match);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic struct platform_driver iproc_adc_driver = {
61662306a36Sopenharmony_ci	.probe  = iproc_adc_probe,
61762306a36Sopenharmony_ci	.remove	= iproc_adc_remove,
61862306a36Sopenharmony_ci	.driver	= {
61962306a36Sopenharmony_ci		.name	= "iproc-static-adc",
62062306a36Sopenharmony_ci		.of_match_table = iproc_adc_of_match,
62162306a36Sopenharmony_ci	},
62262306a36Sopenharmony_ci};
62362306a36Sopenharmony_cimodule_platform_driver(iproc_adc_driver);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom iProc ADC controller driver");
62662306a36Sopenharmony_ciMODULE_AUTHOR("Raveendra Padasalagi <raveendra.padasalagi@broadcom.com>");
62762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
628