836 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			836 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Freescale MXS LRADC ADC driver
 | |
|  *
 | |
|  * Copyright (c) 2012 DENX Software Engineering, GmbH.
 | |
|  * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
 | |
|  *
 | |
|  * Authors:
 | |
|  *  Marek Vasut <marex@denx.de>
 | |
|  *  Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
 | |
|  */
 | |
| 
 | |
| #include <linux/completion.h>
 | |
| #include <linux/device.h>
 | |
| #include <linux/err.h>
 | |
| #include <linux/interrupt.h>
 | |
| #include <linux/mfd/core.h>
 | |
| #include <linux/mfd/mxs-lradc.h>
 | |
| #include <linux/module.h>
 | |
| #include <linux/of_irq.h>
 | |
| #include <linux/platform_device.h>
 | |
| #include <linux/sysfs.h>
 | |
| 
 | |
| #include <linux/iio/buffer.h>
 | |
| #include <linux/iio/iio.h>
 | |
| #include <linux/iio/trigger.h>
 | |
| #include <linux/iio/trigger_consumer.h>
 | |
| #include <linux/iio/triggered_buffer.h>
 | |
| #include <linux/iio/sysfs.h>
 | |
| 
 | |
| /*
 | |
|  * Make this runtime configurable if necessary. Currently, if the buffered mode
 | |
|  * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before
 | |
|  * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000)
 | |
|  * seconds. The result is that the samples arrive every 500mS.
 | |
|  */
 | |
| #define LRADC_DELAY_TIMER_PER	200
 | |
| #define LRADC_DELAY_TIMER_LOOP	5
 | |
| 
 | |
| #define VREF_MV_BASE 1850
 | |
| 
 | |
| static const char *mx23_lradc_adc_irq_names[] = {
 | |
| 	"mxs-lradc-channel0",
 | |
| 	"mxs-lradc-channel1",
 | |
| 	"mxs-lradc-channel2",
 | |
| 	"mxs-lradc-channel3",
 | |
| 	"mxs-lradc-channel4",
 | |
| 	"mxs-lradc-channel5",
 | |
| };
 | |
| 
 | |
| static const char *mx28_lradc_adc_irq_names[] = {
 | |
| 	"mxs-lradc-thresh0",
 | |
| 	"mxs-lradc-thresh1",
 | |
| 	"mxs-lradc-channel0",
 | |
| 	"mxs-lradc-channel1",
 | |
| 	"mxs-lradc-channel2",
 | |
| 	"mxs-lradc-channel3",
 | |
| 	"mxs-lradc-channel4",
 | |
| 	"mxs-lradc-channel5",
 | |
| 	"mxs-lradc-button0",
 | |
| 	"mxs-lradc-button1",
 | |
| };
 | |
| 
 | |
| static const u32 mxs_lradc_adc_vref_mv[][LRADC_MAX_TOTAL_CHANS] = {
 | |
| 	[IMX23_LRADC] = {
 | |
| 		VREF_MV_BASE,		/* CH0 */
 | |
| 		VREF_MV_BASE,		/* CH1 */
 | |
| 		VREF_MV_BASE,		/* CH2 */
 | |
| 		VREF_MV_BASE,		/* CH3 */
 | |
| 		VREF_MV_BASE,		/* CH4 */
 | |
| 		VREF_MV_BASE,		/* CH5 */
 | |
| 		VREF_MV_BASE * 2,	/* CH6 VDDIO */
 | |
| 		VREF_MV_BASE * 4,	/* CH7 VBATT */
 | |
| 		VREF_MV_BASE,		/* CH8 Temp sense 0 */
 | |
| 		VREF_MV_BASE,		/* CH9 Temp sense 1 */
 | |
| 		VREF_MV_BASE,		/* CH10 */
 | |
| 		VREF_MV_BASE,		/* CH11 */
 | |
| 		VREF_MV_BASE,		/* CH12 USB_DP */
 | |
| 		VREF_MV_BASE,		/* CH13 USB_DN */
 | |
| 		VREF_MV_BASE,		/* CH14 VBG */
 | |
| 		VREF_MV_BASE * 4,	/* CH15 VDD5V */
 | |
| 	},
 | |
| 	[IMX28_LRADC] = {
 | |
| 		VREF_MV_BASE,		/* CH0 */
 | |
| 		VREF_MV_BASE,		/* CH1 */
 | |
| 		VREF_MV_BASE,		/* CH2 */
 | |
| 		VREF_MV_BASE,		/* CH3 */
 | |
| 		VREF_MV_BASE,		/* CH4 */
 | |
| 		VREF_MV_BASE,		/* CH5 */
 | |
| 		VREF_MV_BASE,		/* CH6 */
 | |
| 		VREF_MV_BASE * 4,	/* CH7 VBATT */
 | |
| 		VREF_MV_BASE,		/* CH8 Temp sense 0 */
 | |
| 		VREF_MV_BASE,		/* CH9 Temp sense 1 */
 | |
| 		VREF_MV_BASE * 2,	/* CH10 VDDIO */
 | |
| 		VREF_MV_BASE,		/* CH11 VTH */
 | |
| 		VREF_MV_BASE * 2,	/* CH12 VDDA */
 | |
| 		VREF_MV_BASE,		/* CH13 VDDD */
 | |
| 		VREF_MV_BASE,		/* CH14 VBG */
 | |
| 		VREF_MV_BASE * 4,	/* CH15 VDD5V */
 | |
| 	},
 | |
| };
 | |
| 
 | |
| enum mxs_lradc_divbytwo {
 | |
| 	MXS_LRADC_DIV_DISABLED = 0,
 | |
| 	MXS_LRADC_DIV_ENABLED,
 | |
| };
 | |
| 
 | |
| struct mxs_lradc_scale {
 | |
| 	unsigned int		integer;
 | |
| 	unsigned int		nano;
 | |
| };
 | |
| 
 | |
| struct mxs_lradc_adc {
 | |
| 	struct mxs_lradc	*lradc;
 | |
| 	struct device		*dev;
 | |
| 
 | |
| 	void __iomem		*base;
 | |
| 	/* Maximum of 8 channels + 8 byte ts */
 | |
| 	u32			buffer[10] __aligned(8);
 | |
| 	struct iio_trigger	*trig;
 | |
| 	struct completion	completion;
 | |
| 	spinlock_t		lock;
 | |
| 
 | |
| 	const u32		*vref_mv;
 | |
| 	struct mxs_lradc_scale	scale_avail[LRADC_MAX_TOTAL_CHANS][2];
 | |
| 	unsigned long		is_divided;
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Raw I/O operations */
 | |
| static int mxs_lradc_adc_read_single(struct iio_dev *iio_dev, int chan,
 | |
| 				     int *val)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
 | |
| 	struct mxs_lradc *lradc = adc->lradc;
 | |
| 	int ret;
 | |
| 
 | |
| 	/*
 | |
| 	 * See if there is no buffered operation in progress. If there is simply
 | |
| 	 * bail out. This can be improved to support both buffered and raw IO at
 | |
| 	 * the same time, yet the code becomes horribly complicated. Therefore I
 | |
| 	 * applied KISS principle here.
 | |
| 	 */
 | |
| 	ret = iio_device_claim_direct_mode(iio_dev);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	reinit_completion(&adc->completion);
 | |
| 
 | |
| 	/*
 | |
| 	 * No buffered operation in progress, map the channel and trigger it.
 | |
| 	 * Virtual channel 0 is always used here as the others are always not
 | |
| 	 * used if doing raw sampling.
 | |
| 	 */
 | |
| 	if (lradc->soc == IMX28_LRADC)
 | |
| 		writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
 | |
| 		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
 | |
| 	writel(0x1, adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	/* Enable / disable the divider per requirement */
 | |
| 	if (test_bit(chan, &adc->is_divided))
 | |
| 		writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
 | |
| 		       adc->base + LRADC_CTRL2 + STMP_OFFSET_REG_SET);
 | |
| 	else
 | |
| 		writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
 | |
| 		       adc->base + LRADC_CTRL2 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	/* Clean the slot's previous content, then set new one. */
 | |
| 	writel(LRADC_CTRL4_LRADCSELECT_MASK(0),
 | |
| 	       adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
 | |
| 	writel(chan, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
 | |
| 
 | |
| 	writel(0, adc->base + LRADC_CH(0));
 | |
| 
 | |
| 	/* Enable the IRQ and start sampling the channel. */
 | |
| 	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
 | |
| 	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
 | |
| 	writel(BIT(0), adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
 | |
| 
 | |
| 	/* Wait for completion on the channel, 1 second max. */
 | |
| 	ret = wait_for_completion_killable_timeout(&adc->completion, HZ);
 | |
| 	if (!ret)
 | |
| 		ret = -ETIMEDOUT;
 | |
| 	if (ret < 0)
 | |
| 		goto err;
 | |
| 
 | |
| 	/* Read the data. */
 | |
| 	*val = readl(adc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK;
 | |
| 	ret = IIO_VAL_INT;
 | |
| 
 | |
| err:
 | |
| 	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
 | |
| 	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	iio_device_release_direct_mode(iio_dev);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_read_temp(struct iio_dev *iio_dev, int *val)
 | |
| {
 | |
| 	int ret, min, max;
 | |
| 
 | |
| 	ret = mxs_lradc_adc_read_single(iio_dev, 8, &min);
 | |
| 	if (ret != IIO_VAL_INT)
 | |
| 		return ret;
 | |
| 
 | |
| 	ret = mxs_lradc_adc_read_single(iio_dev, 9, &max);
 | |
| 	if (ret != IIO_VAL_INT)
 | |
| 		return ret;
 | |
| 
 | |
| 	*val = max - min;
 | |
| 
 | |
| 	return IIO_VAL_INT;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_read_raw(struct iio_dev *iio_dev,
 | |
| 			      const struct iio_chan_spec *chan,
 | |
| 			      int *val, int *val2, long m)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
 | |
| 
 | |
| 	switch (m) {
 | |
| 	case IIO_CHAN_INFO_RAW:
 | |
| 		if (chan->type == IIO_TEMP)
 | |
| 			return mxs_lradc_adc_read_temp(iio_dev, val);
 | |
| 
 | |
| 		return mxs_lradc_adc_read_single(iio_dev, chan->channel, val);
 | |
| 
 | |
| 	case IIO_CHAN_INFO_SCALE:
 | |
| 		if (chan->type == IIO_TEMP) {
 | |
| 			/*
 | |
| 			 * From the datasheet, we have to multiply by 1.012 and
 | |
| 			 * divide by 4
 | |
| 			 */
 | |
| 			*val = 0;
 | |
| 			*val2 = 253000;
 | |
| 			return IIO_VAL_INT_PLUS_MICRO;
 | |
| 		}
 | |
| 
 | |
| 		*val = adc->vref_mv[chan->channel];
 | |
| 		*val2 = chan->scan_type.realbits -
 | |
| 			test_bit(chan->channel, &adc->is_divided);
 | |
| 		return IIO_VAL_FRACTIONAL_LOG2;
 | |
| 
 | |
| 	case IIO_CHAN_INFO_OFFSET:
 | |
| 		if (chan->type == IIO_TEMP) {
 | |
| 			/*
 | |
| 			 * The calculated value from the ADC is in Kelvin, we
 | |
| 			 * want Celsius for hwmon so the offset is -273.15
 | |
| 			 * The offset is applied before scaling so it is
 | |
| 			 * actually -213.15 * 4 / 1.012 = -1079.644268
 | |
| 			 */
 | |
| 			*val = -1079;
 | |
| 			*val2 = 644268;
 | |
| 
 | |
| 			return IIO_VAL_INT_PLUS_MICRO;
 | |
| 		}
 | |
| 
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev,
 | |
| 				   const struct iio_chan_spec *chan,
 | |
| 				   int val, int val2, long m)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
 | |
| 	struct mxs_lradc_scale *scale_avail =
 | |
| 			adc->scale_avail[chan->channel];
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = iio_device_claim_direct_mode(iio_dev);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	switch (m) {
 | |
| 	case IIO_CHAN_INFO_SCALE:
 | |
| 		ret = -EINVAL;
 | |
| 		if (val == scale_avail[MXS_LRADC_DIV_DISABLED].integer &&
 | |
| 		    val2 == scale_avail[MXS_LRADC_DIV_DISABLED].nano) {
 | |
| 			/* divider by two disabled */
 | |
| 			clear_bit(chan->channel, &adc->is_divided);
 | |
| 			ret = 0;
 | |
| 		} else if (val == scale_avail[MXS_LRADC_DIV_ENABLED].integer &&
 | |
| 			   val2 == scale_avail[MXS_LRADC_DIV_ENABLED].nano) {
 | |
| 			/* divider by two enabled */
 | |
| 			set_bit(chan->channel, &adc->is_divided);
 | |
| 			ret = 0;
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 	default:
 | |
| 		ret = -EINVAL;
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	iio_device_release_direct_mode(iio_dev);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_write_raw_get_fmt(struct iio_dev *iio_dev,
 | |
| 					   const struct iio_chan_spec *chan,
 | |
| 					   long m)
 | |
| {
 | |
| 	return IIO_VAL_INT_PLUS_NANO;
 | |
| }
 | |
| 
 | |
| static ssize_t mxs_lradc_adc_show_scale_avail(struct device *dev,
 | |
| 						 struct device_attribute *attr,
 | |
| 						 char *buf)
 | |
| {
 | |
| 	struct iio_dev *iio = dev_to_iio_dev(dev);
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
 | |
| 	int i, ch, len = 0;
 | |
| 
 | |
| 	ch = iio_attr->address;
 | |
| 	for (i = 0; i < ARRAY_SIZE(adc->scale_avail[ch]); i++)
 | |
| 		len += sprintf(buf + len, "%u.%09u ",
 | |
| 			       adc->scale_avail[ch][i].integer,
 | |
| 			       adc->scale_avail[ch][i].nano);
 | |
| 
 | |
| 	len += sprintf(buf + len, "\n");
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| #define SHOW_SCALE_AVAILABLE_ATTR(ch)\
 | |
| 	IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, 0444,\
 | |
| 			mxs_lradc_adc_show_scale_avail, NULL, ch)
 | |
| 
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(0);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(1);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(2);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(3);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(4);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(5);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(6);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(7);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(10);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(11);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(12);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(13);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(14);
 | |
| static SHOW_SCALE_AVAILABLE_ATTR(15);
 | |
| 
 | |
| static struct attribute *mxs_lradc_adc_attributes[] = {
 | |
| 	&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage2_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage3_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage4_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage5_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage6_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage7_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage10_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage11_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage12_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage13_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage14_scale_available.dev_attr.attr,
 | |
| 	&iio_dev_attr_in_voltage15_scale_available.dev_attr.attr,
 | |
| 	NULL
 | |
| };
 | |
| 
 | |
| static const struct attribute_group mxs_lradc_adc_attribute_group = {
 | |
| 	.attrs = mxs_lradc_adc_attributes,
 | |
| };
 | |
| 
 | |
| static const struct iio_info mxs_lradc_adc_iio_info = {
 | |
| 	.read_raw		= mxs_lradc_adc_read_raw,
 | |
| 	.write_raw		= mxs_lradc_adc_write_raw,
 | |
| 	.write_raw_get_fmt	= mxs_lradc_adc_write_raw_get_fmt,
 | |
| 	.attrs			= &mxs_lradc_adc_attribute_group,
 | |
| };
 | |
| 
 | |
| /* IRQ Handling */
 | |
| static irqreturn_t mxs_lradc_adc_handle_irq(int irq, void *data)
 | |
| {
 | |
| 	struct iio_dev *iio = data;
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	struct mxs_lradc *lradc = adc->lradc;
 | |
| 	unsigned long reg = readl(adc->base + LRADC_CTRL1);
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	if (!(reg & mxs_lradc_irq_mask(lradc)))
 | |
| 		return IRQ_NONE;
 | |
| 
 | |
| 	if (iio_buffer_enabled(iio)) {
 | |
| 		if (reg & lradc->buffer_vchans) {
 | |
| 			spin_lock_irqsave(&adc->lock, flags);
 | |
| 			iio_trigger_poll(iio->trig);
 | |
| 			spin_unlock_irqrestore(&adc->lock, flags);
 | |
| 		}
 | |
| 	} else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
 | |
| 		complete(&adc->completion);
 | |
| 	}
 | |
| 
 | |
| 	writel(reg & mxs_lradc_irq_mask(lradc),
 | |
| 	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Trigger handling */
 | |
| static irqreturn_t mxs_lradc_adc_trigger_handler(int irq, void *p)
 | |
| {
 | |
| 	struct iio_poll_func *pf = p;
 | |
| 	struct iio_dev *iio = pf->indio_dev;
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	const u32 chan_value = LRADC_CH_ACCUMULATE |
 | |
| 		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
 | |
| 	unsigned int i, j = 0;
 | |
| 
 | |
| 	for_each_set_bit(i, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
 | |
| 		adc->buffer[j] = readl(adc->base + LRADC_CH(j));
 | |
| 		writel(chan_value, adc->base + LRADC_CH(j));
 | |
| 		adc->buffer[j] &= LRADC_CH_VALUE_MASK;
 | |
| 		adc->buffer[j] /= LRADC_DELAY_TIMER_LOOP;
 | |
| 		j++;
 | |
| 	}
 | |
| 
 | |
| 	iio_push_to_buffers_with_timestamp(iio, adc->buffer, pf->timestamp);
 | |
| 
 | |
| 	iio_trigger_notify_done(iio->trig);
 | |
| 
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_configure_trigger(struct iio_trigger *trig, bool state)
 | |
| {
 | |
| 	struct iio_dev *iio = iio_trigger_get_drvdata(trig);
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	const u32 st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
 | |
| 
 | |
| 	writel(LRADC_DELAY_KICK, adc->base + (LRADC_DELAY(0) + st));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct iio_trigger_ops mxs_lradc_adc_trigger_ops = {
 | |
| 	.set_trigger_state = &mxs_lradc_adc_configure_trigger,
 | |
| };
 | |
| 
 | |
| static int mxs_lradc_adc_trigger_init(struct iio_dev *iio)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct iio_trigger *trig;
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 
 | |
| 	trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name,
 | |
| 				      iio_device_id(iio));
 | |
| 	if (!trig)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	trig->dev.parent = adc->dev;
 | |
| 	iio_trigger_set_drvdata(trig, iio);
 | |
| 	trig->ops = &mxs_lradc_adc_trigger_ops;
 | |
| 
 | |
| 	ret = iio_trigger_register(trig);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	adc->trig = trig;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void mxs_lradc_adc_trigger_remove(struct iio_dev *iio)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 
 | |
| 	iio_trigger_unregister(adc->trig);
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_buffer_preenable(struct iio_dev *iio)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	struct mxs_lradc *lradc = adc->lradc;
 | |
| 	int chan, ofs = 0;
 | |
| 	unsigned long enable = 0;
 | |
| 	u32 ctrl4_set = 0;
 | |
| 	u32 ctrl4_clr = 0;
 | |
| 	u32 ctrl1_irq = 0;
 | |
| 	const u32 chan_value = LRADC_CH_ACCUMULATE |
 | |
| 		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
 | |
| 
 | |
| 	if (lradc->soc == IMX28_LRADC)
 | |
| 		writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
 | |
| 		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
 | |
| 	writel(lradc->buffer_vchans,
 | |
| 	       adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
 | |
| 		ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
 | |
| 		ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs);
 | |
| 		ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
 | |
| 		writel(chan_value, adc->base + LRADC_CH(ofs));
 | |
| 		bitmap_set(&enable, ofs, 1);
 | |
| 		ofs++;
 | |
| 	}
 | |
| 
 | |
| 	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
 | |
| 	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
 | |
| 	writel(ctrl4_clr, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
 | |
| 	writel(ctrl4_set, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
 | |
| 	writel(ctrl1_irq, adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
 | |
| 	writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
 | |
| 	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_buffer_postdisable(struct iio_dev *iio)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	struct mxs_lradc *lradc = adc->lradc;
 | |
| 
 | |
| 	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
 | |
| 	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	writel(lradc->buffer_vchans,
 | |
| 	       adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
 | |
| 	if (lradc->soc == IMX28_LRADC)
 | |
| 		writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
 | |
| 		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static bool mxs_lradc_adc_validate_scan_mask(struct iio_dev *iio,
 | |
| 					     const unsigned long *mask)
 | |
| {
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 	struct mxs_lradc *lradc = adc->lradc;
 | |
| 	const int map_chans = bitmap_weight(mask, LRADC_MAX_TOTAL_CHANS);
 | |
| 	int rsvd_chans = 0;
 | |
| 	unsigned long rsvd_mask = 0;
 | |
| 
 | |
| 	if (lradc->use_touchbutton)
 | |
| 		rsvd_mask |= CHAN_MASK_TOUCHBUTTON;
 | |
| 	if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_4WIRE)
 | |
| 		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_4WIRE;
 | |
| 	if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_5WIRE)
 | |
| 		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_5WIRE;
 | |
| 
 | |
| 	if (lradc->use_touchbutton)
 | |
| 		rsvd_chans++;
 | |
| 	if (lradc->touchscreen_wire)
 | |
| 		rsvd_chans += 2;
 | |
| 
 | |
| 	/* Test for attempts to map channels with special mode of operation. */
 | |
| 	if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
 | |
| 		return false;
 | |
| 
 | |
| 	/* Test for attempts to map more channels then available slots. */
 | |
| 	if (map_chans + rsvd_chans > LRADC_MAX_MAPPED_CHANS)
 | |
| 		return false;
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static const struct iio_buffer_setup_ops mxs_lradc_adc_buffer_ops = {
 | |
| 	.preenable = &mxs_lradc_adc_buffer_preenable,
 | |
| 	.postdisable = &mxs_lradc_adc_buffer_postdisable,
 | |
| 	.validate_scan_mask = &mxs_lradc_adc_validate_scan_mask,
 | |
| };
 | |
| 
 | |
| /* Driver initialization */
 | |
| #define MXS_ADC_CHAN(idx, chan_type, name) {			\
 | |
| 	.type = (chan_type),					\
 | |
| 	.indexed = 1,						\
 | |
| 	.scan_index = (idx),					\
 | |
| 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
 | |
| 			      BIT(IIO_CHAN_INFO_SCALE),		\
 | |
| 	.channel = (idx),					\
 | |
| 	.address = (idx),					\
 | |
| 	.scan_type = {						\
 | |
| 		.sign = 'u',					\
 | |
| 		.realbits = LRADC_RESOLUTION,			\
 | |
| 		.storagebits = 32,				\
 | |
| 	},							\
 | |
| 	.datasheet_name = (name),				\
 | |
| }
 | |
| 
 | |
| static const struct iio_chan_spec mx23_lradc_chan_spec[] = {
 | |
| 	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
 | |
| 	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
 | |
| 	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
 | |
| 	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
 | |
| 	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
 | |
| 	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
 | |
| 	MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"),
 | |
| 	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
 | |
| 	/* Combined Temperature sensors */
 | |
| 	{
 | |
| 		.type = IIO_TEMP,
 | |
| 		.indexed = 1,
 | |
| 		.scan_index = 8,
 | |
| 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 | |
| 				      BIT(IIO_CHAN_INFO_OFFSET) |
 | |
| 				      BIT(IIO_CHAN_INFO_SCALE),
 | |
| 		.channel = 8,
 | |
| 		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
 | |
| 		.datasheet_name = "TEMP_DIE",
 | |
| 	},
 | |
| 	/* Hidden channel to keep indexes */
 | |
| 	{
 | |
| 		.type = IIO_TEMP,
 | |
| 		.indexed = 1,
 | |
| 		.scan_index = -1,
 | |
| 		.channel = 9,
 | |
| 	},
 | |
| 	MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL),
 | |
| 	MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL),
 | |
| 	MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"),
 | |
| 	MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"),
 | |
| 	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
 | |
| 	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
 | |
| };
 | |
| 
 | |
| static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
 | |
| 	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
 | |
| 	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
 | |
| 	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
 | |
| 	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
 | |
| 	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
 | |
| 	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
 | |
| 	MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"),
 | |
| 	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
 | |
| 	/* Combined Temperature sensors */
 | |
| 	{
 | |
| 		.type = IIO_TEMP,
 | |
| 		.indexed = 1,
 | |
| 		.scan_index = 8,
 | |
| 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 | |
| 				      BIT(IIO_CHAN_INFO_OFFSET) |
 | |
| 				      BIT(IIO_CHAN_INFO_SCALE),
 | |
| 		.channel = 8,
 | |
| 		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
 | |
| 		.datasheet_name = "TEMP_DIE",
 | |
| 	},
 | |
| 	/* Hidden channel to keep indexes */
 | |
| 	{
 | |
| 		.type = IIO_TEMP,
 | |
| 		.indexed = 1,
 | |
| 		.scan_index = -1,
 | |
| 		.channel = 9,
 | |
| 	},
 | |
| 	MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"),
 | |
| 	MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"),
 | |
| 	MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"),
 | |
| 	MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"),
 | |
| 	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
 | |
| 	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
 | |
| };
 | |
| 
 | |
| static void mxs_lradc_adc_hw_init(struct mxs_lradc_adc *adc)
 | |
| {
 | |
| 	/* The ADC always uses DELAY CHANNEL 0. */
 | |
| 	const u32 adc_cfg =
 | |
| 		(1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
 | |
| 		(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
 | |
| 
 | |
| 	/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
 | |
| 	writel(adc_cfg, adc->base + LRADC_DELAY(0));
 | |
| 
 | |
| 	/*
 | |
| 	 * Start internal temperature sensing by clearing bit
 | |
| 	 * HW_LRADC_CTRL2_TEMPSENSE_PWD. This bit can be left cleared
 | |
| 	 * after power up.
 | |
| 	 */
 | |
| 	writel(0, adc->base + LRADC_CTRL2);
 | |
| }
 | |
| 
 | |
| static void mxs_lradc_adc_hw_stop(struct mxs_lradc_adc *adc)
 | |
| {
 | |
| 	writel(0, adc->base + LRADC_DELAY(0));
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_probe(struct platform_device *pdev)
 | |
| {
 | |
| 	struct device *dev = &pdev->dev;
 | |
| 	struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
 | |
| 	struct mxs_lradc_adc *adc;
 | |
| 	struct iio_dev *iio;
 | |
| 	struct resource *iores;
 | |
| 	int ret, irq, virq, i, s, n;
 | |
| 	u64 scale_uv;
 | |
| 	const char **irq_name;
 | |
| 
 | |
| 	/* Allocate the IIO device. */
 | |
| 	iio = devm_iio_device_alloc(dev, sizeof(*adc));
 | |
| 	if (!iio) {
 | |
| 		dev_err(dev, "Failed to allocate IIO device\n");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	adc = iio_priv(iio);
 | |
| 	adc->lradc = lradc;
 | |
| 	adc->dev = dev;
 | |
| 
 | |
| 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | |
| 	if (!iores)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	adc->base = devm_ioremap(dev, iores->start, resource_size(iores));
 | |
| 	if (!adc->base)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	init_completion(&adc->completion);
 | |
| 	spin_lock_init(&adc->lock);
 | |
| 
 | |
| 	platform_set_drvdata(pdev, iio);
 | |
| 
 | |
| 	iio->name = pdev->name;
 | |
| 	iio->dev.of_node = dev->parent->of_node;
 | |
| 	iio->info = &mxs_lradc_adc_iio_info;
 | |
| 	iio->modes = INDIO_DIRECT_MODE;
 | |
| 	iio->masklength = LRADC_MAX_TOTAL_CHANS;
 | |
| 
 | |
| 	if (lradc->soc == IMX23_LRADC) {
 | |
| 		iio->channels = mx23_lradc_chan_spec;
 | |
| 		iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
 | |
| 		irq_name = mx23_lradc_adc_irq_names;
 | |
| 		n = ARRAY_SIZE(mx23_lradc_adc_irq_names);
 | |
| 	} else {
 | |
| 		iio->channels = mx28_lradc_chan_spec;
 | |
| 		iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
 | |
| 		irq_name = mx28_lradc_adc_irq_names;
 | |
| 		n = ARRAY_SIZE(mx28_lradc_adc_irq_names);
 | |
| 	}
 | |
| 
 | |
| 	ret = stmp_reset_block(adc->base);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	for (i = 0; i < n; i++) {
 | |
| 		irq = platform_get_irq_byname(pdev, irq_name[i]);
 | |
| 		if (irq < 0)
 | |
| 			return irq;
 | |
| 
 | |
| 		virq = irq_of_parse_and_map(dev->parent->of_node, irq);
 | |
| 
 | |
| 		ret = devm_request_irq(dev, virq, mxs_lradc_adc_handle_irq,
 | |
| 				       0, irq_name[i], iio);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = mxs_lradc_adc_trigger_init(iio);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
 | |
| 					 &mxs_lradc_adc_trigger_handler,
 | |
| 					 &mxs_lradc_adc_buffer_ops);
 | |
| 	if (ret)
 | |
| 		goto err_trig;
 | |
| 
 | |
| 	adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc];
 | |
| 
 | |
| 	/* Populate available ADC input ranges */
 | |
| 	for (i = 0; i < LRADC_MAX_TOTAL_CHANS; i++) {
 | |
| 		for (s = 0; s < ARRAY_SIZE(adc->scale_avail[i]); s++) {
 | |
| 			/*
 | |
| 			 * [s=0] = optional divider by two disabled (default)
 | |
| 			 * [s=1] = optional divider by two enabled
 | |
| 			 *
 | |
| 			 * The scale is calculated by doing:
 | |
| 			 *   Vref >> (realbits - s)
 | |
| 			 * which multiplies by two on the second component
 | |
| 			 * of the array.
 | |
| 			 */
 | |
| 			scale_uv = ((u64)adc->vref_mv[i] * 100000000) >>
 | |
| 				   (LRADC_RESOLUTION - s);
 | |
| 			adc->scale_avail[i][s].nano =
 | |
| 					do_div(scale_uv, 100000000) * 10;
 | |
| 			adc->scale_avail[i][s].integer = scale_uv;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Configure the hardware. */
 | |
| 	mxs_lradc_adc_hw_init(adc);
 | |
| 
 | |
| 	/* Register IIO device. */
 | |
| 	ret = iio_device_register(iio);
 | |
| 	if (ret) {
 | |
| 		dev_err(dev, "Failed to register IIO device\n");
 | |
| 		goto err_dev;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| err_dev:
 | |
| 	mxs_lradc_adc_hw_stop(adc);
 | |
| 	iio_triggered_buffer_cleanup(iio);
 | |
| err_trig:
 | |
| 	mxs_lradc_adc_trigger_remove(iio);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static int mxs_lradc_adc_remove(struct platform_device *pdev)
 | |
| {
 | |
| 	struct iio_dev *iio = platform_get_drvdata(pdev);
 | |
| 	struct mxs_lradc_adc *adc = iio_priv(iio);
 | |
| 
 | |
| 	iio_device_unregister(iio);
 | |
| 	mxs_lradc_adc_hw_stop(adc);
 | |
| 	iio_triggered_buffer_cleanup(iio);
 | |
| 	mxs_lradc_adc_trigger_remove(iio);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct platform_driver mxs_lradc_adc_driver = {
 | |
| 	.driver = {
 | |
| 		.name	= "mxs-lradc-adc",
 | |
| 	},
 | |
| 	.probe	= mxs_lradc_adc_probe,
 | |
| 	.remove = mxs_lradc_adc_remove,
 | |
| };
 | |
| module_platform_driver(mxs_lradc_adc_driver);
 | |
| 
 | |
| MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
 | |
| MODULE_DESCRIPTION("Freescale MXS LRADC driver general purpose ADC driver");
 | |
| MODULE_LICENSE("GPL");
 | |
| MODULE_ALIAS("platform:mxs-lradc-adc");
 |