162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ST SPEAr ADC driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012 Stefan Roese <sr@denx.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/completion.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/of_address.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/iio/iio.h>
2262306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* SPEAR registers definitions */
2562306a36Sopenharmony_ci#define SPEAR600_ADC_SCAN_RATE_LO(x)	((x) & 0xFFFF)
2662306a36Sopenharmony_ci#define SPEAR600_ADC_SCAN_RATE_HI(x)	(((x) >> 0x10) & 0xFFFF)
2762306a36Sopenharmony_ci#define SPEAR_ADC_CLK_LOW(x)		(((x) & 0xf) << 0)
2862306a36Sopenharmony_ci#define SPEAR_ADC_CLK_HIGH(x)		(((x) & 0xf) << 4)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Bit definitions for SPEAR_ADC_STATUS */
3162306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_START_CONVERSION	BIT(0)
3262306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_CHANNEL_NUM(x)		((x) << 1)
3362306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_ADC_ENABLE		BIT(4)
3462306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_AVG_SAMPLE(x)		((x) << 5)
3562306a36Sopenharmony_ci#define SPEAR_ADC_STATUS_VREF_INTERNAL		BIT(9)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define SPEAR_ADC_DATA_MASK		0x03ff
3862306a36Sopenharmony_ci#define SPEAR_ADC_DATA_BITS		10
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define SPEAR_ADC_MOD_NAME "spear-adc"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define SPEAR_ADC_CHANNEL_NUM		8
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SPEAR_ADC_CLK_MIN			2500000
4562306a36Sopenharmony_ci#define SPEAR_ADC_CLK_MAX			20000000
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct adc_regs_spear3xx {
4862306a36Sopenharmony_ci	u32 status;
4962306a36Sopenharmony_ci	u32 average;
5062306a36Sopenharmony_ci	u32 scan_rate;
5162306a36Sopenharmony_ci	u32 clk;	/* Not avail for 1340 & 1310 */
5262306a36Sopenharmony_ci	u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
5362306a36Sopenharmony_ci	u32 ch_data[SPEAR_ADC_CHANNEL_NUM];
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct chan_data {
5762306a36Sopenharmony_ci	u32 lsb;
5862306a36Sopenharmony_ci	u32 msb;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct adc_regs_spear6xx {
6262306a36Sopenharmony_ci	u32 status;
6362306a36Sopenharmony_ci	u32 pad[2];
6462306a36Sopenharmony_ci	u32 clk;
6562306a36Sopenharmony_ci	u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM];
6662306a36Sopenharmony_ci	struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM];
6762306a36Sopenharmony_ci	u32 scan_rate_lo;
6862306a36Sopenharmony_ci	u32 scan_rate_hi;
6962306a36Sopenharmony_ci	struct chan_data average;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct spear_adc_state {
7362306a36Sopenharmony_ci	struct device_node *np;
7462306a36Sopenharmony_ci	struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
7562306a36Sopenharmony_ci	struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
7662306a36Sopenharmony_ci	struct clk *clk;
7762306a36Sopenharmony_ci	struct completion completion;
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * Lock to protect the device state during a potential concurrent
8062306a36Sopenharmony_ci	 * read access from userspace. Reading a raw value requires a sequence
8162306a36Sopenharmony_ci	 * of register writes, then a wait for a completion callback,
8262306a36Sopenharmony_ci	 * and finally a register read, during which userspace could issue
8362306a36Sopenharmony_ci	 * another read request. This lock protects a read access from
8462306a36Sopenharmony_ci	 * ocurring before another one has finished.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	struct mutex lock;
8762306a36Sopenharmony_ci	u32 current_clk;
8862306a36Sopenharmony_ci	u32 sampling_freq;
8962306a36Sopenharmony_ci	u32 avg_samples;
9062306a36Sopenharmony_ci	u32 vref_external;
9162306a36Sopenharmony_ci	u32 value;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * Functions to access some SPEAr ADC register. Abstracted into
9662306a36Sopenharmony_ci * static inline functions, because of different register offsets
9762306a36Sopenharmony_ci * on different SoC variants (SPEAr300 vs SPEAr600 etc).
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistatic void spear_adc_set_status(struct spear_adc_state *st, u32 val)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	__raw_writel(val, &st->adc_base_spear6xx->status);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void spear_adc_set_clk(struct spear_adc_state *st, u32 val)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	u32 clk_high, clk_low, count;
10762306a36Sopenharmony_ci	u32 apb_clk = clk_get_rate(st->clk);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	count = DIV_ROUND_UP(apb_clk, val);
11062306a36Sopenharmony_ci	clk_low = count / 2;
11162306a36Sopenharmony_ci	clk_high = count - clk_low;
11262306a36Sopenharmony_ci	st->current_clk = apb_clk / count;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	__raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high),
11562306a36Sopenharmony_ci		     &st->adc_base_spear6xx->clk);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void spear_adc_set_ctrl(struct spear_adc_state *st, int n,
11962306a36Sopenharmony_ci			       u32 val)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	__raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic u32 spear_adc_get_average(struct spear_adc_state *st)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	if (of_device_is_compatible(st->np, "st,spear600-adc")) {
12762306a36Sopenharmony_ci		return __raw_readl(&st->adc_base_spear6xx->average.msb) &
12862306a36Sopenharmony_ci			SPEAR_ADC_DATA_MASK;
12962306a36Sopenharmony_ci	} else {
13062306a36Sopenharmony_ci		return __raw_readl(&st->adc_base_spear3xx->average) &
13162306a36Sopenharmony_ci			SPEAR_ADC_DATA_MASK;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	if (of_device_is_compatible(st->np, "st,spear600-adc")) {
13862306a36Sopenharmony_ci		__raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate),
13962306a36Sopenharmony_ci			     &st->adc_base_spear6xx->scan_rate_lo);
14062306a36Sopenharmony_ci		__raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate),
14162306a36Sopenharmony_ci			     &st->adc_base_spear6xx->scan_rate_hi);
14262306a36Sopenharmony_ci	} else {
14362306a36Sopenharmony_ci		__raw_writel(rate, &st->adc_base_spear3xx->scan_rate);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int spear_adc_read_raw(struct iio_dev *indio_dev,
14862306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
14962306a36Sopenharmony_ci			      int *val,
15062306a36Sopenharmony_ci			      int *val2,
15162306a36Sopenharmony_ci			      long mask)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct spear_adc_state *st = iio_priv(indio_dev);
15462306a36Sopenharmony_ci	u32 status;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch (mask) {
15762306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
15862306a36Sopenharmony_ci		mutex_lock(&st->lock);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) |
16162306a36Sopenharmony_ci			SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) |
16262306a36Sopenharmony_ci			SPEAR_ADC_STATUS_START_CONVERSION |
16362306a36Sopenharmony_ci			SPEAR_ADC_STATUS_ADC_ENABLE;
16462306a36Sopenharmony_ci		if (st->vref_external == 0)
16562306a36Sopenharmony_ci			status |= SPEAR_ADC_STATUS_VREF_INTERNAL;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		spear_adc_set_status(st, status);
16862306a36Sopenharmony_ci		wait_for_completion(&st->completion); /* set by ISR */
16962306a36Sopenharmony_ci		*val = st->value;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		mutex_unlock(&st->lock);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		return IIO_VAL_INT;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
17662306a36Sopenharmony_ci		*val = st->vref_external;
17762306a36Sopenharmony_ci		*val2 = SPEAR_ADC_DATA_BITS;
17862306a36Sopenharmony_ci		return IIO_VAL_FRACTIONAL_LOG2;
17962306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
18062306a36Sopenharmony_ci		*val = st->current_clk;
18162306a36Sopenharmony_ci		return IIO_VAL_INT;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return -EINVAL;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int spear_adc_write_raw(struct iio_dev *indio_dev,
18862306a36Sopenharmony_ci			       struct iio_chan_spec const *chan,
18962306a36Sopenharmony_ci			       int val,
19062306a36Sopenharmony_ci			       int val2,
19162306a36Sopenharmony_ci			       long mask)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct spear_adc_state *st = iio_priv(indio_dev);
19462306a36Sopenharmony_ci	int ret = 0;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
19762306a36Sopenharmony_ci		return -EINVAL;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	mutex_lock(&st->lock);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if ((val < SPEAR_ADC_CLK_MIN) ||
20262306a36Sopenharmony_ci	    (val > SPEAR_ADC_CLK_MAX) ||
20362306a36Sopenharmony_ci	    (val2 != 0)) {
20462306a36Sopenharmony_ci		ret = -EINVAL;
20562306a36Sopenharmony_ci		goto out;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	spear_adc_set_clk(st, val);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciout:
21162306a36Sopenharmony_ci	mutex_unlock(&st->lock);
21262306a36Sopenharmony_ci	return ret;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define SPEAR_ADC_CHAN(idx) {				\
21662306a36Sopenharmony_ci	.type = IIO_VOLTAGE,				\
21762306a36Sopenharmony_ci	.indexed = 1,					\
21862306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
21962306a36Sopenharmony_ci	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
22062306a36Sopenharmony_ci	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
22162306a36Sopenharmony_ci	.channel = idx,					\
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic const struct iio_chan_spec spear_adc_iio_channels[] = {
22562306a36Sopenharmony_ci	SPEAR_ADC_CHAN(0),
22662306a36Sopenharmony_ci	SPEAR_ADC_CHAN(1),
22762306a36Sopenharmony_ci	SPEAR_ADC_CHAN(2),
22862306a36Sopenharmony_ci	SPEAR_ADC_CHAN(3),
22962306a36Sopenharmony_ci	SPEAR_ADC_CHAN(4),
23062306a36Sopenharmony_ci	SPEAR_ADC_CHAN(5),
23162306a36Sopenharmony_ci	SPEAR_ADC_CHAN(6),
23262306a36Sopenharmony_ci	SPEAR_ADC_CHAN(7),
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic irqreturn_t spear_adc_isr(int irq, void *dev_id)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct spear_adc_state *st = dev_id;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Read value to clear IRQ */
24062306a36Sopenharmony_ci	st->value = spear_adc_get_average(st);
24162306a36Sopenharmony_ci	complete(&st->completion);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return IRQ_HANDLED;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic int spear_adc_configure(struct spear_adc_state *st)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	int i;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Reset ADC core */
25162306a36Sopenharmony_ci	spear_adc_set_status(st, 0);
25262306a36Sopenharmony_ci	__raw_writel(0, &st->adc_base_spear6xx->clk);
25362306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
25462306a36Sopenharmony_ci		spear_adc_set_ctrl(st, i, 0);
25562306a36Sopenharmony_ci	spear_adc_set_scanrate(st, 0);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	spear_adc_set_clk(st, st->sampling_freq);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return 0;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic const struct iio_info spear_adc_info = {
26362306a36Sopenharmony_ci	.read_raw = &spear_adc_read_raw,
26462306a36Sopenharmony_ci	.write_raw = &spear_adc_write_raw,
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int spear_adc_probe(struct platform_device *pdev)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
27062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
27162306a36Sopenharmony_ci	struct spear_adc_state *st;
27262306a36Sopenharmony_ci	struct iio_dev *indio_dev = NULL;
27362306a36Sopenharmony_ci	int ret = -ENODEV;
27462306a36Sopenharmony_ci	int irq;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state));
27762306a36Sopenharmony_ci	if (!indio_dev) {
27862306a36Sopenharmony_ci		dev_err(dev, "failed allocating iio device\n");
27962306a36Sopenharmony_ci		return -ENOMEM;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	st = iio_priv(indio_dev);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	mutex_init(&st->lock);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	st->np = np;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * SPEAr600 has a different register layout than other SPEAr SoC's
29062306a36Sopenharmony_ci	 * (e.g. SPEAr3xx). Let's provide two register base addresses
29162306a36Sopenharmony_ci	 * to support multi-arch kernels.
29262306a36Sopenharmony_ci	 */
29362306a36Sopenharmony_ci	st->adc_base_spear6xx = devm_platform_ioremap_resource(pdev, 0);
29462306a36Sopenharmony_ci	if (IS_ERR(st->adc_base_spear6xx))
29562306a36Sopenharmony_ci		return PTR_ERR(st->adc_base_spear6xx);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	st->adc_base_spear3xx =
29862306a36Sopenharmony_ci		(struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	st->clk = devm_clk_get(dev, NULL);
30162306a36Sopenharmony_ci	if (IS_ERR(st->clk)) {
30262306a36Sopenharmony_ci		dev_err(dev, "failed getting clock\n");
30362306a36Sopenharmony_ci		return PTR_ERR(st->clk);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	ret = clk_prepare_enable(st->clk);
30762306a36Sopenharmony_ci	if (ret) {
30862306a36Sopenharmony_ci		dev_err(dev, "failed enabling clock\n");
30962306a36Sopenharmony_ci		return ret;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
31362306a36Sopenharmony_ci	if (irq < 0) {
31462306a36Sopenharmony_ci		ret = irq;
31562306a36Sopenharmony_ci		goto errout2;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME,
31962306a36Sopenharmony_ci			       st);
32062306a36Sopenharmony_ci	if (ret < 0) {
32162306a36Sopenharmony_ci		dev_err(dev, "failed requesting interrupt\n");
32262306a36Sopenharmony_ci		goto errout2;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (of_property_read_u32(np, "sampling-frequency",
32662306a36Sopenharmony_ci				 &st->sampling_freq)) {
32762306a36Sopenharmony_ci		dev_err(dev, "sampling-frequency missing in DT\n");
32862306a36Sopenharmony_ci		ret = -EINVAL;
32962306a36Sopenharmony_ci		goto errout2;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/*
33362306a36Sopenharmony_ci	 * Optional avg_samples defaults to 0, resulting in single data
33462306a36Sopenharmony_ci	 * conversion
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	of_property_read_u32(np, "average-samples", &st->avg_samples);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/*
33962306a36Sopenharmony_ci	 * Optional vref_external defaults to 0, resulting in internal vref
34062306a36Sopenharmony_ci	 * selection
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	of_property_read_u32(np, "vref-external", &st->vref_external);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	spear_adc_configure(st);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	platform_set_drvdata(pdev, indio_dev);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	init_completion(&st->completion);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	indio_dev->name = SPEAR_ADC_MOD_NAME;
35162306a36Sopenharmony_ci	indio_dev->info = &spear_adc_info;
35262306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
35362306a36Sopenharmony_ci	indio_dev->channels = spear_adc_iio_channels;
35462306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ret = iio_device_register(indio_dev);
35762306a36Sopenharmony_ci	if (ret)
35862306a36Sopenharmony_ci		goto errout2;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return 0;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cierrout2:
36562306a36Sopenharmony_ci	clk_disable_unprepare(st->clk);
36662306a36Sopenharmony_ci	return ret;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic int spear_adc_remove(struct platform_device *pdev)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
37262306a36Sopenharmony_ci	struct spear_adc_state *st = iio_priv(indio_dev);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	iio_device_unregister(indio_dev);
37562306a36Sopenharmony_ci	clk_disable_unprepare(st->clk);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci#ifdef CONFIG_OF
38162306a36Sopenharmony_cistatic const struct of_device_id spear_adc_dt_ids[] = {
38262306a36Sopenharmony_ci	{ .compatible = "st,spear600-adc", },
38362306a36Sopenharmony_ci	{ /* sentinel */ }
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
38662306a36Sopenharmony_ci#endif
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic struct platform_driver spear_adc_driver = {
38962306a36Sopenharmony_ci	.probe		= spear_adc_probe,
39062306a36Sopenharmony_ci	.remove		= spear_adc_remove,
39162306a36Sopenharmony_ci	.driver		= {
39262306a36Sopenharmony_ci		.name	= SPEAR_ADC_MOD_NAME,
39362306a36Sopenharmony_ci		.of_match_table = of_match_ptr(spear_adc_dt_ids),
39462306a36Sopenharmony_ci	},
39562306a36Sopenharmony_ci};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cimodule_platform_driver(spear_adc_driver);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Roese <sr@denx.de>");
40062306a36Sopenharmony_ciMODULE_DESCRIPTION("SPEAr ADC driver");
40162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
402