diff options
Diffstat (limited to 'drivers/iio/adc')
28 files changed, 15494 insertions, 0 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig new file mode 100644 index 00000000000..a80d23628f1 --- /dev/null +++ b/drivers/iio/adc/Kconfig @@ -0,0 +1,263 @@ +# +# ADC drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Analog to digital converters" + +config AD_SIGMA_DELTA +	tristate +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER + +config AD7266 +	tristate "Analog Devices AD7265/AD7266 ADC driver" +	depends on SPI_MASTER +	select IIO_BUFFER +	select IIO_TRIGGER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices AD7265 and AD7266 +	  ADCs. + +config AD7298 +	tristate "Analog Devices AD7298 ADC driver" +	depends on SPI +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices AD7298 +	  8 Channel ADC with temperature sensor. + +	  To compile this driver as a module, choose M here: the +	  module will be called ad7298. + +config AD7476 +	tristate "Analog Devices AD7476 and similar 1-channel ADCs driver" +	depends on SPI +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices AD7273, AD7274, AD7276, +	  AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, +	  AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC). + +	  If unsure, say N (but it's safe to say "Y"). + +	  To compile this driver as a module, choose M here: the +	  module will be called ad7476. + +config AD7791 +	tristate "Analog Devices AD7791 ADC driver" +	depends on SPI +	select AD_SIGMA_DELTA +	help +	  Say yes here to build support for Analog Devices AD7787, AD7788, AD7789, +	  AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say +	  N (but it is safe to say "Y"). + +	  To compile this driver as a module, choose M here: the module will be +	  called ad7791. + +config AD7793 +	tristate "Analog Devices AD7793 and similar ADCs driver" +	depends on SPI +	select AD_SIGMA_DELTA +	help +	  Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, +	  AD7794 and AD7795 SPI analog to digital converters (ADC). +	  If unsure, say N (but it's safe to say "Y"). + +	  To compile this driver as a module, choose M here: the +	  module will be called AD7793. + +config AD7887 +	tristate "Analog Devices AD7887 ADC driver" +	depends on SPI +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices +	  AD7887 SPI analog to digital converter (ADC). +	  If unsure, say N (but it's safe to say "Y"). + +	  To compile this driver as a module, choose M here: the +	  module will be called ad7887. + +config AD7923 +	tristate "Analog Devices AD7923 and similar ADCs driver" +	depends on SPI +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices +	  AD7904, AD7914, AD7923, AD7924 4 Channel ADCs. + +	  To compile this driver as a module, choose M here: the +	  module will be called ad7923. + +config AD799X +	tristate "Analog Devices AD799x ADC driver" +	depends on I2C +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for Analog Devices: +	  ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 +	  i2c analog to digital converters (ADC). Provides direct access +	  via sysfs. + +config AT91_ADC +	tristate "Atmel AT91 ADC" +	depends on ARCH_AT91 +	depends on INPUT +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	select SYSFS +	help +	  Say yes here to build support for Atmel AT91 ADC. + +config EXYNOS_ADC +	tristate "Exynos ADC driver support" +	depends on ARCH_EXYNOS || (OF && COMPILE_TEST) +	help +	  Core support for the ADC block found in the Samsung EXYNOS series +	  of SoCs for drivers such as the touchscreen and hwmon to use to share +	  this resource. + +config LP8788_ADC +	tristate "LP8788 ADC driver" +	depends on MFD_LP8788 +	help +	  Say yes here to build support for TI LP8788 ADC. + +config MAX1363 +	tristate "Maxim max1363 ADC driver" +	depends on I2C +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for many Maxim i2c analog to digital +	  converters (ADC). (max1361, max1362, max1363, max1364, max1036, +	  max1037, max1038, max1039, max1136, max1136, max1137, max1138, +	  max1139, max1236, max1237, max11238, max1239, max11600, max11601, +	  max11602, max11603, max11604, max11605, max11606, max11607, +	  max11608, max11609, max11610, max11611, max11612, max11613, +	  max11614, max11615, max11616, max11617, max11644, max11645, +	  max11646, max11647) Provides direct access via sysfs and buffered +	  data via the iio dev interface. + +config MCP320X +	tristate "Microchip Technology MCP3204/08" +	depends on SPI +	help +	  Say yes here to build support for Microchip Technology's MCP3204 or +	  MCP3208 analog to digital converter. + +	  This driver can also be built as a module. If so, the module will be +	  called mcp320x. + +config MCP3422 +	tristate "Microchip Technology MCP3422/3/4/6/7/8 driver" +	depends on I2C +	help +	  Say yes here to build support for Microchip Technology's +	  MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428 +	  analog to digital converters. + +	  This driver can also be built as a module. If so, the module will be +	  called mcp3422. + +config MEN_Z188_ADC +	tristate "MEN 16z188 ADC IP Core support" +	depends on MCB +	help +	  Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB +	  carrier. + +	  This driver can also be built as a module. If so, the module will be +	  called men_z188_adc. + +config NAU7802 +	tristate "Nuvoton NAU7802 ADC driver" +	depends on I2C +	help +	  Say yes here to build support for Nuvoton NAU7802 ADC. + +	  To compile this driver as a module, choose M here: the +	  module will be called nau7802. + +config TI_ADC081C +	tristate "Texas Instruments ADC081C021/027" +	depends on I2C +	help +	  If you say yes here you get support for Texas Instruments ADC081C021 +	  and ADC081C027 ADC chips. + +	  This driver can also be built as a module. If so, the module will be +	  called ti-adc081c. + +config TI_AM335X_ADC +	tristate "TI's AM335X ADC driver" +	depends on MFD_TI_AM335X_TSCADC +	select IIO_BUFFER +	select IIO_KFIFO_BUF +	help +	  Say yes here to build support for Texas Instruments ADC +	  driver which is also a MFD client. + +config TWL4030_MADC +	tristate "TWL4030 MADC (Monitoring A/D Converter)" +	depends on TWL4030_CORE +	help +	This driver provides support for Triton TWL4030-MADC. The +	driver supports both RT and SW conversion methods. + +	This driver can also be built as a module. If so, the module will be +	called twl4030-madc. + +config TWL6030_GPADC +	tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" +	depends on TWL4030_CORE +	default n +	help +	  Say yes here if you want support for the TWL6030/TWL6032 General +	  Purpose A/D Converter. This will add support for battery type +	  detection, battery voltage and temperature measurement, die +	  temperature measurement, system supply voltage, audio accessory, +	  USB ID detection. + +	  This driver can also be built as a module. If so, the module will be +	  called twl6030-gpadc. + +config VF610_ADC +	tristate "Freescale vf610 ADC driver" +	depends on OF +	help +	  Say yes here to support for Vybrid board analog-to-digital converter. +	  Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. + +	  This driver can also be built as a module. If so, the module will be +	  called vf610_adc. + +config VIPERBOARD_ADC +	tristate "Viperboard ADC support" +	depends on MFD_VIPERBOARD && USB +	help +	  Say yes here to access the ADC part of the Nano River +	  Technologies Viperboard. + +config XILINX_XADC +	tristate "Xilinx XADC driver" +	depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST +	depends on HAS_IOMEM +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to have support for the Xilinx XADC. The driver does support +	  both the ZYNQ interface to the XADC as well as the AXI-XADC interface. + +	  The driver can also be build as a module. If so, the module will be called +	  xilinx-xadc. + +endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile new file mode 100644 index 00000000000..9d60f2deaaa --- /dev/null +++ b/drivers/iio/adc/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for IIO ADC drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o +obj-$(CONFIG_AD7266) += ad7266.o +obj-$(CONFIG_AD7298) += ad7298.o +obj-$(CONFIG_AD7923) += ad7923.o +obj-$(CONFIG_AD7476) += ad7476.o +obj-$(CONFIG_AD7791) += ad7791.o +obj-$(CONFIG_AD7793) += ad7793.o +obj-$(CONFIG_AD7887) += ad7887.o +obj-$(CONFIG_AD799X) += ad799x.o +obj-$(CONFIG_AT91_ADC) += at91_adc.o +obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o +obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o +obj-$(CONFIG_MAX1363) += max1363.o +obj-$(CONFIG_MCP320X) += mcp320x.o +obj-$(CONFIG_MCP3422) += mcp3422.o +obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o +obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o +obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o +obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o +obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o +obj-$(CONFIG_VF610_ADC) += vf610_adc.o +obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o +xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o +obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c new file mode 100644 index 00000000000..70f78c3062a --- /dev/null +++ b/drivers/iio/adc/ad7266.c @@ -0,0 +1,522 @@ +/* + * AD7266/65 SPI ADC driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/module.h> + +#include <linux/interrupt.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/platform_data/ad7266.h> + +struct ad7266_state { +	struct spi_device	*spi; +	struct regulator	*reg; +	unsigned long		vref_mv; + +	struct spi_transfer	single_xfer[3]; +	struct spi_message	single_msg; + +	enum ad7266_range	range; +	enum ad7266_mode	mode; +	bool			fixed_addr; +	struct gpio		gpios[3]; + +	/* +	 * DMA (thus cache coherency maintenance) requires the +	 * transfer buffers to live in their own cache lines. +	 * The buffer needs to be large enough to hold two samples (4 bytes) and +	 * the naturally aligned timestamp (8 bytes). +	 */ +	struct { +		__be16 sample[2]; +		s64 timestamp; +	} data ____cacheline_aligned; +}; + +static int ad7266_wakeup(struct ad7266_state *st) +{ +	/* Any read with >= 2 bytes will wake the device */ +	return spi_read(st->spi, &st->data.sample[0], 2); +} + +static int ad7266_powerdown(struct ad7266_state *st) +{ +	/* Any read with < 2 bytes will powerdown the device */ +	return spi_read(st->spi, &st->data.sample[0], 1); +} + +static int ad7266_preenable(struct iio_dev *indio_dev) +{ +	struct ad7266_state *st = iio_priv(indio_dev); +	return ad7266_wakeup(st); +} + +static int ad7266_postdisable(struct iio_dev *indio_dev) +{ +	struct ad7266_state *st = iio_priv(indio_dev); +	return ad7266_powerdown(st); +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { +	.preenable = &ad7266_preenable, +	.postenable = &iio_triggered_buffer_postenable, +	.predisable = &iio_triggered_buffer_predisable, +	.postdisable = &ad7266_postdisable, +}; + +static irqreturn_t ad7266_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad7266_state *st = iio_priv(indio_dev); +	int ret; + +	ret = spi_read(st->spi, st->data.sample, 4); +	if (ret == 0) { +		iio_push_to_buffers_with_timestamp(indio_dev, &st->data, +			    pf->timestamp); +	} + +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static void ad7266_select_input(struct ad7266_state *st, unsigned int nr) +{ +	unsigned int i; + +	if (st->fixed_addr) +		return; + +	switch (st->mode) { +	case AD7266_MODE_SINGLE_ENDED: +		nr >>= 1; +		break; +	case AD7266_MODE_PSEUDO_DIFF: +		nr |= 1; +		break; +	case AD7266_MODE_DIFF: +		nr &= ~1; +		break; +	} + +	for (i = 0; i < 3; ++i) +		gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i))); +} + +static int ad7266_update_scan_mode(struct iio_dev *indio_dev, +	const unsigned long *scan_mask) +{ +	struct ad7266_state *st = iio_priv(indio_dev); +	unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength); + +	ad7266_select_input(st, nr); + +	return 0; +} + +static int ad7266_read_single(struct ad7266_state *st, int *val, +	unsigned int address) +{ +	int ret; + +	ad7266_select_input(st, address); + +	ret = spi_sync(st->spi, &st->single_msg); +	*val = be16_to_cpu(st->data.sample[address % 2]); + +	return ret; +} + +static int ad7266_read_raw(struct iio_dev *indio_dev, +	struct iio_chan_spec const *chan, int *val, int *val2, long m) +{ +	struct ad7266_state *st = iio_priv(indio_dev); +	unsigned long scale_mv; +	int ret; + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		if (iio_buffer_enabled(indio_dev)) +			return -EBUSY; + +		ret = ad7266_read_single(st, val, chan->address); +		if (ret) +			return ret; + +		*val = (*val >> 2) & 0xfff; +		if (chan->scan_type.sign == 's') +			*val = sign_extend32(*val, 11); + +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		scale_mv = st->vref_mv; +		if (st->mode == AD7266_MODE_DIFF) +			scale_mv *= 2; +		if (st->range == AD7266_RANGE_2VREF) +			scale_mv *= 2; + +		*val = scale_mv; +		*val2 = chan->scan_type.realbits; +		return IIO_VAL_FRACTIONAL_LOG2; +	case IIO_CHAN_INFO_OFFSET: +		if (st->range == AD7266_RANGE_2VREF && +			st->mode != AD7266_MODE_DIFF) +			*val = 2048; +		else +			*val = 0; +		return IIO_VAL_INT; +	} +	return -EINVAL; +} + +#define AD7266_CHAN(_chan, _sign) {			\ +	.type = IIO_VOLTAGE,				\ +	.indexed = 1,					\ +	.channel = (_chan),				\ +	.address = (_chan),				\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ +		| BIT(IIO_CHAN_INFO_OFFSET),			\ +	.scan_index = (_chan),				\ +	.scan_type = {					\ +		.sign = (_sign),			\ +		.realbits = 12,				\ +		.storagebits = 16,			\ +		.shift = 2,				\ +		.endianness = IIO_BE,			\ +	},						\ +} + +#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_##_name[] = { \ +	AD7266_CHAN(0, (_sign)), \ +	AD7266_CHAN(1, (_sign)), \ +	AD7266_CHAN(2, (_sign)), \ +	AD7266_CHAN(3, (_sign)), \ +	AD7266_CHAN(4, (_sign)), \ +	AD7266_CHAN(5, (_sign)), \ +	AD7266_CHAN(6, (_sign)), \ +	AD7266_CHAN(7, (_sign)), \ +	AD7266_CHAN(8, (_sign)), \ +	AD7266_CHAN(9, (_sign)), \ +	AD7266_CHAN(10, (_sign)), \ +	AD7266_CHAN(11, (_sign)), \ +	IIO_CHAN_SOFT_TIMESTAMP(13), \ +} + +#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_##_name##_fixed[] = { \ +	AD7266_CHAN(0, (_sign)), \ +	AD7266_CHAN(1, (_sign)), \ +	IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(u, 'u'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(s, 's'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(u, 'u'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's'); + +#define AD7266_CHAN_DIFF(_chan, _sign) {			\ +	.type = IIO_VOLTAGE,				\ +	.indexed = 1,					\ +	.channel = (_chan) * 2,				\ +	.channel2 = (_chan) * 2 + 1,			\ +	.address = (_chan),				\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)	\ +		| BIT(IIO_CHAN_INFO_OFFSET),			\ +	.scan_index = (_chan),				\ +	.scan_type = {					\ +		.sign = _sign,			\ +		.realbits = 12,				\ +		.storagebits = 16,			\ +		.shift = 2,				\ +		.endianness = IIO_BE,			\ +	},						\ +	.differential = 1,				\ +} + +#define AD7266_DECLARE_DIFF_CHANNELS(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_diff_##_name[] = { \ +	AD7266_CHAN_DIFF(0, (_sign)), \ +	AD7266_CHAN_DIFF(1, (_sign)), \ +	AD7266_CHAN_DIFF(2, (_sign)), \ +	AD7266_CHAN_DIFF(3, (_sign)), \ +	AD7266_CHAN_DIFF(4, (_sign)), \ +	AD7266_CHAN_DIFF(5, (_sign)), \ +	IIO_CHAN_SOFT_TIMESTAMP(6), \ +} + +static AD7266_DECLARE_DIFF_CHANNELS(s, 's'); +static AD7266_DECLARE_DIFF_CHANNELS(u, 'u'); + +#define AD7266_DECLARE_DIFF_CHANNELS_FIXED(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_diff_fixed_##_name[] = { \ +	AD7266_CHAN_DIFF(0, (_sign)), \ +	AD7266_CHAN_DIFF(1, (_sign)), \ +	IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +static AD7266_DECLARE_DIFF_CHANNELS_FIXED(s, 's'); +static AD7266_DECLARE_DIFF_CHANNELS_FIXED(u, 'u'); + +static const struct iio_info ad7266_info = { +	.read_raw = &ad7266_read_raw, +	.update_scan_mode = &ad7266_update_scan_mode, +	.driver_module = THIS_MODULE, +}; + +static const unsigned long ad7266_available_scan_masks[] = { +	0x003, +	0x00c, +	0x030, +	0x0c0, +	0x300, +	0xc00, +	0x000, +}; + +static const unsigned long ad7266_available_scan_masks_diff[] = { +	0x003, +	0x00c, +	0x030, +	0x000, +}; + +static const unsigned long ad7266_available_scan_masks_fixed[] = { +	0x003, +	0x000, +}; + +struct ad7266_chan_info { +	const struct iio_chan_spec *channels; +	unsigned int num_channels; +	const unsigned long *scan_masks; +}; + +#define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \ +	(((_differential) << 2) | ((_signed) << 1) | ((_fixed) << 0)) + +static const struct ad7266_chan_info ad7266_chan_infos[] = { +	[AD7266_CHAN_INFO_INDEX(0, 0, 0)] = { +		.channels = ad7266_channels_u, +		.num_channels = ARRAY_SIZE(ad7266_channels_u), +		.scan_masks = ad7266_available_scan_masks, +	}, +	[AD7266_CHAN_INFO_INDEX(0, 0, 1)] = { +		.channels = ad7266_channels_u_fixed, +		.num_channels = ARRAY_SIZE(ad7266_channels_u_fixed), +		.scan_masks = ad7266_available_scan_masks_fixed, +	}, +	[AD7266_CHAN_INFO_INDEX(0, 1, 0)] = { +		.channels = ad7266_channels_s, +		.num_channels = ARRAY_SIZE(ad7266_channels_s), +		.scan_masks = ad7266_available_scan_masks, +	}, +	[AD7266_CHAN_INFO_INDEX(0, 1, 1)] = { +		.channels = ad7266_channels_s_fixed, +		.num_channels = ARRAY_SIZE(ad7266_channels_s_fixed), +		.scan_masks = ad7266_available_scan_masks_fixed, +	}, +	[AD7266_CHAN_INFO_INDEX(1, 0, 0)] = { +		.channels = ad7266_channels_diff_u, +		.num_channels = ARRAY_SIZE(ad7266_channels_diff_u), +		.scan_masks = ad7266_available_scan_masks_diff, +	}, +	[AD7266_CHAN_INFO_INDEX(1, 0, 1)] = { +		.channels = ad7266_channels_diff_fixed_u, +		.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_u), +		.scan_masks = ad7266_available_scan_masks_fixed, +	}, +	[AD7266_CHAN_INFO_INDEX(1, 1, 0)] = { +		.channels = ad7266_channels_diff_s, +		.num_channels = ARRAY_SIZE(ad7266_channels_diff_s), +		.scan_masks = ad7266_available_scan_masks_diff, +	}, +	[AD7266_CHAN_INFO_INDEX(1, 1, 1)] = { +		.channels = ad7266_channels_diff_fixed_s, +		.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_s), +		.scan_masks = ad7266_available_scan_masks_fixed, +	}, +}; + +static void ad7266_init_channels(struct iio_dev *indio_dev) +{ +	struct ad7266_state *st = iio_priv(indio_dev); +	bool is_differential, is_signed; +	const struct ad7266_chan_info *chan_info; +	int i; + +	is_differential = st->mode != AD7266_MODE_SINGLE_ENDED; +	is_signed = (st->range == AD7266_RANGE_2VREF) | +		    (st->mode == AD7266_MODE_DIFF); + +	i = AD7266_CHAN_INFO_INDEX(is_differential, is_signed, st->fixed_addr); +	chan_info = &ad7266_chan_infos[i]; + +	indio_dev->channels = chan_info->channels; +	indio_dev->num_channels = chan_info->num_channels; +	indio_dev->available_scan_masks = chan_info->scan_masks; +	indio_dev->masklength = chan_info->num_channels - 1; +} + +static const char * const ad7266_gpio_labels[] = { +	"AD0", "AD1", "AD2", +}; + +static int ad7266_probe(struct spi_device *spi) +{ +	struct ad7266_platform_data *pdata = spi->dev.platform_data; +	struct iio_dev *indio_dev; +	struct ad7266_state *st; +	unsigned int i; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	st->reg = devm_regulator_get(&spi->dev, "vref"); +	if (!IS_ERR_OR_NULL(st->reg)) { +		ret = regulator_enable(st->reg); +		if (ret) +			return ret; + +		ret = regulator_get_voltage(st->reg); +		if (ret < 0) +			goto error_disable_reg; + +		st->vref_mv = ret / 1000; +	} else { +		/* Use internal reference */ +		st->vref_mv = 2500; +	} + +	if (pdata) { +		st->fixed_addr = pdata->fixed_addr; +		st->mode = pdata->mode; +		st->range = pdata->range; + +		if (!st->fixed_addr) { +			for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) { +				st->gpios[i].gpio = pdata->addr_gpios[i]; +				st->gpios[i].flags = GPIOF_OUT_INIT_LOW; +				st->gpios[i].label = ad7266_gpio_labels[i]; +			} +			ret = gpio_request_array(st->gpios, +				ARRAY_SIZE(st->gpios)); +			if (ret) +				goto error_disable_reg; +		} +	} else { +		st->fixed_addr = true; +		st->range = AD7266_RANGE_VREF; +		st->mode = AD7266_MODE_DIFF; +	} + +	spi_set_drvdata(spi, indio_dev); +	st->spi = spi; + +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &ad7266_info; + +	ad7266_init_channels(indio_dev); + +	/* wakeup */ +	st->single_xfer[0].rx_buf = &st->data.sample[0]; +	st->single_xfer[0].len = 2; +	st->single_xfer[0].cs_change = 1; +	/* conversion */ +	st->single_xfer[1].rx_buf = st->data.sample; +	st->single_xfer[1].len = 4; +	st->single_xfer[1].cs_change = 1; +	/* powerdown */ +	st->single_xfer[2].tx_buf = &st->data.sample[0]; +	st->single_xfer[2].len = 1; + +	spi_message_init(&st->single_msg); +	spi_message_add_tail(&st->single_xfer[0], &st->single_msg); +	spi_message_add_tail(&st->single_xfer[1], &st->single_msg); +	spi_message_add_tail(&st->single_xfer[2], &st->single_msg); + +	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, +		&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops); +	if (ret) +		goto error_free_gpios; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_buffer_cleanup; + +	return 0; + +error_buffer_cleanup: +	iio_triggered_buffer_cleanup(indio_dev); +error_free_gpios: +	if (!st->fixed_addr) +		gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); +error_disable_reg: +	if (!IS_ERR_OR_NULL(st->reg)) +		regulator_disable(st->reg); + +	return ret; +} + +static int ad7266_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7266_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	if (!st->fixed_addr) +		gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); +	if (!IS_ERR_OR_NULL(st->reg)) +		regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7266_id[] = { +	{"ad7265", 0}, +	{"ad7266", 0}, +	{ } +}; +MODULE_DEVICE_TABLE(spi, ad7266_id); + +static struct spi_driver ad7266_driver = { +	.driver = { +		.name	= "ad7266", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7266_probe, +	.remove		= ad7266_remove, +	.id_table	= ad7266_id, +}; +module_spi_driver(ad7266_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD7266/65 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c new file mode 100644 index 00000000000..2a3b65c74af --- /dev/null +++ b/drivers/iio/adc/ad7298.c @@ -0,0 +1,394 @@ +/* + * AD7298 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/interrupt.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/platform_data/ad7298.h> + +#define AD7298_WRITE	(1 << 15) /* write to the control register */ +#define AD7298_REPEAT	(1 << 14) /* repeated conversion enable */ +#define AD7298_CH(x)	(1 << (13 - (x))) /* channel select */ +#define AD7298_TSENSE	(1 << 5) /* temperature conversion enable */ +#define AD7298_EXTREF	(1 << 2) /* external reference enable */ +#define AD7298_TAVG	(1 << 1) /* temperature sensor averaging enable */ +#define AD7298_PDD	(1 << 0) /* partial power down enable */ + +#define AD7298_MAX_CHAN		8 +#define AD7298_BITS		12 +#define AD7298_STORAGE_BITS	16 +#define AD7298_INTREF_mV	2500 + +#define AD7298_CH_TEMP		9 + +#define RES_MASK(bits)	((1 << (bits)) - 1) + +struct ad7298_state { +	struct spi_device		*spi; +	struct regulator		*reg; +	unsigned			ext_ref; +	struct spi_transfer		ring_xfer[10]; +	struct spi_transfer		scan_single_xfer[3]; +	struct spi_message		ring_msg; +	struct spi_message		scan_single_msg; +	/* +	 * DMA (thus cache coherency maintenance) requires the +	 * transfer buffers to live in their own cache lines. +	 */ +	__be16				rx_buf[12] ____cacheline_aligned; +	__be16				tx_buf[2]; +}; + +#define AD7298_V_CHAN(index)						\ +	{								\ +		.type = IIO_VOLTAGE,					\ +		.indexed = 1,						\ +		.channel = index,					\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\ +		.address = index,					\ +		.scan_index = index,					\ +		.scan_type = {						\ +			.sign = 'u',					\ +			.realbits = 12,					\ +			.storagebits = 16,				\ +			.endianness = IIO_BE,				\ +		},							\ +	} + +static const struct iio_chan_spec ad7298_channels[] = { +	{ +		.type = IIO_TEMP, +		.indexed = 1, +		.channel = 0, +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | +			BIT(IIO_CHAN_INFO_SCALE) | +			BIT(IIO_CHAN_INFO_OFFSET), +		.address = AD7298_CH_TEMP, +		.scan_index = -1, +		.scan_type = { +			.sign = 's', +			.realbits = 32, +			.storagebits = 32, +		}, +	}, +	AD7298_V_CHAN(0), +	AD7298_V_CHAN(1), +	AD7298_V_CHAN(2), +	AD7298_V_CHAN(3), +	AD7298_V_CHAN(4), +	AD7298_V_CHAN(5), +	AD7298_V_CHAN(6), +	AD7298_V_CHAN(7), +	IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +/** + * ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask + **/ +static int ad7298_update_scan_mode(struct iio_dev *indio_dev, +	const unsigned long *active_scan_mask) +{ +	struct ad7298_state *st = iio_priv(indio_dev); +	int i, m; +	unsigned short command; +	int scan_count; + +	/* Now compute overall size */ +	scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength); + +	command = AD7298_WRITE | st->ext_ref; + +	for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1) +		if (test_bit(i, active_scan_mask)) +			command |= m; + +	st->tx_buf[0] = cpu_to_be16(command); + +	/* build spi ring message */ +	st->ring_xfer[0].tx_buf = &st->tx_buf[0]; +	st->ring_xfer[0].len = 2; +	st->ring_xfer[0].cs_change = 1; +	st->ring_xfer[1].tx_buf = &st->tx_buf[1]; +	st->ring_xfer[1].len = 2; +	st->ring_xfer[1].cs_change = 1; + +	spi_message_init(&st->ring_msg); +	spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); +	spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); + +	for (i = 0; i < scan_count; i++) { +		st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i]; +		st->ring_xfer[i + 2].len = 2; +		st->ring_xfer[i + 2].cs_change = 1; +		spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg); +	} +	/* make sure last transfer cs_change is not set */ +	st->ring_xfer[i + 1].cs_change = 0; + +	return 0; +} + +/** + * ad7298_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad7298_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad7298_state *st = iio_priv(indio_dev); +	int b_sent; + +	b_sent = spi_sync(st->spi, &st->ring_msg); +	if (b_sent) +		goto done; + +	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, +		iio_get_time_ns()); + +done: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) +{ +	int ret; +	st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref | +				   (AD7298_CH(0) >> ch)); + +	ret = spi_sync(st->spi, &st->scan_single_msg); +	if (ret) +		return ret; + +	return be16_to_cpu(st->rx_buf[0]); +} + +static int ad7298_scan_temp(struct ad7298_state *st, int *val) +{ +	int ret; +	__be16 buf; + +	buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | +			  AD7298_TAVG | st->ext_ref); + +	ret = spi_write(st->spi, (u8 *)&buf, 2); +	if (ret) +		return ret; + +	buf = cpu_to_be16(0); + +	ret = spi_write(st->spi, (u8 *)&buf, 2); +	if (ret) +		return ret; + +	usleep_range(101, 1000); /* sleep > 100us */ + +	ret = spi_read(st->spi, (u8 *)&buf, 2); +	if (ret) +		return ret; + +	*val = sign_extend32(be16_to_cpu(buf), 11); + +	return 0; +} + +static int ad7298_get_ref_voltage(struct ad7298_state *st) +{ +	int vref; + +	if (st->ext_ref) { +		vref = regulator_get_voltage(st->reg); +		if (vref < 0) +			return vref; + +		return vref / 1000; +	} else { +		return AD7298_INTREF_mV; +	} +} + +static int ad7298_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	int ret; +	struct ad7298_state *st = iio_priv(indio_dev); + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { +			ret = -EBUSY; +		} else { +			if (chan->address == AD7298_CH_TEMP) +				ret = ad7298_scan_temp(st, val); +			else +				ret = ad7298_scan_direct(st, chan->address); +		} +		mutex_unlock(&indio_dev->mlock); + +		if (ret < 0) +			return ret; + +		if (chan->address != AD7298_CH_TEMP) +			*val = ret & RES_MASK(AD7298_BITS); + +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		switch (chan->type) { +		case IIO_VOLTAGE: +			*val = ad7298_get_ref_voltage(st); +			*val2 = chan->scan_type.realbits; +			return IIO_VAL_FRACTIONAL_LOG2; +		case IIO_TEMP: +			*val = ad7298_get_ref_voltage(st); +			*val2 = 10; +			return IIO_VAL_FRACTIONAL; +		default: +			return -EINVAL; +		} +	case IIO_CHAN_INFO_OFFSET: +		*val = 1093 - 2732500 / ad7298_get_ref_voltage(st); +		return IIO_VAL_INT; +	} +	return -EINVAL; +} + +static const struct iio_info ad7298_info = { +	.read_raw = &ad7298_read_raw, +	.update_scan_mode = ad7298_update_scan_mode, +	.driver_module = THIS_MODULE, +}; + +static int ad7298_probe(struct spi_device *spi) +{ +	struct ad7298_platform_data *pdata = spi->dev.platform_data; +	struct ad7298_state *st; +	struct iio_dev *indio_dev; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	if (pdata && pdata->ext_ref) +		st->ext_ref = AD7298_EXTREF; + +	if (st->ext_ref) { +		st->reg = devm_regulator_get(&spi->dev, "vref"); +		if (IS_ERR(st->reg)) +			return PTR_ERR(st->reg); + +		ret = regulator_enable(st->reg); +		if (ret) +			return ret; +	} + +	spi_set_drvdata(spi, indio_dev); + +	st->spi = spi; + +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->dev.parent = &spi->dev; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = ad7298_channels; +	indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); +	indio_dev->info = &ad7298_info; + +	/* Setup default message */ + +	st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; +	st->scan_single_xfer[0].len = 2; +	st->scan_single_xfer[0].cs_change = 1; +	st->scan_single_xfer[1].tx_buf = &st->tx_buf[1]; +	st->scan_single_xfer[1].len = 2; +	st->scan_single_xfer[1].cs_change = 1; +	st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; +	st->scan_single_xfer[2].len = 2; + +	spi_message_init(&st->scan_single_msg); +	spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); +	spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); +	spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +			&ad7298_trigger_handler, NULL); +	if (ret) +		goto error_disable_reg; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_cleanup_ring; + +	return 0; + +error_cleanup_ring: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: +	if (st->ext_ref) +		regulator_disable(st->reg); + +	return ret; +} + +static int ad7298_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7298_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	if (st->ext_ref) +		regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7298_id[] = { +	{"ad7298", 0}, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7298_id); + +static struct spi_driver ad7298_driver = { +	.driver = { +		.name	= "ad7298", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7298_probe, +	.remove		= ad7298_remove, +	.id_table	= ad7298_id, +}; +module_spi_driver(ad7298_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c new file mode 100644 index 00000000000..d141d452c3d --- /dev/null +++ b/drivers/iio/adc/ad7476.c @@ -0,0 +1,316 @@ +/* + * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define RES_MASK(bits)	((1 << (bits)) - 1) + +struct ad7476_state; + +struct ad7476_chip_info { +	unsigned int			int_vref_uv; +	struct iio_chan_spec		channel[2]; +	void (*reset)(struct ad7476_state *); +}; + +struct ad7476_state { +	struct spi_device		*spi; +	const struct ad7476_chip_info	*chip_info; +	struct regulator		*reg; +	struct spi_transfer		xfer; +	struct spi_message		msg; +	/* +	 * DMA (thus cache coherency maintenance) requires the +	 * transfer buffers to live in their own cache lines. +	 * Make the buffer large enough for one 16 bit sample and one 64 bit +	 * aligned 64 bit timestamp. +	 */ +	unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)] +			____cacheline_aligned; +}; + +enum ad7476_supported_device_ids { +	ID_AD7091R, +	ID_AD7276, +	ID_AD7277, +	ID_AD7278, +	ID_AD7466, +	ID_AD7467, +	ID_AD7468, +	ID_AD7495, +	ID_AD7940, +}; + +static irqreturn_t ad7476_trigger_handler(int irq, void  *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad7476_state *st = iio_priv(indio_dev); +	int b_sent; + +	b_sent = spi_sync(st->spi, &st->msg); +	if (b_sent < 0) +		goto done; + +	iio_push_to_buffers_with_timestamp(indio_dev, st->data, +		iio_get_time_ns()); +done: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static void ad7091_reset(struct ad7476_state *st) +{ +	/* Any transfers with 8 scl cycles will reset the device */ +	spi_read(st->spi, st->data, 1); +} + +static int ad7476_scan_direct(struct ad7476_state *st) +{ +	int ret; + +	ret = spi_sync(st->spi, &st->msg); +	if (ret) +		return ret; + +	return be16_to_cpup((__be16 *)st->data); +} + +static int ad7476_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	int ret; +	struct ad7476_state *st = iio_priv(indio_dev); +	int scale_uv; + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		if (iio_buffer_enabled(indio_dev)) +			ret = -EBUSY; +		else +			ret = ad7476_scan_direct(st); +		mutex_unlock(&indio_dev->mlock); + +		if (ret < 0) +			return ret; +		*val = (ret >> st->chip_info->channel[0].scan_type.shift) & +			RES_MASK(st->chip_info->channel[0].scan_type.realbits); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		if (!st->chip_info->int_vref_uv) { +			scale_uv = regulator_get_voltage(st->reg); +			if (scale_uv < 0) +				return scale_uv; +		} else { +			scale_uv = st->chip_info->int_vref_uv; +		} +		*val = scale_uv / 1000; +		*val2 = chan->scan_type.realbits; +		return IIO_VAL_FRACTIONAL_LOG2; +	} +	return -EINVAL; +} + +#define _AD7476_CHAN(bits, _shift, _info_mask_sep)		\ +	{							\ +	.type = IIO_VOLTAGE,					\ +	.indexed = 1,						\ +	.info_mask_separate = _info_mask_sep,			\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\ +	.scan_type = {						\ +		.sign = 'u',					\ +		.realbits = (bits),				\ +		.storagebits = 16,				\ +		.shift = (_shift),				\ +		.endianness = IIO_BE,				\ +	},							\ +} + +#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \ +		BIT(IIO_CHAN_INFO_RAW)) +#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ +		BIT(IIO_CHAN_INFO_RAW)) +#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0) + +static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { +	[ID_AD7091R] = { +		.channel[0] = AD7091R_CHAN(12), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +		.reset = ad7091_reset, +	}, +	[ID_AD7276] = { +		.channel[0] = AD7940_CHAN(12), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7277] = { +		.channel[0] = AD7940_CHAN(10), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7278] = { +		.channel[0] = AD7940_CHAN(8), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7466] = { +		.channel[0] = AD7476_CHAN(12), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7467] = { +		.channel[0] = AD7476_CHAN(10), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7468] = { +		.channel[0] = AD7476_CHAN(8), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +	[ID_AD7495] = { +		.channel[0] = AD7476_CHAN(12), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +		.int_vref_uv = 2500000, +	}, +	[ID_AD7940] = { +		.channel[0] = AD7940_CHAN(14), +		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +	}, +}; + +static const struct iio_info ad7476_info = { +	.driver_module = THIS_MODULE, +	.read_raw = &ad7476_read_raw, +}; + +static int ad7476_probe(struct spi_device *spi) +{ +	struct ad7476_state *st; +	struct iio_dev *indio_dev; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (!indio_dev) +		return -ENOMEM; + +	st = iio_priv(indio_dev); +	st->chip_info = +		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + +	st->reg = devm_regulator_get(&spi->dev, "vcc"); +	if (IS_ERR(st->reg)) +		return PTR_ERR(st->reg); + +	ret = regulator_enable(st->reg); +	if (ret) +		return ret; + +	spi_set_drvdata(spi, indio_dev); + +	st->spi = spi; + +	/* Establish that the iio_dev is a child of the spi device */ +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = st->chip_info->channel; +	indio_dev->num_channels = 2; +	indio_dev->info = &ad7476_info; +	/* Setup default message */ + +	st->xfer.rx_buf = &st->data; +	st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8; + +	spi_message_init(&st->msg); +	spi_message_add_tail(&st->xfer, &st->msg); + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +			&ad7476_trigger_handler, NULL); +	if (ret) +		goto error_disable_reg; + +	if (st->chip_info->reset) +		st->chip_info->reset(st); + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_ring_unregister; +	return 0; + +error_ring_unregister: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: +	regulator_disable(st->reg); + +	return ret; +} + +static int ad7476_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7476_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7476_id[] = { +	{"ad7091r", ID_AD7091R}, +	{"ad7273", ID_AD7277}, +	{"ad7274", ID_AD7276}, +	{"ad7276", ID_AD7276}, +	{"ad7277", ID_AD7277}, +	{"ad7278", ID_AD7278}, +	{"ad7466", ID_AD7466}, +	{"ad7467", ID_AD7467}, +	{"ad7468", ID_AD7468}, +	{"ad7475", ID_AD7466}, +	{"ad7476", ID_AD7466}, +	{"ad7476a", ID_AD7466}, +	{"ad7477", ID_AD7467}, +	{"ad7477a", ID_AD7467}, +	{"ad7478", ID_AD7468}, +	{"ad7478a", ID_AD7468}, +	{"ad7495", ID_AD7495}, +	{"ad7910", ID_AD7467}, +	{"ad7920", ID_AD7466}, +	{"ad7940", ID_AD7940}, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7476_id); + +static struct spi_driver ad7476_driver = { +	.driver = { +		.name	= "ad7476", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7476_probe, +	.remove		= ad7476_remove, +	.id_table	= ad7476_id, +}; +module_spi_driver(ad7476_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c new file mode 100644 index 00000000000..c19f8fd1b4b --- /dev/null +++ b/drivers/iio/adc/ad7791.c @@ -0,0 +1,453 @@ +/* + * AD7787/AD7788/AD7789/AD7790/AD7791 SPI ADC driver + * + * Copyright 2012 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> + +#include <linux/platform_data/ad7791.h> + +#define AD7791_REG_COMM			0x0 /* For writes */ +#define AD7791_REG_STATUS		0x0 /* For reads */ +#define AD7791_REG_MODE			0x1 +#define AD7791_REG_FILTER		0x2 +#define AD7791_REG_DATA			0x3 + +#define AD7791_MODE_CONTINUOUS		0x00 +#define AD7791_MODE_SINGLE		0x02 +#define AD7791_MODE_POWERDOWN		0x03 + +#define AD7791_CH_AIN1P_AIN1N		0x00 +#define AD7791_CH_AIN2			0x01 +#define AD7791_CH_AIN1N_AIN1N		0x02 +#define AD7791_CH_AVDD_MONITOR		0x03 + +#define AD7791_FILTER_CLK_DIV_1		(0x0 << 4) +#define AD7791_FILTER_CLK_DIV_2		(0x1 << 4) +#define AD7791_FILTER_CLK_DIV_4		(0x2 << 4) +#define AD7791_FILTER_CLK_DIV_8		(0x3 << 4) +#define AD7791_FILTER_CLK_MASK		(0x3 << 4) +#define AD7791_FILTER_RATE_120		0x0 +#define AD7791_FILTER_RATE_100		0x1 +#define AD7791_FILTER_RATE_33_3		0x2 +#define AD7791_FILTER_RATE_20		0x3 +#define AD7791_FILTER_RATE_16_6		0x4 +#define AD7791_FILTER_RATE_16_7		0x5 +#define AD7791_FILTER_RATE_13_3		0x6 +#define AD7791_FILTER_RATE_9_5		0x7 +#define AD7791_FILTER_RATE_MASK		0x7 + +#define AD7791_MODE_BUFFER		BIT(1) +#define AD7791_MODE_UNIPOLAR		BIT(2) +#define AD7791_MODE_BURNOUT		BIT(3) +#define AD7791_MODE_SEL_MASK		(0x3 << 6) +#define AD7791_MODE_SEL(x)		((x) << 6) + +#define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \ +const struct iio_chan_spec name[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ +		(bits), (storagebits), 0), \ +	AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \ +	AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \ +		(bits), (storagebits), 0), \ +	AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR,  \ +		(bits), (storagebits), 0), \ +	IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \ +const struct iio_chan_spec name[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ +		(bits), (storagebits), 0), \ +	AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \ +		(bits), (storagebits), 0), \ +	AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \ +		(bits), (storagebits), 0), \ +	IIO_CHAN_SOFT_TIMESTAMP(3), \ +} + +static DECLARE_AD7787_CHANNELS(ad7787_channels, 24, 32); +static DECLARE_AD7791_CHANNELS(ad7790_channels, 16, 16); +static DECLARE_AD7791_CHANNELS(ad7791_channels, 24, 32); + +enum { +	AD7787, +	AD7788, +	AD7789, +	AD7790, +	AD7791, +}; + +enum ad7791_chip_info_flags { +	AD7791_FLAG_HAS_FILTER		= (1 << 0), +	AD7791_FLAG_HAS_BUFFER		= (1 << 1), +	AD7791_FLAG_HAS_UNIPOLAR	= (1 << 2), +	AD7791_FLAG_HAS_BURNOUT		= (1 << 3), +}; + +struct ad7791_chip_info { +	const struct iio_chan_spec *channels; +	unsigned int num_channels; +	enum ad7791_chip_info_flags flags; +}; + +static const struct ad7791_chip_info ad7791_chip_infos[] = { +	[AD7787] = { +		.channels = ad7787_channels, +		.num_channels = ARRAY_SIZE(ad7787_channels), +		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | +			AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT, +	}, +	[AD7788] = { +		.channels = ad7790_channels, +		.num_channels = ARRAY_SIZE(ad7790_channels), +		.flags = AD7791_FLAG_HAS_UNIPOLAR, +	}, +	[AD7789] = { +		.channels = ad7791_channels, +		.num_channels = ARRAY_SIZE(ad7791_channels), +		.flags = AD7791_FLAG_HAS_UNIPOLAR, +	}, +	[AD7790] = { +		.channels = ad7790_channels, +		.num_channels = ARRAY_SIZE(ad7790_channels), +		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | +			AD7791_FLAG_HAS_BURNOUT, +	}, +	[AD7791] = { +		.channels = ad7791_channels, +		.num_channels = ARRAY_SIZE(ad7791_channels), +		.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | +			AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT, +	}, +}; + +struct ad7791_state { +	struct ad_sigma_delta sd; +	uint8_t mode; +	uint8_t filter; + +	struct regulator *reg; +	const struct ad7791_chip_info *info; +}; + +static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd) +{ +	return container_of(sd, struct ad7791_state, sd); +} + +static int ad7791_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ +	ad_sd_set_comm(sd, channel); + +	return 0; +} + +static int ad7791_set_mode(struct ad_sigma_delta *sd, +	enum ad_sigma_delta_mode mode) +{ +	struct ad7791_state *st = ad_sigma_delta_to_ad7791(sd); + +	switch (mode) { +	case AD_SD_MODE_CONTINUOUS: +		mode = AD7791_MODE_CONTINUOUS; +		break; +	case AD_SD_MODE_SINGLE: +		mode = AD7791_MODE_SINGLE; +		break; +	case AD_SD_MODE_IDLE: +	case AD_SD_MODE_POWERDOWN: +		mode = AD7791_MODE_POWERDOWN; +		break; +	} + +	st->mode &= ~AD7791_MODE_SEL_MASK; +	st->mode |= AD7791_MODE_SEL(mode); + +	return ad_sd_write_reg(sd, AD7791_REG_MODE, sizeof(st->mode), st->mode); +} + +static const struct ad_sigma_delta_info ad7791_sigma_delta_info = { +	.set_channel = ad7791_set_channel, +	.set_mode = ad7791_set_mode, +	.has_registers = true, +	.addr_shift = 4, +	.read_mask = BIT(3), +}; + +static int ad7791_read_raw(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ +	struct ad7791_state *st = iio_priv(indio_dev); +	bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR); + +	switch (info) { +	case IIO_CHAN_INFO_RAW: +		return ad_sigma_delta_single_conversion(indio_dev, chan, val); +	case IIO_CHAN_INFO_OFFSET: +		/** +		 * Unipolar: 0 to VREF +		 * Bipolar -VREF to VREF +		 **/ +		if (unipolar) +			*val = 0; +		else +			*val = -(1 << (chan->scan_type.realbits - 1)); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		/* The monitor channel uses an internal reference. */ +		if (chan->address == AD7791_CH_AVDD_MONITOR) { +			/* +			 * The signal is attenuated by a factor of 5 and +			 * compared against a 1.17V internal reference. +			 */ +			*val = 1170 * 5; +		} else { +			int voltage_uv; + +			voltage_uv = regulator_get_voltage(st->reg); +			if (voltage_uv < 0) +				return voltage_uv; + +			*val = voltage_uv / 1000; +		} +		if (unipolar) +			*val2 = chan->scan_type.realbits; +		else +			*val2 = chan->scan_type.realbits - 1; + +		return IIO_VAL_FRACTIONAL_LOG2; +	} + +	return -EINVAL; +} + +static const char * const ad7791_sample_freq_avail[] = { +	[AD7791_FILTER_RATE_120] = "120", +	[AD7791_FILTER_RATE_100] = "100", +	[AD7791_FILTER_RATE_33_3] = "33.3", +	[AD7791_FILTER_RATE_20] = "20", +	[AD7791_FILTER_RATE_16_6] = "16.6", +	[AD7791_FILTER_RATE_16_7] = "16.7", +	[AD7791_FILTER_RATE_13_3] = "13.3", +	[AD7791_FILTER_RATE_9_5] = "9.5", +}; + +static ssize_t ad7791_read_frequency(struct device *dev, +	struct device_attribute *attr, char *buf) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad7791_state *st = iio_priv(indio_dev); +	unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK; + +	return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]); +} + +static ssize_t ad7791_write_frequency(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t len) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad7791_state *st = iio_priv(indio_dev); +	int i, ret; + +	mutex_lock(&indio_dev->mlock); +	if (iio_buffer_enabled(indio_dev)) { +		mutex_unlock(&indio_dev->mlock); +		return -EBUSY; +	} +	mutex_unlock(&indio_dev->mlock); + +	ret = -EINVAL; + +	for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) { +		if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) { + +			mutex_lock(&indio_dev->mlock); +			st->filter &= ~AD7791_FILTER_RATE_MASK; +			st->filter |= i; +			ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, +					 sizeof(st->filter), st->filter); +			mutex_unlock(&indio_dev->mlock); +			ret = 0; +			break; +		} +	} + +	return ret ? ret : len; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +		ad7791_read_frequency, +		ad7791_write_frequency); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5"); + +static struct attribute *ad7791_attributes[] = { +	&iio_dev_attr_sampling_frequency.dev_attr.attr, +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	NULL +}; + +static const struct attribute_group ad7791_attribute_group = { +	.attrs = ad7791_attributes, +}; + +static const struct iio_info ad7791_info = { +	.read_raw = &ad7791_read_raw, +	.attrs = &ad7791_attribute_group, +	.validate_trigger = ad_sd_validate_trigger, +	.driver_module = THIS_MODULE, +}; + +static const struct iio_info ad7791_no_filter_info = { +	.read_raw = &ad7791_read_raw, +	.validate_trigger = ad_sd_validate_trigger, +	.driver_module = THIS_MODULE, +}; + +static int ad7791_setup(struct ad7791_state *st, +			struct ad7791_platform_data *pdata) +{ +	/* Set to poweron-reset default values */ +	st->mode = AD7791_MODE_BUFFER; +	st->filter = AD7791_FILTER_RATE_16_6; + +	if (!pdata) +		return 0; + +	if ((st->info->flags & AD7791_FLAG_HAS_BUFFER) && !pdata->buffered) +		st->mode &= ~AD7791_MODE_BUFFER; + +	if ((st->info->flags & AD7791_FLAG_HAS_BURNOUT) && +		pdata->burnout_current) +		st->mode |= AD7791_MODE_BURNOUT; + +	if ((st->info->flags & AD7791_FLAG_HAS_UNIPOLAR) && pdata->unipolar) +		st->mode |= AD7791_MODE_UNIPOLAR; + +	return ad_sd_write_reg(&st->sd, AD7791_REG_MODE, sizeof(st->mode), +		st->mode); +} + +static int ad7791_probe(struct spi_device *spi) +{ +	struct ad7791_platform_data *pdata = spi->dev.platform_data; +	struct iio_dev *indio_dev; +	struct ad7791_state *st; +	int ret; + +	if (!spi->irq) { +		dev_err(&spi->dev, "Missing IRQ.\n"); +		return -ENXIO; +	} + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (!indio_dev) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	st->reg = devm_regulator_get(&spi->dev, "refin"); +	if (IS_ERR(st->reg)) +		return PTR_ERR(st->reg); + +	ret = regulator_enable(st->reg); +	if (ret) +		return ret; + +	st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data]; +	ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info); + +	spi_set_drvdata(spi, indio_dev); + +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = st->info->channels; +	indio_dev->num_channels = st->info->num_channels; +	if (st->info->flags & AD7791_FLAG_HAS_FILTER) +		indio_dev->info = &ad7791_info; +	else +		indio_dev->info = &ad7791_no_filter_info; + +	ret = ad_sd_setup_buffer_and_trigger(indio_dev); +	if (ret) +		goto error_disable_reg; + +	ret = ad7791_setup(st, pdata); +	if (ret) +		goto error_remove_trigger; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_remove_trigger; + +	return 0; + +error_remove_trigger: +	ad_sd_cleanup_buffer_and_trigger(indio_dev); +error_disable_reg: +	regulator_disable(st->reg); + +	return ret; +} + +static int ad7791_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7791_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	ad_sd_cleanup_buffer_and_trigger(indio_dev); + +	regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7791_spi_ids[] = { +	{ "ad7787", AD7787 }, +	{ "ad7788", AD7788 }, +	{ "ad7789", AD7789 }, +	{ "ad7790", AD7790 }, +	{ "ad7791", AD7791 }, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7791_spi_ids); + +static struct spi_driver ad7791_driver = { +	.driver = { +		.name	= "ad7791", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7791_probe, +	.remove		= ad7791_remove, +	.id_table	= ad7791_spi_ids, +}; +module_spi_driver(ad7791_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c new file mode 100644 index 00000000000..4dddeabdfbb --- /dev/null +++ b/drivers/iio/adc/ad7793.c @@ -0,0 +1,865 @@ +/* + * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver + * + * Copyright 2011-2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> +#include <linux/platform_data/ad7793.h> + +/* Registers */ +#define AD7793_REG_COMM		0 /* Communications Register (WO, 8-bit) */ +#define AD7793_REG_STAT		0 /* Status Register	     (RO, 8-bit) */ +#define AD7793_REG_MODE		1 /* Mode Register	     (RW, 16-bit */ +#define AD7793_REG_CONF		2 /* Configuration Register  (RW, 16-bit) */ +#define AD7793_REG_DATA		3 /* Data Register	     (RO, 16-/24-bit) */ +#define AD7793_REG_ID		4 /* ID Register	     (RO, 8-bit) */ +#define AD7793_REG_IO		5 /* IO Register	     (RO, 8-bit) */ +#define AD7793_REG_OFFSET	6 /* Offset Register	     (RW, 16-bit +				   * (AD7792)/24-bit (AD7793)) */ +#define AD7793_REG_FULLSALE	7 /* Full-Scale Register +				   * (RW, 16-bit (AD7792)/24-bit (AD7793)) */ + +/* Communications Register Bit Designations (AD7793_REG_COMM) */ +#define AD7793_COMM_WEN		(1 << 7) /* Write Enable */ +#define AD7793_COMM_WRITE	(0 << 6) /* Write Operation */ +#define AD7793_COMM_READ	(1 << 6) /* Read Operation */ +#define AD7793_COMM_ADDR(x)	(((x) & 0x7) << 3) /* Register Address */ +#define AD7793_COMM_CREAD	(1 << 2) /* Continuous Read of Data Register */ + +/* Status Register Bit Designations (AD7793_REG_STAT) */ +#define AD7793_STAT_RDY		(1 << 7) /* Ready */ +#define AD7793_STAT_ERR		(1 << 6) /* Error (Overrange, Underrange) */ +#define AD7793_STAT_CH3		(1 << 2) /* Channel 3 */ +#define AD7793_STAT_CH2		(1 << 1) /* Channel 2 */ +#define AD7793_STAT_CH1		(1 << 0) /* Channel 1 */ + +/* Mode Register Bit Designations (AD7793_REG_MODE) */ +#define AD7793_MODE_SEL(x)	(((x) & 0x7) << 13) /* Operation Mode Select */ +#define AD7793_MODE_SEL_MASK	(0x7 << 13) /* Operation Mode Select mask */ +#define AD7793_MODE_CLKSRC(x)	(((x) & 0x3) << 6) /* ADC Clock Source Select */ +#define AD7793_MODE_RATE(x)	((x) & 0xF) /* Filter Update Rate Select */ + +#define AD7793_MODE_CONT		0 /* Continuous Conversion Mode */ +#define AD7793_MODE_SINGLE		1 /* Single Conversion Mode */ +#define AD7793_MODE_IDLE		2 /* Idle Mode */ +#define AD7793_MODE_PWRDN		3 /* Power-Down Mode */ +#define AD7793_MODE_CAL_INT_ZERO	4 /* Internal Zero-Scale Calibration */ +#define AD7793_MODE_CAL_INT_FULL	5 /* Internal Full-Scale Calibration */ +#define AD7793_MODE_CAL_SYS_ZERO	6 /* System Zero-Scale Calibration */ +#define AD7793_MODE_CAL_SYS_FULL	7 /* System Full-Scale Calibration */ + +#define AD7793_CLK_INT		0 /* Internal 64 kHz Clock not +				   * available at the CLK pin */ +#define AD7793_CLK_INT_CO	1 /* Internal 64 kHz Clock available +				   * at the CLK pin */ +#define AD7793_CLK_EXT		2 /* External 64 kHz Clock */ +#define AD7793_CLK_EXT_DIV2	3 /* External Clock divided by 2 */ + +/* Configuration Register Bit Designations (AD7793_REG_CONF) */ +#define AD7793_CONF_VBIAS(x)	(((x) & 0x3) << 14) /* Bias Voltage +						     * Generator Enable */ +#define AD7793_CONF_BO_EN	(1 << 13) /* Burnout Current Enable */ +#define AD7793_CONF_UNIPOLAR	(1 << 12) /* Unipolar/Bipolar Enable */ +#define AD7793_CONF_BOOST	(1 << 11) /* Boost Enable */ +#define AD7793_CONF_GAIN(x)	(((x) & 0x7) << 8) /* Gain Select */ +#define AD7793_CONF_REFSEL(x)	((x) << 6) /* INT/EXT Reference Select */ +#define AD7793_CONF_BUF		(1 << 4) /* Buffered Mode Enable */ +#define AD7793_CONF_CHAN(x)	((x) & 0xf) /* Channel select */ +#define AD7793_CONF_CHAN_MASK	0xf /* Channel select mask */ + +#define AD7793_CH_AIN1P_AIN1M	0 /* AIN1(+) - AIN1(-) */ +#define AD7793_CH_AIN2P_AIN2M	1 /* AIN2(+) - AIN2(-) */ +#define AD7793_CH_AIN3P_AIN3M	2 /* AIN3(+) - AIN3(-) */ +#define AD7793_CH_AIN1M_AIN1M	3 /* AIN1(-) - AIN1(-) */ +#define AD7793_CH_TEMP		6 /* Temp Sensor */ +#define AD7793_CH_AVDD_MONITOR	7 /* AVDD Monitor */ + +#define AD7795_CH_AIN4P_AIN4M	4 /* AIN4(+) - AIN4(-) */ +#define AD7795_CH_AIN5P_AIN5M	5 /* AIN5(+) - AIN5(-) */ +#define AD7795_CH_AIN6P_AIN6M	6 /* AIN6(+) - AIN6(-) */ +#define AD7795_CH_AIN1M_AIN1M	8 /* AIN1(-) - AIN1(-) */ + +/* ID Register Bit Designations (AD7793_REG_ID) */ +#define AD7785_ID		0xB +#define AD7792_ID		0xA +#define AD7793_ID		0xB +#define AD7794_ID		0xF +#define AD7795_ID		0xF +#define AD7796_ID		0xA +#define AD7797_ID		0xB +#define AD7798_ID		0x8 +#define AD7799_ID		0x9 +#define AD7793_ID_MASK		0xF + +/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */ +#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2	0 /* IEXC1 connect to IOUT1, +						   * IEXC2 connect to IOUT2 */ +#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1	1 /* IEXC1 connect to IOUT2, +						   * IEXC2 connect to IOUT1 */ +#define AD7793_IO_IEXC1_IEXC2_IOUT1		2 /* Both current sources +						   * IEXC1,2 connect to IOUT1 */ +#define AD7793_IO_IEXC1_IEXC2_IOUT2		3 /* Both current sources +						   * IEXC1,2 connect to IOUT2 */ + +#define AD7793_IO_IXCEN_10uA	(1 << 0) /* Excitation Current 10uA */ +#define AD7793_IO_IXCEN_210uA	(2 << 0) /* Excitation Current 210uA */ +#define AD7793_IO_IXCEN_1mA	(3 << 0) /* Excitation Current 1mA */ + +/* NOTE: + * The AD7792/AD7793 features a dual use data out ready DOUT/RDY output. + * In order to avoid contentions on the SPI bus, it's therefore necessary + * to use spi bus locking. + * + * The DOUT/RDY output must also be wired to an interrupt capable GPIO. + */ + +#define AD7793_FLAG_HAS_CLKSEL		BIT(0) +#define AD7793_FLAG_HAS_REFSEL		BIT(1) +#define AD7793_FLAG_HAS_VBIAS		BIT(2) +#define AD7793_HAS_EXITATION_CURRENT	BIT(3) +#define AD7793_FLAG_HAS_GAIN		BIT(4) +#define AD7793_FLAG_HAS_BUFFER		BIT(5) + +struct ad7793_chip_info { +	unsigned int id; +	const struct iio_chan_spec *channels; +	unsigned int num_channels; +	unsigned int flags; + +	const struct iio_info *iio_info; +	const u16 *sample_freq_avail; +}; + +struct ad7793_state { +	const struct ad7793_chip_info	*chip_info; +	struct regulator		*reg; +	u16				int_vref_mv; +	u16				mode; +	u16				conf; +	u32				scale_avail[8][2]; + +	struct ad_sigma_delta		sd; + +}; + +enum ad7793_supported_device_ids { +	ID_AD7785, +	ID_AD7792, +	ID_AD7793, +	ID_AD7794, +	ID_AD7795, +	ID_AD7796, +	ID_AD7797, +	ID_AD7798, +	ID_AD7799, +}; + +static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd) +{ +	return container_of(sd, struct ad7793_state, sd); +} + +static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ +	struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); + +	st->conf &= ~AD7793_CONF_CHAN_MASK; +	st->conf |= AD7793_CONF_CHAN(channel); + +	return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf); +} + +static int ad7793_set_mode(struct ad_sigma_delta *sd, +			   enum ad_sigma_delta_mode mode) +{ +	struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); + +	st->mode &= ~AD7793_MODE_SEL_MASK; +	st->mode |= AD7793_MODE_SEL(mode); + +	return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode); +} + +static const struct ad_sigma_delta_info ad7793_sigma_delta_info = { +	.set_channel = ad7793_set_channel, +	.set_mode = ad7793_set_mode, +	.has_registers = true, +	.addr_shift = 3, +	.read_mask = BIT(6), +}; + +static const struct ad_sd_calib_data ad7793_calib_arr[6] = { +	{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M}, +	{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M}, +	{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M}, +	{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M}, +	{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M}, +	{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M} +}; + +static int ad7793_calibrate_all(struct ad7793_state *st) +{ +	return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr, +				   ARRAY_SIZE(ad7793_calib_arr)); +} + +static int ad7793_check_platform_data(struct ad7793_state *st, +	const struct ad7793_platform_data *pdata) +{ +	if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 || +		pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) && +		((pdata->exitation_current != AD7793_IX_10uA) && +		(pdata->exitation_current != AD7793_IX_210uA))) +		return -EINVAL; + +	if (!(st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL) && +		pdata->clock_src != AD7793_CLK_SRC_INT) +		return -EINVAL; + +	if (!(st->chip_info->flags & AD7793_FLAG_HAS_REFSEL) && +		pdata->refsel != AD7793_REFSEL_REFIN1) +		return -EINVAL; + +	if (!(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS) && +		pdata->bias_voltage != AD7793_BIAS_VOLTAGE_DISABLED) +		return -EINVAL; + +	if (!(st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) && +		pdata->exitation_current != AD7793_IX_DISABLED) +		return -EINVAL; + +	return 0; +} + +static int ad7793_setup(struct iio_dev *indio_dev, +	const struct ad7793_platform_data *pdata, +	unsigned int vref_mv) +{ +	struct ad7793_state *st = iio_priv(indio_dev); +	int i, ret = -1; +	unsigned long long scale_uv; +	u32 id; + +	ret = ad7793_check_platform_data(st, pdata); +	if (ret) +		return ret; + +	/* reset the serial interface */ +	ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret)); +	if (ret < 0) +		goto out; +	usleep_range(500, 2000); /* Wait for at least 500us */ + +	/* write/read test for device presence */ +	ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); +	if (ret) +		goto out; + +	id &= AD7793_ID_MASK; + +	if (id != st->chip_info->id) { +		dev_err(&st->sd.spi->dev, "device ID query failed\n"); +		goto out; +	} + +	st->mode = AD7793_MODE_RATE(1); +	st->conf = 0; + +	if (st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL) +		st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src); +	if (st->chip_info->flags & AD7793_FLAG_HAS_REFSEL) +		st->conf |= AD7793_CONF_REFSEL(pdata->refsel); +	if (st->chip_info->flags & AD7793_FLAG_HAS_VBIAS) +		st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage); +	if (pdata->buffered || !(st->chip_info->flags & AD7793_FLAG_HAS_BUFFER)) +		st->conf |= AD7793_CONF_BUF; +	if (pdata->boost_enable && +		(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS)) +		st->conf |= AD7793_CONF_BOOST; +	if (pdata->burnout_current) +		st->conf |= AD7793_CONF_BO_EN; +	if (pdata->unipolar) +		st->conf |= AD7793_CONF_UNIPOLAR; + +	if (!(st->chip_info->flags & AD7793_FLAG_HAS_GAIN)) +		st->conf |= AD7793_CONF_GAIN(7); + +	ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE); +	if (ret) +		goto out; + +	ret = ad7793_set_channel(&st->sd, 0); +	if (ret) +		goto out; + +	if (st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) { +		ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1, +				pdata->exitation_current | +				(pdata->current_source_direction << 2)); +		if (ret) +			goto out; +	} + +	ret = ad7793_calibrate_all(st); +	if (ret) +		goto out; + +	/* Populate available ADC input ranges */ +	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { +		scale_uv = ((u64)vref_mv * 100000000) +			>> (st->chip_info->channels[0].scan_type.realbits - +			(!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1)); +		scale_uv >>= i; + +		st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; +		st->scale_avail[i][0] = scale_uv; +	} + +	return 0; +out: +	dev_err(&st->sd.spi->dev, "setup failed\n"); +	return ret; +} + +static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, +					33, 19, 17, 16, 12, 10, 8, 6, 4}; + +static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0, +					33, 0, 17, 16, 12, 10, 8, 6, 4}; + +static ssize_t ad7793_read_frequency(struct device *dev, +		struct device_attribute *attr, +		char *buf) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad7793_state *st = iio_priv(indio_dev); + +	return sprintf(buf, "%d\n", +	       st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]); +} + +static ssize_t ad7793_write_frequency(struct device *dev, +		struct device_attribute *attr, +		const char *buf, +		size_t len) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad7793_state *st = iio_priv(indio_dev); +	long lval; +	int i, ret; + +	mutex_lock(&indio_dev->mlock); +	if (iio_buffer_enabled(indio_dev)) { +		mutex_unlock(&indio_dev->mlock); +		return -EBUSY; +	} +	mutex_unlock(&indio_dev->mlock); + +	ret = kstrtol(buf, 10, &lval); +	if (ret) +		return ret; + +	if (lval == 0) +		return -EINVAL; + +	ret = -EINVAL; + +	for (i = 0; i < 16; i++) +		if (lval == st->chip_info->sample_freq_avail[i]) { +			mutex_lock(&indio_dev->mlock); +			st->mode &= ~AD7793_MODE_RATE(-1); +			st->mode |= AD7793_MODE_RATE(i); +			ad_sd_write_reg(&st->sd, AD7793_REG_MODE, +					 sizeof(st->mode), st->mode); +			mutex_unlock(&indio_dev->mlock); +			ret = 0; +		} + +	return ret ? ret : len; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +		ad7793_read_frequency, +		ad7793_write_frequency); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( +	"470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); + +static IIO_CONST_ATTR_NAMED(sampling_frequency_available_ad7797, +	sampling_frequency_available, "123 62 50 33 17 16 12 10 8 6 4"); + +static ssize_t ad7793_show_scale_available(struct device *dev, +			struct device_attribute *attr, char *buf) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad7793_state *st = iio_priv(indio_dev); +	int i, len = 0; + +	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) +		len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], +			       st->scale_avail[i][1]); + +	len += sprintf(buf + len, "\n"); + +	return len; +} + +static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, +		in_voltage-voltage_scale_available, S_IRUGO, +		ad7793_show_scale_available, NULL, 0); + +static struct attribute *ad7793_attributes[] = { +	&iio_dev_attr_sampling_frequency.dev_attr.attr, +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	&iio_dev_attr_in_m_in_scale_available.dev_attr.attr, +	NULL +}; + +static const struct attribute_group ad7793_attribute_group = { +	.attrs = ad7793_attributes, +}; + +static struct attribute *ad7797_attributes[] = { +	&iio_dev_attr_sampling_frequency.dev_attr.attr, +	&iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr, +	NULL +}; + +static const struct attribute_group ad7797_attribute_group = { +	.attrs = ad7797_attributes, +}; + +static int ad7793_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	struct ad7793_state *st = iio_priv(indio_dev); +	int ret; +	unsigned long long scale_uv; +	bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		ret = ad_sigma_delta_single_conversion(indio_dev, chan, val); +		if (ret < 0) +			return ret; + +		return IIO_VAL_INT; + +	case IIO_CHAN_INFO_SCALE: +		switch (chan->type) { +		case IIO_VOLTAGE: +			if (chan->differential) { +				*val = st-> +					scale_avail[(st->conf >> 8) & 0x7][0]; +				*val2 = st-> +					scale_avail[(st->conf >> 8) & 0x7][1]; +				return IIO_VAL_INT_PLUS_NANO; +			} else { +				/* 1170mV / 2^23 * 6 */ +				scale_uv = (1170ULL * 1000000000ULL * 6ULL); +			} +			break; +		case IIO_TEMP: +				/* 1170mV / 0.81 mV/C / 2^23 */ +				scale_uv = 1444444444444444ULL; +			break; +		default: +			return -EINVAL; +		} + +		scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1)); +		*val = 0; +		*val2 = scale_uv; +		return IIO_VAL_INT_PLUS_NANO; +	case IIO_CHAN_INFO_OFFSET: +		if (!unipolar) +			*val = -(1 << (chan->scan_type.realbits - 1)); +		else +			*val = 0; + +		/* Kelvin to Celsius */ +		if (chan->type == IIO_TEMP) { +			unsigned long long offset; +			unsigned int shift; + +			shift = chan->scan_type.realbits - (unipolar ? 0 : 1); +			offset = 273ULL << shift; +			do_div(offset, 1444); +			*val -= offset; +		} +		return IIO_VAL_INT; +	} +	return -EINVAL; +} + +static int ad7793_write_raw(struct iio_dev *indio_dev, +			       struct iio_chan_spec const *chan, +			       int val, +			       int val2, +			       long mask) +{ +	struct ad7793_state *st = iio_priv(indio_dev); +	int ret, i; +	unsigned int tmp; + +	mutex_lock(&indio_dev->mlock); +	if (iio_buffer_enabled(indio_dev)) { +		mutex_unlock(&indio_dev->mlock); +		return -EBUSY; +	} + +	switch (mask) { +	case IIO_CHAN_INFO_SCALE: +		ret = -EINVAL; +		for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) +			if (val2 == st->scale_avail[i][1]) { +				ret = 0; +				tmp = st->conf; +				st->conf &= ~AD7793_CONF_GAIN(-1); +				st->conf |= AD7793_CONF_GAIN(i); + +				if (tmp == st->conf) +					break; + +				ad_sd_write_reg(&st->sd, AD7793_REG_CONF, +						sizeof(st->conf), st->conf); +				ad7793_calibrate_all(st); +				break; +			} +		break; +	default: +		ret = -EINVAL; +	} + +	mutex_unlock(&indio_dev->mlock); +	return ret; +} + +static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev, +			       struct iio_chan_spec const *chan, +			       long mask) +{ +	return IIO_VAL_INT_PLUS_NANO; +} + +static const struct iio_info ad7793_info = { +	.read_raw = &ad7793_read_raw, +	.write_raw = &ad7793_write_raw, +	.write_raw_get_fmt = &ad7793_write_raw_get_fmt, +	.attrs = &ad7793_attribute_group, +	.validate_trigger = ad_sd_validate_trigger, +	.driver_module = THIS_MODULE, +}; + +static const struct iio_info ad7797_info = { +	.read_raw = &ad7793_read_raw, +	.write_raw = &ad7793_write_raw, +	.write_raw_get_fmt = &ad7793_write_raw_get_fmt, +	.attrs = &ad7793_attribute_group, +	.validate_trigger = ad_sd_validate_trigger, +	.driver_module = THIS_MODULE, +}; + +#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \ +const struct iio_chan_spec _name##_channels[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ +	AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ +	AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ +	AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ +	AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ +	AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ +	IIO_CHAN_SOFT_TIMESTAMP(6), \ +} + +#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \ +const struct iio_chan_spec _name##_channels[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ +	AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ +	AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ +	AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ +	IIO_CHAN_SOFT_TIMESTAMP(9), \ +} + +#define DECLARE_AD7797_CHANNELS(_name, _b, _sb) \ +const struct iio_chan_spec _name##_channels[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ +	AD_SD_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ +	AD_SD_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \ +	AD_SD_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ +	IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DECLARE_AD7799_CHANNELS(_name, _b, _sb) \ +const struct iio_chan_spec _name##_channels[] = { \ +	AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ +	AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ +	AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ +	AD_SD_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ +	IIO_CHAN_SOFT_TIMESTAMP(5), \ +} + +static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4); +static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0); +static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0); +static DECLARE_AD7795_CHANNELS(ad7794, 16, 32); +static DECLARE_AD7795_CHANNELS(ad7795, 24, 32); +static DECLARE_AD7797_CHANNELS(ad7796, 16, 16); +static DECLARE_AD7797_CHANNELS(ad7797, 24, 32); +static DECLARE_AD7799_CHANNELS(ad7798, 16, 16); +static DECLARE_AD7799_CHANNELS(ad7799, 24, 32); + +static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { +	[ID_AD7785] = { +		.id = AD7785_ID, +		.channels = ad7785_channels, +		.num_channels = ARRAY_SIZE(ad7785_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL | +			AD7793_FLAG_HAS_REFSEL | +			AD7793_FLAG_HAS_VBIAS | +			AD7793_HAS_EXITATION_CURRENT | +			AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7792] = { +		.id = AD7792_ID, +		.channels = ad7792_channels, +		.num_channels = ARRAY_SIZE(ad7792_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL | +			AD7793_FLAG_HAS_REFSEL | +			AD7793_FLAG_HAS_VBIAS | +			AD7793_HAS_EXITATION_CURRENT | +			AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7793] = { +		.id = AD7793_ID, +		.channels = ad7793_channels, +		.num_channels = ARRAY_SIZE(ad7793_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL | +			AD7793_FLAG_HAS_REFSEL | +			AD7793_FLAG_HAS_VBIAS | +			AD7793_HAS_EXITATION_CURRENT | +			AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7794] = { +		.id = AD7794_ID, +		.channels = ad7794_channels, +		.num_channels = ARRAY_SIZE(ad7794_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL | +			AD7793_FLAG_HAS_REFSEL | +			AD7793_FLAG_HAS_VBIAS | +			AD7793_HAS_EXITATION_CURRENT | +			AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7795] = { +		.id = AD7795_ID, +		.channels = ad7795_channels, +		.num_channels = ARRAY_SIZE(ad7795_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL | +			AD7793_FLAG_HAS_REFSEL | +			AD7793_FLAG_HAS_VBIAS | +			AD7793_HAS_EXITATION_CURRENT | +			AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7796] = { +		.id = AD7796_ID, +		.channels = ad7796_channels, +		.num_channels = ARRAY_SIZE(ad7796_channels), +		.iio_info = &ad7797_info, +		.sample_freq_avail = ad7797_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL, +	}, +	[ID_AD7797] = { +		.id = AD7797_ID, +		.channels = ad7797_channels, +		.num_channels = ARRAY_SIZE(ad7797_channels), +		.iio_info = &ad7797_info, +		.sample_freq_avail = ad7797_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_CLKSEL, +	}, +	[ID_AD7798] = { +		.id = AD7798_ID, +		.channels = ad7798_channels, +		.num_channels = ARRAY_SIZE(ad7798_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +	[ID_AD7799] = { +		.id = AD7799_ID, +		.channels = ad7799_channels, +		.num_channels = ARRAY_SIZE(ad7799_channels), +		.iio_info = &ad7793_info, +		.sample_freq_avail = ad7793_sample_freq_avail, +		.flags = AD7793_FLAG_HAS_GAIN | +			AD7793_FLAG_HAS_BUFFER, +	}, +}; + +static int ad7793_probe(struct spi_device *spi) +{ +	const struct ad7793_platform_data *pdata = spi->dev.platform_data; +	struct ad7793_state *st; +	struct iio_dev *indio_dev; +	int ret, vref_mv = 0; + +	if (!pdata) { +		dev_err(&spi->dev, "no platform data?\n"); +		return -ENODEV; +	} + +	if (!spi->irq) { +		dev_err(&spi->dev, "no IRQ?\n"); +		return -ENODEV; +	} + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); + +	if (pdata->refsel != AD7793_REFSEL_INTERNAL) { +		st->reg = devm_regulator_get(&spi->dev, "refin"); +		if (IS_ERR(st->reg)) +			return PTR_ERR(st->reg); + +		ret = regulator_enable(st->reg); +		if (ret) +			return ret; + +		vref_mv = regulator_get_voltage(st->reg); +		if (vref_mv < 0) { +			ret = vref_mv; +			goto error_disable_reg; +		} + +		vref_mv /= 1000; +	} else { +		vref_mv = 1170; /* Build-in ref */ +	} + +	st->chip_info = +		&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + +	spi_set_drvdata(spi, indio_dev); + +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = st->chip_info->channels; +	indio_dev->num_channels = st->chip_info->num_channels; +	indio_dev->info = st->chip_info->iio_info; + +	ret = ad_sd_setup_buffer_and_trigger(indio_dev); +	if (ret) +		goto error_disable_reg; + +	ret = ad7793_setup(indio_dev, pdata, vref_mv); +	if (ret) +		goto error_remove_trigger; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_remove_trigger; + +	return 0; + +error_remove_trigger: +	ad_sd_cleanup_buffer_and_trigger(indio_dev); +error_disable_reg: +	if (pdata->refsel != AD7793_REFSEL_INTERNAL) +		regulator_disable(st->reg); + +	return ret; +} + +static int ad7793_remove(struct spi_device *spi) +{ +	const struct ad7793_platform_data *pdata = spi->dev.platform_data; +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7793_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	ad_sd_cleanup_buffer_and_trigger(indio_dev); + +	if (pdata->refsel != AD7793_REFSEL_INTERNAL) +		regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7793_id[] = { +	{"ad7785", ID_AD7785}, +	{"ad7792", ID_AD7792}, +	{"ad7793", ID_AD7793}, +	{"ad7794", ID_AD7794}, +	{"ad7795", ID_AD7795}, +	{"ad7796", ID_AD7796}, +	{"ad7797", ID_AD7797}, +	{"ad7798", ID_AD7798}, +	{"ad7799", ID_AD7799}, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7793_id); + +static struct spi_driver ad7793_driver = { +	.driver = { +		.name	= "ad7793", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7793_probe, +	.remove		= ad7793_remove, +	.id_table	= ad7793_id, +}; +module_spi_driver(ad7793_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c new file mode 100644 index 00000000000..749a6cadab8 --- /dev/null +++ b/drivers/iio/adc/ad7887.c @@ -0,0 +1,370 @@ +/* + * AD7887 SPI ADC driver + * + * Copyright 2010-2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/interrupt.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> + +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/platform_data/ad7887.h> + +#define AD7887_REF_DIS		(1 << 5) /* on-chip reference disable */ +#define AD7887_DUAL		(1 << 4) /* dual-channel mode */ +#define AD7887_CH_AIN1		(1 << 3) /* convert on channel 1, DUAL=1 */ +#define AD7887_CH_AIN0		(0 << 3) /* convert on channel 0, DUAL=0,1 */ +#define AD7887_PM_MODE1		(0)	 /* CS based shutdown */ +#define AD7887_PM_MODE2		(1)	 /* full on */ +#define AD7887_PM_MODE3		(2)	 /* auto shutdown after conversion */ +#define AD7887_PM_MODE4		(3)	 /* standby mode */ + +enum ad7887_channels { +	AD7887_CH0, +	AD7887_CH0_CH1, +	AD7887_CH1, +}; + +#define RES_MASK(bits)	((1 << (bits)) - 1) + +/** + * struct ad7887_chip_info - chip specifc information + * @int_vref_mv:	the internal reference voltage + * @channel:		channel specification + */ +struct ad7887_chip_info { +	u16				int_vref_mv; +	struct iio_chan_spec		channel[3]; +}; + +struct ad7887_state { +	struct spi_device		*spi; +	const struct ad7887_chip_info	*chip_info; +	struct regulator		*reg; +	struct spi_transfer		xfer[4]; +	struct spi_message		msg[3]; +	struct spi_message		*ring_msg; +	unsigned char			tx_cmd_buf[4]; + +	/* +	 * DMA (thus cache coherency maintenance) requires the +	 * transfer buffers to live in their own cache lines. +	 * Buffer needs to be large enough to hold two 16 bit samples and a +	 * 64 bit aligned 64 bit timestamp. +	 */ +	unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)] +		____cacheline_aligned; +}; + +enum ad7887_supported_device_ids { +	ID_AD7887 +}; + +static int ad7887_ring_preenable(struct iio_dev *indio_dev) +{ +	struct ad7887_state *st = iio_priv(indio_dev); + +	/* We know this is a single long so can 'cheat' */ +	switch (*indio_dev->active_scan_mask) { +	case (1 << 0): +		st->ring_msg = &st->msg[AD7887_CH0]; +		break; +	case (1 << 1): +		st->ring_msg = &st->msg[AD7887_CH1]; +		/* Dummy read: push CH1 setting down to hardware */ +		spi_sync(st->spi, st->ring_msg); +		break; +	case ((1 << 1) | (1 << 0)): +		st->ring_msg = &st->msg[AD7887_CH0_CH1]; +		break; +	} + +	return 0; +} + +static int ad7887_ring_postdisable(struct iio_dev *indio_dev) +{ +	struct ad7887_state *st = iio_priv(indio_dev); + +	/* dummy read: restore default CH0 settin */ +	return spi_sync(st->spi, &st->msg[AD7887_CH0]); +} + +/** + * ad7887_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad7887_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad7887_state *st = iio_priv(indio_dev); +	int b_sent; + +	b_sent = spi_sync(st->spi, st->ring_msg); +	if (b_sent) +		goto done; + +	iio_push_to_buffers_with_timestamp(indio_dev, st->data, +		iio_get_time_ns()); +done: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = { +	.preenable = &ad7887_ring_preenable, +	.postenable = &iio_triggered_buffer_postenable, +	.predisable = &iio_triggered_buffer_predisable, +	.postdisable = &ad7887_ring_postdisable, +}; + +static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch) +{ +	int ret = spi_sync(st->spi, &st->msg[ch]); +	if (ret) +		return ret; + +	return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1]; +} + +static int ad7887_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	int ret; +	struct ad7887_state *st = iio_priv(indio_dev); + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		if (iio_buffer_enabled(indio_dev)) +			ret = -EBUSY; +		else +			ret = ad7887_scan_direct(st, chan->address); +		mutex_unlock(&indio_dev->mlock); + +		if (ret < 0) +			return ret; +		*val = ret >> chan->scan_type.shift; +		*val &= RES_MASK(chan->scan_type.realbits); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		if (st->reg) { +			*val = regulator_get_voltage(st->reg); +			if (*val < 0) +				return *val; +			*val /= 1000; +		} else { +			*val = st->chip_info->int_vref_mv; +		} + +		*val2 = chan->scan_type.realbits; + +		return IIO_VAL_FRACTIONAL_LOG2; +	} +	return -EINVAL; +} + + +static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { +	/* +	 * More devices added in future +	 */ +	[ID_AD7887] = { +		.channel[0] = { +			.type = IIO_VOLTAGE, +			.indexed = 1, +			.channel = 1, +			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), +			.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +			.address = 1, +			.scan_index = 1, +			.scan_type = { +				.sign = 'u', +				.realbits = 12, +				.storagebits = 16, +				.shift = 0, +				.endianness = IIO_BE, +			}, +		}, +		.channel[1] = { +			.type = IIO_VOLTAGE, +			.indexed = 1, +			.channel = 0, +			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), +			.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +			.address = 0, +			.scan_index = 0, +			.scan_type = { +				.sign = 'u', +				.realbits = 12, +				.storagebits = 16, +				.shift = 0, +				.endianness = IIO_BE, +			}, +		}, +		.channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2), +		.int_vref_mv = 2500, +	}, +}; + +static const struct iio_info ad7887_info = { +	.read_raw = &ad7887_read_raw, +	.driver_module = THIS_MODULE, +}; + +static int ad7887_probe(struct spi_device *spi) +{ +	struct ad7887_platform_data *pdata = spi->dev.platform_data; +	struct ad7887_state *st; +	struct iio_dev *indio_dev; +	uint8_t mode; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	if (!pdata || !pdata->use_onchip_ref) { +		st->reg = devm_regulator_get(&spi->dev, "vref"); +		if (IS_ERR(st->reg)) +			return PTR_ERR(st->reg); + +		ret = regulator_enable(st->reg); +		if (ret) +			return ret; +	} + +	st->chip_info = +		&ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + +	spi_set_drvdata(spi, indio_dev); +	st->spi = spi; + +	/* Estabilish that the iio_dev is a child of the spi device */ +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->info = &ad7887_info; +	indio_dev->modes = INDIO_DIRECT_MODE; + +	/* Setup default message */ + +	mode = AD7887_PM_MODE4; +	if (!pdata || !pdata->use_onchip_ref) +		mode |= AD7887_REF_DIS; +	if (pdata && pdata->en_dual) +		mode |= AD7887_DUAL; + +	st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode; + +	st->xfer[0].rx_buf = &st->data[0]; +	st->xfer[0].tx_buf = &st->tx_cmd_buf[0]; +	st->xfer[0].len = 2; + +	spi_message_init(&st->msg[AD7887_CH0]); +	spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]); + +	if (pdata && pdata->en_dual) { +		st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode; + +		st->xfer[1].rx_buf = &st->data[0]; +		st->xfer[1].tx_buf = &st->tx_cmd_buf[2]; +		st->xfer[1].len = 2; + +		st->xfer[2].rx_buf = &st->data[2]; +		st->xfer[2].tx_buf = &st->tx_cmd_buf[0]; +		st->xfer[2].len = 2; + +		spi_message_init(&st->msg[AD7887_CH0_CH1]); +		spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]); +		spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]); + +		st->xfer[3].rx_buf = &st->data[2]; +		st->xfer[3].tx_buf = &st->tx_cmd_buf[2]; +		st->xfer[3].len = 2; + +		spi_message_init(&st->msg[AD7887_CH1]); +		spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]); + +		indio_dev->channels = st->chip_info->channel; +		indio_dev->num_channels = 3; +	} else { +		indio_dev->channels = &st->chip_info->channel[1]; +		indio_dev->num_channels = 2; +	} + +	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, +			&ad7887_trigger_handler, &ad7887_ring_setup_ops); +	if (ret) +		goto error_disable_reg; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_unregister_ring; + +	return 0; +error_unregister_ring: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: +	if (st->reg) +		regulator_disable(st->reg); + +	return ret; +} + +static int ad7887_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7887_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	if (st->reg) +		regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7887_id[] = { +	{"ad7887", ID_AD7887}, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7887_id); + +static struct spi_driver ad7887_driver = { +	.driver = { +		.name	= "ad7887", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7887_probe, +	.remove		= ad7887_remove, +	.id_table	= ad7887_id, +}; +module_spi_driver(ad7887_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c new file mode 100644 index 00000000000..28732c28e81 --- /dev/null +++ b/drivers/iio/adc/ad7923.c @@ -0,0 +1,371 @@ +/* + * AD7904/AD7914/AD7923/AD7924 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc (from AD7923 Driver) + * Copyright 2012 CS Systemes d'Information + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/interrupt.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define AD7923_WRITE_CR		(1 << 11)	/* write control register */ +#define AD7923_RANGE		(1 << 1)	/* range to REFin */ +#define AD7923_CODING		(1 << 0)	/* coding is straight binary */ +#define AD7923_PM_MODE_AS	(1)		/* auto shutdown */ +#define AD7923_PM_MODE_FS	(2)		/* full shutdown */ +#define AD7923_PM_MODE_OPS	(3)		/* normal operation */ +#define AD7923_CHANNEL_0	(0)		/* analog input 0 */ +#define AD7923_CHANNEL_1	(1)		/* analog input 1 */ +#define AD7923_CHANNEL_2	(2)		/* analog input 2 */ +#define AD7923_CHANNEL_3	(3)		/* analog input 3 */ +#define AD7923_SEQUENCE_OFF	(0)		/* no sequence fonction */ +#define AD7923_SEQUENCE_PROTECT	(2)		/* no interrupt write cycle */ +#define AD7923_SEQUENCE_ON	(3)		/* continuous sequence */ + +#define AD7923_MAX_CHAN		4 + +#define AD7923_PM_MODE_WRITE(mode)	(mode << 4)	/* write mode */ +#define AD7923_CHANNEL_WRITE(channel)	(channel << 6)	/* write channel */ +#define AD7923_SEQUENCE_WRITE(sequence)	(((sequence & 1) << 3) \ +					+ ((sequence & 2) << 9)) +						/* write sequence fonction */ +/* left shift for CR : bit 11 transmit in first */ +#define AD7923_SHIFT_REGISTER	4 + +/* val = value, dec = left shift, bits = number of bits of the mask */ +#define EXTRACT(val, dec, bits)		((val >> dec) & ((1 << bits) - 1)) + +struct ad7923_state { +	struct spi_device		*spi; +	struct spi_transfer		ring_xfer[5]; +	struct spi_transfer		scan_single_xfer[2]; +	struct spi_message		ring_msg; +	struct spi_message		scan_single_msg; + +	struct regulator		*reg; + +	unsigned int			settings; + +	/* +	 * DMA (thus cache coherency maintenance) requires the +	 * transfer buffers to live in their own cache lines. +	 */ +	__be16				rx_buf[4] ____cacheline_aligned; +	__be16				tx_buf[4]; +}; + +struct ad7923_chip_info { +	const struct iio_chan_spec *channels; +	unsigned int num_channels; +}; + +enum ad7923_id { +	AD7904, +	AD7914, +	AD7924, +}; + +#define AD7923_V_CHAN(index, bits)					\ +	{								\ +		.type = IIO_VOLTAGE,					\ +		.indexed = 1,						\ +		.channel = index,					\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\ +		.address = index,					\ +		.scan_index = index,					\ +		.scan_type = {						\ +			.sign = 'u',					\ +			.realbits = (bits),				\ +			.storagebits = 16,				\ +			.endianness = IIO_BE,				\ +		},							\ +	} + +#define DECLARE_AD7923_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ +	AD7923_V_CHAN(0, bits), \ +	AD7923_V_CHAN(1, bits), \ +	AD7923_V_CHAN(2, bits), \ +	AD7923_V_CHAN(3, bits), \ +	IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +static DECLARE_AD7923_CHANNELS(ad7904, 8); +static DECLARE_AD7923_CHANNELS(ad7914, 10); +static DECLARE_AD7923_CHANNELS(ad7924, 12); + +static const struct ad7923_chip_info ad7923_chip_info[] = { +	[AD7904] = { +		.channels = ad7904_channels, +		.num_channels = ARRAY_SIZE(ad7904_channels), +	}, +	[AD7914] = { +		.channels = ad7914_channels, +		.num_channels = ARRAY_SIZE(ad7914_channels), +	}, +	[AD7924] = { +		.channels = ad7924_channels, +		.num_channels = ARRAY_SIZE(ad7924_channels), +	}, +}; + +/** + * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask + **/ +static int ad7923_update_scan_mode(struct iio_dev *indio_dev, +	const unsigned long *active_scan_mask) +{ +	struct ad7923_state *st = iio_priv(indio_dev); +	int i, cmd, len; + +	len = 0; +	for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) { +		cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) | +			AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) | +			st->settings; +		cmd <<= AD7923_SHIFT_REGISTER; +		st->tx_buf[len++] = cpu_to_be16(cmd); +	} +	/* build spi ring message */ +	st->ring_xfer[0].tx_buf = &st->tx_buf[0]; +	st->ring_xfer[0].len = len; +	st->ring_xfer[0].cs_change = 1; + +	spi_message_init(&st->ring_msg); +	spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); + +	for (i = 0; i < len; i++) { +		st->ring_xfer[i + 1].rx_buf = &st->rx_buf[i]; +		st->ring_xfer[i + 1].len = 2; +		st->ring_xfer[i + 1].cs_change = 1; +		spi_message_add_tail(&st->ring_xfer[i + 1], &st->ring_msg); +	} +	/* make sure last transfer cs_change is not set */ +	st->ring_xfer[i + 1].cs_change = 0; + +	return 0; +} + +/** + * ad7923_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad7923_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad7923_state *st = iio_priv(indio_dev); +	int b_sent; + +	b_sent = spi_sync(st->spi, &st->ring_msg); +	if (b_sent) +		goto done; + +	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, +		iio_get_time_ns()); + +done: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch) +{ +	int ret, cmd; + +	cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(ch) | +		AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) | +		st->settings; +	cmd <<= AD7923_SHIFT_REGISTER; +	st->tx_buf[0] = cpu_to_be16(cmd); + +	ret = spi_sync(st->spi, &st->scan_single_msg); +	if (ret) +		return ret; + +	return be16_to_cpu(st->rx_buf[0]); +} + +static int ad7923_get_range(struct ad7923_state *st) +{ +	int vref; + +	vref = regulator_get_voltage(st->reg); +	if (vref < 0) +		return vref; + +	vref /= 1000; + +	if (!(st->settings & AD7923_RANGE)) +		vref *= 2; + +	return vref; +} + +static int ad7923_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	int ret; +	struct ad7923_state *st = iio_priv(indio_dev); + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		if (iio_buffer_enabled(indio_dev)) +			ret = -EBUSY; +		else +			ret = ad7923_scan_direct(st, chan->address); +		mutex_unlock(&indio_dev->mlock); + +		if (ret < 0) +			return ret; + +		if (chan->address == EXTRACT(ret, 12, 4)) +			*val = EXTRACT(ret, 0, 12); +		else +			return -EIO; + +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		ret = ad7923_get_range(st); +		if (ret < 0) +			return ret; +		*val = ret; +		*val2 = chan->scan_type.realbits; +		return IIO_VAL_FRACTIONAL_LOG2; +	} +	return -EINVAL; +} + +static const struct iio_info ad7923_info = { +	.read_raw = &ad7923_read_raw, +	.update_scan_mode = ad7923_update_scan_mode, +	.driver_module = THIS_MODULE, +}; + +static int ad7923_probe(struct spi_device *spi) +{ +	struct ad7923_state *st; +	struct iio_dev *indio_dev; +	const struct ad7923_chip_info *info; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	spi_set_drvdata(spi, indio_dev); + +	st->spi = spi; +	st->settings = AD7923_CODING | AD7923_RANGE | +			AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS); + +	info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data]; + +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->dev.parent = &spi->dev; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = info->channels; +	indio_dev->num_channels = info->num_channels; +	indio_dev->info = &ad7923_info; + +	/* Setup default message */ + +	st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; +	st->scan_single_xfer[0].len = 2; +	st->scan_single_xfer[0].cs_change = 1; +	st->scan_single_xfer[1].rx_buf = &st->rx_buf[0]; +	st->scan_single_xfer[1].len = 2; + +	spi_message_init(&st->scan_single_msg); +	spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); +	spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); + +	st->reg = devm_regulator_get(&spi->dev, "refin"); +	if (IS_ERR(st->reg)) +		return PTR_ERR(st->reg); + +	ret = regulator_enable(st->reg); +	if (ret) +		return ret; + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +			&ad7923_trigger_handler, NULL); +	if (ret) +		goto error_disable_reg; + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_cleanup_ring; + +	return 0; + +error_cleanup_ring: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: +	regulator_disable(st->reg); + +	return ret; +} + +static int ad7923_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct ad7923_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	regulator_disable(st->reg); + +	return 0; +} + +static const struct spi_device_id ad7923_id[] = { +	{"ad7904", AD7904}, +	{"ad7914", AD7914}, +	{"ad7923", AD7924}, +	{"ad7924", AD7924}, +	{} +}; +MODULE_DEVICE_TABLE(spi, ad7923_id); + +static struct spi_driver ad7923_driver = { +	.driver = { +		.name	= "ad7923", +		.owner	= THIS_MODULE, +	}, +	.probe		= ad7923_probe, +	.remove		= ad7923_remove, +	.id_table	= ad7923_id, +}; +module_spi_driver(ad7923_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>"); +MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c new file mode 100644 index 00000000000..6eba301ee03 --- /dev/null +++ b/drivers/iio/adc/ad799x.c @@ -0,0 +1,795 @@ +/* + * iio/adc/ad799x.c + * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. + * + * based on iio/adc/max1363 + * Copyright (C) 2008-2010 Jonathan Cameron + * + * based on linux/drivers/i2c/chips/max123x + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x.c + * + * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, + * ad7998 and similar chips. + * + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define AD799X_CHANNEL_SHIFT			4 +#define AD799X_STORAGEBITS			16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL				0x08 +#define AD7991_FLTR				0x04 +#define AD7991_BIT_TRIAL_DELAY			0x02 +#define AD7991_SAMPLE_DELAY			0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR				0x08 +#define AD7998_ALERT_EN				0x04 +#define AD7998_BUSY_ALERT			0x02 +#define AD7998_BUSY_ALERT_POL			0x01 + +#define AD7998_CONV_RES_REG			0x0 +#define AD7998_ALERT_STAT_REG			0x1 +#define AD7998_CONF_REG				0x2 +#define AD7998_CYCLE_TMR_REG			0x3 + +#define AD7998_DATALOW_REG(x)			((x) * 3 + 0x4) +#define AD7998_DATAHIGH_REG(x)			((x) * 3 + 0x5) +#define AD7998_HYST_REG(x)			((x) * 3 + 0x6) + +#define AD7998_CYC_MASK				0x7 +#define AD7998_CYC_DIS				0x0 +#define AD7998_CYC_TCONF_32			0x1 +#define AD7998_CYC_TCONF_64			0x2 +#define AD7998_CYC_TCONF_128			0x3 +#define AD7998_CYC_TCONF_256			0x4 +#define AD7998_CYC_TCONF_512			0x5 +#define AD7998_CYC_TCONF_1024			0x6 +#define AD7998_CYC_TCONF_2048			0x7 + +#define AD7998_ALERT_STAT_CLEAR			0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE			0x80 +#define AD7997_8_READ_SEQUENCE			0x70 +/* TODO: move this into a common header */ +#define RES_MASK(bits)	((1 << (bits)) - 1) + +enum { +	ad7991, +	ad7995, +	ad7999, +	ad7992, +	ad7993, +	ad7994, +	ad7997, +	ad7998 +}; + +/** + * struct ad799x_chip_info - chip specific information + * @channel:		channel specification + * @num_channels:	number of channels + * @monitor_mode:	whether the chip supports monitor interrupts + * @default_config:	device default configuration + * @event_attrs:	pointer to the monitor event attribute group + */ +struct ad799x_chip_info { +	struct iio_chan_spec		channel[9]; +	int				num_channels; +	u16				default_config; +	const struct iio_info		*info; +}; + +struct ad799x_state { +	struct i2c_client		*client; +	const struct ad799x_chip_info	*chip_info; +	struct regulator		*reg; +	struct regulator		*vref; +	unsigned			id; +	u16				config; + +	u8				*rx_buf; +	unsigned int			transfer_size; +}; + +/** + * ad799x_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad799x_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad799x_state *st = iio_priv(indio_dev); +	int b_sent; +	u8 cmd; + +	switch (st->id) { +	case ad7991: +	case ad7995: +	case ad7999: +		cmd = st->config | +			(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT); +		break; +	case ad7992: +	case ad7993: +	case ad7994: +		cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) | +			AD7998_CONV_RES_REG; +		break; +	case ad7997: +	case ad7998: +		cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; +		break; +	default: +		cmd = 0; +	} + +	b_sent = i2c_smbus_read_i2c_block_data(st->client, +			cmd, st->transfer_size, st->rx_buf); +	if (b_sent < 0) +		goto out; + +	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, +			iio_get_time_ns()); +out: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +/* + * ad799x register access by I2C + */ +static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) +{ +	struct i2c_client *client = st->client; +	int ret = 0; + +	ret = i2c_smbus_read_word_swapped(client, reg); +	if (ret < 0) { +		dev_err(&client->dev, "I2C read error\n"); +		return ret; +	} + +	*data = (u16)ret; + +	return 0; +} + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) +{ +	struct i2c_client *client = st->client; +	int ret = 0; + +	ret = i2c_smbus_read_byte_data(client, reg); +	if (ret < 0) { +		dev_err(&client->dev, "I2C read error\n"); +		return ret; +	} + +	*data = (u8)ret; + +	return 0; +} + +static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) +{ +	struct i2c_client *client = st->client; +	int ret = 0; + +	ret = i2c_smbus_write_word_swapped(client, reg, data); +	if (ret < 0) +		dev_err(&client->dev, "I2C write error\n"); + +	return ret; +} + +static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) +{ +	struct i2c_client *client = st->client; +	int ret = 0; + +	ret = i2c_smbus_write_byte_data(client, reg, data); +	if (ret < 0) +		dev_err(&client->dev, "I2C write error\n"); + +	return ret; +} + +static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, +	const unsigned long *scan_mask) +{ +	struct ad799x_state *st = iio_priv(indio_dev); + +	kfree(st->rx_buf); +	st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); +	if (!st->rx_buf) +		return -ENOMEM; + +	st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2; + +	switch (st->id) { +	case ad7997: +	case ad7998: +		return ad799x_i2c_write16(st, AD7998_CONF_REG, +			st->config | (*scan_mask << AD799X_CHANNEL_SHIFT)); +	default: +		break; +	} + +	return 0; +} + +static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) +{ +	u16 rxbuf; +	u8 cmd; +	int ret; + +	switch (st->id) { +	case ad7991: +	case ad7995: +	case ad7999: +		cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT); +		break; +	case ad7992: +	case ad7993: +	case ad7994: +		cmd = (1 << ch) << AD799X_CHANNEL_SHIFT; +		break; +	case ad7997: +	case ad7998: +		cmd = (ch << AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE; +		break; +	default: +		return -EINVAL; +	} + +	ret = ad799x_i2c_read16(st, cmd, &rxbuf); +	if (ret < 0) +		return ret; + +	return rxbuf; +} + +static int ad799x_read_raw(struct iio_dev *indio_dev, +			   struct iio_chan_spec const *chan, +			   int *val, +			   int *val2, +			   long m) +{ +	int ret; +	struct ad799x_state *st = iio_priv(indio_dev); + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		if (iio_buffer_enabled(indio_dev)) +			ret = -EBUSY; +		else +			ret = ad799x_scan_direct(st, chan->scan_index); +		mutex_unlock(&indio_dev->mlock); + +		if (ret < 0) +			return ret; +		*val = (ret >> chan->scan_type.shift) & +			RES_MASK(chan->scan_type.realbits); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		ret = regulator_get_voltage(st->vref); +		if (ret < 0) +			return ret; +		*val = ret / 1000; +		*val2 = chan->scan_type.realbits; +		return IIO_VAL_FRACTIONAL_LOG2; +	} +	return -EINVAL; +} +static const unsigned int ad7998_frequencies[] = { +	[AD7998_CYC_DIS]	= 0, +	[AD7998_CYC_TCONF_32]	= 15625, +	[AD7998_CYC_TCONF_64]	= 7812, +	[AD7998_CYC_TCONF_128]	= 3906, +	[AD7998_CYC_TCONF_512]	= 976, +	[AD7998_CYC_TCONF_1024]	= 488, +	[AD7998_CYC_TCONF_2048]	= 244, +}; +static ssize_t ad799x_read_frequency(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad799x_state *st = iio_priv(indio_dev); + +	int ret; +	u8 val; +	ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); +	if (ret) +		return ret; + +	val &= AD7998_CYC_MASK; + +	return sprintf(buf, "%u\n", ad7998_frequencies[val]); +} + +static ssize_t ad799x_write_frequency(struct device *dev, +					 struct device_attribute *attr, +					 const char *buf, +					 size_t len) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct ad799x_state *st = iio_priv(indio_dev); + +	long val; +	int ret, i; +	u8 t; + +	ret = kstrtol(buf, 10, &val); +	if (ret) +		return ret; + +	mutex_lock(&indio_dev->mlock); +	ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); +	if (ret) +		goto error_ret_mutex; +	/* Wipe the bits clean */ +	t &= ~AD7998_CYC_MASK; + +	for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) +		if (val == ad7998_frequencies[i]) +			break; +	if (i == ARRAY_SIZE(ad7998_frequencies)) { +		ret = -EINVAL; +		goto error_ret_mutex; +	} +	t |= i; +	ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + +error_ret_mutex: +	mutex_unlock(&indio_dev->mlock); + +	return ret ? ret : len; +} + +static int ad799x_read_event_config(struct iio_dev *indio_dev, +				    const struct iio_chan_spec *chan, +				    enum iio_event_type type, +				    enum iio_event_direction dir) +{ +	return 1; +} + +static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, +					 enum iio_event_direction dir, +					 enum iio_event_info info) +{ +	switch (info) { +	case IIO_EV_INFO_VALUE: +		if (dir == IIO_EV_DIR_FALLING) +			return AD7998_DATALOW_REG(chan->channel); +		else +			return AD7998_DATAHIGH_REG(chan->channel); +	case IIO_EV_INFO_HYSTERESIS: +		return AD7998_HYST_REG(chan->channel); +	default: +		return -EINVAL; +	} + +	return 0; +} + +static int ad799x_write_event_value(struct iio_dev *indio_dev, +				    const struct iio_chan_spec *chan, +				    enum iio_event_type type, +				    enum iio_event_direction dir, +				    enum iio_event_info info, +				    int val, int val2) +{ +	int ret; +	struct ad799x_state *st = iio_priv(indio_dev); + +	if (val < 0 || val > RES_MASK(chan->scan_type.realbits)) +		return -EINVAL; + +	mutex_lock(&indio_dev->mlock); +	ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), +		val << chan->scan_type.shift); +	mutex_unlock(&indio_dev->mlock); + +	return ret; +} + +static int ad799x_read_event_value(struct iio_dev *indio_dev, +				    const struct iio_chan_spec *chan, +				    enum iio_event_type type, +				    enum iio_event_direction dir, +				    enum iio_event_info info, +				    int *val, int *val2) +{ +	int ret; +	struct ad799x_state *st = iio_priv(indio_dev); +	u16 valin; + +	mutex_lock(&indio_dev->mlock); +	ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), +		&valin); +	mutex_unlock(&indio_dev->mlock); +	if (ret < 0) +		return ret; +	*val = (valin >> chan->scan_type.shift) & +		RES_MASK(chan->scan_type.realbits); + +	return IIO_VAL_INT; +} + +static irqreturn_t ad799x_event_handler(int irq, void *private) +{ +	struct iio_dev *indio_dev = private; +	struct ad799x_state *st = iio_priv(private); +	u8 status; +	int i, ret; + +	ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status); +	if (ret) +		goto done; + +	if (!status) +		goto done; + +	ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); + +	for (i = 0; i < 8; i++) { +		if (status & (1 << i)) +			iio_push_event(indio_dev, +				       i & 0x1 ? +				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, +							    (i >> 1), +							    IIO_EV_TYPE_THRESH, +							    IIO_EV_DIR_RISING) : +				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, +							    (i >> 1), +							    IIO_EV_TYPE_THRESH, +							    IIO_EV_DIR_FALLING), +				       iio_get_time_ns()); +	} + +done: +	return IRQ_HANDLED; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +			      ad799x_read_frequency, +			      ad799x_write_frequency); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); + +static struct attribute *ad799x_event_attributes[] = { +	&iio_dev_attr_sampling_frequency.dev_attr.attr, +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	NULL, +}; + +static struct attribute_group ad799x_event_attrs_group = { +	.attrs = ad799x_event_attributes, +	.name = "events", +}; + +static const struct iio_info ad7991_info = { +	.read_raw = &ad799x_read_raw, +	.driver_module = THIS_MODULE, +}; + +static const struct iio_info ad7993_4_7_8_info = { +	.read_raw = &ad799x_read_raw, +	.event_attrs = &ad799x_event_attrs_group, +	.read_event_config = &ad799x_read_event_config, +	.read_event_value = &ad799x_read_event_value, +	.write_event_value = &ad799x_write_event_value, +	.driver_module = THIS_MODULE, +	.update_scan_mode = ad7997_8_update_scan_mode, +}; + +static const struct iio_event_spec ad799x_events[] = { +	{ +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_RISING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE) | +			BIT(IIO_EV_INFO_ENABLE), +	}, { +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_FALLING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE) | +			BIT(IIO_EV_INFO_ENABLE), +	}, { +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_EITHER, +		.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), +	}, +}; + +#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \ +	.type = IIO_VOLTAGE, \ +	.indexed = 1, \ +	.channel = (_index), \ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +	.scan_index = (_index), \ +	.scan_type = { \ +		.sign = 'u', \ +		.realbits = (_realbits), \ +		.storagebits = 16, \ +		.shift = 12 - (_realbits), \ +		.endianness = IIO_BE, \ +	}, \ +	.event_spec = _ev_spec, \ +	.num_event_specs = _num_ev_spec, \ +} + +#define AD799X_CHANNEL(_index, _realbits) \ +	_AD799X_CHANNEL(_index, _realbits, NULL, 0) + +#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \ +	_AD799X_CHANNEL(_index, _realbits, ad799x_events, \ +		ARRAY_SIZE(ad799x_events)) + +static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { +	[ad7991] = { +		.channel = { +			AD799X_CHANNEL(0, 12), +			AD799X_CHANNEL(1, 12), +			AD799X_CHANNEL(2, 12), +			AD799X_CHANNEL(3, 12), +			IIO_CHAN_SOFT_TIMESTAMP(4), +		}, +		.num_channels = 5, +		.info = &ad7991_info, +	}, +	[ad7995] = { +		.channel = { +			AD799X_CHANNEL(0, 10), +			AD799X_CHANNEL(1, 10), +			AD799X_CHANNEL(2, 10), +			AD799X_CHANNEL(3, 10), +			IIO_CHAN_SOFT_TIMESTAMP(4), +		}, +		.num_channels = 5, +		.info = &ad7991_info, +	}, +	[ad7999] = { +		.channel = { +			AD799X_CHANNEL(0, 8), +			AD799X_CHANNEL(1, 8), +			AD799X_CHANNEL(2, 8), +			AD799X_CHANNEL(3, 8), +			IIO_CHAN_SOFT_TIMESTAMP(4), +		}, +		.num_channels = 5, +		.info = &ad7991_info, +	}, +	[ad7992] = { +		.channel = { +			AD799X_CHANNEL_WITH_EVENTS(0, 12), +			AD799X_CHANNEL_WITH_EVENTS(1, 12), +			IIO_CHAN_SOFT_TIMESTAMP(3), +		}, +		.num_channels = 3, +		.default_config = AD7998_ALERT_EN, +		.info = &ad7993_4_7_8_info, +	}, +	[ad7993] = { +		.channel = { +			AD799X_CHANNEL_WITH_EVENTS(0, 10), +			AD799X_CHANNEL_WITH_EVENTS(1, 10), +			AD799X_CHANNEL_WITH_EVENTS(2, 10), +			AD799X_CHANNEL_WITH_EVENTS(3, 10), +			IIO_CHAN_SOFT_TIMESTAMP(4), +		}, +		.num_channels = 5, +		.default_config = AD7998_ALERT_EN, +		.info = &ad7993_4_7_8_info, +	}, +	[ad7994] = { +		.channel = { +			AD799X_CHANNEL_WITH_EVENTS(0, 12), +			AD799X_CHANNEL_WITH_EVENTS(1, 12), +			AD799X_CHANNEL_WITH_EVENTS(2, 12), +			AD799X_CHANNEL_WITH_EVENTS(3, 12), +			IIO_CHAN_SOFT_TIMESTAMP(4), +		}, +		.num_channels = 5, +		.default_config = AD7998_ALERT_EN, +		.info = &ad7993_4_7_8_info, +	}, +	[ad7997] = { +		.channel = { +			AD799X_CHANNEL_WITH_EVENTS(0, 10), +			AD799X_CHANNEL_WITH_EVENTS(1, 10), +			AD799X_CHANNEL_WITH_EVENTS(2, 10), +			AD799X_CHANNEL_WITH_EVENTS(3, 10), +			AD799X_CHANNEL(4, 10), +			AD799X_CHANNEL(5, 10), +			AD799X_CHANNEL(6, 10), +			AD799X_CHANNEL(7, 10), +			IIO_CHAN_SOFT_TIMESTAMP(8), +		}, +		.num_channels = 9, +		.default_config = AD7998_ALERT_EN, +		.info = &ad7993_4_7_8_info, +	}, +	[ad7998] = { +		.channel = { +			AD799X_CHANNEL_WITH_EVENTS(0, 12), +			AD799X_CHANNEL_WITH_EVENTS(1, 12), +			AD799X_CHANNEL_WITH_EVENTS(2, 12), +			AD799X_CHANNEL_WITH_EVENTS(3, 12), +			AD799X_CHANNEL(4, 12), +			AD799X_CHANNEL(5, 12), +			AD799X_CHANNEL(6, 12), +			AD799X_CHANNEL(7, 12), +			IIO_CHAN_SOFT_TIMESTAMP(8), +		}, +		.num_channels = 9, +		.default_config = AD7998_ALERT_EN, +		.info = &ad7993_4_7_8_info, +	}, +}; + +static int ad799x_probe(struct i2c_client *client, +				   const struct i2c_device_id *id) +{ +	int ret; +	struct ad799x_state *st; +	struct iio_dev *indio_dev; + +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); +	/* this is only used for device removal purposes */ +	i2c_set_clientdata(client, indio_dev); + +	st->id = id->driver_data; +	st->chip_info = &ad799x_chip_info_tbl[st->id]; +	st->config = st->chip_info->default_config; + +	/* TODO: Add pdata options for filtering and bit delay */ + +	st->reg = devm_regulator_get(&client->dev, "vcc"); +	if (IS_ERR(st->reg)) +		return PTR_ERR(st->reg); +	ret = regulator_enable(st->reg); +	if (ret) +		return ret; +	st->vref = devm_regulator_get(&client->dev, "vref"); +	if (IS_ERR(st->vref)) { +		ret = PTR_ERR(st->vref); +		goto error_disable_reg; +	} +	ret = regulator_enable(st->vref); +	if (ret) +		goto error_disable_reg; + +	st->client = client; + +	indio_dev->dev.parent = &client->dev; +	indio_dev->name = id->name; +	indio_dev->info = st->chip_info->info; + +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = st->chip_info->channel; +	indio_dev->num_channels = st->chip_info->num_channels; + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +		&ad799x_trigger_handler, NULL); +	if (ret) +		goto error_disable_vref; + +	if (client->irq > 0) { +		ret = devm_request_threaded_irq(&client->dev, +						client->irq, +						NULL, +						ad799x_event_handler, +						IRQF_TRIGGER_FALLING | +						IRQF_ONESHOT, +						client->name, +						indio_dev); +		if (ret) +			goto error_cleanup_ring; +	} +	ret = iio_device_register(indio_dev); +	if (ret) +		goto error_cleanup_ring; + +	return 0; + +error_cleanup_ring: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_vref: +	regulator_disable(st->vref); +error_disable_reg: +	regulator_disable(st->reg); + +	return ret; +} + +static int ad799x_remove(struct i2c_client *client) +{ +	struct iio_dev *indio_dev = i2c_get_clientdata(client); +	struct ad799x_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); + +	iio_triggered_buffer_cleanup(indio_dev); +	regulator_disable(st->vref); +	regulator_disable(st->reg); +	kfree(st->rx_buf); + +	return 0; +} + +static const struct i2c_device_id ad799x_id[] = { +	{ "ad7991", ad7991 }, +	{ "ad7995", ad7995 }, +	{ "ad7999", ad7999 }, +	{ "ad7992", ad7992 }, +	{ "ad7993", ad7993 }, +	{ "ad7994", ad7994 }, +	{ "ad7997", ad7997 }, +	{ "ad7998", ad7998 }, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_id); + +static struct i2c_driver ad799x_driver = { +	.driver = { +		.name = "ad799x", +	}, +	.probe = ad799x_probe, +	.remove = ad799x_remove, +	.id_table = ad799x_id, +}; +module_i2c_driver(ad799x_driver); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD799x ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c new file mode 100644 index 00000000000..9a4e0e32a77 --- /dev/null +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -0,0 +1,553 @@ +/* + * Support code for Analog Devices Sigma-Delta ADCs + * + * Copyright 2012 Analog Devices Inc. + *  Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> + +#include <asm/unaligned.h> + + +#define AD_SD_COMM_CHAN_MASK	0x3 + +#define AD_SD_REG_COMM		0x00 +#define AD_SD_REG_DATA		0x03 + +/** + * ad_sd_set_comm() - Set communications register + * + * @sigma_delta: The sigma delta device + * @comm: New value for the communications register + */ +void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm) +{ +	/* Some variants use the lower two bits of the communications register +	 * to select the channel */ +	sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK; +} +EXPORT_SYMBOL_GPL(ad_sd_set_comm); + +/** + * ad_sd_write_reg() - Write a register + * + * @sigma_delta: The sigma delta device + * @reg: Address of the register + * @size: Size of the register (0-3) + * @val: Value to write to the register + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, +	unsigned int size, unsigned int val) +{ +	uint8_t *data = sigma_delta->data; +	struct spi_transfer t = { +		.tx_buf		= data, +		.len		= size + 1, +		.cs_change	= sigma_delta->bus_locked, +	}; +	struct spi_message m; +	int ret; + +	data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm; + +	switch (size) { +	case 3: +		data[1] = val >> 16; +		data[2] = val >> 8; +		data[3] = val; +		break; +	case 2: +		put_unaligned_be16(val, &data[1]); +		break; +	case 1: +		data[1] = val; +		break; +	case 0: +		break; +	default: +		return -EINVAL; +	} + +	spi_message_init(&m); +	spi_message_add_tail(&t, &m); + +	if (sigma_delta->bus_locked) +		ret = spi_sync_locked(sigma_delta->spi, &m); +	else +		ret = spi_sync(sigma_delta->spi, &m); + +	return ret; +} +EXPORT_SYMBOL_GPL(ad_sd_write_reg); + +static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, +	unsigned int reg, unsigned int size, uint8_t *val) +{ +	uint8_t *data = sigma_delta->data; +	int ret; +	struct spi_transfer t[] = { +		{ +			.tx_buf = data, +			.len = 1, +		}, { +			.rx_buf = val, +			.len = size, +			.cs_change = sigma_delta->bus_locked, +		}, +	}; +	struct spi_message m; + +	spi_message_init(&m); + +	if (sigma_delta->info->has_registers) { +		data[0] = reg << sigma_delta->info->addr_shift; +		data[0] |= sigma_delta->info->read_mask; +		spi_message_add_tail(&t[0], &m); +	} +	spi_message_add_tail(&t[1], &m); + +	if (sigma_delta->bus_locked) +		ret = spi_sync_locked(sigma_delta->spi, &m); +	else +		ret = spi_sync(sigma_delta->spi, &m); + +	return ret; +} + +/** + * ad_sd_read_reg() - Read a register + * + * @sigma_delta: The sigma delta device + * @reg: Address of the register + * @size: Size of the register (1-4) + * @val: Read value + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, +	unsigned int reg, unsigned int size, unsigned int *val) +{ +	int ret; + +	ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data); +	if (ret < 0) +		goto out; + +	switch (size) { +	case 4: +		*val = get_unaligned_be32(sigma_delta->data); +		break; +	case 3: +		*val = (sigma_delta->data[0] << 16) | +			(sigma_delta->data[1] << 8) | +			sigma_delta->data[2]; +		break; +	case 2: +		*val = get_unaligned_be16(sigma_delta->data); +		break; +	case 1: +		*val = sigma_delta->data[0]; +		break; +	default: +		ret = -EINVAL; +		break; +	} + +out: +	return ret; +} +EXPORT_SYMBOL_GPL(ad_sd_read_reg); + +static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, +	unsigned int mode, unsigned int channel) +{ +	int ret; + +	ret = ad_sigma_delta_set_channel(sigma_delta, channel); +	if (ret) +		return ret; + +	spi_bus_lock(sigma_delta->spi->master); +	sigma_delta->bus_locked = true; +	reinit_completion(&sigma_delta->completion); + +	ret = ad_sigma_delta_set_mode(sigma_delta, mode); +	if (ret < 0) +		goto out; + +	sigma_delta->irq_dis = false; +	enable_irq(sigma_delta->spi->irq); +	ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ); +	if (ret == 0) { +		sigma_delta->irq_dis = true; +		disable_irq_nosync(sigma_delta->spi->irq); +		ret = -EIO; +	} else { +		ret = 0; +	} +out: +	sigma_delta->bus_locked = false; +	spi_bus_unlock(sigma_delta->spi->master); +	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + +	return ret; +} + +/** + * ad_sd_calibrate_all() - Performs channel calibration + * @sigma_delta: The sigma delta device + * @cb: Array of channels and calibration type to perform + * @n: Number of items in cb + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta, +	const struct ad_sd_calib_data *cb, unsigned int n) +{ +	unsigned int i; +	int ret; + +	for (i = 0; i < n; i++) { +		ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel); +		if (ret) +			return ret; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_calibrate_all); + +/** + * ad_sigma_delta_single_conversion() - Performs a single data conversion + * @indio_dev: The IIO device + * @chan: The conversion is done for this channel + * @val: Pointer to the location where to store the read value + * + * Returns: 0 on success, an error value otherwise. + */ +int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, int *val) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); +	unsigned int sample, raw_sample; +	int ret = 0; + +	if (iio_buffer_enabled(indio_dev)) +		return -EBUSY; + +	mutex_lock(&indio_dev->mlock); +	ad_sigma_delta_set_channel(sigma_delta, chan->address); + +	spi_bus_lock(sigma_delta->spi->master); +	sigma_delta->bus_locked = true; +	reinit_completion(&sigma_delta->completion); + +	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); + +	sigma_delta->irq_dis = false; +	enable_irq(sigma_delta->spi->irq); +	ret = wait_for_completion_interruptible_timeout( +			&sigma_delta->completion, HZ); + +	sigma_delta->bus_locked = false; +	spi_bus_unlock(sigma_delta->spi->master); + +	if (ret == 0) +		ret = -EIO; +	if (ret < 0) +		goto out; + +	ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA, +		DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8), +		&raw_sample); + +out: +	if (!sigma_delta->irq_dis) { +		disable_irq_nosync(sigma_delta->spi->irq); +		sigma_delta->irq_dis = true; +	} + +	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); +	mutex_unlock(&indio_dev->mlock); + +	if (ret) +		return ret; + +	sample = raw_sample >> chan->scan_type.shift; +	sample &= (1 << chan->scan_type.realbits) - 1; +	*val = sample; + +	ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample); +	if (ret) +		return ret; + +	return IIO_VAL_INT; +} +EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion); + +static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); +	unsigned int channel; +	int ret; + +	ret = iio_triggered_buffer_postenable(indio_dev); +	if (ret < 0) +		return ret; + +	channel = find_first_bit(indio_dev->active_scan_mask, +				 indio_dev->masklength); +	ret = ad_sigma_delta_set_channel(sigma_delta, +		indio_dev->channels[channel].address); +	if (ret) +		goto err_predisable; + +	spi_bus_lock(sigma_delta->spi->master); +	sigma_delta->bus_locked = true; +	ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); +	if (ret) +		goto err_unlock; + +	sigma_delta->irq_dis = false; +	enable_irq(sigma_delta->spi->irq); + +	return 0; + +err_unlock: +	spi_bus_unlock(sigma_delta->spi->master); +err_predisable: + +	return ret; +} + +static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + +	reinit_completion(&sigma_delta->completion); +	wait_for_completion_timeout(&sigma_delta->completion, HZ); + +	if (!sigma_delta->irq_dis) { +		disable_irq_nosync(sigma_delta->spi->irq); +		sigma_delta->irq_dis = true; +	} + +	ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + +	sigma_delta->bus_locked = false; +	return spi_bus_unlock(sigma_delta->spi->master); +} + +static irqreturn_t ad_sd_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); +	unsigned int reg_size; +	uint8_t data[16]; +	int ret; + +	memset(data, 0x00, 16); + +	reg_size = indio_dev->channels[0].scan_type.realbits + +			indio_dev->channels[0].scan_type.shift; +	reg_size = DIV_ROUND_UP(reg_size, 8); + +	switch (reg_size) { +	case 4: +	case 2: +	case 1: +		ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA, +			reg_size, &data[0]); +		break; +	case 3: +		/* We store 24 bit samples in a 32 bit word. Keep the upper +		 * byte set to zero. */ +		ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA, +			reg_size, &data[1]); +		break; +	} + +	iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); + +	iio_trigger_notify_done(indio_dev->trig); +	sigma_delta->irq_dis = false; +	enable_irq(sigma_delta->spi->irq); + +	return IRQ_HANDLED; +} + +static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = { +	.postenable = &ad_sd_buffer_postenable, +	.predisable = &iio_triggered_buffer_predisable, +	.postdisable = &ad_sd_buffer_postdisable, +	.validate_scan_mask = &iio_validate_scan_mask_onehot, +}; + +static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private) +{ +	struct ad_sigma_delta *sigma_delta = private; + +	complete(&sigma_delta->completion); +	disable_irq_nosync(irq); +	sigma_delta->irq_dis = true; +	iio_trigger_poll(sigma_delta->trig, iio_get_time_ns()); + +	return IRQ_HANDLED; +} + +/** + * ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices + * @indio_dev: The IIO device + * @trig: The new trigger + * + * Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta + * device, -EINVAL otherwise. + */ +int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + +	if (sigma_delta->trig != trig) +		return -EINVAL; + +	return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_validate_trigger); + +static const struct iio_trigger_ops ad_sd_trigger_ops = { +	.owner = THIS_MODULE, +}; + +static int ad_sd_probe_trigger(struct iio_dev *indio_dev) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); +	int ret; + +	sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, +						indio_dev->id); +	if (sigma_delta->trig == NULL) { +		ret = -ENOMEM; +		goto error_ret; +	} +	sigma_delta->trig->ops = &ad_sd_trigger_ops; +	init_completion(&sigma_delta->completion); + +	ret = request_irq(sigma_delta->spi->irq, +			  ad_sd_data_rdy_trig_poll, +			  IRQF_TRIGGER_LOW, +			  indio_dev->name, +			  sigma_delta); +	if (ret) +		goto error_free_trig; + +	if (!sigma_delta->irq_dis) { +		sigma_delta->irq_dis = true; +		disable_irq_nosync(sigma_delta->spi->irq); +	} +	sigma_delta->trig->dev.parent = &sigma_delta->spi->dev; +	iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta); + +	ret = iio_trigger_register(sigma_delta->trig); +	if (ret) +		goto error_free_irq; + +	/* select default trigger */ +	indio_dev->trig = sigma_delta->trig; + +	return 0; + +error_free_irq: +	free_irq(sigma_delta->spi->irq, sigma_delta); +error_free_trig: +	iio_trigger_free(sigma_delta->trig); +error_ret: +	return ret; +} + +static void ad_sd_remove_trigger(struct iio_dev *indio_dev) +{ +	struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + +	iio_trigger_unregister(sigma_delta->trig); +	free_irq(sigma_delta->spi->irq, sigma_delta); +	iio_trigger_free(sigma_delta->trig); +} + +/** + * ad_sd_setup_buffer_and_trigger() - + * @indio_dev: The IIO device + */ +int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev) +{ +	int ret; + +	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, +			&ad_sd_trigger_handler, &ad_sd_buffer_setup_ops); +	if (ret) +		return ret; + +	ret = ad_sd_probe_trigger(indio_dev); +	if (ret) { +		iio_triggered_buffer_cleanup(indio_dev); +		return ret; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger); + +/** + * ad_sd_cleanup_buffer_and_trigger() - + * @indio_dev: The IIO device + */ +void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev) +{ +	ad_sd_remove_trigger(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +} +EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger); + +/** + * ad_sd_init() - Initializes a ad_sigma_delta struct + * @sigma_delta: The ad_sigma_delta device + * @indio_dev: The IIO device which the Sigma Delta device is used for + * @spi: The SPI device for the ad_sigma_delta device + * @info: Device specific callbacks and options + * + * This function needs to be called before any other operations are performed on + * the ad_sigma_delta struct. + */ +int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, +	struct spi_device *spi, const struct ad_sigma_delta_info *info) +{ +	sigma_delta->spi = spi; +	sigma_delta->info = info; +	iio_device_set_drvdata(indio_dev, sigma_delta); + +	return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_init); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c new file mode 100644 index 00000000000..2b6a9ce9927 --- /dev/null +++ b/drivers/iio/adc/at91_adc.c @@ -0,0 +1,1437 @@ +/* + * Driver for the ADC present in the Atmel AT91 evaluation boards. + * + * Copyright 2011 Free Electrons + * + * Licensed under the GPLv2 or later. + */ + +#include <linux/bitmap.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/wait.h> + +#include <linux/platform_data/at91_adc.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +/* Registers */ +#define AT91_ADC_CR		0x00		/* Control Register */ +#define		AT91_ADC_SWRST		(1 << 0)	/* Software Reset */ +#define		AT91_ADC_START		(1 << 1)	/* Start Conversion */ + +#define AT91_ADC_MR		0x04		/* Mode Register */ +#define		AT91_ADC_TSAMOD		(3 << 0)	/* ADC mode */ +#define		AT91_ADC_TSAMOD_ADC_ONLY_MODE		(0 << 0)	/* ADC Mode */ +#define		AT91_ADC_TSAMOD_TS_ONLY_MODE		(1 << 0)	/* Touch Screen Only Mode */ +#define		AT91_ADC_TRGEN		(1 << 0)	/* Trigger Enable */ +#define		AT91_ADC_TRGSEL		(7 << 1)	/* Trigger Selection */ +#define			AT91_ADC_TRGSEL_TC0		(0 << 1) +#define			AT91_ADC_TRGSEL_TC1		(1 << 1) +#define			AT91_ADC_TRGSEL_TC2		(2 << 1) +#define			AT91_ADC_TRGSEL_EXTERNAL	(6 << 1) +#define		AT91_ADC_LOWRES		(1 << 4)	/* Low Resolution */ +#define		AT91_ADC_SLEEP		(1 << 5)	/* Sleep Mode */ +#define		AT91_ADC_PENDET		(1 << 6)	/* Pen contact detection enable */ +#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)	/* Prescalar Rate Selection */ +#define		AT91_ADC_PRESCAL_9G45	(0xff << 8) +#define			AT91_ADC_PRESCAL_(x)	((x) << 8) +#define		AT91_ADC_STARTUP_9260	(0x1f << 16)	/* Startup Up Time */ +#define		AT91_ADC_STARTUP_9G45	(0x7f << 16) +#define		AT91_ADC_STARTUP_9X5	(0xf << 16) +#define			AT91_ADC_STARTUP_(x)	((x) << 16) +#define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */ +#define			AT91_ADC_SHTIM_(x)	((x) << 24) +#define		AT91_ADC_PENDBC		(0x0f << 28)	/* Pen Debounce time */ +#define			AT91_ADC_PENDBC_(x)	((x) << 28) + +#define AT91_ADC_TSR		0x0C +#define		AT91_ADC_TSR_SHTIM	(0xf  << 24)	/* Sample & Hold Time */ +#define			AT91_ADC_TSR_SHTIM_(x)	((x) << 24) + +#define AT91_ADC_CHER		0x10		/* Channel Enable Register */ +#define AT91_ADC_CHDR		0x14		/* Channel Disable Register */ +#define AT91_ADC_CHSR		0x18		/* Channel Status Register */ +#define		AT91_ADC_CH(n)		(1 << (n))	/* Channel Number */ + +#define AT91_ADC_SR		0x1C		/* Status Register */ +#define		AT91_ADC_EOC(n)		(1 << (n))	/* End of Conversion on Channel N */ +#define		AT91_ADC_OVRE(n)	(1 << ((n) + 8))/* Overrun Error on Channel N */ +#define		AT91_ADC_DRDY		(1 << 16)	/* Data Ready */ +#define		AT91_ADC_GOVRE		(1 << 17)	/* General Overrun Error */ +#define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */ +#define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */ + +#define AT91_ADC_SR_9X5		0x30		/* Status Register for 9x5 */ +#define		AT91_ADC_SR_DRDY_9X5	(1 << 24)	/* Data Ready */ + +#define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */ +#define		AT91_ADC_LDATA		(0x3ff) + +#define AT91_ADC_IER		0x24		/* Interrupt Enable Register */ +#define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */ +#define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */ +#define		AT91RL_ADC_IER_PEN	(1 << 20) +#define		AT91RL_ADC_IER_NOPEN	(1 << 21) +#define		AT91_ADC_IER_PEN	(1 << 29) +#define		AT91_ADC_IER_NOPEN	(1 << 30) +#define		AT91_ADC_IER_XRDY	(1 << 20) +#define		AT91_ADC_IER_YRDY	(1 << 21) +#define		AT91_ADC_IER_PRDY	(1 << 22) +#define		AT91_ADC_ISR_PENS	(1 << 31) + +#define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */ +#define		AT91_ADC_DATA		(0x3ff) + +#define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */ + +#define AT91_ADC_ACR		0x94	/* Analog Control Register */ +#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */ + +#define AT91_ADC_TSMR		0xB0 +#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */ +#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0) +#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0) +#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0) +#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0) +#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */ +#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4) +#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */ +#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */ +#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28) +#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */ +#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */ +#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */ + +#define AT91_ADC_TSXPOSR	0xB4 +#define AT91_ADC_TSYPOSR	0xB8 +#define AT91_ADC_TSPRESSR	0xBC + +#define AT91_ADC_TRGR_9260	AT91_ADC_MR +#define AT91_ADC_TRGR_9G45	0x08 +#define AT91_ADC_TRGR_9X5	0xC0 + +/* Trigger Register bit field */ +#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16) +#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16) +#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0) +#define			AT91_ADC_TRGR_NONE		(0 << 0) +#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0) + +#define AT91_ADC_CHAN(st, ch) \ +	(st->registers->channel_base + (ch * 4)) +#define at91_adc_readl(st, reg) \ +	(readl_relaxed(st->reg_base + reg)) +#define at91_adc_writel(st, reg, val) \ +	(writel_relaxed(val, st->reg_base + reg)) + +#define DRIVER_NAME		"at91_adc" +#define MAX_POS_BITS		12 + +#define TOUCH_SAMPLE_PERIOD_US		2000	/* 2ms */ +#define TOUCH_PEN_DETECT_DEBOUNCE_US	200 + +#define MAX_RLPOS_BITS         10 +#define TOUCH_SAMPLE_PERIOD_US_RL      10000   /* 10ms, the SoC can't keep up with 2ms */ +#define TOUCH_SHTIM                    0xa + +/** + * struct at91_adc_reg_desc - Various informations relative to registers + * @channel_base:	Base offset for the channel data registers + * @drdy_mask:		Mask of the DRDY field in the relevant registers +			(Interruptions registers mostly) + * @status_register:	Offset of the Interrupt Status Register + * @trigger_register:	Offset of the Trigger setup register + * @mr_prescal_mask:	Mask of the PRESCAL field in the adc MR register + * @mr_startup_mask:	Mask of the STARTUP field in the adc MR register + */ +struct at91_adc_reg_desc { +	u8	channel_base; +	u32	drdy_mask; +	u8	status_register; +	u8	trigger_register; +	u32	mr_prescal_mask; +	u32	mr_startup_mask; +}; + +struct at91_adc_caps { +	bool	has_ts;		/* Support touch screen */ +	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */ +	/* +	 * Numbers of sampling data will be averaged. Can be 0~3. +	 * Hardware can average (2 ^ ts_filter_average) sample data. +	 */ +	u8	ts_filter_average; +	/* Pen Detection input pull-up resistor, can be 0~3 */ +	u8	ts_pen_detect_sensitivity; + +	/* startup time calculate function */ +	u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz); + +	u8	num_channels; +	struct at91_adc_reg_desc registers; +}; + +struct at91_adc_state { +	struct clk		*adc_clk; +	u16			*buffer; +	unsigned long		channels_mask; +	struct clk		*clk; +	bool			done; +	int			irq; +	u16			last_value; +	struct mutex		lock; +	u8			num_channels; +	void __iomem		*reg_base; +	struct at91_adc_reg_desc *registers; +	u8			startup_time; +	u8			sample_hold_time; +	bool			sleep_mode; +	struct iio_trigger	**trig; +	struct at91_adc_trigger	*trigger_list; +	u32			trigger_number; +	bool			use_external; +	u32			vref_mv; +	u32			res;		/* resolution used for convertions */ +	bool			low_res;	/* the resolution corresponds to the lowest one */ +	wait_queue_head_t	wq_data_avail; +	struct at91_adc_caps	*caps; + +	/* +	 * Following ADC channels are shared by touchscreen: +	 * +	 * CH0 -- Touch screen XP/UL +	 * CH1 -- Touch screen XM/UR +	 * CH2 -- Touch screen YP/LL +	 * CH3 -- Touch screen YM/Sense +	 * CH4 -- Touch screen LR(5-wire only) +	 * +	 * The bitfields below represents the reserved channel in the +	 * touchscreen mode. +	 */ +#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0) +#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0) +	enum atmel_adc_ts_type	touchscreen_type; +	struct input_dev	*ts_input; + +	u16			ts_sample_period_val; +	u32			ts_pressure_threshold; +	u16			ts_pendbc; + +	bool			ts_bufferedmeasure; +	u32			ts_prev_absx; +	u32			ts_prev_absy; +}; + +static irqreturn_t at91_adc_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *idev = pf->indio_dev; +	struct at91_adc_state *st = iio_priv(idev); +	int i, j = 0; + +	for (i = 0; i < idev->masklength; i++) { +		if (!test_bit(i, idev->active_scan_mask)) +			continue; +		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i)); +		j++; +	} + +	iio_push_to_buffers_with_timestamp(idev, st->buffer, pf->timestamp); + +	iio_trigger_notify_done(idev->trig); + +	/* Needed to ACK the DRDY interruption */ +	at91_adc_readl(st, AT91_ADC_LCDR); + +	enable_irq(st->irq); + +	return IRQ_HANDLED; +} + +/* Handler for classic adc channel eoc trigger */ +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) +{ +	struct at91_adc_state *st = iio_priv(idev); + +	if (iio_buffer_enabled(idev)) { +		disable_irq_nosync(irq); +		iio_trigger_poll(idev->trig, iio_get_time_ns()); +	} else { +		st->last_value = at91_adc_readl(st, AT91_ADC_LCDR); +		st->done = true; +		wake_up_interruptible(&st->wq_data_avail); +	} +} + +static int at91_ts_sample(struct at91_adc_state *st) +{ +	unsigned int xscale, yscale, reg, z1, z2; +	unsigned int x, y, pres, xpos, ypos; +	unsigned int rxp = 1; +	unsigned int factor = 1000; +	struct iio_dev *idev = iio_priv_to_dev(st); + +	unsigned int xyz_mask_bits = st->res; +	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1; + +	/* calculate position */ +	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */ +	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR); +	xpos = reg & xyz_mask; +	x = (xpos << MAX_POS_BITS) - xpos; +	xscale = (reg >> 16) & xyz_mask; +	if (xscale == 0) { +		dev_err(&idev->dev, "Error: xscale == 0!\n"); +		return -1; +	} +	x /= xscale; + +	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */ +	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR); +	ypos = reg & xyz_mask; +	y = (ypos << MAX_POS_BITS) - ypos; +	yscale = (reg >> 16) & xyz_mask; +	if (yscale == 0) { +		dev_err(&idev->dev, "Error: yscale == 0!\n"); +		return -1; +	} +	y /= yscale; + +	/* calculate the pressure */ +	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR); +	z1 = reg & xyz_mask; +	z2 = (reg >> 16) & xyz_mask; + +	if (z1 != 0) +		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor) +			/ factor; +	else +		pres = st->ts_pressure_threshold;	/* no pen contacted */ + +	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n", +				xpos, xscale, ypos, yscale, z1, z2, pres); + +	if (pres < st->ts_pressure_threshold) { +		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n", +					x, y, pres / factor); +		input_report_abs(st->ts_input, ABS_X, x); +		input_report_abs(st->ts_input, ABS_Y, y); +		input_report_abs(st->ts_input, ABS_PRESSURE, pres); +		input_report_key(st->ts_input, BTN_TOUCH, 1); +		input_sync(st->ts_input); +	} else { +		dev_dbg(&idev->dev, "pressure too low: not reporting\n"); +	} + +	return 0; +} + +static irqreturn_t at91_adc_rl_interrupt(int irq, void *private) +{ +	struct iio_dev *idev = private; +	struct at91_adc_state *st = iio_priv(idev); +	u32 status = at91_adc_readl(st, st->registers->status_register); +	unsigned int reg; + +	status &= at91_adc_readl(st, AT91_ADC_IMR); +	if (status & st->registers->drdy_mask) +		handle_adc_eoc_trigger(irq, idev); + +	if (status & AT91RL_ADC_IER_PEN) { +		/* Disabling pen debounce is required to get a NOPEN irq */ +		reg = at91_adc_readl(st, AT91_ADC_MR); +		reg &= ~AT91_ADC_PENDBC; +		at91_adc_writel(st, AT91_ADC_MR, reg); + +		at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); +		at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_NOPEN +				| AT91_ADC_EOC(3)); +		/* Set up period trigger for sampling */ +		at91_adc_writel(st, st->registers->trigger_register, +			AT91_ADC_TRGR_MOD_PERIOD_TRIG | +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); +	} else if (status & AT91RL_ADC_IER_NOPEN) { +		reg = at91_adc_readl(st, AT91_ADC_MR); +		reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; +		at91_adc_writel(st, AT91_ADC_MR, reg); +		at91_adc_writel(st, st->registers->trigger_register, +			AT91_ADC_TRGR_NONE); + +		at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_NOPEN +				| AT91_ADC_EOC(3)); +		at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); +		st->ts_bufferedmeasure = false; +		input_report_key(st->ts_input, BTN_TOUCH, 0); +		input_sync(st->ts_input); +	} else if (status & AT91_ADC_EOC(3)) { +		/* Conversion finished */ +		if (st->ts_bufferedmeasure) { +			/* +			 * Last measurement is always discarded, since it can +			 * be erroneous. +			 * Always report previous measurement +			 */ +			input_report_abs(st->ts_input, ABS_X, st->ts_prev_absx); +			input_report_abs(st->ts_input, ABS_Y, st->ts_prev_absy); +			input_report_key(st->ts_input, BTN_TOUCH, 1); +			input_sync(st->ts_input); +		} else +			st->ts_bufferedmeasure = true; + +		/* Now make new measurement */ +		st->ts_prev_absx = at91_adc_readl(st, AT91_ADC_CHAN(st, 3)) +				   << MAX_RLPOS_BITS; +		st->ts_prev_absx /= at91_adc_readl(st, AT91_ADC_CHAN(st, 2)); + +		st->ts_prev_absy = at91_adc_readl(st, AT91_ADC_CHAN(st, 1)) +				   << MAX_RLPOS_BITS; +		st->ts_prev_absy /= at91_adc_readl(st, AT91_ADC_CHAN(st, 0)); +	} + +	return IRQ_HANDLED; +} + +static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) +{ +	struct iio_dev *idev = private; +	struct at91_adc_state *st = iio_priv(idev); +	u32 status = at91_adc_readl(st, st->registers->status_register); +	const uint32_t ts_data_irq_mask = +		AT91_ADC_IER_XRDY | +		AT91_ADC_IER_YRDY | +		AT91_ADC_IER_PRDY; + +	if (status & st->registers->drdy_mask) +		handle_adc_eoc_trigger(irq, idev); + +	if (status & AT91_ADC_IER_PEN) { +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN | +			ts_data_irq_mask); +		/* Set up period trigger for sampling */ +		at91_adc_writel(st, st->registers->trigger_register, +			AT91_ADC_TRGR_MOD_PERIOD_TRIG | +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); +	} else if (status & AT91_ADC_IER_NOPEN) { +		at91_adc_writel(st, st->registers->trigger_register, 0); +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN | +			ts_data_irq_mask); +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); + +		input_report_key(st->ts_input, BTN_TOUCH, 0); +		input_sync(st->ts_input); +	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) { +		/* Now all touchscreen data is ready */ + +		if (status & AT91_ADC_ISR_PENS) { +			/* validate data by pen contact */ +			at91_ts_sample(st); +		} else { +			/* triggered by event that is no pen contact, just read +			 * them to clean the interrupt and discard all. +			 */ +			at91_adc_readl(st, AT91_ADC_TSXPOSR); +			at91_adc_readl(st, AT91_ADC_TSYPOSR); +			at91_adc_readl(st, AT91_ADC_TSPRESSR); +		} +	} + +	return IRQ_HANDLED; +} + +static int at91_adc_channel_init(struct iio_dev *idev) +{ +	struct at91_adc_state *st = iio_priv(idev); +	struct iio_chan_spec *chan_array, *timestamp; +	int bit, idx = 0; +	unsigned long rsvd_mask = 0; + +	/* If touchscreen is enable, then reserve the adc channels */ +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE; +	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE) +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE; + +	/* set up the channel mask to reserve touchscreen channels */ +	st->channels_mask &= ~rsvd_mask; + +	idev->num_channels = bitmap_weight(&st->channels_mask, +					   st->num_channels) + 1; + +	chan_array = devm_kzalloc(&idev->dev, +				  ((idev->num_channels + 1) * +					sizeof(struct iio_chan_spec)), +				  GFP_KERNEL); + +	if (!chan_array) +		return -ENOMEM; + +	for_each_set_bit(bit, &st->channels_mask, st->num_channels) { +		struct iio_chan_spec *chan = chan_array + idx; + +		chan->type = IIO_VOLTAGE; +		chan->indexed = 1; +		chan->channel = bit; +		chan->scan_index = idx; +		chan->scan_type.sign = 'u'; +		chan->scan_type.realbits = st->res; +		chan->scan_type.storagebits = 16; +		chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); +		chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); +		idx++; +	} +	timestamp = chan_array + idx; + +	timestamp->type = IIO_TIMESTAMP; +	timestamp->channel = -1; +	timestamp->scan_index = idx; +	timestamp->scan_type.sign = 's'; +	timestamp->scan_type.realbits = 64; +	timestamp->scan_type.storagebits = 64; + +	idev->channels = chan_array; +	return idev->num_channels; +} + +static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev, +					     struct at91_adc_trigger *triggers, +					     const char *trigger_name) +{ +	struct at91_adc_state *st = iio_priv(idev); +	int i; + +	for (i = 0; i < st->trigger_number; i++) { +		char *name = kasprintf(GFP_KERNEL, +				"%s-dev%d-%s", +				idev->name, +				idev->id, +				triggers[i].name); +		if (!name) +			return -ENOMEM; + +		if (strcmp(trigger_name, name) == 0) { +			kfree(name); +			if (triggers[i].value == 0) +				return -EINVAL; +			return triggers[i].value; +		} + +		kfree(name); +	} + +	return -EINVAL; +} + +static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) +{ +	struct iio_dev *idev = iio_trigger_get_drvdata(trig); +	struct at91_adc_state *st = iio_priv(idev); +	struct iio_buffer *buffer = idev->buffer; +	struct at91_adc_reg_desc *reg = st->registers; +	u32 status = at91_adc_readl(st, reg->trigger_register); +	int value; +	u8 bit; + +	value = at91_adc_get_trigger_value_by_name(idev, +						   st->trigger_list, +						   idev->trig->name); +	if (value < 0) +		return value; + +	if (state) { +		st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); +		if (st->buffer == NULL) +			return -ENOMEM; + +		at91_adc_writel(st, reg->trigger_register, +				status | value); + +		for_each_set_bit(bit, buffer->scan_mask, +				 st->num_channels) { +			struct iio_chan_spec const *chan = idev->channels + bit; +			at91_adc_writel(st, AT91_ADC_CHER, +					AT91_ADC_CH(chan->channel)); +		} + +		at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask); + +	} else { +		at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask); + +		at91_adc_writel(st, reg->trigger_register, +				status & ~value); + +		for_each_set_bit(bit, buffer->scan_mask, +				 st->num_channels) { +			struct iio_chan_spec const *chan = idev->channels + bit; +			at91_adc_writel(st, AT91_ADC_CHDR, +					AT91_ADC_CH(chan->channel)); +		} +		kfree(st->buffer); +	} + +	return 0; +} + +static const struct iio_trigger_ops at91_adc_trigger_ops = { +	.owner = THIS_MODULE, +	.set_trigger_state = &at91_adc_configure_trigger, +}; + +static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, +						     struct at91_adc_trigger *trigger) +{ +	struct iio_trigger *trig; +	int ret; + +	trig = iio_trigger_alloc("%s-dev%d-%s", idev->name, +				 idev->id, trigger->name); +	if (trig == NULL) +		return NULL; + +	trig->dev.parent = idev->dev.parent; +	iio_trigger_set_drvdata(trig, idev); +	trig->ops = &at91_adc_trigger_ops; + +	ret = iio_trigger_register(trig); +	if (ret) +		return NULL; + +	return trig; +} + +static int at91_adc_trigger_init(struct iio_dev *idev) +{ +	struct at91_adc_state *st = iio_priv(idev); +	int i, ret; + +	st->trig = devm_kzalloc(&idev->dev, +				st->trigger_number * sizeof(*st->trig), +				GFP_KERNEL); + +	if (st->trig == NULL) { +		ret = -ENOMEM; +		goto error_ret; +	} + +	for (i = 0; i < st->trigger_number; i++) { +		if (st->trigger_list[i].is_external && !(st->use_external)) +			continue; + +		st->trig[i] = at91_adc_allocate_trigger(idev, +							st->trigger_list + i); +		if (st->trig[i] == NULL) { +			dev_err(&idev->dev, +				"Could not allocate trigger %d\n", i); +			ret = -ENOMEM; +			goto error_trigger; +		} +	} + +	return 0; + +error_trigger: +	for (i--; i >= 0; i--) { +		iio_trigger_unregister(st->trig[i]); +		iio_trigger_free(st->trig[i]); +	} +error_ret: +	return ret; +} + +static void at91_adc_trigger_remove(struct iio_dev *idev) +{ +	struct at91_adc_state *st = iio_priv(idev); +	int i; + +	for (i = 0; i < st->trigger_number; i++) { +		iio_trigger_unregister(st->trig[i]); +		iio_trigger_free(st->trig[i]); +	} +} + +static int at91_adc_buffer_init(struct iio_dev *idev) +{ +	return iio_triggered_buffer_setup(idev, &iio_pollfunc_store_time, +		&at91_adc_trigger_handler, NULL); +} + +static void at91_adc_buffer_remove(struct iio_dev *idev) +{ +	iio_triggered_buffer_cleanup(idev); +} + +static int at91_adc_read_raw(struct iio_dev *idev, +			     struct iio_chan_spec const *chan, +			     int *val, int *val2, long mask) +{ +	struct at91_adc_state *st = iio_priv(idev); +	int ret; + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&st->lock); + +		at91_adc_writel(st, AT91_ADC_CHER, +				AT91_ADC_CH(chan->channel)); +		at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask); +		at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START); + +		ret = wait_event_interruptible_timeout(st->wq_data_avail, +						       st->done, +						       msecs_to_jiffies(1000)); +		if (ret == 0) +			ret = -ETIMEDOUT; +		if (ret < 0) { +			mutex_unlock(&st->lock); +			return ret; +		} + +		*val = st->last_value; + +		at91_adc_writel(st, AT91_ADC_CHDR, +				AT91_ADC_CH(chan->channel)); +		at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask); + +		st->last_value = 0; +		st->done = false; +		mutex_unlock(&st->lock); +		return IIO_VAL_INT; + +	case IIO_CHAN_INFO_SCALE: +		*val = st->vref_mv; +		*val2 = chan->scan_type.realbits; +		return IIO_VAL_FRACTIONAL_LOG2; +	default: +		break; +	} +	return -EINVAL; +} + +static int at91_adc_of_get_resolution(struct at91_adc_state *st, +				      struct platform_device *pdev) +{ +	struct iio_dev *idev = iio_priv_to_dev(st); +	struct device_node *np = pdev->dev.of_node; +	int count, i, ret = 0; +	char *res_name, *s; +	u32 *resolutions; + +	count = of_property_count_strings(np, "atmel,adc-res-names"); +	if (count < 2) { +		dev_err(&idev->dev, "You must specified at least two resolution names for " +				    "adc-res-names property in the DT\n"); +		return count; +	} + +	resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL); +	if (!resolutions) +		return -ENOMEM; + +	if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) { +		dev_err(&idev->dev, "Missing adc-res property in the DT.\n"); +		ret = -ENODEV; +		goto ret; +	} + +	if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name)) +		res_name = "highres"; + +	for (i = 0; i < count; i++) { +		if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s)) +			continue; + +		if (strcmp(res_name, s)) +			continue; + +		st->res = resolutions[i]; +		if (!strcmp(res_name, "lowres")) +			st->low_res = true; +		else +			st->low_res = false; + +		dev_info(&idev->dev, "Resolution used: %u bits\n", st->res); +		goto ret; +	} + +	dev_err(&idev->dev, "There is no resolution for %s\n", res_name); + +ret: +	kfree(resolutions); +	return ret; +} + +static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz) +{ +	/* +	 * Number of ticks needed to cover the startup time of the ADC +	 * as defined in the electrical characteristics of the board, +	 * divided by 8. The formula thus is : +	 *   Startup Time = (ticks + 1) * 8 / ADC Clock +	 */ +	return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8; +} + +static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz) +{ +	/* +	 * For sama5d3x and at91sam9x5, the formula changes to: +	 * Startup Time = <lookup_table_value> / ADC Clock +	 */ +	const int startup_lookup[] = { +		0  , 8  , 16 , 24 , +		64 , 80 , 96 , 112, +		512, 576, 640, 704, +		768, 832, 896, 960 +		}; +	int i, size = ARRAY_SIZE(startup_lookup); +	unsigned int ticks; + +	ticks = startup_time * adc_clk_khz / 1000; +	for (i = 0; i < size; i++) +		if (ticks < startup_lookup[i]) +			break; + +	ticks = i; +	if (ticks == size) +		/* Reach the end of lookup table */ +		ticks = size - 1; + +	return ticks; +} + +static const struct of_device_id at91_adc_dt_ids[]; + +static int at91_adc_probe_dt_ts(struct device_node *node, +	struct at91_adc_state *st, struct device *dev) +{ +	int ret; +	u32 prop; + +	ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop); +	if (ret) { +		dev_info(dev, "ADC Touch screen is disabled.\n"); +		return 0; +	} + +	switch (prop) { +	case 4: +	case 5: +		st->touchscreen_type = prop; +		break; +	default: +		dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop); +		return -EINVAL; +	} + +	if (!st->caps->has_tsmr) +		return 0; +	prop = 0; +	of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); +	st->ts_pressure_threshold = prop; +	if (st->ts_pressure_threshold) { +		return 0; +	} else { +		dev_err(dev, "Invalid pressure threshold for the touchscreen\n"); +		return -EINVAL; +	} +} + +static int at91_adc_probe_dt(struct at91_adc_state *st, +			     struct platform_device *pdev) +{ +	struct iio_dev *idev = iio_priv_to_dev(st); +	struct device_node *node = pdev->dev.of_node; +	struct device_node *trig_node; +	int i = 0, ret; +	u32 prop; + +	if (!node) +		return -EINVAL; + +	st->caps = (struct at91_adc_caps *) +		of_match_device(at91_adc_dt_ids, &pdev->dev)->data; + +	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); + +	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { +		dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); +		ret = -EINVAL; +		goto error_ret; +	} +	st->channels_mask = prop; + +	st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); + +	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { +		dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); +		ret = -EINVAL; +		goto error_ret; +	} +	st->startup_time = prop; + +	prop = 0; +	of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); +	st->sample_hold_time = prop; + +	if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { +		dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); +		ret = -EINVAL; +		goto error_ret; +	} +	st->vref_mv = prop; + +	ret = at91_adc_of_get_resolution(st, pdev); +	if (ret) +		goto error_ret; + +	st->registers = &st->caps->registers; +	st->num_channels = st->caps->num_channels; +	st->trigger_number = of_get_child_count(node); +	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number * +					sizeof(struct at91_adc_trigger), +					GFP_KERNEL); +	if (!st->trigger_list) { +		dev_err(&idev->dev, "Could not allocate trigger list memory.\n"); +		ret = -ENOMEM; +		goto error_ret; +	} + +	for_each_child_of_node(node, trig_node) { +		struct at91_adc_trigger *trig = st->trigger_list + i; +		const char *name; + +		if (of_property_read_string(trig_node, "trigger-name", &name)) { +			dev_err(&idev->dev, "Missing trigger-name property in the DT.\n"); +			ret = -EINVAL; +			goto error_ret; +		} +	        trig->name = name; + +		if (of_property_read_u32(trig_node, "trigger-value", &prop)) { +			dev_err(&idev->dev, "Missing trigger-value property in the DT.\n"); +			ret = -EINVAL; +			goto error_ret; +		} +	        trig->value = prop; +		trig->is_external = of_property_read_bool(trig_node, "trigger-external"); +		i++; +	} + +	/* Check if touchscreen is supported. */ +	if (st->caps->has_ts) +		return at91_adc_probe_dt_ts(node, st, &idev->dev); +	else +		dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n"); + +	return 0; + +error_ret: +	return ret; +} + +static int at91_adc_probe_pdata(struct at91_adc_state *st, +				struct platform_device *pdev) +{ +	struct at91_adc_data *pdata = pdev->dev.platform_data; + +	if (!pdata) +		return -EINVAL; + +	st->caps = (struct at91_adc_caps *) +			platform_get_device_id(pdev)->driver_data; + +	st->use_external = pdata->use_external_triggers; +	st->vref_mv = pdata->vref; +	st->channels_mask = pdata->channels_used; +	st->num_channels = st->caps->num_channels; +	st->startup_time = pdata->startup_time; +	st->trigger_number = pdata->trigger_number; +	st->trigger_list = pdata->trigger_list; +	st->registers = &st->caps->registers; +	st->touchscreen_type = pdata->touchscreen_type; + +	return 0; +} + +static const struct iio_info at91_adc_info = { +	.driver_module = THIS_MODULE, +	.read_raw = &at91_adc_read_raw, +}; + +/* Touchscreen related functions */ +static int atmel_ts_open(struct input_dev *dev) +{ +	struct at91_adc_state *st = input_get_drvdata(dev); + +	if (st->caps->has_tsmr) +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); +	else +		at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); +	return 0; +} + +static void atmel_ts_close(struct input_dev *dev) +{ +	struct at91_adc_state *st = input_get_drvdata(dev); + +	if (st->caps->has_tsmr) +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); +	else +		at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); +} + +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) +{ +	u32 reg = 0; +	int i = 0; + +	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid +	 * pen detect noise. +	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock +	 */ +	st->ts_pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / +				 1000, 1); + +	while (st->ts_pendbc >> ++i) +		;	/* Empty! Find the shift offset */ +	if (abs(st->ts_pendbc - (1 << i)) < abs(st->ts_pendbc - (1 << (i - 1)))) +		st->ts_pendbc = i; +	else +		st->ts_pendbc = i - 1; + +	if (!st->caps->has_tsmr) { +		reg = at91_adc_readl(st, AT91_ADC_MR); +		reg |= AT91_ADC_TSAMOD_TS_ONLY_MODE | AT91_ADC_PENDET; + +		reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; +		at91_adc_writel(st, AT91_ADC_MR, reg); + +		reg = AT91_ADC_TSR_SHTIM_(TOUCH_SHTIM) & AT91_ADC_TSR_SHTIM; +		at91_adc_writel(st, AT91_ADC_TSR, reg); + +		st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US_RL * +						    adc_clk_khz / 1000) - 1, 1); + +		return 0; +	} + +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) +		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; +	else +		reg = AT91_ADC_TSMR_TSMODE_5WIRE; + +	reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) +	       & AT91_ADC_TSMR_TSAV; +	reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC; +	reg |= AT91_ADC_TSMR_NOTSDMA; +	reg |= AT91_ADC_TSMR_PENDET_ENA; +	reg |= 0x03 << 8;	/* TSFREQ, needs to be bigger than TSAV */ + +	at91_adc_writel(st, AT91_ADC_TSMR, reg); + +	/* Change adc internal resistor value for better pen detection, +	 * default value is 100 kOhm. +	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm +	 * option only available on ES2 and higher +	 */ +	at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity +			& AT91_ADC_ACR_PENDETSENS); + +	/* Sample Period Time = (TRGPER + 1) / ADCClock */ +	st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * +			adc_clk_khz / 1000) - 1, 1); + +	return 0; +} + +static int at91_ts_register(struct at91_adc_state *st, +		struct platform_device *pdev) +{ +	struct input_dev *input; +	struct iio_dev *idev = iio_priv_to_dev(st); +	int ret; + +	input = input_allocate_device(); +	if (!input) { +		dev_err(&idev->dev, "Failed to allocate TS device!\n"); +		return -ENOMEM; +	} + +	input->name = DRIVER_NAME; +	input->id.bustype = BUS_HOST; +	input->dev.parent = &pdev->dev; +	input->open = atmel_ts_open; +	input->close = atmel_ts_close; + +	__set_bit(EV_ABS, input->evbit); +	__set_bit(EV_KEY, input->evbit); +	__set_bit(BTN_TOUCH, input->keybit); +	if (st->caps->has_tsmr) { +		input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, +				     0, 0); +		input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, +				     0, 0); +		input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); +	} else { +		if (st->touchscreen_type != ATMEL_ADC_TOUCHSCREEN_4WIRE) { +			dev_err(&pdev->dev, +				"This touchscreen controller only support 4 wires\n"); +			ret = -EINVAL; +			goto err; +		} + +		input_set_abs_params(input, ABS_X, 0, (1 << MAX_RLPOS_BITS) - 1, +				     0, 0); +		input_set_abs_params(input, ABS_Y, 0, (1 << MAX_RLPOS_BITS) - 1, +				     0, 0); +	} + +	st->ts_input = input; +	input_set_drvdata(input, st); + +	ret = input_register_device(input); +	if (ret) +		goto err; + +	return ret; + +err: +	input_free_device(st->ts_input); +	return ret; +} + +static void at91_ts_unregister(struct at91_adc_state *st) +{ +	input_unregister_device(st->ts_input); +} + +static int at91_adc_probe(struct platform_device *pdev) +{ +	unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim; +	int ret; +	struct iio_dev *idev; +	struct at91_adc_state *st; +	struct resource *res; +	u32 reg; + +	idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state)); +	if (!idev) +		return -ENOMEM; + +	st = iio_priv(idev); + +	if (pdev->dev.of_node) +		ret = at91_adc_probe_dt(st, pdev); +	else +		ret = at91_adc_probe_pdata(st, pdev); + +	if (ret) { +		dev_err(&pdev->dev, "No platform data available.\n"); +		return -EINVAL; +	} + +	platform_set_drvdata(pdev, idev); + +	idev->dev.parent = &pdev->dev; +	idev->name = dev_name(&pdev->dev); +	idev->modes = INDIO_DIRECT_MODE; +	idev->info = &at91_adc_info; + +	st->irq = platform_get_irq(pdev, 0); +	if (st->irq < 0) { +		dev_err(&pdev->dev, "No IRQ ID is designated\n"); +		return -ENODEV; +	} + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + +	st->reg_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(st->reg_base)) { +		return PTR_ERR(st->reg_base); +	} + +	/* +	 * Disable all IRQs before setting up the handler +	 */ +	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); +	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); + +	if (st->caps->has_tsmr) +		ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, +				  pdev->dev.driver->name, idev); +	else +		ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, +				  pdev->dev.driver->name, idev); +	if (ret) { +		dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); +		return ret; +	} + +	st->clk = devm_clk_get(&pdev->dev, "adc_clk"); +	if (IS_ERR(st->clk)) { +		dev_err(&pdev->dev, "Failed to get the clock.\n"); +		ret = PTR_ERR(st->clk); +		goto error_free_irq; +	} + +	ret = clk_prepare_enable(st->clk); +	if (ret) { +		dev_err(&pdev->dev, +			"Could not prepare or enable the clock.\n"); +		goto error_free_irq; +	} + +	st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); +	if (IS_ERR(st->adc_clk)) { +		dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); +		ret = PTR_ERR(st->adc_clk); +		goto error_disable_clk; +	} + +	ret = clk_prepare_enable(st->adc_clk); +	if (ret) { +		dev_err(&pdev->dev, +			"Could not prepare or enable the ADC clock.\n"); +		goto error_disable_clk; +	} + +	/* +	 * Prescaler rate computation using the formula from the Atmel's +	 * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being +	 * specified by the electrical characteristics of the board. +	 */ +	mstrclk = clk_get_rate(st->clk); +	adc_clk = clk_get_rate(st->adc_clk); +	adc_clk_khz = adc_clk / 1000; + +	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n", +		mstrclk, adc_clk); + +	prsc = (mstrclk / (2 * adc_clk)) - 1; + +	if (!st->startup_time) { +		dev_err(&pdev->dev, "No startup time available.\n"); +		ret = -EINVAL; +		goto error_disable_adc_clk; +	} +	ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); + +	/* +	 * a minimal Sample and Hold Time is necessary for the ADC to guarantee +	 * the best converted final value between two channels selection +	 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock +	 */ +	if (st->sample_hold_time > 0) +		shtim = round_up((st->sample_hold_time * adc_clk_khz / 1000) +				 - 1, 1); +	else +		shtim = 0; + +	reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask; +	reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask; +	if (st->low_res) +		reg |= AT91_ADC_LOWRES; +	if (st->sleep_mode) +		reg |= AT91_ADC_SLEEP; +	reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM; +	at91_adc_writel(st, AT91_ADC_MR, reg); + +	/* Setup the ADC channels available on the board */ +	ret = at91_adc_channel_init(idev); +	if (ret < 0) { +		dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); +		goto error_disable_adc_clk; +	} + +	init_waitqueue_head(&st->wq_data_avail); +	mutex_init(&st->lock); + +	/* +	 * Since touch screen will set trigger register as period trigger. So +	 * when touch screen is enabled, then we have to disable hardware +	 * trigger for classic adc. +	 */ +	if (!st->touchscreen_type) { +		ret = at91_adc_buffer_init(idev); +		if (ret < 0) { +			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); +			goto error_disable_adc_clk; +		} + +		ret = at91_adc_trigger_init(idev); +		if (ret < 0) { +			dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); +			at91_adc_buffer_remove(idev); +			goto error_disable_adc_clk; +		} +	} else { +		ret = at91_ts_register(st, pdev); +		if (ret) +			goto error_disable_adc_clk; + +		at91_ts_hw_init(st, adc_clk_khz); +	} + +	ret = iio_device_register(idev); +	if (ret < 0) { +		dev_err(&pdev->dev, "Couldn't register the device.\n"); +		goto error_iio_device_register; +	} + +	return 0; + +error_iio_device_register: +	if (!st->touchscreen_type) { +		at91_adc_trigger_remove(idev); +		at91_adc_buffer_remove(idev); +	} else { +		at91_ts_unregister(st); +	} +error_disable_adc_clk: +	clk_disable_unprepare(st->adc_clk); +error_disable_clk: +	clk_disable_unprepare(st->clk); +error_free_irq: +	free_irq(st->irq, idev); +	return ret; +} + +static int at91_adc_remove(struct platform_device *pdev) +{ +	struct iio_dev *idev = platform_get_drvdata(pdev); +	struct at91_adc_state *st = iio_priv(idev); + +	iio_device_unregister(idev); +	if (!st->touchscreen_type) { +		at91_adc_trigger_remove(idev); +		at91_adc_buffer_remove(idev); +	} else { +		at91_ts_unregister(st); +	} +	clk_disable_unprepare(st->adc_clk); +	clk_disable_unprepare(st->clk); +	free_irq(st->irq, idev); + +	return 0; +} + +static struct at91_adc_caps at91sam9260_caps = { +	.calc_startup_ticks = calc_startup_ticks_9260, +	.num_channels = 4, +	.registers = { +		.channel_base = AT91_ADC_CHR(0), +		.drdy_mask = AT91_ADC_DRDY, +		.status_register = AT91_ADC_SR, +		.trigger_register = AT91_ADC_TRGR_9260, +		.mr_prescal_mask = AT91_ADC_PRESCAL_9260, +		.mr_startup_mask = AT91_ADC_STARTUP_9260, +	}, +}; + +static struct at91_adc_caps at91sam9rl_caps = { +	.has_ts = true, +	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */ +	.num_channels = 6, +	.registers = { +		.channel_base = AT91_ADC_CHR(0), +		.drdy_mask = AT91_ADC_DRDY, +		.status_register = AT91_ADC_SR, +		.trigger_register = AT91_ADC_TRGR_9G45, +		.mr_prescal_mask = AT91_ADC_PRESCAL_9260, +		.mr_startup_mask = AT91_ADC_STARTUP_9G45, +	}, +}; + +static struct at91_adc_caps at91sam9g45_caps = { +	.has_ts = true, +	.calc_startup_ticks = calc_startup_ticks_9260,	/* same as 9260 */ +	.num_channels = 8, +	.registers = { +		.channel_base = AT91_ADC_CHR(0), +		.drdy_mask = AT91_ADC_DRDY, +		.status_register = AT91_ADC_SR, +		.trigger_register = AT91_ADC_TRGR_9G45, +		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45, +		.mr_startup_mask = AT91_ADC_STARTUP_9G45, +	}, +}; + +static struct at91_adc_caps at91sam9x5_caps = { +	.has_ts = true, +	.has_tsmr = true, +	.ts_filter_average = 3, +	.ts_pen_detect_sensitivity = 2, +	.calc_startup_ticks = calc_startup_ticks_9x5, +	.num_channels = 12, +	.registers = { +		.channel_base = AT91_ADC_CDR0_9X5, +		.drdy_mask = AT91_ADC_SR_DRDY_9X5, +		.status_register = AT91_ADC_SR_9X5, +		.trigger_register = AT91_ADC_TRGR_9X5, +		/* prescal mask is same as 9G45 */ +		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45, +		.mr_startup_mask = AT91_ADC_STARTUP_9X5, +	}, +}; + +static const struct of_device_id at91_adc_dt_ids[] = { +	{ .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps }, +	{ .compatible = "atmel,at91sam9rl-adc", .data = &at91sam9rl_caps }, +	{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps }, +	{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps }, +	{}, +}; +MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); + +static const struct platform_device_id at91_adc_ids[] = { +	{ +		.name = "at91sam9260-adc", +		.driver_data = (unsigned long)&at91sam9260_caps, +	}, { +		.name = "at91sam9rl-adc", +		.driver_data = (unsigned long)&at91sam9rl_caps, +	}, { +		.name = "at91sam9g45-adc", +		.driver_data = (unsigned long)&at91sam9g45_caps, +	}, { +		.name = "at91sam9x5-adc", +		.driver_data = (unsigned long)&at91sam9x5_caps, +	}, { +		/* terminator */ +	} +}; +MODULE_DEVICE_TABLE(platform, at91_adc_ids); + +static struct platform_driver at91_adc_driver = { +	.probe = at91_adc_probe, +	.remove = at91_adc_remove, +	.id_table = at91_adc_ids, +	.driver = { +		   .name = DRIVER_NAME, +		   .of_match_table = of_match_ptr(at91_adc_dt_ids), +	}, +}; + +module_platform_driver(at91_adc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atmel AT91 ADC Driver"); +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c new file mode 100644 index 00000000000..010578f1d76 --- /dev/null +++ b/drivers/iio/adc/exynos_adc.c @@ -0,0 +1,456 @@ +/* + *  exynos_adc.c - Support for ADC in EXYNOS SoCs + * + *  8 ~ 10 channel, 10/12-bit ADC + * + *  Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/err.h> + +#include <linux/iio/iio.h> +#include <linux/iio/machine.h> +#include <linux/iio/driver.h> + +enum adc_version { +	ADC_V1, +	ADC_V2 +}; + +/* EXYNOS4412/5250 ADC_V1 registers definitions */ +#define ADC_V1_CON(x)		((x) + 0x00) +#define ADC_V1_DLY(x)		((x) + 0x08) +#define ADC_V1_DATX(x)		((x) + 0x0C) +#define ADC_V1_INTCLR(x)	((x) + 0x18) +#define ADC_V1_MUX(x)		((x) + 0x1c) + +/* Future ADC_V2 registers definitions */ +#define ADC_V2_CON1(x)		((x) + 0x00) +#define ADC_V2_CON2(x)		((x) + 0x04) +#define ADC_V2_STAT(x)		((x) + 0x08) +#define ADC_V2_INT_EN(x)	((x) + 0x10) +#define ADC_V2_INT_ST(x)	((x) + 0x14) +#define ADC_V2_VER(x)		((x) + 0x20) + +/* Bit definitions for ADC_V1 */ +#define ADC_V1_CON_RES		(1u << 16) +#define ADC_V1_CON_PRSCEN	(1u << 14) +#define ADC_V1_CON_PRSCLV(x)	(((x) & 0xFF) << 6) +#define ADC_V1_CON_STANDBY	(1u << 2) + +/* Bit definitions for ADC_V2 */ +#define ADC_V2_CON1_SOFT_RESET	(1u << 2) + +#define ADC_V2_CON2_OSEL	(1u << 10) +#define ADC_V2_CON2_ESEL	(1u << 9) +#define ADC_V2_CON2_HIGHF	(1u << 8) +#define ADC_V2_CON2_C_TIME(x)	(((x) & 7) << 4) +#define ADC_V2_CON2_ACH_SEL(x)	(((x) & 0xF) << 0) +#define ADC_V2_CON2_ACH_MASK	0xF + +#define MAX_ADC_V2_CHANNELS	10 +#define MAX_ADC_V1_CHANNELS	8 + +/* Bit definitions common for ADC_V1 and ADC_V2 */ +#define ADC_CON_EN_START	(1u << 0) +#define ADC_DATX_MASK		0xFFF + +#define EXYNOS_ADC_TIMEOUT	(msecs_to_jiffies(100)) + +struct exynos_adc { +	void __iomem		*regs; +	void __iomem		*enable_reg; +	struct clk		*clk; +	unsigned int		irq; +	struct regulator	*vdd; + +	struct completion	completion; + +	u32			value; +	unsigned int            version; +}; + +static const struct of_device_id exynos_adc_match[] = { +	{ .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 }, +	{ .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 }, +	{}, +}; +MODULE_DEVICE_TABLE(of, exynos_adc_match); + +static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) +{ +	const struct of_device_id *match; + +	match = of_match_node(exynos_adc_match, pdev->dev.of_node); +	return (unsigned int)match->data; +} + +static void exynos_adc_hw_init(struct exynos_adc *info) +{ +	u32 con1, con2; + +	if (info->version == ADC_V2) { +		con1 = ADC_V2_CON1_SOFT_RESET; +		writel(con1, ADC_V2_CON1(info->regs)); + +		con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | +			ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); +		writel(con2, ADC_V2_CON2(info->regs)); + +		/* Enable interrupts */ +		writel(1, ADC_V2_INT_EN(info->regs)); +	} else { +		/* set default prescaler values and Enable prescaler */ +		con1 =  ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; + +		/* Enable 12-bit ADC resolution */ +		con1 |= ADC_V1_CON_RES; +		writel(con1, ADC_V1_CON(info->regs)); +	} +} + +static int exynos_read_raw(struct iio_dev *indio_dev, +				struct iio_chan_spec const *chan, +				int *val, +				int *val2, +				long mask) +{ +	struct exynos_adc *info = iio_priv(indio_dev); +	unsigned long timeout; +	u32 con1, con2; +	int ret; + +	if (mask != IIO_CHAN_INFO_RAW) +		return -EINVAL; + +	mutex_lock(&indio_dev->mlock); +	reinit_completion(&info->completion); + +	/* Select the channel to be used and Trigger conversion */ +	if (info->version == ADC_V2) { +		con2 = readl(ADC_V2_CON2(info->regs)); +		con2 &= ~ADC_V2_CON2_ACH_MASK; +		con2 |= ADC_V2_CON2_ACH_SEL(chan->address); +		writel(con2, ADC_V2_CON2(info->regs)); + +		con1 = readl(ADC_V2_CON1(info->regs)); +		writel(con1 | ADC_CON_EN_START, +				ADC_V2_CON1(info->regs)); +	} else { +		writel(chan->address, ADC_V1_MUX(info->regs)); + +		con1 = readl(ADC_V1_CON(info->regs)); +		writel(con1 | ADC_CON_EN_START, +				ADC_V1_CON(info->regs)); +	} + +	timeout = wait_for_completion_timeout +			(&info->completion, EXYNOS_ADC_TIMEOUT); +	if (timeout == 0) { +		dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); +		exynos_adc_hw_init(info); +		ret = -ETIMEDOUT; +	} else { +		*val = info->value; +		*val2 = 0; +		ret = IIO_VAL_INT; +	} + +	mutex_unlock(&indio_dev->mlock); + +	return ret; +} + +static irqreturn_t exynos_adc_isr(int irq, void *dev_id) +{ +	struct exynos_adc *info = (struct exynos_adc *)dev_id; + +	/* Read value */ +	info->value = readl(ADC_V1_DATX(info->regs)) & +						ADC_DATX_MASK; +	/* clear irq */ +	if (info->version == ADC_V2) +		writel(1, ADC_V2_INT_ST(info->regs)); +	else +		writel(1, ADC_V1_INTCLR(info->regs)); + +	complete(&info->completion); + +	return IRQ_HANDLED; +} + +static int exynos_adc_reg_access(struct iio_dev *indio_dev, +			      unsigned reg, unsigned writeval, +			      unsigned *readval) +{ +	struct exynos_adc *info = iio_priv(indio_dev); + +	if (readval == NULL) +		return -EINVAL; + +	*readval = readl(info->regs + reg); + +	return 0; +} + +static const struct iio_info exynos_adc_iio_info = { +	.read_raw = &exynos_read_raw, +	.debugfs_reg_access = &exynos_adc_reg_access, +	.driver_module = THIS_MODULE, +}; + +#define ADC_CHANNEL(_index, _id) {			\ +	.type = IIO_VOLTAGE,				\ +	.indexed = 1,					\ +	.channel = _index,				\ +	.address = _index,				\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +	.datasheet_name = _id,				\ +} + +static const struct iio_chan_spec exynos_adc_iio_channels[] = { +	ADC_CHANNEL(0, "adc0"), +	ADC_CHANNEL(1, "adc1"), +	ADC_CHANNEL(2, "adc2"), +	ADC_CHANNEL(3, "adc3"), +	ADC_CHANNEL(4, "adc4"), +	ADC_CHANNEL(5, "adc5"), +	ADC_CHANNEL(6, "adc6"), +	ADC_CHANNEL(7, "adc7"), +	ADC_CHANNEL(8, "adc8"), +	ADC_CHANNEL(9, "adc9"), +}; + +static int exynos_adc_remove_devices(struct device *dev, void *c) +{ +	struct platform_device *pdev = to_platform_device(dev); + +	platform_device_unregister(pdev); + +	return 0; +} + +static int exynos_adc_probe(struct platform_device *pdev) +{ +	struct exynos_adc *info = NULL; +	struct device_node *np = pdev->dev.of_node; +	struct iio_dev *indio_dev = NULL; +	struct resource	*mem; +	int ret = -ENODEV; +	int irq; + +	if (!np) +		return ret; + +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); +	if (!indio_dev) { +		dev_err(&pdev->dev, "failed allocating iio device\n"); +		return -ENOMEM; +	} + +	info = iio_priv(indio_dev); + +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	info->regs = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(info->regs)) +		return PTR_ERR(info->regs); + +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(info->enable_reg)) +		return PTR_ERR(info->enable_reg); + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "no irq resource?\n"); +		return irq; +	} + +	info->irq = irq; + +	init_completion(&info->completion); + +	info->clk = devm_clk_get(&pdev->dev, "adc"); +	if (IS_ERR(info->clk)) { +		dev_err(&pdev->dev, "failed getting clock, err = %ld\n", +							PTR_ERR(info->clk)); +		return PTR_ERR(info->clk); +	} + +	info->vdd = devm_regulator_get(&pdev->dev, "vdd"); +	if (IS_ERR(info->vdd)) { +		dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", +							PTR_ERR(info->vdd)); +		return PTR_ERR(info->vdd); +	} + +	ret = regulator_enable(info->vdd); +	if (ret) +		return ret; + +	ret = clk_prepare_enable(info->clk); +	if (ret) +		goto err_disable_reg; + +	writel(1, info->enable_reg); + +	info->version = exynos_adc_get_version(pdev); + +	platform_set_drvdata(pdev, indio_dev); + +	indio_dev->name = dev_name(&pdev->dev); +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->dev.of_node = pdev->dev.of_node; +	indio_dev->info = &exynos_adc_iio_info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = exynos_adc_iio_channels; + +	if (info->version == ADC_V1) +		indio_dev->num_channels = MAX_ADC_V1_CHANNELS; +	else +		indio_dev->num_channels = MAX_ADC_V2_CHANNELS; + +	ret = request_irq(info->irq, exynos_adc_isr, +					0, dev_name(&pdev->dev), info); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", +							info->irq); +		goto err_disable_clk; +	} + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto err_irq; + +	exynos_adc_hw_init(info); + +	ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed adding child nodes\n"); +		goto err_of_populate; +	} + +	return 0; + +err_of_populate: +	device_for_each_child(&indio_dev->dev, NULL, +				exynos_adc_remove_devices); +	iio_device_unregister(indio_dev); +err_irq: +	free_irq(info->irq, info); +err_disable_clk: +	writel(0, info->enable_reg); +	clk_disable_unprepare(info->clk); +err_disable_reg: +	regulator_disable(info->vdd); +	return ret; +} + +static int exynos_adc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); +	struct exynos_adc *info = iio_priv(indio_dev); + +	device_for_each_child(&indio_dev->dev, NULL, +				exynos_adc_remove_devices); +	iio_device_unregister(indio_dev); +	free_irq(info->irq, info); +	writel(0, info->enable_reg); +	clk_disable_unprepare(info->clk); +	regulator_disable(info->vdd); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int exynos_adc_suspend(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct exynos_adc *info = iio_priv(indio_dev); +	u32 con; + +	if (info->version == ADC_V2) { +		con = readl(ADC_V2_CON1(info->regs)); +		con &= ~ADC_CON_EN_START; +		writel(con, ADC_V2_CON1(info->regs)); +	} else { +		con = readl(ADC_V1_CON(info->regs)); +		con |= ADC_V1_CON_STANDBY; +		writel(con, ADC_V1_CON(info->regs)); +	} + +	writel(0, info->enable_reg); +	clk_disable_unprepare(info->clk); +	regulator_disable(info->vdd); + +	return 0; +} + +static int exynos_adc_resume(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct exynos_adc *info = iio_priv(indio_dev); +	int ret; + +	ret = regulator_enable(info->vdd); +	if (ret) +		return ret; + +	ret = clk_prepare_enable(info->clk); +	if (ret) +		return ret; + +	writel(1, info->enable_reg); +	exynos_adc_hw_init(info); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, +			exynos_adc_suspend, +			exynos_adc_resume); + +static struct platform_driver exynos_adc_driver = { +	.probe		= exynos_adc_probe, +	.remove		= exynos_adc_remove, +	.driver		= { +		.name	= "exynos-adc", +		.owner	= THIS_MODULE, +		.of_match_table = exynos_adc_match, +		.pm	= &exynos_adc_pm_ops, +	}, +}; + +module_platform_driver(exynos_adc_driver); + +MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>"); +MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c new file mode 100644 index 00000000000..5c8c91595f4 --- /dev/null +++ b/drivers/iio/adc/lp8788_adc.c @@ -0,0 +1,255 @@ +/* + * TI LP8788 MFD - ADC driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/driver.h> +#include <linux/iio/machine.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* register address */ +#define LP8788_ADC_CONF			0x60 +#define LP8788_ADC_RAW			0x61 +#define LP8788_ADC_DONE			0x63 + +#define ADC_CONV_START			1 + +struct lp8788_adc { +	struct lp8788 *lp; +	struct iio_map *map; +	struct mutex lock; +}; + +static const int lp8788_scale[LPADC_MAX] = { +	[LPADC_VBATT_5P5] = 1343101, +	[LPADC_VIN_CHG]   = 3052503, +	[LPADC_IBATT]     = 610500, +	[LPADC_IC_TEMP]   = 61050, +	[LPADC_VBATT_6P0] = 1465201, +	[LPADC_VBATT_5P0] = 1221001, +	[LPADC_ADC1]      = 610500, +	[LPADC_ADC2]      = 610500, +	[LPADC_VDD]       = 1025641, +	[LPADC_VCOIN]     = 757020, +	[LPADC_ADC3]      = 610500, +	[LPADC_ADC4]      = 610500, +}; + +static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id, +				int *val) +{ +	unsigned int msb; +	unsigned int lsb; +	unsigned int result; +	u8 data; +	u8 rawdata[2]; +	int size = ARRAY_SIZE(rawdata); +	int retry = 5; +	int ret; + +	data = (id << 1) | ADC_CONV_START; +	ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data); +	if (ret) +		goto err_io; + +	/* retry until adc conversion is done */ +	data = 0; +	while (retry--) { +		usleep_range(100, 200); + +		ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data); +		if (ret) +			goto err_io; + +		/* conversion done */ +		if (data) +			break; +	} + +	ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size); +	if (ret) +		goto err_io; + +	msb = (rawdata[0] << 4) & 0x00000ff0; +	lsb = (rawdata[1] >> 4) & 0x0000000f; +	result = msb | lsb; +	*val = result; + +	return 0; + +err_io: +	return ret; +} + +static int lp8788_adc_read_raw(struct iio_dev *indio_dev, +			struct iio_chan_spec const *chan, +			int *val, int *val2, long mask) +{ +	struct lp8788_adc *adc = iio_priv(indio_dev); +	enum lp8788_adc_id id = chan->channel; +	int ret; + +	mutex_lock(&adc->lock); + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT; +		break; +	case IIO_CHAN_INFO_SCALE: +		*val = lp8788_scale[id] / 1000000; +		*val2 = lp8788_scale[id] % 1000000; +		ret = IIO_VAL_INT_PLUS_MICRO; +		break; +	default: +		ret = -EINVAL; +		break; +	} + +	mutex_unlock(&adc->lock); + +	return ret; +} + +static const struct iio_info lp8788_adc_info = { +	.read_raw = &lp8788_adc_read_raw, +	.driver_module = THIS_MODULE, +}; + +#define LP8788_CHAN(_id, _type) {				\ +		.type = _type,					\ +		.indexed = 1,					\ +		.channel = LPADC_##_id,				\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\ +			BIT(IIO_CHAN_INFO_SCALE),		\ +		.datasheet_name = #_id,				\ +} + +static const struct iio_chan_spec lp8788_adc_channels[] = { +	[LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE), +	[LPADC_VIN_CHG]   = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE), +	[LPADC_IBATT]     = LP8788_CHAN(IBATT, IIO_CURRENT), +	[LPADC_IC_TEMP]   = LP8788_CHAN(IC_TEMP, IIO_TEMP), +	[LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE), +	[LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE), +	[LPADC_ADC1]      = LP8788_CHAN(ADC1, IIO_VOLTAGE), +	[LPADC_ADC2]      = LP8788_CHAN(ADC2, IIO_VOLTAGE), +	[LPADC_VDD]       = LP8788_CHAN(VDD, IIO_VOLTAGE), +	[LPADC_VCOIN]     = LP8788_CHAN(VCOIN, IIO_VOLTAGE), +	[LPADC_ADC3]      = LP8788_CHAN(ADC3, IIO_VOLTAGE), +	[LPADC_ADC4]      = LP8788_CHAN(ADC4, IIO_VOLTAGE), +}; + +/* default maps used by iio consumer (lp8788-charger driver) */ +static struct iio_map lp8788_default_iio_maps[] = { +	{ +		.consumer_dev_name = "lp8788-charger", +		.consumer_channel = "lp8788_vbatt_5p0", +		.adc_channel_label = "VBATT_5P0", +	}, +	{ +		.consumer_dev_name = "lp8788-charger", +		.consumer_channel = "lp8788_adc1", +		.adc_channel_label = "ADC1", +	}, +	{ } +}; + +static int lp8788_iio_map_register(struct iio_dev *indio_dev, +				struct lp8788_platform_data *pdata, +				struct lp8788_adc *adc) +{ +	struct iio_map *map; +	int ret; + +	map = (!pdata || !pdata->adc_pdata) ? +		lp8788_default_iio_maps : pdata->adc_pdata; + +	ret = iio_map_array_register(indio_dev, map); +	if (ret) { +		dev_err(&indio_dev->dev, "iio map err: %d\n", ret); +		return ret; +	} + +	adc->map = map; +	return 0; +} + +static int lp8788_adc_probe(struct platform_device *pdev) +{ +	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); +	struct iio_dev *indio_dev; +	struct lp8788_adc *adc; +	int ret; + +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); +	if (!indio_dev) +		return -ENOMEM; + +	adc = iio_priv(indio_dev); +	adc->lp = lp; +	platform_set_drvdata(pdev, indio_dev); + +	indio_dev->dev.of_node = pdev->dev.of_node; +	ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc); +	if (ret) +		return ret; + +	mutex_init(&adc->lock); + +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->name = pdev->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &lp8788_adc_info; +	indio_dev->channels = lp8788_adc_channels; +	indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels); + +	ret = iio_device_register(indio_dev); +	if (ret) { +		dev_err(&pdev->dev, "iio dev register err: %d\n", ret); +		goto err_iio_device; +	} + +	return 0; + +err_iio_device: +	iio_map_array_unregister(indio_dev); +	return ret; +} + +static int lp8788_adc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); + +	iio_device_unregister(indio_dev); +	iio_map_array_unregister(indio_dev); + +	return 0; +} + +static struct platform_driver lp8788_adc_driver = { +	.probe = lp8788_adc_probe, +	.remove = lp8788_adc_remove, +	.driver = { +		.name = LP8788_DEV_ADC, +		.owner = THIS_MODULE, +	}, +}; +module_platform_driver(lp8788_adc_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-adc"); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c new file mode 100644 index 00000000000..1b3b74be5c2 --- /dev/null +++ b/drivers/iio/adc/max1363.c @@ -0,0 +1,1701 @@ + /* +  * iio/adc/max1363.c +  * Copyright (C) 2008-2010 Jonathan Cameron +  * +  * based on linux/drivers/i2c/chips/max123x +  * Copyright (C) 2002-2004 Stefan Eletzhofer +  * +  * based on linux/drivers/acron/char/pcf8583.c +  * Copyright (C) 2000 Russell King +  * +  * Driver for max1363 and similar chips. +  * +  * This program is free software; you can redistribute it and/or modify +  * it under the terms of the GNU General Public License version 2 as +  * published by the Free Software Foundation. +  */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> +#include <linux/iio/buffer.h> +#include <linux/iio/driver.h> +#include <linux/iio/kfifo_buf.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define MAX1363_SETUP_BYTE(a) ((a) | 0x80) + +/* There is a fair bit more defined here than currently + * used, but the intention is to support everything these + * chips do in the long run */ + +/* see data sheets */ +/* max1363 and max1236, max1237, max1238, max1239 */ +#define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD	0x00 +#define MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF	0x20 +#define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT	0x40 +#define MAX1363_SETUP_AIN3_IS_REF_REF_IS_INT	0x60 +#define MAX1363_SETUP_POWER_UP_INT_REF		0x10 +#define MAX1363_SETUP_POWER_DOWN_INT_REF	0x00 + +/* think about including max11600 etc - more settings */ +#define MAX1363_SETUP_EXT_CLOCK			0x08 +#define MAX1363_SETUP_INT_CLOCK			0x00 +#define MAX1363_SETUP_UNIPOLAR			0x00 +#define MAX1363_SETUP_BIPOLAR			0x04 +#define MAX1363_SETUP_RESET			0x00 +#define MAX1363_SETUP_NORESET			0x02 +/* max1363 only - though don't care on others. + * For now monitor modes are not implemented as the relevant + * line is not connected on my test board. + * The definitions are here as I intend to add this soon. + */ +#define MAX1363_SETUP_MONITOR_SETUP		0x01 + +/* Specific to the max1363 */ +#define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4)) +#define MAX1363_MON_INT_ENABLE			0x01 + +/* defined for readability reasons */ +/* All chips */ +#define MAX1363_CONFIG_BYTE(a) ((a)) + +#define MAX1363_CONFIG_SE			0x01 +#define MAX1363_CONFIG_DE			0x00 +#define MAX1363_CONFIG_SCAN_TO_CS		0x00 +#define MAX1363_CONFIG_SCAN_SINGLE_8		0x20 +#define MAX1363_CONFIG_SCAN_MONITOR_MODE	0x40 +#define MAX1363_CONFIG_SCAN_SINGLE_1		0x60 +/* max123{6-9} only */ +#define MAX1236_SCAN_MID_TO_CHANNEL		0x40 + +/* max1363 only - merely part of channel selects or don't care for others */ +#define MAX1363_CONFIG_EN_MON_MODE_READ 0x18 + +#define MAX1363_CHANNEL_SEL(a) ((a) << 1) + +/* max1363 strictly 0x06 - but doesn't matter */ +#define MAX1363_CHANNEL_SEL_MASK		0x1E +#define MAX1363_SCAN_MASK			0x60 +#define MAX1363_SE_DE_MASK			0x01 + +#define MAX1363_MAX_CHANNELS 25 +/** + * struct max1363_mode - scan mode information + * @conf:	The corresponding value of the configuration register + * @modemask:	Bit mask corresponding to channels enabled in this mode + */ +struct max1363_mode { +	int8_t		conf; +	DECLARE_BITMAP(modemask, MAX1363_MAX_CHANNELS); +}; + +/* This must be maintained along side the max1363_mode_table in max1363_core */ +enum max1363_modes { +	/* Single read of a single channel */ +	_s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11, +	/* Differential single read */ +	d0m1, d2m3, d4m5, d6m7, d8m9, d10m11, +	d1m0, d3m2, d5m4, d7m6, d9m8, d11m10, +	/* Scan to channel and mid to channel where overlapping */ +	s0to1, s0to2, s2to3, s0to3, s0to4, s0to5, s0to6, +	s6to7, s0to7, s6to8, s0to8, s6to9, +	s0to9, s6to10, s0to10, s6to11, s0to11, +	/* Differential scan to channel and mid to channel where overlapping */ +	d0m1to2m3, d0m1to4m5, d0m1to6m7, d6m7to8m9, +	d0m1to8m9, d6m7to10m11, d0m1to10m11, d1m0to3m2, +	d1m0to5m4, d1m0to7m6, d7m6to9m8, d1m0to9m8, +	d7m6to11m10, d1m0to11m10, +}; + +/** + * struct max1363_chip_info - chip specifc information + * @info:		iio core function callbacks structure + * @channels:		channel specification + * @num_channels:       number of channels + * @mode_list:		array of available scan modes + * @default_mode:	the scan mode in which the chip starts up + * @int_vref_mv:	the internal reference voltage + * @num_modes:		number of modes + * @bits:		accuracy of the adc in bits + */ +struct max1363_chip_info { +	const struct iio_info		*info; +	const struct iio_chan_spec	*channels; +	int				num_channels; +	const enum max1363_modes	*mode_list; +	enum max1363_modes		default_mode; +	u16				int_vref_mv; +	u8				num_modes; +	u8				bits; +}; + +/** + * struct max1363_state - driver instance specific data + * @client:		i2c_client + * @setupbyte:		cache of current device setup byte + * @configbyte:		cache of current device config byte + * @chip_info:		chip model specific constants, available modes, etc. + * @current_mode:	the scan mode of this chip + * @requestedmask:	a valid requested set of channels + * @reg:		supply regulator + * @monitor_on:		whether monitor mode is enabled + * @monitor_speed:	parameter corresponding to device monitor speed setting + * @mask_high:		bitmask for enabled high thresholds + * @mask_low:		bitmask for enabled low thresholds + * @thresh_high:	high threshold values + * @thresh_low:		low threshold values + * @vref:		Reference voltage regulator + * @vref_uv:		Actual (external or internal) reference voltage + * @send:		function used to send data to the chip + * @recv:		function used to receive data from the chip + */ +struct max1363_state { +	struct i2c_client		*client; +	u8				setupbyte; +	u8				configbyte; +	const struct max1363_chip_info	*chip_info; +	const struct max1363_mode	*current_mode; +	u32				requestedmask; +	struct regulator		*reg; + +	/* Using monitor modes and buffer at the same time is +	   currently not supported */ +	bool				monitor_on; +	unsigned int			monitor_speed:3; +	u8				mask_high; +	u8				mask_low; +	/* 4x unipolar first then the fours bipolar ones */ +	s16				thresh_high[8]; +	s16				thresh_low[8]; +	struct regulator		*vref; +	u32				vref_uv; +	int				(*send)(const struct i2c_client *client, +						const char *buf, int count); +	int				(*recv)(const struct i2c_client *client, +						char *buf, int count); +}; + +#define MAX1363_MODE_SINGLE(_num, _mask) {				\ +		.conf = MAX1363_CHANNEL_SEL(_num)			\ +			| MAX1363_CONFIG_SCAN_SINGLE_1			\ +			| MAX1363_CONFIG_SE,				\ +			.modemask[0] = _mask,				\ +			} + +#define MAX1363_MODE_SCAN_TO_CHANNEL(_num, _mask) {			\ +		.conf = MAX1363_CHANNEL_SEL(_num)			\ +			| MAX1363_CONFIG_SCAN_TO_CS			\ +			| MAX1363_CONFIG_SE,				\ +			.modemask[0] = _mask,				\ +			} + +/* note not available for max1363 hence naming */ +#define MAX1236_MODE_SCAN_MID_TO_CHANNEL(_mid, _num, _mask) {		\ +		.conf = MAX1363_CHANNEL_SEL(_num)			\ +			| MAX1236_SCAN_MID_TO_CHANNEL			\ +			| MAX1363_CONFIG_SE,				\ +			.modemask[0] = _mask				\ +} + +#define MAX1363_MODE_DIFF_SINGLE(_nump, _numm, _mask) {			\ +		.conf = MAX1363_CHANNEL_SEL(_nump)			\ +			| MAX1363_CONFIG_SCAN_SINGLE_1			\ +			| MAX1363_CONFIG_DE,				\ +			.modemask[0] = _mask				\ +			} + +/* Can't think how to automate naming so specify for now */ +#define MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(_num, _numvals, _mask) {	\ +		.conf = MAX1363_CHANNEL_SEL(_num)			\ +			| MAX1363_CONFIG_SCAN_TO_CS			\ +			| MAX1363_CONFIG_DE,				\ +			.modemask[0] = _mask				\ +			} + +/* note only available for max1363 hence naming */ +#define MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(_num, _numvals, _mask) {	\ +		.conf = MAX1363_CHANNEL_SEL(_num)			\ +			| MAX1236_SCAN_MID_TO_CHANNEL			\ +			| MAX1363_CONFIG_SE,				\ +			.modemask[0] = _mask				\ +} + +static const struct max1363_mode max1363_mode_table[] = { +	/* All of the single channel options first */ +	MAX1363_MODE_SINGLE(0, 1 << 0), +	MAX1363_MODE_SINGLE(1, 1 << 1), +	MAX1363_MODE_SINGLE(2, 1 << 2), +	MAX1363_MODE_SINGLE(3, 1 << 3), +	MAX1363_MODE_SINGLE(4, 1 << 4), +	MAX1363_MODE_SINGLE(5, 1 << 5), +	MAX1363_MODE_SINGLE(6, 1 << 6), +	MAX1363_MODE_SINGLE(7, 1 << 7), +	MAX1363_MODE_SINGLE(8, 1 << 8), +	MAX1363_MODE_SINGLE(9, 1 << 9), +	MAX1363_MODE_SINGLE(10, 1 << 10), +	MAX1363_MODE_SINGLE(11, 1 << 11), + +	MAX1363_MODE_DIFF_SINGLE(0, 1, 1 << 12), +	MAX1363_MODE_DIFF_SINGLE(2, 3, 1 << 13), +	MAX1363_MODE_DIFF_SINGLE(4, 5, 1 << 14), +	MAX1363_MODE_DIFF_SINGLE(6, 7, 1 << 15), +	MAX1363_MODE_DIFF_SINGLE(8, 9, 1 << 16), +	MAX1363_MODE_DIFF_SINGLE(10, 11, 1 << 17), +	MAX1363_MODE_DIFF_SINGLE(1, 0, 1 << 18), +	MAX1363_MODE_DIFF_SINGLE(3, 2, 1 << 19), +	MAX1363_MODE_DIFF_SINGLE(5, 4, 1 << 20), +	MAX1363_MODE_DIFF_SINGLE(7, 6, 1 << 21), +	MAX1363_MODE_DIFF_SINGLE(9, 8, 1 << 22), +	MAX1363_MODE_DIFF_SINGLE(11, 10, 1 << 23), + +	/* The multichannel scans next */ +	MAX1363_MODE_SCAN_TO_CHANNEL(1, 0x003), +	MAX1363_MODE_SCAN_TO_CHANNEL(2, 0x007), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(2, 3, 0x00C), +	MAX1363_MODE_SCAN_TO_CHANNEL(3, 0x00F), +	MAX1363_MODE_SCAN_TO_CHANNEL(4, 0x01F), +	MAX1363_MODE_SCAN_TO_CHANNEL(5, 0x03F), +	MAX1363_MODE_SCAN_TO_CHANNEL(6, 0x07F), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 7, 0x0C0), +	MAX1363_MODE_SCAN_TO_CHANNEL(7, 0x0FF), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 8, 0x1C0), +	MAX1363_MODE_SCAN_TO_CHANNEL(8, 0x1FF), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 9, 0x3C0), +	MAX1363_MODE_SCAN_TO_CHANNEL(9, 0x3FF), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 10, 0x7C0), +	MAX1363_MODE_SCAN_TO_CHANNEL(10, 0x7FF), +	MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 11, 0xFC0), +	MAX1363_MODE_SCAN_TO_CHANNEL(11, 0xFFF), + +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(2, 2, 0x003000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(4, 3, 0x007000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(6, 4, 0x00F000), +	MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(8, 2, 0x018000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(8, 5, 0x01F000), +	MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(10, 3, 0x038000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(10, 6, 0x3F000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(3, 2, 0x0C0000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(5, 3, 0x1C0000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(7, 4, 0x3C0000), +	MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(9, 2, 0x600000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(9, 5, 0x7C0000), +	MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(11, 3, 0xE00000), +	MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(11, 6, 0xFC0000), +}; + +static const struct max1363_mode +*max1363_match_mode(const unsigned long *mask, +	const struct max1363_chip_info *ci) +{ +	int i; +	if (mask) +		for (i = 0; i < ci->num_modes; i++) +			if (bitmap_subset(mask, +					  max1363_mode_table[ci->mode_list[i]]. +					  modemask, +					  MAX1363_MAX_CHANNELS)) +				return &max1363_mode_table[ci->mode_list[i]]; +	return NULL; +} + +static int max1363_smbus_send(const struct i2c_client *client, const char *buf, +		int count) +{ +	int i, err; + +	for (i = err = 0; err == 0 && i < count; ++i) +		err = i2c_smbus_write_byte(client, buf[i]); + +	return err ? err : count; +} + +static int max1363_smbus_recv(const struct i2c_client *client, char *buf, +		int count) +{ +	int i, ret; + +	for (i = 0; i < count; ++i) { +		ret = i2c_smbus_read_byte(client); +		if (ret < 0) +			return ret; +		buf[i] = ret; +	} + +	return count; +} + +static int max1363_write_basic_config(struct max1363_state *st) +{ +	u8 tx_buf[2] = { st->setupbyte, st->configbyte }; + +	return st->send(st->client, tx_buf, 2); +} + +static int max1363_set_scan_mode(struct max1363_state *st) +{ +	st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK +			    | MAX1363_SCAN_MASK +			    | MAX1363_SE_DE_MASK); +	st->configbyte |= st->current_mode->conf; + +	return max1363_write_basic_config(st); +} + +static int max1363_read_single_chan(struct iio_dev *indio_dev, +				    struct iio_chan_spec const *chan, +				    int *val, +				    long m) +{ +	int ret = 0; +	s32 data; +	u8 rxbuf[2]; +	struct max1363_state *st = iio_priv(indio_dev); +	struct i2c_client *client = st->client; + +	mutex_lock(&indio_dev->mlock); +	/* +	 * If monitor mode is enabled, the method for reading a single +	 * channel will have to be rather different and has not yet +	 * been implemented. +	 * +	 * Also, cannot read directly if buffered capture enabled. +	 */ +	if (st->monitor_on || iio_buffer_enabled(indio_dev)) { +		ret = -EBUSY; +		goto error_ret; +	} + +	/* Check to see if current scan mode is correct */ +	if (st->current_mode != &max1363_mode_table[chan->address]) { +		/* Update scan mode if needed */ +		st->current_mode = &max1363_mode_table[chan->address]; +		ret = max1363_set_scan_mode(st); +		if (ret < 0) +			goto error_ret; +	} +	if (st->chip_info->bits != 8) { +		/* Get reading */ +		data = st->recv(client, rxbuf, 2); +		if (data < 0) { +			ret = data; +			goto error_ret; +		} +		data = (rxbuf[1] | rxbuf[0] << 8) & +		  ((1 << st->chip_info->bits) - 1); +	} else { +		/* Get reading */ +		data = st->recv(client, rxbuf, 1); +		if (data < 0) { +			ret = data; +			goto error_ret; +		} +		data = rxbuf[0]; +	} +	*val = data; +error_ret: +	mutex_unlock(&indio_dev->mlock); +	return ret; + +} + +static int max1363_read_raw(struct iio_dev *indio_dev, +			    struct iio_chan_spec const *chan, +			    int *val, +			    int *val2, +			    long m) +{ +	struct max1363_state *st = iio_priv(indio_dev); +	int ret; + +	switch (m) { +	case IIO_CHAN_INFO_RAW: +		ret = max1363_read_single_chan(indio_dev, chan, val, m); +		if (ret < 0) +			return ret; +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		*val = st->vref_uv / 1000; +		*val2 = st->chip_info->bits; +		return IIO_VAL_FRACTIONAL_LOG2; +	default: +		return -EINVAL; +	} +	return 0; +} + +/* Applies to max1363 */ +static const enum max1363_modes max1363_mode_list[] = { +	_s0, _s1, _s2, _s3, +	s0to1, s0to2, s0to3, +	d0m1, d2m3, d1m0, d3m2, +	d0m1to2m3, d1m0to3m2, +}; + +static const struct iio_event_spec max1363_events[] = { +	{ +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_RISING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE) | +			BIT(IIO_EV_INFO_ENABLE), +	}, { +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_FALLING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE) | +			BIT(IIO_EV_INFO_ENABLE), +	}, +}; + +#define MAX1363_CHAN_U(num, addr, si, bits, ev_spec, num_ev_spec)	\ +	{								\ +		.type = IIO_VOLTAGE,					\ +		.indexed = 1,						\ +		.channel = num,						\ +		.address = addr,					\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\ +		.datasheet_name = "AIN"#num,				\ +		.scan_type = {						\ +			.sign = 'u',					\ +			.realbits = bits,				\ +			.storagebits = (bits > 8) ? 16 : 8,		\ +			.endianness = IIO_BE,				\ +		},							\ +		.scan_index = si,					\ +		.event_spec = ev_spec,					\ +		.num_event_specs = num_ev_spec,				\ +	} + +/* bipolar channel */ +#define MAX1363_CHAN_B(num, num2, addr, si, bits, ev_spec, num_ev_spec)	\ +	{								\ +		.type = IIO_VOLTAGE,					\ +		.differential = 1,					\ +		.indexed = 1,						\ +		.channel = num,						\ +		.channel2 = num2,					\ +		.address = addr,					\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\ +		.datasheet_name = "AIN"#num"-AIN"#num2,			\ +		.scan_type = {						\ +			.sign = 's',					\ +			.realbits = bits,				\ +			.storagebits = (bits > 8) ? 16 : 8,		\ +			.endianness = IIO_BE,				\ +		},							\ +		.scan_index = si,					\ +		.event_spec = ev_spec,					\ +		.num_event_specs = num_ev_spec,				\ +	} + +#define MAX1363_4X_CHANS(bits, ev_spec, num_ev_spec) {			\ +	MAX1363_CHAN_U(0, _s0, 0, bits, ev_spec, num_ev_spec),		\ +	MAX1363_CHAN_U(1, _s1, 1, bits, ev_spec, num_ev_spec),		\ +	MAX1363_CHAN_U(2, _s2, 2, bits, ev_spec, num_ev_spec),		\ +	MAX1363_CHAN_U(3, _s3, 3, bits, ev_spec, num_ev_spec),		\ +	MAX1363_CHAN_B(0, 1, d0m1, 4, bits, ev_spec, num_ev_spec),	\ +	MAX1363_CHAN_B(2, 3, d2m3, 5, bits, ev_spec, num_ev_spec),	\ +	MAX1363_CHAN_B(1, 0, d1m0, 6, bits, ev_spec, num_ev_spec),	\ +	MAX1363_CHAN_B(3, 2, d3m2, 7, bits, ev_spec, num_ev_spec),	\ +	IIO_CHAN_SOFT_TIMESTAMP(8)					\ +	} + +static const struct iio_chan_spec max1036_channels[] = +	MAX1363_4X_CHANS(8, NULL, 0); +static const struct iio_chan_spec max1136_channels[] = +	MAX1363_4X_CHANS(10, NULL, 0); +static const struct iio_chan_spec max1236_channels[] = +	MAX1363_4X_CHANS(12, NULL, 0); +static const struct iio_chan_spec max1361_channels[] = +	MAX1363_4X_CHANS(10, max1363_events, ARRAY_SIZE(max1363_events)); +static const struct iio_chan_spec max1363_channels[] = +	MAX1363_4X_CHANS(12, max1363_events, ARRAY_SIZE(max1363_events)); + +/* Applies to max1236, max1237 */ +static const enum max1363_modes max1236_mode_list[] = { +	_s0, _s1, _s2, _s3, +	s0to1, s0to2, s0to3, +	d0m1, d2m3, d1m0, d3m2, +	d0m1to2m3, d1m0to3m2, +	s2to3, +}; + +/* Applies to max1238, max1239 */ +static const enum max1363_modes max1238_mode_list[] = { +	_s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11, +	s0to1, s0to2, s0to3, s0to4, s0to5, s0to6, +	s0to7, s0to8, s0to9, s0to10, s0to11, +	d0m1, d2m3, d4m5, d6m7, d8m9, d10m11, +	d1m0, d3m2, d5m4, d7m6, d9m8, d11m10, +	d0m1to2m3, d0m1to4m5, d0m1to6m7, d0m1to8m9, d0m1to10m11, +	d1m0to3m2, d1m0to5m4, d1m0to7m6, d1m0to9m8, d1m0to11m10, +	s6to7, s6to8, s6to9, s6to10, s6to11, +	d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10, +}; + +#define MAX1363_12X_CHANS(bits) {				\ +	MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0),		\ +	MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0),		\ +	MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0),		\ +	MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0),		\ +	MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0),		\ +	MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0),		\ +	MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0),		\ +	MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0),		\ +	MAX1363_CHAN_U(8, _s8, 8, bits, NULL, 0),		\ +	MAX1363_CHAN_U(9, _s9, 9, bits, NULL, 0),		\ +	MAX1363_CHAN_U(10, _s10, 10, bits, NULL, 0),		\ +	MAX1363_CHAN_U(11, _s11, 11, bits, NULL, 0),		\ +	MAX1363_CHAN_B(0, 1, d0m1, 12, bits, NULL, 0),		\ +	MAX1363_CHAN_B(2, 3, d2m3, 13, bits, NULL, 0),		\ +	MAX1363_CHAN_B(4, 5, d4m5, 14, bits, NULL, 0),		\ +	MAX1363_CHAN_B(6, 7, d6m7, 15, bits, NULL, 0),		\ +	MAX1363_CHAN_B(8, 9, d8m9, 16, bits, NULL, 0),		\ +	MAX1363_CHAN_B(10, 11, d10m11, 17, bits, NULL, 0),	\ +	MAX1363_CHAN_B(1, 0, d1m0, 18, bits, NULL, 0),		\ +	MAX1363_CHAN_B(3, 2, d3m2, 19, bits, NULL, 0),		\ +	MAX1363_CHAN_B(5, 4, d5m4, 20, bits, NULL, 0),		\ +	MAX1363_CHAN_B(7, 6, d7m6, 21, bits, NULL, 0),		\ +	MAX1363_CHAN_B(9, 8, d9m8, 22, bits, NULL, 0),		\ +	MAX1363_CHAN_B(11, 10, d11m10, 23, bits, NULL, 0),	\ +	IIO_CHAN_SOFT_TIMESTAMP(24)				\ +	} +static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8); +static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10); +static const struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12); + +static const enum max1363_modes max11607_mode_list[] = { +	_s0, _s1, _s2, _s3, +	s0to1, s0to2, s0to3, +	s2to3, +	d0m1, d2m3, d1m0, d3m2, +	d0m1to2m3, d1m0to3m2, +}; + +static const enum max1363_modes max11608_mode_list[] = { +	_s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, +	s0to1, s0to2, s0to3, s0to4, s0to5, s0to6, s0to7, +	s6to7, +	d0m1, d2m3, d4m5, d6m7, +	d1m0, d3m2, d5m4, d7m6, +	d0m1to2m3, d0m1to4m5, d0m1to6m7, +	d1m0to3m2, d1m0to5m4, d1m0to7m6, +}; + +#define MAX1363_8X_CHANS(bits) {			\ +	MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0),	\ +	MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0),	\ +	MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0),	\ +	MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0),	\ +	MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0),	\ +	MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0),	\ +	MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0),	\ +	MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0),	\ +	MAX1363_CHAN_B(0, 1, d0m1, 8, bits, NULL, 0),	\ +	MAX1363_CHAN_B(2, 3, d2m3, 9, bits, NULL, 0),	\ +	MAX1363_CHAN_B(4, 5, d4m5, 10, bits, NULL, 0),	\ +	MAX1363_CHAN_B(6, 7, d6m7, 11, bits, NULL, 0),	\ +	MAX1363_CHAN_B(1, 0, d1m0, 12, bits, NULL, 0),	\ +	MAX1363_CHAN_B(3, 2, d3m2, 13, bits, NULL, 0),	\ +	MAX1363_CHAN_B(5, 4, d5m4, 14, bits, NULL, 0),	\ +	MAX1363_CHAN_B(7, 6, d7m6, 15, bits, NULL, 0),	\ +	IIO_CHAN_SOFT_TIMESTAMP(16)			\ +} +static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8); +static const struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10); +static const struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12); + +static const enum max1363_modes max11644_mode_list[] = { +	_s0, _s1, s0to1, d0m1, d1m0, +}; + +#define MAX1363_2X_CHANS(bits) {			\ +	MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0),	\ +	MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0),	\ +	MAX1363_CHAN_B(0, 1, d0m1, 2, bits, NULL, 0),	\ +	MAX1363_CHAN_B(1, 0, d1m0, 3, bits, NULL, 0),	\ +	IIO_CHAN_SOFT_TIMESTAMP(4)			\ +	} + +static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10); +static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12); + +enum { max1361, +       max1362, +       max1363, +       max1364, +       max1036, +       max1037, +       max1038, +       max1039, +       max1136, +       max1137, +       max1138, +       max1139, +       max1236, +       max1237, +       max1238, +       max1239, +       max11600, +       max11601, +       max11602, +       max11603, +       max11604, +       max11605, +       max11606, +       max11607, +       max11608, +       max11609, +       max11610, +       max11611, +       max11612, +       max11613, +       max11614, +       max11615, +       max11616, +       max11617, +       max11644, +       max11645, +       max11646, +       max11647 +}; + +static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, +					      8300, 4200, 2000, 1000 }; + +static ssize_t max1363_monitor_show_freq(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	struct max1363_state *st = iio_priv(dev_to_iio_dev(dev)); +	return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); +} + +static ssize_t max1363_monitor_store_freq(struct device *dev, +					struct device_attribute *attr, +					const char *buf, +					size_t len) +{ +	struct iio_dev *indio_dev = dev_to_iio_dev(dev); +	struct max1363_state *st = iio_priv(indio_dev); +	int i, ret; +	unsigned long val; +	bool found = false; + +	ret = kstrtoul(buf, 10, &val); +	if (ret) +		return -EINVAL; +	for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) +		if (val == max1363_monitor_speeds[i]) { +			found = true; +			break; +		} +	if (!found) +		return -EINVAL; + +	mutex_lock(&indio_dev->mlock); +	st->monitor_speed = i; +	mutex_unlock(&indio_dev->mlock); + +	return 0; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, +			max1363_monitor_show_freq, +			max1363_monitor_store_freq); + +static IIO_CONST_ATTR(sampling_frequency_available, +		"133000 665000 33300 16600 8300 4200 2000 1000"); + +static int max1363_read_thresh(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, int *val, +	int *val2) +{ +	struct max1363_state *st = iio_priv(indio_dev); +	if (dir == IIO_EV_DIR_FALLING) +		*val = st->thresh_low[chan->channel]; +	else +		*val = st->thresh_high[chan->channel]; +	return IIO_VAL_INT; +} + +static int max1363_write_thresh(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, int val, +	int val2) +{ +	struct max1363_state *st = iio_priv(indio_dev); +	/* make it handle signed correctly as well */ +	switch (st->chip_info->bits) { +	case 10: +		if (val > 0x3FF) +			return -EINVAL; +		break; +	case 12: +		if (val > 0xFFF) +			return -EINVAL; +		break; +	} + +	switch (dir) { +	case IIO_EV_DIR_FALLING: +		st->thresh_low[chan->channel] = val; +		break; +	case IIO_EV_DIR_RISING: +		st->thresh_high[chan->channel] = val; +		break; +	default: +		return -EINVAL; +	} + +	return 0; +} + +static const u64 max1363_event_codes[] = { +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 2, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 3, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 2, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), +	IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 3, +			     IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), +}; + +static irqreturn_t max1363_event_handler(int irq, void *private) +{ +	struct iio_dev *indio_dev = private; +	struct max1363_state *st = iio_priv(indio_dev); +	s64 timestamp = iio_get_time_ns(); +	unsigned long mask, loc; +	u8 rx; +	u8 tx[2] = { st->setupbyte, +		     MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; + +	st->recv(st->client, &rx, 1); +	mask = rx; +	for_each_set_bit(loc, &mask, 8) +		iio_push_event(indio_dev, max1363_event_codes[loc], timestamp); +	st->send(st->client, tx, 2); + +	return IRQ_HANDLED; +} + +static int max1363_read_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir) +{ +	struct max1363_state *st = iio_priv(indio_dev); +	int val; +	int number = chan->channel; + +	mutex_lock(&indio_dev->mlock); +	if (dir == IIO_EV_DIR_FALLING) +		val = (1 << number) & st->mask_low; +	else +		val = (1 << number) & st->mask_high; +	mutex_unlock(&indio_dev->mlock); + +	return val; +} + +static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) +{ +	u8 *tx_buf; +	int ret, i = 3, j; +	unsigned long numelements; +	int len; +	const long *modemask; + +	if (!enabled) { +		/* transition to buffered capture is not currently supported */ +		st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; +		st->configbyte &= ~MAX1363_SCAN_MASK; +		st->monitor_on = false; +		return max1363_write_basic_config(st); +	} + +	/* Ensure we are in the relevant mode */ +	st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; +	st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK +			    | MAX1363_SCAN_MASK +			| MAX1363_SE_DE_MASK); +	st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; +	if ((st->mask_low | st->mask_high) & 0x0F) { +		st->configbyte |= max1363_mode_table[s0to3].conf; +		modemask = max1363_mode_table[s0to3].modemask; +	} else if ((st->mask_low | st->mask_high) & 0x30) { +		st->configbyte |= max1363_mode_table[d0m1to2m3].conf; +		modemask = max1363_mode_table[d0m1to2m3].modemask; +	} else { +		st->configbyte |= max1363_mode_table[d1m0to3m2].conf; +		modemask = max1363_mode_table[d1m0to3m2].modemask; +	} +	numelements = bitmap_weight(modemask, MAX1363_MAX_CHANNELS); +	len = 3 * numelements + 3; +	tx_buf = kmalloc(len, GFP_KERNEL); +	if (!tx_buf) { +		ret = -ENOMEM; +		goto error_ret; +	} +	tx_buf[0] = st->configbyte; +	tx_buf[1] = st->setupbyte; +	tx_buf[2] = (st->monitor_speed << 1); + +	/* +	 * So we need to do yet another bit of nefarious scan mode +	 * setup to match what we need. +	 */ +	for (j = 0; j < 8; j++) +		if (test_bit(j, modemask)) { +			/* Establish the mode is in the scan */ +			if (st->mask_low & (1 << j)) { +				tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; +				tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; +			} else if (j < 4) { +				tx_buf[i] = 0; +				tx_buf[i + 1] = 0; +			} else { +				tx_buf[i] = 0x80; +				tx_buf[i + 1] = 0; +			} +			if (st->mask_high & (1 << j)) { +				tx_buf[i + 1] |= +					(st->thresh_high[j] >> 8) & 0x0F; +				tx_buf[i + 2] = st->thresh_high[j] & 0xFF; +			} else if (j < 4) { +				tx_buf[i + 1] |= 0x0F; +				tx_buf[i + 2] = 0xFF; +			} else { +				tx_buf[i + 1] |= 0x07; +				tx_buf[i + 2] = 0xFF; +			} +			i += 3; +		} + + +	ret = st->send(st->client, tx_buf, len); +	if (ret < 0) +		goto error_ret; +	if (ret != len) { +		ret = -EIO; +		goto error_ret; +	} + +	/* +	 * Now that we hopefully have sensible thresholds in place it is +	 * time to turn the interrupts on. +	 * It is unclear from the data sheet if this should be necessary +	 * (i.e. whether monitor mode setup is atomic) but it appears to +	 * be in practice. +	 */ +	tx_buf[0] = st->setupbyte; +	tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; +	ret = st->send(st->client, tx_buf, 2); +	if (ret < 0) +		goto error_ret; +	if (ret != 2) { +		ret = -EIO; +		goto error_ret; +	} +	ret = 0; +	st->monitor_on = true; +error_ret: + +	kfree(tx_buf); + +	return ret; +} + +/* + * To keep this manageable we always use one of 3 scan modes. + * Scan 0...3, 0-1,2-3 and 1-0,3-2 + */ + +static inline int __max1363_check_event_mask(int thismask, int checkmask) +{ +	int ret = 0; +	/* Is it unipolar */ +	if (thismask < 4) { +		if (checkmask & ~0x0F) { +			ret = -EBUSY; +			goto error_ret; +		} +	} else if (thismask < 6) { +		if (checkmask & ~0x30) { +			ret = -EBUSY; +			goto error_ret; +		} +	} else if (checkmask & ~0xC0) +		ret = -EBUSY; +error_ret: +	return ret; +} + +static int max1363_write_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, int state) +{ +	int ret = 0; +	struct max1363_state *st = iio_priv(indio_dev); +	u16 unifiedmask; +	int number = chan->channel; + +	mutex_lock(&indio_dev->mlock); +	unifiedmask = st->mask_low | st->mask_high; +	if (dir == IIO_EV_DIR_FALLING) { + +		if (state == 0) +			st->mask_low &= ~(1 << number); +		else { +			ret = __max1363_check_event_mask((1 << number), +							 unifiedmask); +			if (ret) +				goto error_ret; +			st->mask_low |= (1 << number); +		} +	} else { +		if (state == 0) +			st->mask_high &= ~(1 << number); +		else { +			ret = __max1363_check_event_mask((1 << number), +							 unifiedmask); +			if (ret) +				goto error_ret; +			st->mask_high |= (1 << number); +		} +	} + +	max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); +error_ret: +	mutex_unlock(&indio_dev->mlock); + +	return ret; +} + +/* + * As with scan_elements, only certain sets of these can + * be combined. + */ +static struct attribute *max1363_event_attributes[] = { +	&iio_dev_attr_sampling_frequency.dev_attr.attr, +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	NULL, +}; + +static struct attribute_group max1363_event_attribute_group = { +	.attrs = max1363_event_attributes, +	.name = "events", +}; + +static int max1363_update_scan_mode(struct iio_dev *indio_dev, +				    const unsigned long *scan_mask) +{ +	struct max1363_state *st = iio_priv(indio_dev); + +	/* +	 * Need to figure out the current mode based upon the requested +	 * scan mask in iio_dev +	 */ +	st->current_mode = max1363_match_mode(scan_mask, st->chip_info); +	if (!st->current_mode) +		return -EINVAL; +	max1363_set_scan_mode(st); +	return 0; +} + +static const struct iio_info max1238_info = { +	.read_raw = &max1363_read_raw, +	.driver_module = THIS_MODULE, +	.update_scan_mode = &max1363_update_scan_mode, +}; + +static const struct iio_info max1363_info = { +	.read_event_value = &max1363_read_thresh, +	.write_event_value = &max1363_write_thresh, +	.read_event_config = &max1363_read_event_config, +	.write_event_config = &max1363_write_event_config, +	.read_raw = &max1363_read_raw, +	.update_scan_mode = &max1363_update_scan_mode, +	.driver_module = THIS_MODULE, +	.event_attrs = &max1363_event_attribute_group, +}; + +/* max1363 and max1368 tested - rest from data sheet */ +static const struct max1363_chip_info max1363_chip_info_tbl[] = { +	[max1361] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max1363_mode_list, +		.num_modes = ARRAY_SIZE(max1363_mode_list), +		.default_mode = s0to3, +		.channels = max1361_channels, +		.num_channels = ARRAY_SIZE(max1361_channels), +		.info = &max1363_info, +	}, +	[max1362] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max1363_mode_list, +		.num_modes = ARRAY_SIZE(max1363_mode_list), +		.default_mode = s0to3, +		.channels = max1361_channels, +		.num_channels = ARRAY_SIZE(max1361_channels), +		.info = &max1363_info, +	}, +	[max1363] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max1363_mode_list, +		.num_modes = ARRAY_SIZE(max1363_mode_list), +		.default_mode = s0to3, +		.channels = max1363_channels, +		.num_channels = ARRAY_SIZE(max1363_channels), +		.info = &max1363_info, +	}, +	[max1364] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max1363_mode_list, +		.num_modes = ARRAY_SIZE(max1363_mode_list), +		.default_mode = s0to3, +		.channels = max1363_channels, +		.num_channels = ARRAY_SIZE(max1363_channels), +		.info = &max1363_info, +	}, +	[max1036] = { +		.bits = 8, +		.int_vref_mv = 4096, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1036_channels, +		.num_channels = ARRAY_SIZE(max1036_channels), +	}, +	[max1037] = { +		.bits = 8, +		.int_vref_mv = 2048, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1036_channels, +		.num_channels = ARRAY_SIZE(max1036_channels), +	}, +	[max1038] = { +		.bits = 8, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1038_channels, +		.num_channels = ARRAY_SIZE(max1038_channels), +	}, +	[max1039] = { +		.bits = 8, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1038_channels, +		.num_channels = ARRAY_SIZE(max1038_channels), +	}, +	[max1136] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1136_channels, +		.num_channels = ARRAY_SIZE(max1136_channels), +	}, +	[max1137] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1136_channels, +		.num_channels = ARRAY_SIZE(max1136_channels), +	}, +	[max1138] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1138_channels, +		.num_channels = ARRAY_SIZE(max1138_channels), +	}, +	[max1139] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1138_channels, +		.num_channels = ARRAY_SIZE(max1138_channels), +	}, +	[max1236] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1236_channels, +		.num_channels = ARRAY_SIZE(max1236_channels), +	}, +	[max1237] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max1236_mode_list, +		.num_modes = ARRAY_SIZE(max1236_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1236_channels, +		.num_channels = ARRAY_SIZE(max1236_channels), +	}, +	[max1238] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1238_channels, +		.num_channels = ARRAY_SIZE(max1238_channels), +	}, +	[max1239] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1238_channels, +		.num_channels = ARRAY_SIZE(max1238_channels), +	}, +	[max11600] = { +		.bits = 8, +		.int_vref_mv = 4096, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1036_channels, +		.num_channels = ARRAY_SIZE(max1036_channels), +	}, +	[max11601] = { +		.bits = 8, +		.int_vref_mv = 2048, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1036_channels, +		.num_channels = ARRAY_SIZE(max1036_channels), +	}, +	[max11602] = { +		.bits = 8, +		.int_vref_mv = 4096, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11602_channels, +		.num_channels = ARRAY_SIZE(max11602_channels), +	}, +	[max11603] = { +		.bits = 8, +		.int_vref_mv = 2048, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11602_channels, +		.num_channels = ARRAY_SIZE(max11602_channels), +	}, +	[max11604] = { +		.bits = 8, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1038_channels, +		.num_channels = ARRAY_SIZE(max1038_channels), +	}, +	[max11605] = { +		.bits = 8, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1038_channels, +		.num_channels = ARRAY_SIZE(max1038_channels), +	}, +	[max11606] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1136_channels, +		.num_channels = ARRAY_SIZE(max1136_channels), +	}, +	[max11607] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1136_channels, +		.num_channels = ARRAY_SIZE(max1136_channels), +	}, +	[max11608] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11608_channels, +		.num_channels = ARRAY_SIZE(max11608_channels), +	}, +	[max11609] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11608_channels, +		.num_channels = ARRAY_SIZE(max11608_channels), +	}, +	[max11610] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1138_channels, +		.num_channels = ARRAY_SIZE(max1138_channels), +	}, +	[max11611] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1138_channels, +		.num_channels = ARRAY_SIZE(max1138_channels), +	}, +	[max11612] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1363_channels, +		.num_channels = ARRAY_SIZE(max1363_channels), +	}, +	[max11613] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max11607_mode_list, +		.num_modes = ARRAY_SIZE(max11607_mode_list), +		.default_mode = s0to3, +		.info = &max1238_info, +		.channels = max1363_channels, +		.num_channels = ARRAY_SIZE(max1363_channels), +	}, +	[max11614] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11614_channels, +		.num_channels = ARRAY_SIZE(max11614_channels), +	}, +	[max11615] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max11608_mode_list, +		.num_modes = ARRAY_SIZE(max11608_mode_list), +		.default_mode = s0to7, +		.info = &max1238_info, +		.channels = max11614_channels, +		.num_channels = ARRAY_SIZE(max11614_channels), +	}, +	[max11616] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1238_channels, +		.num_channels = ARRAY_SIZE(max1238_channels), +	}, +	[max11617] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max1238_mode_list, +		.num_modes = ARRAY_SIZE(max1238_mode_list), +		.default_mode = s0to11, +		.info = &max1238_info, +		.channels = max1238_channels, +		.num_channels = ARRAY_SIZE(max1238_channels), +	}, +	[max11644] = { +		.bits = 12, +		.int_vref_mv = 2048, +		.mode_list = max11644_mode_list, +		.num_modes = ARRAY_SIZE(max11644_mode_list), +		.default_mode = s0to1, +		.info = &max1238_info, +		.channels = max11644_channels, +		.num_channels = ARRAY_SIZE(max11644_channels), +	}, +	[max11645] = { +		.bits = 12, +		.int_vref_mv = 4096, +		.mode_list = max11644_mode_list, +		.num_modes = ARRAY_SIZE(max11644_mode_list), +		.default_mode = s0to1, +		.info = &max1238_info, +		.channels = max11644_channels, +		.num_channels = ARRAY_SIZE(max11644_channels), +	}, +	[max11646] = { +		.bits = 10, +		.int_vref_mv = 2048, +		.mode_list = max11644_mode_list, +		.num_modes = ARRAY_SIZE(max11644_mode_list), +		.default_mode = s0to1, +		.info = &max1238_info, +		.channels = max11646_channels, +		.num_channels = ARRAY_SIZE(max11646_channels), +	}, +	[max11647] = { +		.bits = 10, +		.int_vref_mv = 4096, +		.mode_list = max11644_mode_list, +		.num_modes = ARRAY_SIZE(max11644_mode_list), +		.default_mode = s0to1, +		.info = &max1238_info, +		.channels = max11646_channels, +		.num_channels = ARRAY_SIZE(max11646_channels), +	}, +}; + +static int max1363_initial_setup(struct max1363_state *st) +{ +	st->setupbyte = MAX1363_SETUP_INT_CLOCK +		| MAX1363_SETUP_UNIPOLAR +		| MAX1363_SETUP_NORESET; + +	if (st->vref) +		st->setupbyte |= MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF; +	else +		st->setupbyte |= MAX1363_SETUP_POWER_UP_INT_REF +		  | MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT; + +	/* Set scan mode writes the config anyway so wait until then */ +	st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte); +	st->current_mode = &max1363_mode_table[st->chip_info->default_mode]; +	st->configbyte = MAX1363_CONFIG_BYTE(st->configbyte); + +	return max1363_set_scan_mode(st); +} + +static int max1363_alloc_scan_masks(struct iio_dev *indio_dev) +{ +	struct max1363_state *st = iio_priv(indio_dev); +	unsigned long *masks; +	int i; + +	masks = devm_kzalloc(&indio_dev->dev, +			BITS_TO_LONGS(MAX1363_MAX_CHANNELS) * sizeof(long) * +			(st->chip_info->num_modes + 1), GFP_KERNEL); +	if (!masks) +		return -ENOMEM; + +	for (i = 0; i < st->chip_info->num_modes; i++) +		bitmap_copy(masks + BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i, +			    max1363_mode_table[st->chip_info->mode_list[i]] +			    .modemask, MAX1363_MAX_CHANNELS); + +	indio_dev->available_scan_masks = masks; + +	return 0; +} + +static irqreturn_t max1363_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct max1363_state *st = iio_priv(indio_dev); +	__u8 *rxbuf; +	int b_sent; +	size_t d_size; +	unsigned long numvals = bitmap_weight(st->current_mode->modemask, +					      MAX1363_MAX_CHANNELS); + +	/* Ensure the timestamp is 8 byte aligned */ +	if (st->chip_info->bits != 8) +		d_size = numvals*2; +	else +		d_size = numvals; +	if (indio_dev->scan_timestamp) { +		d_size += sizeof(s64); +		if (d_size % sizeof(s64)) +			d_size += sizeof(s64) - (d_size % sizeof(s64)); +	} +	/* Monitor mode prevents reading. Whilst not currently implemented +	 * might as well have this test in here in the meantime as it does +	 * no harm. +	 */ +	if (numvals == 0) +		goto done; + +	rxbuf = kmalloc(d_size,	GFP_KERNEL); +	if (rxbuf == NULL) +		goto done; +	if (st->chip_info->bits != 8) +		b_sent = st->recv(st->client, rxbuf, numvals * 2); +	else +		b_sent = st->recv(st->client, rxbuf, numvals); +	if (b_sent < 0) +		goto done_free; + +	iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns()); + +done_free: +	kfree(rxbuf); +done: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static int max1363_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	int ret; +	struct max1363_state *st; +	struct iio_dev *indio_dev; +	struct regulator *vref; + +	indio_dev = devm_iio_device_alloc(&client->dev, +					  sizeof(struct max1363_state)); +	if (!indio_dev) +		return -ENOMEM; + +	indio_dev->dev.of_node = client->dev.of_node; +	ret = iio_map_array_register(indio_dev, client->dev.platform_data); +	if (ret < 0) +		return ret; + +	st = iio_priv(indio_dev); + +	st->reg = devm_regulator_get(&client->dev, "vcc"); +	if (IS_ERR(st->reg)) { +		ret = PTR_ERR(st->reg); +		goto error_unregister_map; +	} + +	ret = regulator_enable(st->reg); +	if (ret) +		goto error_unregister_map; + +	/* this is only used for device removal purposes */ +	i2c_set_clientdata(client, indio_dev); + +	st->chip_info = &max1363_chip_info_tbl[id->driver_data]; +	st->client = client; + +	st->vref_uv = st->chip_info->int_vref_mv * 1000; +	vref = devm_regulator_get_optional(&client->dev, "vref"); +	if (!IS_ERR(vref)) { +		int vref_uv; + +		ret = regulator_enable(vref); +		if (ret) +			goto error_disable_reg; +		st->vref = vref; +		vref_uv = regulator_get_voltage(vref); +		if (vref_uv <= 0) { +			ret = -EINVAL; +			goto error_disable_reg; +		} +		st->vref_uv = vref_uv; +	} + +	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +		st->send = i2c_master_send; +		st->recv = i2c_master_recv; +	} else if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE) +			&& st->chip_info->bits == 8) { +		st->send = max1363_smbus_send; +		st->recv = max1363_smbus_recv; +	} else { +		ret = -EOPNOTSUPP; +		goto error_disable_reg; +	} + +	ret = max1363_alloc_scan_masks(indio_dev); +	if (ret) +		goto error_disable_reg; + +	/* Establish that the iio_dev is a child of the i2c device */ +	indio_dev->dev.parent = &client->dev; +	indio_dev->name = id->name; +	indio_dev->channels = st->chip_info->channels; +	indio_dev->num_channels = st->chip_info->num_channels; +	indio_dev->info = st->chip_info->info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	ret = max1363_initial_setup(st); +	if (ret < 0) +		goto error_disable_reg; + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +		&max1363_trigger_handler, NULL); +	if (ret) +		goto error_disable_reg; + +	if (client->irq) { +		ret = devm_request_threaded_irq(&client->dev, st->client->irq, +					   NULL, +					   &max1363_event_handler, +					   IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					   "max1363_event", +					   indio_dev); + +		if (ret) +			goto error_uninit_buffer; +	} + +	ret = iio_device_register(indio_dev); +	if (ret < 0) +		goto error_uninit_buffer; + +	return 0; + +error_uninit_buffer: +	iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: +	if (st->vref) +		regulator_disable(st->vref); +	regulator_disable(st->reg); +error_unregister_map: +	iio_map_array_unregister(indio_dev); +	return ret; +} + +static int max1363_remove(struct i2c_client *client) +{ +	struct iio_dev *indio_dev = i2c_get_clientdata(client); +	struct max1363_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	if (st->vref) +		regulator_disable(st->vref); +	regulator_disable(st->reg); +	iio_map_array_unregister(indio_dev); + +	return 0; +} + +static const struct i2c_device_id max1363_id[] = { +	{ "max1361", max1361 }, +	{ "max1362", max1362 }, +	{ "max1363", max1363 }, +	{ "max1364", max1364 }, +	{ "max1036", max1036 }, +	{ "max1037", max1037 }, +	{ "max1038", max1038 }, +	{ "max1039", max1039 }, +	{ "max1136", max1136 }, +	{ "max1137", max1137 }, +	{ "max1138", max1138 }, +	{ "max1139", max1139 }, +	{ "max1236", max1236 }, +	{ "max1237", max1237 }, +	{ "max1238", max1238 }, +	{ "max1239", max1239 }, +	{ "max11600", max11600 }, +	{ "max11601", max11601 }, +	{ "max11602", max11602 }, +	{ "max11603", max11603 }, +	{ "max11604", max11604 }, +	{ "max11605", max11605 }, +	{ "max11606", max11606 }, +	{ "max11607", max11607 }, +	{ "max11608", max11608 }, +	{ "max11609", max11609 }, +	{ "max11610", max11610 }, +	{ "max11611", max11611 }, +	{ "max11612", max11612 }, +	{ "max11613", max11613 }, +	{ "max11614", max11614 }, +	{ "max11615", max11615 }, +	{ "max11616", max11616 }, +	{ "max11617", max11617 }, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, max1363_id); + +static struct i2c_driver max1363_driver = { +	.driver = { +		.name = "max1363", +	}, +	.probe = max1363_probe, +	.remove = max1363_remove, +	.id_table = max1363_id, +}; +module_i2c_driver(max1363_driver); + +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); +MODULE_DESCRIPTION("Maxim 1363 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c new file mode 100644 index 00000000000..28a086e4877 --- /dev/null +++ b/drivers/iio/adc/mcp320x.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com> + * + * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips. + * Datasheet can be found here: + * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +#define MCP_SINGLE_ENDED	(1 << 3) +#define MCP_START_BIT		(1 << 4) + +enum { +	mcp3204, +	mcp3208, +}; + +struct mcp320x { +	struct spi_device *spi; +	struct spi_message msg; +	struct spi_transfer transfer[2]; + +	u8 tx_buf; +	u8 rx_buf[2]; + +	struct regulator *reg; +	struct mutex lock; +}; + +static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg) +{ +	int ret; + +	adc->tx_buf = msg; +	ret = spi_sync(adc->spi, &adc->msg); +	if (ret < 0) +		return ret; + +	return ((adc->rx_buf[0] & 0x3f) << 6)  | +		(adc->rx_buf[1] >> 2); +} + +static int mcp320x_read_raw(struct iio_dev *indio_dev, +			    struct iio_chan_spec const *channel, int *val, +			    int *val2, long mask) +{ +	struct mcp320x *adc = iio_priv(indio_dev); +	int ret = -EINVAL; + +	mutex_lock(&adc->lock); + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		if (channel->differential) +			ret = mcp320x_adc_conversion(adc, +				MCP_START_BIT | channel->address); +		else +			ret = mcp320x_adc_conversion(adc, +				MCP_START_BIT | MCP_SINGLE_ENDED | +				channel->address); +		if (ret < 0) +			goto out; + +		*val = ret; +		ret = IIO_VAL_INT; +		break; + +	case IIO_CHAN_INFO_SCALE: +		/* Digital output code = (4096 * Vin) / Vref */ +		ret = regulator_get_voltage(adc->reg); +		if (ret < 0) +			goto out; + +		*val = ret / 1000; +		*val2 = 12; +		ret = IIO_VAL_FRACTIONAL_LOG2; +		break; + +	default: +		break; +	} + +out: +	mutex_unlock(&adc->lock); + +	return ret; +} + +#define MCP320X_VOLTAGE_CHANNEL(num)				\ +	{							\ +		.type = IIO_VOLTAGE,				\ +		.indexed = 1,					\ +		.channel = (num),				\ +		.address = (num),				\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ +	} + +#define MCP320X_VOLTAGE_CHANNEL_DIFF(num)			\ +	{							\ +		.type = IIO_VOLTAGE,				\ +		.indexed = 1,					\ +		.channel = (num * 2),				\ +		.channel2 = (num * 2 + 1),			\ +		.address = (num * 2),				\ +		.differential = 1,				\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ +	} + +static const struct iio_chan_spec mcp3204_channels[] = { +	MCP320X_VOLTAGE_CHANNEL(0), +	MCP320X_VOLTAGE_CHANNEL(1), +	MCP320X_VOLTAGE_CHANNEL(2), +	MCP320X_VOLTAGE_CHANNEL(3), +	MCP320X_VOLTAGE_CHANNEL_DIFF(0), +	MCP320X_VOLTAGE_CHANNEL_DIFF(1), +}; + +static const struct iio_chan_spec mcp3208_channels[] = { +	MCP320X_VOLTAGE_CHANNEL(0), +	MCP320X_VOLTAGE_CHANNEL(1), +	MCP320X_VOLTAGE_CHANNEL(2), +	MCP320X_VOLTAGE_CHANNEL(3), +	MCP320X_VOLTAGE_CHANNEL(4), +	MCP320X_VOLTAGE_CHANNEL(5), +	MCP320X_VOLTAGE_CHANNEL(6), +	MCP320X_VOLTAGE_CHANNEL(7), +	MCP320X_VOLTAGE_CHANNEL_DIFF(0), +	MCP320X_VOLTAGE_CHANNEL_DIFF(1), +	MCP320X_VOLTAGE_CHANNEL_DIFF(2), +	MCP320X_VOLTAGE_CHANNEL_DIFF(3), +}; + +static const struct iio_info mcp320x_info = { +	.read_raw = mcp320x_read_raw, +	.driver_module = THIS_MODULE, +}; + +struct mcp3208_chip_info { +	const struct iio_chan_spec *channels; +	unsigned int num_channels; +}; + +static const struct mcp3208_chip_info mcp3208_chip_infos[] = { +	[mcp3204] = { +		.channels = mcp3204_channels, +		.num_channels = ARRAY_SIZE(mcp3204_channels) +	}, +	[mcp3208] = { +		.channels = mcp3208_channels, +		.num_channels = ARRAY_SIZE(mcp3208_channels) +	}, +}; + +static int mcp320x_probe(struct spi_device *spi) +{ +	struct iio_dev *indio_dev; +	struct mcp320x *adc; +	const struct mcp3208_chip_info *chip_info; +	int ret; + +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); +	if (!indio_dev) +		return -ENOMEM; + +	adc = iio_priv(indio_dev); +	adc->spi = spi; + +	indio_dev->dev.parent = &spi->dev; +	indio_dev->name = spi_get_device_id(spi)->name; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &mcp320x_info; + +	chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data]; +	indio_dev->channels = chip_info->channels; +	indio_dev->num_channels = chip_info->num_channels; + +	adc->transfer[0].tx_buf = &adc->tx_buf; +	adc->transfer[0].len = sizeof(adc->tx_buf); +	adc->transfer[1].rx_buf = adc->rx_buf; +	adc->transfer[1].len = sizeof(adc->rx_buf); + +	spi_message_init_with_transfers(&adc->msg, adc->transfer, +					ARRAY_SIZE(adc->transfer)); + +	adc->reg = devm_regulator_get(&spi->dev, "vref"); +	if (IS_ERR(adc->reg)) +		return PTR_ERR(adc->reg); + +	ret = regulator_enable(adc->reg); +	if (ret < 0) +		return ret; + +	mutex_init(&adc->lock); + +	ret = iio_device_register(indio_dev); +	if (ret < 0) +		goto reg_disable; + +	return 0; + +reg_disable: +	regulator_disable(adc->reg); + +	return ret; +} + +static int mcp320x_remove(struct spi_device *spi) +{ +	struct iio_dev *indio_dev = spi_get_drvdata(spi); +	struct mcp320x *adc = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	regulator_disable(adc->reg); + +	return 0; +} + +static const struct spi_device_id mcp320x_id[] = { +	{ "mcp3204", mcp3204 }, +	{ "mcp3208", mcp3208 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, mcp320x_id); + +static struct spi_driver mcp320x_driver = { +	.driver = { +		.name = "mcp320x", +		.owner = THIS_MODULE, +	}, +	.probe = mcp320x_probe, +	.remove = mcp320x_remove, +	.id_table = mcp320x_id, +}; +module_spi_driver(mcp320x_driver); + +MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>"); +MODULE_DESCRIPTION("Microchip Technology MCP3204/08"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c new file mode 100644 index 00000000000..51672256072 --- /dev/null +++ b/drivers/iio/adc/mcp3422.c @@ -0,0 +1,426 @@ +/* + * mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family + * + * Copyright (C) 2013, Angelo Compagnucci + * Author: Angelo Compagnucci <angelo.compagnucci@gmail.com> + * + * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf + *            http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf + * + * This driver exports the value of analog input voltage to sysfs, the + * voltage unit is nV. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/sysfs.h> +#include <linux/of.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +/* Masks */ +#define MCP3422_CHANNEL_MASK	0x60 +#define MCP3422_PGA_MASK	0x03 +#define MCP3422_SRATE_MASK	0x0C +#define MCP3422_SRATE_240	0x0 +#define MCP3422_SRATE_60	0x1 +#define MCP3422_SRATE_15	0x2 +#define MCP3422_SRATE_3	0x3 +#define MCP3422_PGA_1	0 +#define MCP3422_PGA_2	1 +#define MCP3422_PGA_4	2 +#define MCP3422_PGA_8	3 +#define MCP3422_CONT_SAMPLING	0x10 + +#define MCP3422_CHANNEL(config)	(((config) & MCP3422_CHANNEL_MASK) >> 5) +#define MCP3422_PGA(config)	((config) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE(config)	(((config) & MCP3422_SRATE_MASK) >> 2) + +#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK) +#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK) +#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK) + +#define MCP3422_CHAN(_index) \ +	{ \ +		.type = IIO_VOLTAGE, \ +		.indexed = 1, \ +		.channel = _index, \ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ +				| BIT(IIO_CHAN_INFO_SCALE), \ +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +	} + +/* LSB is in nV to eliminate floating point */ +static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625}; + +/* + *  scales calculated as: + *  rates_to_lsb[sample_rate] / (1 << pga); + *  pga is 1 for 0, 2 + */ + +static const int mcp3422_scales[4][4] = { +	{ 1000000, 250000, 62500, 15625 }, +	{ 500000 , 125000, 31250, 7812 }, +	{ 250000 , 62500 , 15625, 3906 }, +	{ 125000 , 31250 , 7812 , 1953 } }; + +/* Constant msleep times for data acquisitions */ +static const int mcp3422_read_times[4] = { +	[MCP3422_SRATE_240] = 1000 / 240, +	[MCP3422_SRATE_60] = 1000 / 60, +	[MCP3422_SRATE_15] = 1000 / 15, +	[MCP3422_SRATE_3] = 1000 / 3 }; + +/* sample rates to integer conversion table */ +static const int mcp3422_sample_rates[4] = { +	[MCP3422_SRATE_240] = 240, +	[MCP3422_SRATE_60] = 60, +	[MCP3422_SRATE_15] = 15, +	[MCP3422_SRATE_3] = 3 }; + +/* sample rates to sign extension table */ +static const int mcp3422_sign_extend[4] = { +	[MCP3422_SRATE_240] = 11, +	[MCP3422_SRATE_60] = 13, +	[MCP3422_SRATE_15] = 15, +	[MCP3422_SRATE_3] = 17 }; + +/* Client data (each client gets its own) */ +struct mcp3422 { +	struct i2c_client *i2c; +	u8 id; +	u8 config; +	u8 pga[4]; +	struct mutex lock; +}; + +static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig) +{ +	int ret; + +	mutex_lock(&adc->lock); + +	ret = i2c_master_send(adc->i2c, &newconfig, 1); +	if (ret > 0) { +		adc->config = newconfig; +		ret = 0; +	} + +	mutex_unlock(&adc->lock); + +	return ret; +} + +static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config) +{ +	int ret = 0; +	u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); +	u8 buf[4] = {0, 0, 0, 0}; +	u32 temp; + +	if (sample_rate == MCP3422_SRATE_3) { +		ret = i2c_master_recv(adc->i2c, buf, 4); +		temp = buf[0] << 16 | buf[1] << 8 | buf[2]; +		*config = buf[3]; +	} else { +		ret = i2c_master_recv(adc->i2c, buf, 3); +		temp = buf[0] << 8 | buf[1]; +		*config = buf[2]; +	} + +	*value = sign_extend32(temp, mcp3422_sign_extend[sample_rate]); + +	return ret; +} + +static int mcp3422_read_channel(struct mcp3422 *adc, +				struct iio_chan_spec const *channel, int *value) +{ +	int ret; +	u8 config; +	u8 req_channel = channel->channel; + +	if (req_channel != MCP3422_CHANNEL(adc->config)) { +		config = adc->config; +		config &= ~MCP3422_CHANNEL_MASK; +		config |= MCP3422_CHANNEL_VALUE(req_channel); +		config &= ~MCP3422_PGA_MASK; +		config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); +		ret = mcp3422_update_config(adc, config); +		if (ret < 0) +			return ret; +		msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]); +	} + +	return mcp3422_read(adc, value, &config); +} + +static int mcp3422_read_raw(struct iio_dev *iio, +			struct iio_chan_spec const *channel, int *val1, +			int *val2, long mask) +{ +	struct mcp3422 *adc = iio_priv(iio); +	int err; + +	u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); +	u8 pga		 = MCP3422_PGA(adc->config); + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		err = mcp3422_read_channel(adc, channel, val1); +		if (err < 0) +			return -EINVAL; +		return IIO_VAL_INT; + +	case IIO_CHAN_INFO_SCALE: + +		*val1 = 0; +		*val2 = mcp3422_scales[sample_rate][pga]; +		return IIO_VAL_INT_PLUS_NANO; + +	case IIO_CHAN_INFO_SAMP_FREQ: +		*val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)]; +		return IIO_VAL_INT; + +	default: +		break; +	} + +	return -EINVAL; +} + +static int mcp3422_write_raw(struct iio_dev *iio, +			struct iio_chan_spec const *channel, int val1, +			int val2, long mask) +{ +	struct mcp3422 *adc = iio_priv(iio); +	u8 temp; +	u8 config = adc->config; +	u8 req_channel = channel->channel; +	u8 sample_rate = MCP3422_SAMPLE_RATE(config); +	u8 i; + +	switch (mask) { +	case IIO_CHAN_INFO_SCALE: +		if (val1 != 0) +			return -EINVAL; + +		for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { +			if (val2 == mcp3422_scales[sample_rate][i]) { +				adc->pga[req_channel] = i; + +				config &= ~MCP3422_CHANNEL_MASK; +				config |= MCP3422_CHANNEL_VALUE(req_channel); +				config &= ~MCP3422_PGA_MASK; +				config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + +				return mcp3422_update_config(adc, config); +			} +		} +		return -EINVAL; + +	case IIO_CHAN_INFO_SAMP_FREQ: +		switch (val1) { +		case 240: +			temp = MCP3422_SRATE_240; +			break; +		case 60: +			temp = MCP3422_SRATE_60; +			break; +		case 15: +			temp = MCP3422_SRATE_15; +			break; +		case 3: +			if (adc->id > 4) +				return -EINVAL; +			temp = MCP3422_SRATE_3; +			break; +		default: +			return -EINVAL; +		} + +		config &= ~MCP3422_CHANNEL_MASK; +		config |= MCP3422_CHANNEL_VALUE(req_channel); +		config &= ~MCP3422_SRATE_MASK; +		config |= MCP3422_SAMPLE_RATE_VALUE(temp); + +		return mcp3422_update_config(adc, config); + +	default: +		break; +	} + +	return -EINVAL; +} + +static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, +		struct iio_chan_spec const *chan, long mask) +{ +	switch (mask) { +	case IIO_CHAN_INFO_SCALE: +		return IIO_VAL_INT_PLUS_NANO; +	case IIO_CHAN_INFO_SAMP_FREQ: +		return IIO_VAL_INT_PLUS_MICRO; +	default: +		return -EINVAL; +	} +} + +static ssize_t mcp3422_show_samp_freqs(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + +	if (adc->id > 4) +		return sprintf(buf, "240 60 15\n"); + +	return sprintf(buf, "240 60 15 3\n"); +} + +static ssize_t mcp3422_show_scales(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); +	u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + +	return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", +		mcp3422_scales[sample_rate][0], +		mcp3422_scales[sample_rate][1], +		mcp3422_scales[sample_rate][2], +		mcp3422_scales[sample_rate][3]); +} + +static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, +		mcp3422_show_samp_freqs, NULL, 0); +static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, +		mcp3422_show_scales, NULL, 0); + +static struct attribute *mcp3422_attributes[] = { +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr, +	&iio_dev_attr_in_voltage_scale_available.dev_attr.attr, +	NULL, +}; + +static const struct attribute_group mcp3422_attribute_group = { +	.attrs = mcp3422_attributes, +}; + +static const struct iio_chan_spec mcp3422_channels[] = { +	MCP3422_CHAN(0), +	MCP3422_CHAN(1), +}; + +static const struct iio_chan_spec mcp3424_channels[] = { +	MCP3422_CHAN(0), +	MCP3422_CHAN(1), +	MCP3422_CHAN(2), +	MCP3422_CHAN(3), +}; + +static const struct iio_info mcp3422_info = { +	.read_raw = mcp3422_read_raw, +	.write_raw = mcp3422_write_raw, +	.write_raw_get_fmt = mcp3422_write_raw_get_fmt, +	.attrs = &mcp3422_attribute_group, +	.driver_module = THIS_MODULE, +}; + +static int mcp3422_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct iio_dev *indio_dev; +	struct mcp3422 *adc; +	int err; +	u8 config; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) +		return -ENODEV; + +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc)); +	if (!indio_dev) +		return -ENOMEM; + +	adc = iio_priv(indio_dev); +	adc->i2c = client; +	adc->id = (u8)(id->driver_data); + +	mutex_init(&adc->lock); + +	indio_dev->dev.parent = &client->dev; +	indio_dev->name = dev_name(&client->dev); +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &mcp3422_info; + +	switch (adc->id) { +	case 2: +	case 3: +	case 6: +	case 7: +		indio_dev->channels = mcp3422_channels; +		indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); +		break; +	case 4: +	case 8: +		indio_dev->channels = mcp3424_channels; +		indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); +		break; +	} + +	/* meaningful default configuration */ +	config = (MCP3422_CONT_SAMPLING +		| MCP3422_CHANNEL_VALUE(1) +		| MCP3422_PGA_VALUE(MCP3422_PGA_1) +		| MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240)); +	mcp3422_update_config(adc, config); + +	err = devm_iio_device_register(&client->dev, indio_dev); +	if (err < 0) +		return err; + +	i2c_set_clientdata(client, indio_dev); + +	return 0; +} + +static const struct i2c_device_id mcp3422_id[] = { +	{ "mcp3422", 2 }, +	{ "mcp3423", 3 }, +	{ "mcp3424", 4 }, +	{ "mcp3426", 6 }, +	{ "mcp3427", 7 }, +	{ "mcp3428", 8 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, mcp3422_id); + +#ifdef CONFIG_OF +static const struct of_device_id mcp3422_of_match[] = { +	{ .compatible = "mcp3422" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, mcp3422_of_match); +#endif + +static struct i2c_driver mcp3422_driver = { +	.driver = { +		.name = "mcp3422", +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(mcp3422_of_match), +	}, +	.probe = mcp3422_probe, +	.id_table = mcp3422_id, +}; +module_i2c_driver(mcp3422_driver); + +MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); +MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c new file mode 100644 index 00000000000..b58d6302521 --- /dev/null +++ b/drivers/iio/adc/men_z188_adc.c @@ -0,0 +1,172 @@ +/* + * MEN 16z188 Analog to Digial Converter + * + * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) + * Author: Johannes Thumshirn <johannes.thumshirn@men.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mcb.h> +#include <linux/io.h> +#include <linux/iio/iio.h> + +#define Z188_ADC_MAX_CHAN	8 +#define Z188_ADC_GAIN		0x0700000 +#define Z188_MODE_VOLTAGE	BIT(27) +#define Z188_CFG_AUTO		0x1 +#define Z188_CTRL_REG		0x40 + +#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc) +#define ADC_OVR(x) ((x) & 0x1) + +struct z188_adc { +	struct resource *mem; +	void __iomem *base; +}; + +#define Z188_ADC_CHANNEL(idx) {					\ +		.type = IIO_VOLTAGE,				\ +		.indexed = 1,					\ +		.channel = (idx),				\ +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \ +} + +static const struct iio_chan_spec z188_adc_iio_channels[] = { +	Z188_ADC_CHANNEL(0), +	Z188_ADC_CHANNEL(1), +	Z188_ADC_CHANNEL(2), +	Z188_ADC_CHANNEL(3), +	Z188_ADC_CHANNEL(4), +	Z188_ADC_CHANNEL(5), +	Z188_ADC_CHANNEL(6), +	Z188_ADC_CHANNEL(7), +}; + +static int z188_iio_read_raw(struct iio_dev *iio_dev, +			struct iio_chan_spec const *chan, +			int *val, +			int *val2, +			long info) +{ +	struct z188_adc *adc = iio_priv(iio_dev); +	int ret; +	u16 tmp; + +	switch (info) { +	case IIO_CHAN_INFO_RAW: +		tmp = readw(adc->base + chan->channel * 4); + +		if (ADC_OVR(tmp)) { +			dev_info(&iio_dev->dev, +				"Oversampling error on ADC channel %d\n", +				chan->channel); +			return -EIO; +		} +		*val = ADC_DATA(tmp); +		ret = IIO_VAL_INT; +		break; +	default: +		ret = -EINVAL; +		break; +	} + +	return ret; +} + +static struct iio_info z188_adc_info = { +	.read_raw = &z188_iio_read_raw, +	.driver_module = THIS_MODULE, +}; + +static void men_z188_config_channels(void __iomem *addr) +{ +	int i; +	u32 cfg; +	u32 ctl; + +	ctl = readl(addr + Z188_CTRL_REG); +	ctl |= Z188_CFG_AUTO; +	writel(ctl, addr + Z188_CTRL_REG); + +	for (i = 0; i < Z188_ADC_MAX_CHAN; i++) { +		cfg = readl(addr + i); +		cfg &= ~Z188_ADC_GAIN; +		cfg |= Z188_MODE_VOLTAGE; +		writel(cfg, addr + i); +	} +} + +static int men_z188_probe(struct mcb_device *dev, +			const struct mcb_device_id *id) +{ +	struct z188_adc *adc; +	struct iio_dev *indio_dev; +	struct resource *mem; + +	indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc)); +	if (!indio_dev) +		return -ENOMEM; + +	adc = iio_priv(indio_dev); +	indio_dev->name = "z188-adc"; +	indio_dev->dev.parent = &dev->dev; +	indio_dev->info = &z188_adc_info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = z188_adc_iio_channels; +	indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels); + +	mem = mcb_request_mem(dev, "z188-adc"); +	if (IS_ERR(mem)) +		return PTR_ERR(mem); + +	adc->base = ioremap(mem->start, resource_size(mem)); +	if (adc->base == NULL) +		goto err; + +	men_z188_config_channels(adc->base); + +	adc->mem = mem; +	mcb_set_drvdata(dev, indio_dev); + +	return iio_device_register(indio_dev); + +err: +	mcb_release_mem(mem); +	return -ENXIO; +} + +static void men_z188_remove(struct mcb_device *dev) +{ +	struct iio_dev *indio_dev  = mcb_get_drvdata(dev); +	struct z188_adc *adc = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	iounmap(adc->base); +	mcb_release_mem(adc->mem); +} + +static const struct mcb_device_id men_z188_ids[] = { +	{ .device = 0xbc }, +}; +MODULE_DEVICE_TABLE(mcb, men_z188_ids); + +static struct mcb_driver men_z188_driver = { +	.driver = { +		.name = "z188-adc", +		.owner = THIS_MODULE, +	}, +	.probe = men_z188_probe, +	.remove = men_z188_remove, +	.id_table = men_z188_ids, +}; +module_mcb_driver(men_z188_driver); + +MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core"); +MODULE_ALIAS("mcb:16z188"); diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c new file mode 100644 index 00000000000..e525aa6475c --- /dev/null +++ b/drivers/iio/adc/nau7802.c @@ -0,0 +1,582 @@ +/* + * Driver for the Nuvoton NAU7802 ADC + * + * Copyright 2013 Free Electrons + * + * Licensed under the GPLv2 or later. + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/wait.h> +#include <linux/log2.h> +#include <linux/of.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define NAU7802_REG_PUCTRL	0x00 +#define NAU7802_PUCTRL_RR(x)		(x << 0) +#define NAU7802_PUCTRL_RR_BIT		NAU7802_PUCTRL_RR(1) +#define NAU7802_PUCTRL_PUD(x)		(x << 1) +#define NAU7802_PUCTRL_PUD_BIT		NAU7802_PUCTRL_PUD(1) +#define NAU7802_PUCTRL_PUA(x)		(x << 2) +#define NAU7802_PUCTRL_PUA_BIT		NAU7802_PUCTRL_PUA(1) +#define NAU7802_PUCTRL_PUR(x)		(x << 3) +#define NAU7802_PUCTRL_PUR_BIT		NAU7802_PUCTRL_PUR(1) +#define NAU7802_PUCTRL_CS(x)		(x << 4) +#define NAU7802_PUCTRL_CS_BIT		NAU7802_PUCTRL_CS(1) +#define NAU7802_PUCTRL_CR(x)		(x << 5) +#define NAU7802_PUCTRL_CR_BIT		NAU7802_PUCTRL_CR(1) +#define NAU7802_PUCTRL_AVDDS(x)		(x << 7) +#define NAU7802_PUCTRL_AVDDS_BIT	NAU7802_PUCTRL_AVDDS(1) +#define NAU7802_REG_CTRL1	0x01 +#define NAU7802_CTRL1_VLDO(x)		(x << 3) +#define NAU7802_CTRL1_GAINS(x)		(x) +#define NAU7802_CTRL1_GAINS_BITS	0x07 +#define NAU7802_REG_CTRL2	0x02 +#define NAU7802_CTRL2_CHS(x)		(x << 7) +#define NAU7802_CTRL2_CRS(x)		(x << 4) +#define NAU7802_SAMP_FREQ_320	0x07 +#define NAU7802_CTRL2_CHS_BIT		NAU7802_CTRL2_CHS(1) +#define NAU7802_REG_ADC_B2	0x12 +#define NAU7802_REG_ADC_B1	0x13 +#define NAU7802_REG_ADC_B0	0x14 +#define NAU7802_REG_ADC_CTRL	0x15 + +#define NAU7802_MIN_CONVERSIONS 6 + +struct nau7802_state { +	struct i2c_client	*client; +	s32			last_value; +	struct mutex		lock; +	struct mutex		data_lock; +	u32			vref_mv; +	u32			conversion_count; +	u32			min_conversions; +	u8			sample_rate; +	u32			scale_avail[8]; +	struct completion	value_ok; +}; + +#define NAU7802_CHANNEL(chan) {					\ +	.type = IIO_VOLTAGE,					\ +	.indexed = 1,						\ +	.channel = (chan),					\ +	.scan_index = (chan),					\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\ +				BIT(IIO_CHAN_INFO_SAMP_FREQ)	\ +} + +static const struct iio_chan_spec nau7802_chan_array[] = { +	NAU7802_CHANNEL(0), +	NAU7802_CHANNEL(1), +}; + +static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80, +						10, 10, 10, 320}; + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320"); + +static struct attribute *nau7802_attributes[] = { +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	NULL +}; + +static const struct attribute_group nau7802_attribute_group = { +	.attrs = nau7802_attributes, +}; + +static int nau7802_set_gain(struct nau7802_state *st, int gain) +{ +	int ret; + +	mutex_lock(&st->lock); +	st->conversion_count = 0; + +	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1); +	if (ret < 0) +		goto nau7802_sysfs_set_gain_out; +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1, +					(ret & (~NAU7802_CTRL1_GAINS_BITS)) | +					gain); + +nau7802_sysfs_set_gain_out: +	mutex_unlock(&st->lock); + +	return ret; +} + +static int nau7802_read_conversion(struct nau7802_state *st) +{ +	int data; + +	mutex_lock(&st->data_lock); +	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B2); +	if (data < 0) +		goto nau7802_read_conversion_out; +	st->last_value = data << 16; + +	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B1); +	if (data < 0) +		goto nau7802_read_conversion_out; +	st->last_value |= data << 8; + +	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B0); +	if (data < 0) +		goto nau7802_read_conversion_out; +	st->last_value |= data; + +	st->last_value = sign_extend32(st->last_value, 23); + +nau7802_read_conversion_out: +	mutex_unlock(&st->data_lock); + +	return data; +} + +/* + * Conversions are synchronised on the rising edge of NAU7802_PUCTRL_CS_BIT + */ +static int nau7802_sync(struct nau7802_state *st) +{ +	int ret; + +	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL); +	if (ret < 0) +		return ret; +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, +				ret | NAU7802_PUCTRL_CS_BIT); + +	return ret; +} + +static irqreturn_t nau7802_eoc_trigger(int irq, void *private) +{ +	struct iio_dev *indio_dev = private; +	struct nau7802_state *st = iio_priv(indio_dev); +	int status; + +	status = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL); +	if (status < 0) +		return IRQ_HANDLED; + +	if (!(status & NAU7802_PUCTRL_CR_BIT)) +		return IRQ_NONE; + +	if (nau7802_read_conversion(st) < 0) +		return IRQ_HANDLED; + +	/* +	 * Because there is actually only one ADC for both channels, we have to +	 * wait for enough conversions to happen before getting a significant +	 * value when changing channels and the values are far apart. +	 */ +	if (st->conversion_count < NAU7802_MIN_CONVERSIONS) +		st->conversion_count++; +	if (st->conversion_count >= NAU7802_MIN_CONVERSIONS) +		complete_all(&st->value_ok); + +	return IRQ_HANDLED; +} + +static int nau7802_read_irq(struct iio_dev *indio_dev, +			struct iio_chan_spec const *chan, +			int *val) +{ +	struct nau7802_state *st = iio_priv(indio_dev); +	int ret; + +	reinit_completion(&st->value_ok); +	enable_irq(st->client->irq); + +	nau7802_sync(st); + +	/* read registers to ensure we flush everything */ +	ret = nau7802_read_conversion(st); +	if (ret < 0) +		goto read_chan_info_failure; + +	/* Wait for a conversion to finish */ +	ret = wait_for_completion_interruptible_timeout(&st->value_ok, +			msecs_to_jiffies(1000)); +	if (ret == 0) +		ret = -ETIMEDOUT; + +	if (ret < 0) +		goto read_chan_info_failure; + +	disable_irq(st->client->irq); + +	*val = st->last_value; + +	return IIO_VAL_INT; + +read_chan_info_failure: +	disable_irq(st->client->irq); + +	return ret; +} + +static int nau7802_read_poll(struct iio_dev *indio_dev, +			struct iio_chan_spec const *chan, +			int *val) +{ +	struct nau7802_state *st = iio_priv(indio_dev); +	int ret; + +	nau7802_sync(st); + +	/* read registers to ensure we flush everything */ +	ret = nau7802_read_conversion(st); +	if (ret < 0) +		return ret; + +	/* +	 * Because there is actually only one ADC for both channels, we have to +	 * wait for enough conversions to happen before getting a significant +	 * value when changing channels and the values are far appart. +	 */ +	do { +		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL); +		if (ret < 0) +			return ret; + +		while (!(ret & NAU7802_PUCTRL_CR_BIT)) { +			if (st->sample_rate != NAU7802_SAMP_FREQ_320) +				msleep(20); +			else +				mdelay(4); +			ret = i2c_smbus_read_byte_data(st->client, +							NAU7802_REG_PUCTRL); +			if (ret < 0) +				return ret; +		} + +		ret = nau7802_read_conversion(st); +		if (ret < 0) +			return ret; +		if (st->conversion_count < NAU7802_MIN_CONVERSIONS) +			st->conversion_count++; +	} while (st->conversion_count < NAU7802_MIN_CONVERSIONS); + +	*val = st->last_value; + +	return IIO_VAL_INT; +} + +static int nau7802_read_raw(struct iio_dev *indio_dev, +			    struct iio_chan_spec const *chan, +			    int *val, int *val2, long mask) +{ +	struct nau7802_state *st = iio_priv(indio_dev); +	int ret; + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&st->lock); +		/* +		 * Select the channel to use +		 *   - Channel 1 is value 0 in the CHS register +		 *   - Channel 2 is value 1 in the CHS register +		 */ +		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL2); +		if (ret < 0) { +			mutex_unlock(&st->lock); +			return ret; +		} + +		if (((ret & NAU7802_CTRL2_CHS_BIT) && !chan->channel) || +				(!(ret & NAU7802_CTRL2_CHS_BIT) && +				 chan->channel)) { +			st->conversion_count = 0; +			ret = i2c_smbus_write_byte_data(st->client, +					NAU7802_REG_CTRL2, +					NAU7802_CTRL2_CHS(chan->channel) | +					NAU7802_CTRL2_CRS(st->sample_rate)); + +			if (ret < 0) { +				mutex_unlock(&st->lock); +				return ret; +			} +		} + +		if (st->client->irq) +			ret = nau7802_read_irq(indio_dev, chan, val); +		else +			ret = nau7802_read_poll(indio_dev, chan, val); + +		mutex_unlock(&st->lock); +		return ret; + +	case IIO_CHAN_INFO_SCALE: +		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1); +		if (ret < 0) +			return ret; + +		/* +		 * We have 24 bits of signed data, that means 23 bits of data +		 * plus the sign bit +		 */ +		*val = st->vref_mv; +		*val2 = 23 + (ret & NAU7802_CTRL1_GAINS_BITS); + +		return IIO_VAL_FRACTIONAL_LOG2; + +	case IIO_CHAN_INFO_SAMP_FREQ: +		*val =  nau7802_sample_freq_avail[st->sample_rate]; +		*val2 = 0; +		return IIO_VAL_INT; + +	default: +		break; +	} + +	return -EINVAL; +} + +static int nau7802_write_raw(struct iio_dev *indio_dev, +			     struct iio_chan_spec const *chan, +			     int val, int val2, long mask) +{ +	struct nau7802_state *st = iio_priv(indio_dev); +	int i, ret; + +	switch (mask) { +	case IIO_CHAN_INFO_SCALE: +		for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) +			if (val2 == st->scale_avail[i]) +				return nau7802_set_gain(st, i); + +		break; + +	case IIO_CHAN_INFO_SAMP_FREQ: +		for (i = 0; i < ARRAY_SIZE(nau7802_sample_freq_avail); i++) +			if (val == nau7802_sample_freq_avail[i]) { +				mutex_lock(&st->lock); +				st->sample_rate = i; +				st->conversion_count = 0; +				ret = i2c_smbus_write_byte_data(st->client, +					NAU7802_REG_CTRL2, +					NAU7802_CTRL2_CRS(st->sample_rate)); +				mutex_unlock(&st->lock); +				return ret; +			} + +		break; + +	default: +		break; +	} + +	return -EINVAL; +} + +static int nau7802_write_raw_get_fmt(struct iio_dev *indio_dev, +				     struct iio_chan_spec const *chan, +				     long mask) +{ +	return IIO_VAL_INT_PLUS_NANO; +} + +static const struct iio_info nau7802_info = { +	.driver_module = THIS_MODULE, +	.read_raw = &nau7802_read_raw, +	.write_raw = &nau7802_write_raw, +	.write_raw_get_fmt = nau7802_write_raw_get_fmt, +	.attrs = &nau7802_attribute_group, +}; + +static int nau7802_probe(struct i2c_client *client, +			const struct i2c_device_id *id) +{ +	struct iio_dev *indio_dev; +	struct nau7802_state *st; +	struct device_node *np = client->dev.of_node; +	int i, ret; +	u8 data; +	u32 tmp = 0; + +	if (!client->dev.of_node) { +		dev_err(&client->dev, "No device tree node available.\n"); +		return -EINVAL; +	} + +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); +	if (indio_dev == NULL) +		return -ENOMEM; + +	st = iio_priv(indio_dev); + +	i2c_set_clientdata(client, indio_dev); + +	indio_dev->dev.parent = &client->dev; +	indio_dev->name = dev_name(&client->dev); +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &nau7802_info; + +	st->client = client; + +	/* Reset the device */ +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, +				  NAU7802_PUCTRL_RR_BIT); +	if (ret < 0) +		return ret; + +	/* Enter normal operation mode */ +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, +				  NAU7802_PUCTRL_PUD_BIT); +	if (ret < 0) +		return ret; + +	/* +	 * After about 200 usecs, the device should be ready and then +	 * the Power Up bit will be set to 1. If not, wait for it. +	 */ +	udelay(210); +	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL); +	if (ret < 0) +		return ret; +	if (!(ret & NAU7802_PUCTRL_PUR_BIT)) +		return ret; + +	of_property_read_u32(np, "nuvoton,vldo", &tmp); +	st->vref_mv = tmp; + +	data = NAU7802_PUCTRL_PUD_BIT | NAU7802_PUCTRL_PUA_BIT | +		NAU7802_PUCTRL_CS_BIT; +	if (tmp >= 2400) +		data |= NAU7802_PUCTRL_AVDDS_BIT; + +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, data); +	if (ret < 0) +		return ret; +	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_ADC_CTRL, 0x30); +	if (ret < 0) +		return ret; + +	if (tmp >= 2400) { +		data = NAU7802_CTRL1_VLDO((4500 - tmp) / 300); +		ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1, +						data); +		if (ret < 0) +			return ret; +	} + +	/* Populate available ADC input ranges */ +	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) +		st->scale_avail[i] = (((u64)st->vref_mv) * 1000000000ULL) +					   >> (23 + i); + +	init_completion(&st->value_ok); + +	/* +	 * The ADC fires continuously and we can't do anything about +	 * it. So we need to have the IRQ disabled by default, and we +	 * will enable them back when we will need them.. +	 */ +	if (client->irq) { +		ret = request_threaded_irq(client->irq, +				NULL, +				nau7802_eoc_trigger, +				IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +				client->dev.driver->name, +				indio_dev); +		if (ret) { +			/* +			 * What may happen here is that our IRQ controller is +			 * not able to get level interrupt but this is required +			 * by this ADC as when going over 40 sample per second, +			 * the interrupt line may stay high between conversions. +			 * So, we continue no matter what but we switch to +			 * polling mode. +			 */ +			dev_info(&client->dev, +				"Failed to allocate IRQ, using polling mode\n"); +			client->irq = 0; +		} else +			disable_irq(client->irq); +	} + +	if (!client->irq) { +		/* +		 * We are polling, use the fastest sample rate by +		 * default +		 */ +		st->sample_rate = NAU7802_SAMP_FREQ_320; +		ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2, +					  NAU7802_CTRL2_CRS(st->sample_rate)); +		if (ret) +			goto error_free_irq; +	} + +	/* Setup the ADC channels available on the board */ +	indio_dev->num_channels = ARRAY_SIZE(nau7802_chan_array); +	indio_dev->channels = nau7802_chan_array; + +	mutex_init(&st->lock); +	mutex_init(&st->data_lock); + +	ret = iio_device_register(indio_dev); +	if (ret < 0) { +		dev_err(&client->dev, "Couldn't register the device.\n"); +		goto error_device_register; +	} + +	return 0; + +error_device_register: +	mutex_destroy(&st->lock); +	mutex_destroy(&st->data_lock); +error_free_irq: +	if (client->irq) +		free_irq(client->irq, indio_dev); + +	return ret; +} + +static int nau7802_remove(struct i2c_client *client) +{ +	struct iio_dev *indio_dev = i2c_get_clientdata(client); +	struct nau7802_state *st = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	mutex_destroy(&st->lock); +	mutex_destroy(&st->data_lock); +	if (client->irq) +		free_irq(client->irq, indio_dev); + +	return 0; +} + +static const struct i2c_device_id nau7802_i2c_id[] = { +	{ "nau7802", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id); + +static const struct of_device_id nau7802_dt_ids[] = { +	{ .compatible = "nuvoton,nau7802" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, nau7802_dt_ids); + +static struct i2c_driver nau7802_driver = { +	.probe = nau7802_probe, +	.remove = nau7802_remove, +	.id_table = nau7802_i2c_id, +	.driver = { +		   .name = "nau7802", +		   .of_match_table = nau7802_dt_ids, +	}, +}; + +module_i2c_driver(nau7802_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Nuvoton NAU7802 ADC Driver"); +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c new file mode 100644 index 00000000000..b3a82b4d1a7 --- /dev/null +++ b/drivers/iio/adc/ti-adc081c.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2012 Avionic Design GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> + +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +struct adc081c { +	struct i2c_client *i2c; +	struct regulator *ref; +}; + +#define REG_CONV_RES 0x00 + +static int adc081c_read_raw(struct iio_dev *iio, +			    struct iio_chan_spec const *channel, int *value, +			    int *shift, long mask) +{ +	struct adc081c *adc = iio_priv(iio); +	int err; + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES); +		if (err < 0) +			return err; + +		*value = (err >> 4) & 0xff; +		return IIO_VAL_INT; + +	case IIO_CHAN_INFO_SCALE: +		err = regulator_get_voltage(adc->ref); +		if (err < 0) +			return err; + +		*value = err / 1000; +		*shift = 8; + +		return IIO_VAL_FRACTIONAL_LOG2; + +	default: +		break; +	} + +	return -EINVAL; +} + +static const struct iio_chan_spec adc081c_channel = { +	.type = IIO_VOLTAGE, +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), +}; + +static const struct iio_info adc081c_info = { +	.read_raw = adc081c_read_raw, +	.driver_module = THIS_MODULE, +}; + +static int adc081c_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct iio_dev *iio; +	struct adc081c *adc; +	int err; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) +		return -ENODEV; + +	iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); +	if (!iio) +		return -ENOMEM; + +	adc = iio_priv(iio); +	adc->i2c = client; + +	adc->ref = devm_regulator_get(&client->dev, "vref"); +	if (IS_ERR(adc->ref)) +		return PTR_ERR(adc->ref); + +	err = regulator_enable(adc->ref); +	if (err < 0) +		return err; + +	iio->dev.parent = &client->dev; +	iio->name = dev_name(&client->dev); +	iio->modes = INDIO_DIRECT_MODE; +	iio->info = &adc081c_info; + +	iio->channels = &adc081c_channel; +	iio->num_channels = 1; + +	err = iio_device_register(iio); +	if (err < 0) +		goto regulator_disable; + +	i2c_set_clientdata(client, iio); + +	return 0; + +regulator_disable: +	regulator_disable(adc->ref); + +	return err; +} + +static int adc081c_remove(struct i2c_client *client) +{ +	struct iio_dev *iio = i2c_get_clientdata(client); +	struct adc081c *adc = iio_priv(iio); + +	iio_device_unregister(iio); +	regulator_disable(adc->ref); + +	return 0; +} + +static const struct i2c_device_id adc081c_id[] = { +	{ "adc081c", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, adc081c_id); + +#ifdef CONFIG_OF +static const struct of_device_id adc081c_of_match[] = { +	{ .compatible = "ti,adc081c" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, adc081c_of_match); +#endif + +static struct i2c_driver adc081c_driver = { +	.driver = { +		.name = "adc081c", +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(adc081c_of_match), +	}, +	.probe = adc081c_probe, +	.remove = adc081c_remove, +	.id_table = adc081c_id, +}; +module_i2c_driver(adc081c_driver); + +MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); +MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c new file mode 100644 index 00000000000..d5dc4c6ce86 --- /dev/null +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -0,0 +1,559 @@ +/* + * TI ADC MFD driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/iio/iio.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/iio/machine.h> +#include <linux/iio/driver.h> + +#include <linux/mfd/ti_am335x_tscadc.h> +#include <linux/iio/buffer.h> +#include <linux/iio/kfifo_buf.h> + +struct tiadc_device { +	struct ti_tscadc_dev *mfd_tscadc; +	int channels; +	u8 channel_line[8]; +	u8 channel_step[8]; +	int buffer_en_ch_steps; +	u16 data[8]; +}; + +static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) +{ +	return readl(adc->mfd_tscadc->tscadc_base + reg); +} + +static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, +					unsigned int val) +{ +	writel(val, adc->mfd_tscadc->tscadc_base + reg); +} + +static u32 get_adc_step_mask(struct tiadc_device *adc_dev) +{ +	u32 step_en; + +	step_en = ((1 << adc_dev->channels) - 1); +	step_en <<= TOTAL_STEPS - adc_dev->channels + 1; +	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]; +} + +static void tiadc_step_config(struct iio_dev *indio_dev) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	unsigned int stepconfig; +	int i, steps; + +	/* +	 * There are 16 configurable steps and 8 analog input +	 * lines available which are shared between Touchscreen and ADC. +	 * +	 * Steps backwards i.e. from 16 towards 0 are used by ADC +	 * depending on number of input lines needed. +	 * Channel would represent which analog input +	 * needs to be given to ADC to digitalize data. +	 */ + +	steps = TOTAL_STEPS - adc_dev->channels; +	if (iio_buffer_enabled(indio_dev)) +		stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 +					| STEPCONFIG_MODE_SWCNT; +	else +		stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; + +	for (i = 0; i < adc_dev->channels; i++) { +		int chan; + +		chan = adc_dev->channel_line[i]; +		tiadc_writel(adc_dev, REG_STEPCONFIG(steps), +				stepconfig | STEPCONFIG_INP(chan)); +		tiadc_writel(adc_dev, REG_STEPDELAY(steps), +				STEPCONFIG_OPENDLY); +		adc_dev->channel_step[i] = steps; +		steps++; +	} +} + +static irqreturn_t tiadc_irq_h(int irq, void *private) +{ +	struct iio_dev *indio_dev = private; +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	unsigned int status, config; +	status = tiadc_readl(adc_dev, REG_IRQSTATUS); + +	/* +	 * ADC and touchscreen share the IRQ line. +	 * FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only +	 */ +	if (status & IRQENB_FIFO1OVRRUN) { +		/* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ +		config = tiadc_readl(adc_dev, REG_CTRL); +		config &= ~(CNTRLREG_TSCSSENB); +		tiadc_writel(adc_dev, REG_CTRL, config); +		tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN +				| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); +		tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); +		return IRQ_HANDLED; +	} else if (status & IRQENB_FIFO1THRES) { +		/* Disable irq and wake worker thread */ +		tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES); +		return IRQ_WAKE_THREAD; +	} + +	return IRQ_NONE; +} + +static irqreturn_t tiadc_worker_h(int irq, void *private) +{ +	struct iio_dev *indio_dev = private; +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	int i, k, fifo1count, read; +	u16 *data = adc_dev->data; + +	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); +	for (k = 0; k < fifo1count; k = k + i) { +		for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { +			read = tiadc_readl(adc_dev, REG_FIFO1); +			data[i] = read & FIFOREAD_DATA_MASK; +		} +		iio_push_to_buffers(indio_dev, (u8 *) data); +	} + +	tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); +	tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); + +	return IRQ_HANDLED; +} + +static int tiadc_buffer_preenable(struct iio_dev *indio_dev) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	int i, fifo1count, read; + +	tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | +				IRQENB_FIFO1OVRRUN | +				IRQENB_FIFO1UNDRFLW)); + +	/* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ +	fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); +	for (i = 0; i < fifo1count; i++) +		read = tiadc_readl(adc_dev, REG_FIFO1); + +	return 0; +} + +static int tiadc_buffer_postenable(struct iio_dev *indio_dev) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	struct iio_buffer *buffer = indio_dev->buffer; +	unsigned int enb = 0; +	u8 bit; + +	tiadc_step_config(indio_dev); +	for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels) +		enb |= (get_adc_step_bit(adc_dev, bit) << 1); +	adc_dev->buffer_en_ch_steps = enb; + +	am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb); + +	tiadc_writel(adc_dev,  REG_IRQSTATUS, IRQENB_FIFO1THRES +				| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); +	tiadc_writel(adc_dev,  REG_IRQENABLE, IRQENB_FIFO1THRES +				| IRQENB_FIFO1OVRRUN); + +	return 0; +} + +static int tiadc_buffer_predisable(struct iio_dev *indio_dev) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	int fifo1count, i, read; + +	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); +	for (i = 0; i < fifo1count; i++) +		read = tiadc_readl(adc_dev, REG_FIFO1); + +	return 0; +} + +static int tiadc_buffer_postdisable(struct iio_dev *indio_dev) +{ +	tiadc_step_config(indio_dev); + +	return 0; +} + +static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { +	.preenable = &tiadc_buffer_preenable, +	.postenable = &tiadc_buffer_postenable, +	.predisable = &tiadc_buffer_predisable, +	.postdisable = &tiadc_buffer_postdisable, +}; + +static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev, +	irqreturn_t (*pollfunc_bh)(int irq, void *p), +	irqreturn_t (*pollfunc_th)(int irq, void *p), +	int irq, +	unsigned long flags, +	const struct iio_buffer_setup_ops *setup_ops) +{ +	struct iio_buffer *buffer; +	int ret; + +	buffer = iio_kfifo_allocate(indio_dev); +	if (!buffer) +		return -ENOMEM; + +	iio_device_attach_buffer(indio_dev, buffer); + +	ret = request_threaded_irq(irq,	pollfunc_th, pollfunc_bh, +				flags, indio_dev->name, indio_dev); +	if (ret) +		goto error_kfifo_free; + +	indio_dev->setup_ops = setup_ops; +	indio_dev->modes |= INDIO_BUFFER_HARDWARE; + +	ret = iio_buffer_register(indio_dev, +				  indio_dev->channels, +				  indio_dev->num_channels); +	if (ret) +		goto error_free_irq; + +	return 0; + +error_free_irq: +	free_irq(irq, indio_dev); +error_kfifo_free: +	iio_kfifo_free(indio_dev->buffer); +	return ret; +} + +static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); + +	free_irq(adc_dev->mfd_tscadc->irq, indio_dev); +	iio_kfifo_free(indio_dev->buffer); +	iio_buffer_unregister(indio_dev); +} + + +static const char * const chan_name_ain[] = { +	"AIN0", +	"AIN1", +	"AIN2", +	"AIN3", +	"AIN4", +	"AIN5", +	"AIN6", +	"AIN7", +}; + +static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	struct iio_chan_spec *chan_array; +	struct iio_chan_spec *chan; +	int i; + +	indio_dev->num_channels = channels; +	chan_array = kcalloc(channels, +			sizeof(struct iio_chan_spec), GFP_KERNEL); +	if (chan_array == NULL) +		return -ENOMEM; + +	chan = chan_array; +	for (i = 0; i < channels; i++, chan++) { + +		chan->type = IIO_VOLTAGE; +		chan->indexed = 1; +		chan->channel = adc_dev->channel_line[i]; +		chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); +		chan->datasheet_name = chan_name_ain[chan->channel]; +		chan->scan_index = i; +		chan->scan_type.sign = 'u'; +		chan->scan_type.realbits = 12; +		chan->scan_type.storagebits = 16; +	} + +	indio_dev->channels = chan_array; + +	return 0; +} + +static void tiadc_channels_remove(struct iio_dev *indio_dev) +{ +	kfree(indio_dev->channels); +} + +static int tiadc_read_raw(struct iio_dev *indio_dev, +		struct iio_chan_spec const *chan, +		int *val, int *val2, long mask) +{ +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	int i, map_val; +	unsigned int fifo1count, read, stepid; +	bool found = false; +	u32 step_en; +	unsigned long timeout; + +	if (iio_buffer_enabled(indio_dev)) +		return -EBUSY; + +	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); + +	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 = adc_dev->channel_step[chan->scan_index]; + +	/* +	 * 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. +	 */ +	for (i = 0; i < fifo1count; i++) { +		read = tiadc_readl(adc_dev, REG_FIFO1); +		stepid = read & FIFOREAD_CHNLID_MASK; +		stepid = stepid >> 0x10; + +		if (stepid == map_val) { +			read = read & FIFOREAD_DATA_MASK; +			found = true; +			*val = (u16) read; +		} +	} +	am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); + +	if (found == false) +		return -EBUSY; +	return IIO_VAL_INT; +} + +static const struct iio_info tiadc_info = { +	.read_raw = &tiadc_read_raw, +	.driver_module = THIS_MODULE, +}; + +static int tiadc_probe(struct platform_device *pdev) +{ +	struct iio_dev		*indio_dev; +	struct tiadc_device	*adc_dev; +	struct device_node	*node = pdev->dev.of_node; +	struct property		*prop; +	const __be32		*cur; +	int			err; +	u32			val; +	int			channels = 0; + +	if (!node) { +		dev_err(&pdev->dev, "Could not find valid DT data.\n"); +		return -EINVAL; +	} + +	indio_dev = devm_iio_device_alloc(&pdev->dev, +					  sizeof(struct tiadc_device)); +	if (indio_dev == NULL) { +		dev_err(&pdev->dev, "failed to allocate iio device\n"); +		return -ENOMEM; +	} +	adc_dev = iio_priv(indio_dev); + +	adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev); + +	of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { +		adc_dev->channel_line[channels] = val; +		channels++; +	} +	adc_dev->channels = channels; + +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->name = dev_name(&pdev->dev); +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &tiadc_info; + +	tiadc_step_config(indio_dev); +	tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD); + +	err = tiadc_channel_init(indio_dev, adc_dev->channels); +	if (err < 0) +		return err; + +	err = tiadc_iio_buffered_hardware_setup(indio_dev, +		&tiadc_worker_h, +		&tiadc_irq_h, +		adc_dev->mfd_tscadc->irq, +		IRQF_SHARED, +		&tiadc_buffer_setup_ops); + +	if (err) +		goto err_free_channels; + +	err = iio_device_register(indio_dev); +	if (err) +		goto err_buffer_unregister; + +	platform_set_drvdata(pdev, indio_dev); + +	return 0; + +err_buffer_unregister: +	tiadc_iio_buffered_hardware_remove(indio_dev); +err_free_channels: +	tiadc_channels_remove(indio_dev); +	return err; +} + +static int tiadc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	u32 step_en; + +	iio_device_unregister(indio_dev); +	tiadc_iio_buffered_hardware_remove(indio_dev); +	tiadc_channels_remove(indio_dev); + +	step_en = get_adc_step_mask(adc_dev); +	am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en); + +	return 0; +} + +#ifdef CONFIG_PM +static int tiadc_suspend(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	struct ti_tscadc_dev *tscadc_dev; +	unsigned int idle; + +	tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); +	if (!device_may_wakeup(tscadc_dev->dev)) { +		idle = tiadc_readl(adc_dev, REG_CTRL); +		idle &= ~(CNTRLREG_TSCSSENB); +		tiadc_writel(adc_dev, REG_CTRL, (idle | +				CNTRLREG_POWERDOWN)); +	} + +	return 0; +} + +static int tiadc_resume(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct tiadc_device *adc_dev = iio_priv(indio_dev); +	unsigned int restore; + +	/* Make sure ADC is powered up */ +	restore = tiadc_readl(adc_dev, REG_CTRL); +	restore &= ~(CNTRLREG_POWERDOWN); +	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; +} + +static const struct dev_pm_ops tiadc_pm_ops = { +	.suspend = tiadc_suspend, +	.resume = tiadc_resume, +}; +#define TIADC_PM_OPS (&tiadc_pm_ops) +#else +#define TIADC_PM_OPS NULL +#endif + +static const struct of_device_id ti_adc_dt_ids[] = { +	{ .compatible = "ti,am3359-adc", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); + +static struct platform_driver tiadc_driver = { +	.driver = { +		.name   = "TI-am335x-adc", +		.owner	= THIS_MODULE, +		.pm	= TIADC_PM_OPS, +		.of_match_table = ti_adc_dt_ids, +	}, +	.probe	= tiadc_probe, +	.remove	= tiadc_remove, +}; +module_platform_driver(tiadc_driver); + +MODULE_DESCRIPTION("TI ADC controller driver"); +MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c new file mode 100644 index 00000000000..eb86786e698 --- /dev/null +++ b/drivers/iio/adc/twl4030-madc.c @@ -0,0 +1,896 @@ +/* + * + * TWL4030 MADC module driver-This driver monitors the real time + * conversion of analog signals like battery temperature, + * battery type, battery level etc. + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * J Keerthy <j-keerthy@ti.com> + * + * Based on twl4030-madc.c + * Copyright (C) 2008 Nokia Corporation + * Mikko Ylinen <mikko.k.ylinen@nokia.com> + * + * Amit Kucheria <amit.kucheria@canonical.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/i2c/twl.h> +#include <linux/i2c/twl4030-madc.h> +#include <linux/module.h> +#include <linux/stddef.h> +#include <linux/mutex.h> +#include <linux/bitops.h> +#include <linux/jiffies.h> +#include <linux/types.h> +#include <linux/gfp.h> +#include <linux/err.h> + +#include <linux/iio/iio.h> + +/** + * struct twl4030_madc_data - a container for madc info + * @dev:		Pointer to device structure for madc + * @lock:		Mutex protecting this data structure + * @requests:		Array of request struct corresponding to SW1, SW2 and RT + * @use_second_irq:	IRQ selection (main or co-processor) + * @imr:		Interrupt mask register of MADC + * @isr:		Interrupt status register of MADC + */ +struct twl4030_madc_data { +	struct device *dev; +	struct mutex lock;	/* mutex protecting this data structure */ +	struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; +	bool use_second_irq; +	u8 imr; +	u8 isr; +}; + +static int twl4030_madc_read(struct iio_dev *iio_dev, +			     const struct iio_chan_spec *chan, +			     int *val, int *val2, long mask) +{ +	struct twl4030_madc_data *madc = iio_priv(iio_dev); +	struct twl4030_madc_request req; +	int ret; + +	req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1; + +	req.channels = BIT(chan->channel); +	req.active = false; +	req.func_cb = NULL; +	req.type = TWL4030_MADC_WAIT; +	req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); +	req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); + +	ret = twl4030_madc_conversion(&req); +	if (ret < 0) +		return ret; + +	*val = req.rbuf[chan->channel]; + +	return IIO_VAL_INT; +} + +static const struct iio_info twl4030_madc_iio_info = { +	.read_raw = &twl4030_madc_read, +	.driver_module = THIS_MODULE, +}; + +#define TWL4030_ADC_CHANNEL(_channel, _type, _name) {	\ +	.type = _type,					\ +	.channel = _channel,				\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \ +			      BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ +			      BIT(IIO_CHAN_INFO_PROCESSED), \ +	.datasheet_name = _name,			\ +	.indexed = 1,					\ +} + +static const struct iio_chan_spec twl4030_madc_iio_channels[] = { +	TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"), +	TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"), +	TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"), +	TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"), +	TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"), +	TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"), +	TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"), +	TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"), +	TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"), +	TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"), +	TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"), +	TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"), +	TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"), +	TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"), +	TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"), +	TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"), +}; + +static struct twl4030_madc_data *twl4030_madc; + +struct twl4030_prescale_divider_ratios { +	s16 numerator; +	s16 denominator; +}; + +static const struct twl4030_prescale_divider_ratios +twl4030_divider_ratios[16] = { +	{1, 1},		/* CHANNEL 0 No Prescaler */ +	{1, 1},		/* CHANNEL 1 No Prescaler */ +	{6, 10},	/* CHANNEL 2 */ +	{6, 10},	/* CHANNEL 3 */ +	{6, 10},	/* CHANNEL 4 */ +	{6, 10},	/* CHANNEL 5 */ +	{6, 10},	/* CHANNEL 6 */ +	{6, 10},	/* CHANNEL 7 */ +	{3, 14},	/* CHANNEL 8 */ +	{1, 3},		/* CHANNEL 9 */ +	{1, 1},		/* CHANNEL 10 No Prescaler */ +	{15, 100},	/* CHANNEL 11 */ +	{1, 4},		/* CHANNEL 12 */ +	{1, 1},		/* CHANNEL 13 Reserved channels */ +	{1, 1},		/* CHANNEL 14 Reseved channels */ +	{5, 11},	/* CHANNEL 15 */ +}; + + +/* Conversion table from -3 to 55 degrees Celcius */ +static int twl4030_therm_tbl[] = { +	30800,	29500,	28300,	27100, +	26000,	24900,	23900,	22900,	22000,	21100,	20300,	19400,	18700, +	17900,	17200,	16500,	15900,	15300,	14700,	14100,	13600,	13100, +	12600,	12100,	11600,	11200,	10800,	10400,	10000,	9630,	9280, +	8950,	8620,	8310,	8020,	7730,	7460,	7200,	6950,	6710, +	6470,	6250,	6040,	5830,	5640,	5450,	5260,	5090,	4920, +	4760,	4600,	4450,	4310,	4170,	4040,	3910,	3790,	3670, +	3550 +}; + +/* + * Structure containing the registers + * of different conversion methods supported by MADC. + * Hardware or RT real time conversion request initiated by external host + * processor for RT Signal conversions. + * External host processors can also request for non RT conversions + * SW1 and SW2 software conversions also called asynchronous or GPC request. + */ +static +const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { +	[TWL4030_MADC_RT] = { +			     .sel = TWL4030_MADC_RTSELECT_LSB, +			     .avg = TWL4030_MADC_RTAVERAGE_LSB, +			     .rbase = TWL4030_MADC_RTCH0_LSB, +			     }, +	[TWL4030_MADC_SW1] = { +			      .sel = TWL4030_MADC_SW1SELECT_LSB, +			      .avg = TWL4030_MADC_SW1AVERAGE_LSB, +			      .rbase = TWL4030_MADC_GPCH0_LSB, +			      .ctrl = TWL4030_MADC_CTRL_SW1, +			      }, +	[TWL4030_MADC_SW2] = { +			      .sel = TWL4030_MADC_SW2SELECT_LSB, +			      .avg = TWL4030_MADC_SW2AVERAGE_LSB, +			      .rbase = TWL4030_MADC_GPCH0_LSB, +			      .ctrl = TWL4030_MADC_CTRL_SW2, +			      }, +}; + +/** + * twl4030_madc_channel_raw_read() - Function to read a particular channel value + * @madc:	pointer to struct twl4030_madc_data + * @reg:	lsb of ADC Channel + * + * Return: 0 on success, an error code otherwise. + */ +static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) +{ +	u16 val; +	int ret; +	/* +	 * For each ADC channel, we have MSB and LSB register pair. MSB address +	 * is always LSB address+1. reg parameter is the address of LSB register +	 */ +	ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg); +	if (ret) { +		dev_err(madc->dev, "unable to read register 0x%X\n", reg); +		return ret; +	} + +	return (int)(val >> 6); +} + +/* + * Return battery temperature in degrees Celsius + * Or < 0 on failure. + */ +static int twl4030battery_temperature(int raw_volt) +{ +	u8 val; +	int temp, curr, volt, res, ret; + +	volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; +	/* Getting and calculating the supply current in micro amperes */ +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, +		REG_BCICTL2); +	if (ret < 0) +		return ret; + +	curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; +	/* Getting and calculating the thermistor resistance in ohms */ +	res = volt * 1000 / curr; +	/* calculating temperature */ +	for (temp = 58; temp >= 0; temp--) { +		int actual = twl4030_therm_tbl[temp]; +		if ((actual - res) >= 0) +			break; +	} + +	return temp + 1; +} + +static int twl4030battery_current(int raw_volt) +{ +	int ret; +	u8 val; + +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, +		TWL4030_BCI_BCICTL1); +	if (ret) +		return ret; +	if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */ +		return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1; +	else /* slope of 0.88 mV/mA */ +		return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2; +} + +/* + * Function to read channel values + * @madc - pointer to twl4030_madc_data struct + * @reg_base - Base address of the first channel + * @Channels - 16 bit bitmap. If the bit is set, channel's value is read + * @buf - The channel values are stored here. if read fails error + * @raw - Return raw values without conversion + * value is stored + * Returns the number of successfully read channels. + */ +static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, +				      u8 reg_base, unsigned +				      long channels, int *buf, +				      bool raw) +{ +	int count = 0; +	int i; +	u8 reg; + +	for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) { +		reg = reg_base + (2 * i); +		buf[i] = twl4030_madc_channel_raw_read(madc, reg); +		if (buf[i] < 0) { +			dev_err(madc->dev, "Unable to read register 0x%X\n", +				reg); +			return buf[i]; +		} +		if (raw) { +			count++; +			continue; +		} +		switch (i) { +		case 10: +			buf[i] = twl4030battery_current(buf[i]); +			if (buf[i] < 0) { +				dev_err(madc->dev, "err reading current\n"); +				return buf[i]; +			} else { +				count++; +				buf[i] = buf[i] - 750; +			} +			break; +		case 1: +			buf[i] = twl4030battery_temperature(buf[i]); +			if (buf[i] < 0) { +				dev_err(madc->dev, "err reading temperature\n"); +				return buf[i]; +			} else { +				buf[i] -= 3; +				count++; +			} +			break; +		default: +			count++; +			/* Analog Input (V) = conv_result * step_size / R +			 * conv_result = decimal value of 10-bit conversion +			 *		 result +			 * step size = 1.5 / (2 ^ 10 -1) +			 * R = Prescaler ratio for input channels. +			 * Result given in mV hence multiplied by 1000. +			 */ +			buf[i] = (buf[i] * 3 * 1000 * +				 twl4030_divider_ratios[i].denominator) +				/ (2 * 1023 * +				twl4030_divider_ratios[i].numerator); +		} +	} + +	return count; +} + +/* + * Enables irq. + * @madc - pointer to twl4030_madc_data struct + * @id - irq number to be enabled + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 + * corresponding to RT, SW1, SW2 conversion requests. + * If the i2c read fails it returns an error else returns 0. + */ +static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) +{ +	u8 val; +	int ret; + +	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); +	if (ret) { +		dev_err(madc->dev, "unable to read imr register 0x%X\n", +			madc->imr); +		return ret; +	} + +	val &= ~(1 << id); +	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); +	if (ret) { +		dev_err(madc->dev, +			"unable to write imr register 0x%X\n", madc->imr); +		return ret; +	} + +	return 0; +} + +/* + * Disables irq. + * @madc - pointer to twl4030_madc_data struct + * @id - irq number to be disabled + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 + * corresponding to RT, SW1, SW2 conversion requests. + * Returns error if i2c read/write fails. + */ +static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id) +{ +	u8 val; +	int ret; + +	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); +	if (ret) { +		dev_err(madc->dev, "unable to read imr register 0x%X\n", +			madc->imr); +		return ret; +	} +	val |= (1 << id); +	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); +	if (ret) { +		dev_err(madc->dev, +			"unable to write imr register 0x%X\n", madc->imr); +		return ret; +	} + +	return 0; +} + +static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) +{ +	struct twl4030_madc_data *madc = _madc; +	const struct twl4030_madc_conversion_method *method; +	u8 isr_val, imr_val; +	int i, len, ret; +	struct twl4030_madc_request *r; + +	mutex_lock(&madc->lock); +	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr); +	if (ret) { +		dev_err(madc->dev, "unable to read isr register 0x%X\n", +			madc->isr); +		goto err_i2c; +	} +	ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr); +	if (ret) { +		dev_err(madc->dev, "unable to read imr register 0x%X\n", +			madc->imr); +		goto err_i2c; +	} +	isr_val &= ~imr_val; +	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { +		if (!(isr_val & (1 << i))) +			continue; +		ret = twl4030_madc_disable_irq(madc, i); +		if (ret < 0) +			dev_dbg(madc->dev, "Disable interrupt failed %d\n", i); +		madc->requests[i].result_pending = 1; +	} +	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { +		r = &madc->requests[i]; +		/* No pending results for this method, move to next one */ +		if (!r->result_pending) +			continue; +		method = &twl4030_conversion_methods[r->method]; +		/* Read results */ +		len = twl4030_madc_read_channels(madc, method->rbase, +						 r->channels, r->rbuf, r->raw); +		/* Return results to caller */ +		if (r->func_cb != NULL) { +			r->func_cb(len, r->channels, r->rbuf); +			r->func_cb = NULL; +		} +		/* Free request */ +		r->result_pending = 0; +		r->active = 0; +	} +	mutex_unlock(&madc->lock); + +	return IRQ_HANDLED; + +err_i2c: +	/* +	 * In case of error check whichever request is active +	 * and service the same. +	 */ +	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { +		r = &madc->requests[i]; +		if (r->active == 0) +			continue; +		method = &twl4030_conversion_methods[r->method]; +		/* Read results */ +		len = twl4030_madc_read_channels(madc, method->rbase, +						 r->channels, r->rbuf, r->raw); +		/* Return results to caller */ +		if (r->func_cb != NULL) { +			r->func_cb(len, r->channels, r->rbuf); +			r->func_cb = NULL; +		} +		/* Free request */ +		r->result_pending = 0; +		r->active = 0; +	} +	mutex_unlock(&madc->lock); + +	return IRQ_HANDLED; +} + +static int twl4030_madc_set_irq(struct twl4030_madc_data *madc, +				struct twl4030_madc_request *req) +{ +	struct twl4030_madc_request *p; +	int ret; + +	p = &madc->requests[req->method]; +	memcpy(p, req, sizeof(*req)); +	ret = twl4030_madc_enable_irq(madc, req->method); +	if (ret < 0) { +		dev_err(madc->dev, "enable irq failed!!\n"); +		return ret; +	} + +	return 0; +} + +/* + * Function which enables the madc conversion + * by writing to the control register. + * @madc - pointer to twl4030_madc_data struct + * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1 + * corresponding to RT SW1 or SW2 conversion methods. + * Returns 0 if succeeds else a negative error value + */ +static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc, +					 int conv_method) +{ +	const struct twl4030_madc_conversion_method *method; +	int ret = 0; + +	if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2) +		return -ENOTSUPP; + +	method = &twl4030_conversion_methods[conv_method]; +	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START, +			       method->ctrl); +	if (ret) { +		dev_err(madc->dev, "unable to write ctrl register 0x%X\n", +			method->ctrl); +		return ret; +	} + +	return 0; +} + +/* + * Function that waits for conversion to be ready + * @madc - pointer to twl4030_madc_data struct + * @timeout_ms - timeout value in milliseconds + * @status_reg - ctrl register + * returns 0 if succeeds else a negative error value + */ +static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, +					      unsigned int timeout_ms, +					      u8 status_reg) +{ +	unsigned long timeout; +	int ret; + +	timeout = jiffies + msecs_to_jiffies(timeout_ms); +	do { +		u8 reg; + +		ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg); +		if (ret) { +			dev_err(madc->dev, +				"unable to read status register 0x%X\n", +				status_reg); +			return ret; +		} +		if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW)) +			return 0; +		usleep_range(500, 2000); +	} while (!time_after(jiffies, timeout)); +	dev_err(madc->dev, "conversion timeout!\n"); + +	return -EAGAIN; +} + +/* + * An exported function which can be called from other kernel drivers. + * @req twl4030_madc_request structure + * req->rbuf will be filled with read values of channels based on the + * channel index. If a particular channel reading fails there will + * be a negative error value in the corresponding array element. + * returns 0 if succeeds else error value + */ +int twl4030_madc_conversion(struct twl4030_madc_request *req) +{ +	const struct twl4030_madc_conversion_method *method; +	int ret; + +	if (!req || !twl4030_madc) +		return -EINVAL; + +	mutex_lock(&twl4030_madc->lock); +	if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { +		ret = -EINVAL; +		goto out; +	} +	/* Do we have a conversion request ongoing */ +	if (twl4030_madc->requests[req->method].active) { +		ret = -EBUSY; +		goto out; +	} +	method = &twl4030_conversion_methods[req->method]; +	/* Select channels to be converted */ +	ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel); +	if (ret) { +		dev_err(twl4030_madc->dev, +			"unable to write sel register 0x%X\n", method->sel); +		goto out; +	} +	/* Select averaging for all channels if do_avg is set */ +	if (req->do_avg) { +		ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, +				       method->avg); +		if (ret) { +			dev_err(twl4030_madc->dev, +				"unable to write avg register 0x%X\n", +				method->avg); +			goto out; +		} +	} +	if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { +		ret = twl4030_madc_set_irq(twl4030_madc, req); +		if (ret < 0) +			goto out; +		ret = twl4030_madc_start_conversion(twl4030_madc, req->method); +		if (ret < 0) +			goto out; +		twl4030_madc->requests[req->method].active = 1; +		ret = 0; +		goto out; +	} +	/* With RT method we should not be here anymore */ +	if (req->method == TWL4030_MADC_RT) { +		ret = -EINVAL; +		goto out; +	} +	ret = twl4030_madc_start_conversion(twl4030_madc, req->method); +	if (ret < 0) +		goto out; +	twl4030_madc->requests[req->method].active = 1; +	/* Wait until conversion is ready (ctrl register returns EOC) */ +	ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl); +	if (ret) { +		twl4030_madc->requests[req->method].active = 0; +		goto out; +	} +	ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, +					 req->channels, req->rbuf, req->raw); +	twl4030_madc->requests[req->method].active = 0; + +out: +	mutex_unlock(&twl4030_madc->lock); + +	return ret; +} +EXPORT_SYMBOL_GPL(twl4030_madc_conversion); + +int twl4030_get_madc_conversion(int channel_no) +{ +	struct twl4030_madc_request req; +	int temp = 0; +	int ret; + +	req.channels = (1 << channel_no); +	req.method = TWL4030_MADC_SW2; +	req.active = 0; +	req.raw = 0; +	req.func_cb = NULL; +	ret = twl4030_madc_conversion(&req); +	if (ret < 0) +		return ret; +	if (req.rbuf[channel_no] > 0) +		temp = req.rbuf[channel_no]; + +	return temp; +} +EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); + +/** + * twl4030_madc_set_current_generator() - setup bias current + * + * @madc:	pointer to twl4030_madc_data struct + * @chan:	can be one of the two values: + *		TWL4030_BCI_ITHEN + *		Enables bias current for main battery type reading + *		TWL4030_BCI_TYPEN + *		Enables bias current for main battery temperature sensing + * @on:		enable or disable chan. + * + * Function to enable or disable bias current for + * main battery type reading or temperature sensing + */ +static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, +					      int chan, int on) +{ +	int ret; +	int regmask; +	u8 regval; + +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, +			      ®val, TWL4030_BCI_BCICTL1); +	if (ret) { +		dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", +			TWL4030_BCI_BCICTL1); +		return ret; +	} + +	regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; +	if (on) +		regval |= regmask; +	else +		regval &= ~regmask; + +	ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, +			       regval, TWL4030_BCI_BCICTL1); +	if (ret) { +		dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", +			TWL4030_BCI_BCICTL1); +		return ret; +	} + +	return 0; +} + +/* + * Function that sets MADC software power on bit to enable MADC + * @madc - pointer to twl4030_madc_data struct + * @on - Enable or disable MADC software power on bit. + * returns error if i2c read/write fails else 0 + */ +static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) +{ +	u8 regval; +	int ret; + +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, +			      ®val, TWL4030_MADC_CTRL1); +	if (ret) { +		dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", +			TWL4030_MADC_CTRL1); +		return ret; +	} +	if (on) +		regval |= TWL4030_MADC_MADCON; +	else +		regval &= ~TWL4030_MADC_MADCON; +	ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1); +	if (ret) { +		dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n", +			TWL4030_MADC_CTRL1); +		return ret; +	} + +	return 0; +} + +/* + * Initialize MADC and request for threaded irq + */ +static int twl4030_madc_probe(struct platform_device *pdev) +{ +	struct twl4030_madc_data *madc; +	struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); +	struct device_node *np = pdev->dev.of_node; +	int irq, ret; +	u8 regval; +	struct iio_dev *iio_dev = NULL; + +	if (!pdata && !np) { +		dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n"); +		return -EINVAL; +	} + +	iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc)); +	if (!iio_dev) { +		dev_err(&pdev->dev, "failed allocating iio device\n"); +		return -ENOMEM; +	} + +	madc = iio_priv(iio_dev); +	madc->dev = &pdev->dev; + +	iio_dev->name = dev_name(&pdev->dev); +	iio_dev->dev.parent = &pdev->dev; +	iio_dev->dev.of_node = pdev->dev.of_node; +	iio_dev->info = &twl4030_madc_iio_info; +	iio_dev->modes = INDIO_DIRECT_MODE; +	iio_dev->channels = twl4030_madc_iio_channels; +	iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels); + +	/* +	 * Phoenix provides 2 interrupt lines. The first one is connected to +	 * the OMAP. The other one can be connected to the other processor such +	 * as modem. Hence two separate ISR and IMR registers. +	 */ +	if (pdata) +		madc->use_second_irq = (pdata->irq_line != 1); +	else +		madc->use_second_irq = of_property_read_bool(np, +				       "ti,system-uses-second-madc-irq"); + +	madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 : +					   TWL4030_MADC_IMR1; +	madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 : +					   TWL4030_MADC_ISR1; + +	ret = twl4030_madc_set_power(madc, 1); +	if (ret < 0) +		return ret; +	ret = twl4030_madc_set_current_generator(madc, 0, 1); +	if (ret < 0) +		goto err_current_generator; + +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, +			      ®val, TWL4030_BCI_BCICTL1); +	if (ret) { +		dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", +			TWL4030_BCI_BCICTL1); +		goto err_i2c; +	} +	regval |= TWL4030_BCI_MESBAT; +	ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, +			       regval, TWL4030_BCI_BCICTL1); +	if (ret) { +		dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", +			TWL4030_BCI_BCICTL1); +		goto err_i2c; +	} + +	/* Check that MADC clock is on */ +	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, ®val, TWL4030_REG_GPBR1); +	if (ret) { +		dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n", +				TWL4030_REG_GPBR1); +		goto err_i2c; +	} + +	/* If MADC clk is not on, turn it on */ +	if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) { +		dev_info(&pdev->dev, "clk disabled, enabling\n"); +		regval |= TWL4030_GPBR1_MADC_HFCLK_EN; +		ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval, +				       TWL4030_REG_GPBR1); +		if (ret) { +			dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n", +					TWL4030_REG_GPBR1); +			goto err_i2c; +		} +	} + +	platform_set_drvdata(pdev, iio_dev); +	mutex_init(&madc->lock); + +	irq = platform_get_irq(pdev, 0); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +				   twl4030_madc_threaded_irq_handler, +				   IRQF_TRIGGER_RISING, "twl4030_madc", madc); +	if (ret) { +		dev_err(&pdev->dev, "could not request irq\n"); +		goto err_i2c; +	} +	twl4030_madc = madc; + +	ret = iio_device_register(iio_dev); +	if (ret) { +		dev_err(&pdev->dev, "could not register iio device\n"); +		goto err_i2c; +	} + +	return 0; + +err_i2c: +	twl4030_madc_set_current_generator(madc, 0, 0); +err_current_generator: +	twl4030_madc_set_power(madc, 0); +	return ret; +} + +static int twl4030_madc_remove(struct platform_device *pdev) +{ +	struct iio_dev *iio_dev = platform_get_drvdata(pdev); +	struct twl4030_madc_data *madc = iio_priv(iio_dev); + +	iio_device_unregister(iio_dev); + +	twl4030_madc_set_current_generator(madc, 0, 0); +	twl4030_madc_set_power(madc, 0); + +	return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id twl_madc_of_match[] = { +	{ .compatible = "ti,twl4030-madc", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, twl_madc_of_match); +#endif + +static struct platform_driver twl4030_madc_driver = { +	.probe = twl4030_madc_probe, +	.remove = twl4030_madc_remove, +	.driver = { +		   .name = "twl4030_madc", +		   .owner = THIS_MODULE, +		   .of_match_table = of_match_ptr(twl_madc_of_match), +	}, +}; + +module_platform_driver(twl4030_madc_driver); + +MODULE_DESCRIPTION("TWL4030 ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("J Keerthy"); +MODULE_ALIAS("platform:twl4030_madc"); diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c new file mode 100644 index 00000000000..15282f148b3 --- /dev/null +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -0,0 +1,1010 @@ +/* + * TWL6030 GPADC module driver + * + * Copyright (C) 2009-2013 Texas Instruments Inc. + * Nishant Kamat <nskamat@ti.com> + * Balaji T K <balajitk@ti.com> + * Graeme Gregory <gg@slimlogic.co.uk> + * Girish S Ghongdemath <girishsg@ti.com> + * Ambresh K <ambresh@ti.com> + * Oleksandr Kozaruk <oleksandr.kozaruk@ti.com + * + * Based on twl4030-madc.c + * Copyright (C) 2008 Nokia Corporation + * Mikko Ylinen <mikko.k.ylinen@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of_platform.h> +#include <linux/i2c/twl.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define DRIVER_NAME		"twl6030_gpadc" + +/* + * twl6030 per TRM has 17 channels, and twl6032 has 19 channels + * 2 test network channels are not used, + * 2 die temperature channels are not used either, as it is not + * defined how to convert ADC value to temperature + */ +#define TWL6030_GPADC_USED_CHANNELS		13 +#define TWL6030_GPADC_MAX_CHANNELS		15 +#define TWL6032_GPADC_USED_CHANNELS		15 +#define TWL6032_GPADC_MAX_CHANNELS		19 +#define TWL6030_GPADC_NUM_TRIM_REGS		16 + +#define TWL6030_GPADC_CTRL_P1			0x05 + +#define TWL6032_GPADC_GPSELECT_ISB		0x07 +#define TWL6032_GPADC_CTRL_P1			0x08 + +#define TWL6032_GPADC_GPCH0_LSB			0x0d +#define TWL6032_GPADC_GPCH0_MSB			0x0e + +#define TWL6030_GPADC_CTRL_P1_SP1		BIT(3) + +#define TWL6030_GPADC_GPCH0_LSB			(0x29) + +#define TWL6030_GPADC_RT_SW1_EOC_MASK		BIT(5) + +#define TWL6030_GPADC_TRIM1			0xCD + +#define TWL6030_REG_TOGGLE1			0x90 +#define TWL6030_GPADCS				BIT(1) +#define TWL6030_GPADCR				BIT(0) + +/** + * struct twl6030_chnl_calib - channel calibration + * @gain:		slope coefficient for ideal curve + * @gain_error:		gain error + * @offset_error:	offset of the real curve + */ +struct twl6030_chnl_calib { +	s32 gain; +	s32 gain_error; +	s32 offset_error; +}; + +/** + * struct twl6030_ideal_code - GPADC calibration parameters + * GPADC is calibrated in two points: close to the beginning and + * to the and of the measurable input range + * + * @channel:	channel number + * @code1:	ideal code for the input at the beginning + * @code2:	ideal code for at the end of the range + * @volt1:	voltage input at the beginning(low voltage) + * @volt2:	voltage input at the end(high voltage) + */ +struct twl6030_ideal_code { +	int channel; +	u16 code1; +	u16 code2; +	u16 volt1; +	u16 volt2; +}; + +struct twl6030_gpadc_data; + +/** + * struct twl6030_gpadc_platform_data - platform specific data + * @nchannels:		number of GPADC channels + * @iio_channels:	iio channels + * @twl6030_ideal:	pointer to calibration parameters + * @start_conversion:	pointer to ADC start conversion function + * @channel_to_reg	pointer to ADC function to convert channel to + *			register address for reading conversion result + * @calibrate:		pointer to calibration function + */ +struct twl6030_gpadc_platform_data { +	const int nchannels; +	const struct iio_chan_spec *iio_channels; +	const struct twl6030_ideal_code *ideal; +	int (*start_conversion)(int channel); +	u8 (*channel_to_reg)(int channel); +	int (*calibrate)(struct twl6030_gpadc_data *gpadc); +}; + +/** + * struct twl6030_gpadc_data - GPADC data + * @dev:		device pointer + * @lock:		mutual exclusion lock for the structure + * @irq_complete:	completion to signal end of conversion + * @twl6030_cal_tbl:	pointer to calibration data for each + *			channel with gain error and offset + * @pdata:		pointer to device specific data + */ +struct twl6030_gpadc_data { +	struct device	*dev; +	struct mutex	lock; +	struct completion	irq_complete; +	struct twl6030_chnl_calib	*twl6030_cal_tbl; +	const struct twl6030_gpadc_platform_data *pdata; +}; + +/* + * channels 11, 12, 13, 15 and 16 have no calibration data + * calibration offset is same for channels 1, 3, 4, 5 + * + * The data is taken from GPADC_TRIM registers description. + * GPADC_TRIM registers keep difference between the code measured + * at volt1 and volt2 input voltages and corresponding code1 and code2 + */ +static const struct twl6030_ideal_code +	twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = { +	[0] = { /* ch 0, external, battery type, resistor value */ +		.channel = 0, +		.code1 = 116, +		.code2 = 745, +		.volt1 = 141, +		.volt2 = 910, +	}, +	[1] = { /* ch 1, external, battery temperature, NTC resistor value */ +		.channel = 1, +		.code1 = 82, +		.code2 = 900, +		.volt1 = 100, +		.volt2 = 1100, +	}, +	[2] = { /* ch 2, external, audio accessory/general purpose */ +		.channel = 2, +		.code1 = 55, +		.code2 = 818, +		.volt1 = 101, +		.volt2 = 1499, +	}, +	[3] = { /* ch 3, external, general purpose */ +		.channel = 3, +		.code1 = 82, +		.code2 = 900, +		.volt1 = 100, +		.volt2 = 1100, +	}, +	[4] = { /* ch 4, external, temperature measurement/general purpose */ +		.channel = 4, +		.code1 = 82, +		.code2 = 900, +		.volt1 = 100, +		.volt2 = 1100, +	}, +	[5] = { /* ch 5, external, general purpose */ +		.channel = 5, +		.code1 = 82, +		.code2 = 900, +		.volt1 = 100, +		.volt2 = 1100, +	}, +	[6] = { /* ch 6, external, general purpose */ +		.channel = 6, +		.code1 = 82, +		.code2 = 900, +		.volt1 = 100, +		.volt2 = 1100, +	}, +	[7] = { /* ch 7, internal, main battery */ +		.channel = 7, +		.code1 = 614, +		.code2 = 941, +		.volt1 = 3001, +		.volt2 = 4599, +	}, +	[8] = { /* ch 8, internal, backup battery */ +		.channel = 8, +		.code1 = 82, +		.code2 = 688, +		.volt1 = 501, +		.volt2 = 4203, +	}, +	[9] = { /* ch 9, internal, external charger input */ +		.channel = 9, +		.code1 = 182, +		.code2 = 818, +		.volt1 = 2001, +		.volt2 = 8996, +	}, +	[10] = { /* ch 10, internal, VBUS */ +		.channel = 10, +		.code1 = 149, +		.code2 = 818, +		.volt1 = 1001, +		.volt2 = 5497, +	}, +	[11] = { /* ch 11, internal, VBUS charging current */ +		.channel = 11, +	}, +		/* ch 12, internal, Die temperature */ +		/* ch 13, internal, Die temperature */ +	[12] = { /* ch 14, internal, USB ID line */ +		.channel = 14, +		.code1 = 48, +		.code2 = 714, +		.volt1 = 323, +		.volt2 = 4800, +	}, +}; + +static const struct twl6030_ideal_code +			twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = { +	[0] = { /* ch 0, external, battery type, resistor value */ +		.channel = 0, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[1] = { /* ch 1, external, battery temperature, NTC resistor value */ +		.channel = 1, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[2] = { /* ch 2, external, audio accessory/general purpose */ +		.channel = 2, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 660, +		.volt2 = 1500, +	}, +	[3] = { /* ch 3, external, temperature with external diode/general +								purpose */ +		.channel = 3, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[4] = { /* ch 4, external, temperature measurement/general purpose */ +		.channel = 4, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[5] = { /* ch 5, external, general purpose */ +		.channel = 5, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[6] = { /* ch 6, external, general purpose */ +		.channel = 6, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 440, +		.volt2 = 1000, +	}, +	[7] = { /* ch7, internal, system supply */ +		.channel = 7, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 2200, +		.volt2 = 5000, +	}, +	[8] = { /* ch8, internal, backup battery */ +		.channel = 8, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 2200, +		.volt2 = 5000, +	}, +	[9] = { /* ch 9, internal, external charger input */ +		.channel = 9, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 3960, +		.volt2 = 9000, +	}, +	[10] = { /* ch10, internal, VBUS */ +		.channel = 10, +		.code1 = 150, +		.code2 = 751, +		.volt1 = 1000, +		.volt2 = 5000, +	}, +	[11] = { /* ch 11, internal, VBUS DC-DC output current */ +		.channel = 11, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 660, +		.volt2 = 1500, +	}, +		/* ch 12, internal, Die temperature */ +		/* ch 13, internal, Die temperature */ +	[12] = { /* ch 14, internal, USB ID line */ +		.channel = 14, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 2420, +		.volt2 = 5500, +	}, +		/* ch 15, internal, test network */ +		/* ch 16, internal, test network */ +	[13] = { /* ch 17, internal, battery charging current */ +		.channel = 17, +	}, +	[14] = { /* ch 18, internal, battery voltage */ +		.channel = 18, +		.code1 = 1441, +		.code2 = 3276, +		.volt1 = 2200, +		.volt2 = 5000, +	}, +}; + +static inline int twl6030_gpadc_write(u8 reg, u8 val) +{ +	return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg); +} + +static inline int twl6030_gpadc_read(u8 reg, u8 *val) +{ + +	return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2); +} + +static int twl6030_gpadc_enable_irq(u8 mask) +{ +	int ret; + +	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B); +	if (ret < 0) +		return ret; + +	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B); + +	return ret; +} + +static void twl6030_gpadc_disable_irq(u8 mask) +{ +	twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B); +	twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B); +} + +static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev) +{ +	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); + +	complete(&gpadc->irq_complete); + +	return IRQ_HANDLED; +} + +static int twl6030_start_conversion(int channel) +{ +	return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1, +					TWL6030_GPADC_CTRL_P1_SP1); +} + +static int twl6032_start_conversion(int channel) +{ +	int ret; + +	ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel); +	if (ret) +		return ret; + +	return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1, +						TWL6030_GPADC_CTRL_P1_SP1); +} + +static u8 twl6030_channel_to_reg(int channel) +{ +	return TWL6030_GPADC_GPCH0_LSB + 2 * channel; +} + +static u8 twl6032_channel_to_reg(int channel) +{ +	/* +	 * for any prior chosen channel, when the conversion is ready +	 * the result is avalable in GPCH0_LSB, GPCH0_MSB. +	 */ + +	return TWL6032_GPADC_GPCH0_LSB; +} + +static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal, +		int channel, int size) +{ +	int i; + +	for (i = 0; i < size; i++) +		if (ideal[i].channel == channel) +			break; + +	return i; +} + +static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data +		*pdata, int channel) +{ +	const struct twl6030_ideal_code *ideal = pdata->ideal; +	int i; + +	i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels); +	/* not calibrated channels have 0 in all structure members */ +	return pdata->ideal[i].code2; +} + +static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc, +		int channel, int raw_code) +{ +	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; +	int corrected_code; +	int i; + +	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); +	corrected_code = ((raw_code * 1000) - +		gpadc->twl6030_cal_tbl[i].offset_error) / +		gpadc->twl6030_cal_tbl[i].gain_error; + +	return corrected_code; +} + +static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc, +		int channel, int *res) +{ +	u8 reg = gpadc->pdata->channel_to_reg(channel); +	__le16 val; +	int raw_code; +	int ret; + +	ret = twl6030_gpadc_read(reg, (u8 *)&val); +	if (ret) { +		dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg); +		return ret; +	} + +	raw_code = le16_to_cpu(val); +	dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code); + +	if (twl6030_channel_calibrated(gpadc->pdata, channel)) +		*res = twl6030_gpadc_make_correction(gpadc, channel, raw_code); +	else +		*res = raw_code; + +	return ret; +} + +static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc, +		int channel, int *val) +{ +	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; +	int corrected_code; +	int channel_value; +	int i; +	int ret; + +	ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code); +	if (ret) +		return ret; + +	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); +	channel_value = corrected_code * +			gpadc->twl6030_cal_tbl[i].gain; + +	/* Shift back into mV range */ +	channel_value /= 1000; + +	dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code); +	dev_dbg(gpadc->dev, "GPADC value: %d", channel_value); + +	*val = channel_value; + +	return ret; +} + +static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev, +			     const struct iio_chan_spec *chan, +			     int *val, int *val2, long mask) +{ +	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); +	int ret; +	long timeout; + +	mutex_lock(&gpadc->lock); + +	ret = gpadc->pdata->start_conversion(chan->channel); +	if (ret) { +		dev_err(gpadc->dev, "failed to start conversion\n"); +		goto err; +	} +	/* wait for conversion to complete */ +	timeout = wait_for_completion_interruptible_timeout( +				&gpadc->irq_complete, msecs_to_jiffies(5000)); +	if (timeout == 0) { +		ret = -ETIMEDOUT; +		goto err; +	} else if (timeout < 0) { +		ret = -EINTR; +		goto err; +	} + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val); +		ret = ret ? -EIO : IIO_VAL_INT; +		break; + +	case IIO_CHAN_INFO_PROCESSED: +		ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val); +		ret = ret ? -EIO : IIO_VAL_INT; +		break; + +	default: +		break; +	} +err: +	mutex_unlock(&gpadc->lock); + +	return ret; +} + +/* + * The GPADC channels are calibrated using a two point calibration method. + * The channels measured with two known values: volt1 and volt2, and + * ideal corresponding output codes are known: code1, code2. + * The difference(d1, d2) between ideal and measured codes stored in trim + * registers. + * The goal is to find offset and gain of the real curve for each calibrated + * channel. + * gain: k = 1 + ((d2 - d1) / (x2 - x1)) + * offset: b = d1 + (k - 1) * x1 + */ +static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc, +		int channel, int d1, int d2) +{ +	int b, k, gain, x1, x2, i; +	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; + +	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); + +	/* Gain */ +	gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) / +		(ideal[i].code2 - ideal[i].code1); + +	x1 = ideal[i].code1; +	x2 = ideal[i].code2; + +	/* k - real curve gain */ +	k = 1000 + (((d2 - d1) * 1000) / (x2 - x1)); + +	/* b - offset of the real curve gain */ +	b = (d1 * 1000) - (k - 1000) * x1; + +	gpadc->twl6030_cal_tbl[i].gain = gain; +	gpadc->twl6030_cal_tbl[i].gain_error = k; +	gpadc->twl6030_cal_tbl[i].offset_error = b; + +	dev_dbg(gpadc->dev, "GPADC d1   for Chn: %d = %d\n", channel, d1); +	dev_dbg(gpadc->dev, "GPADC d2   for Chn: %d = %d\n", channel, d2); +	dev_dbg(gpadc->dev, "GPADC x1   for Chn: %d = %d\n", channel, x1); +	dev_dbg(gpadc->dev, "GPADC x2   for Chn: %d = %d\n", channel, x2); +	dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain); +	dev_dbg(gpadc->dev, "GPADC k    for Chn: %d = %d\n", channel, k); +	dev_dbg(gpadc->dev, "GPADC b    for Chn: %d = %d\n", channel, b); +} + +static inline int twl6030_gpadc_get_trim_offset(s8 d) +{ +	/* +	 * XXX NOTE! +	 * bit 0 - sign, bit 7 - reserved, 6..1 - trim value +	 * though, the documentation states that trim value +	 * is absolute value, the correct conversion results are +	 * obtained if the value is interpreted as 2's complement. +	 */ +	__u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6); + +	return sign_extend32(temp, 6); +} + +static int twl6030_calibration(struct twl6030_gpadc_data *gpadc) +{ +	int ret; +	int chn; +	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; +	s8 d1, d2; + +	/* +	 * for calibration two measurements have been performed at +	 * factory, for some channels, during the production test and +	 * have been stored in registers. This two stored values are +	 * used to correct the measurements. The values represent +	 * offsets for the given input from the output on ideal curve. +	 */ +	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, +			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); +	if (ret < 0) { +		dev_err(gpadc->dev, "calibration failed\n"); +		return ret; +	} + +	for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) { + +		switch (chn) { +		case 0: +			d1 = trim_regs[0]; +			d2 = trim_regs[1]; +			break; +		case 1: +		case 3: +		case 4: +		case 5: +		case 6: +			d1 = trim_regs[4]; +			d2 = trim_regs[5]; +			break; +		case 2: +			d1 = trim_regs[12]; +			d2 = trim_regs[13]; +			break; +		case 7: +			d1 = trim_regs[6]; +			d2 = trim_regs[7]; +			break; +		case 8: +			d1 = trim_regs[2]; +			d2 = trim_regs[3]; +			break; +		case 9: +			d1 = trim_regs[8]; +			d2 = trim_regs[9]; +			break; +		case 10: +			d1 = trim_regs[10]; +			d2 = trim_regs[11]; +			break; +		case 14: +			d1 = trim_regs[14]; +			d2 = trim_regs[15]; +			break; +		default: +			continue; +		} + +		d1 = twl6030_gpadc_get_trim_offset(d1); +		d2 = twl6030_gpadc_get_trim_offset(d2); + +		twl6030_calibrate_channel(gpadc, chn, d1, d2); +	} + +	return 0; +} + +static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0, +		unsigned int reg1, unsigned int mask0, unsigned int mask1, +		unsigned int shift0) +{ +	int val; + +	val = (trim_regs[reg0] & mask0) << shift0; +	val |= (trim_regs[reg1] & mask1) >> 1; +	if (trim_regs[reg1] & 0x01) +		val = -val; + +	return val; +} + +static int twl6032_calibration(struct twl6030_gpadc_data *gpadc) +{ +	int chn, d1 = 0, d2 = 0, temp; +	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; +	int ret; + +	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, +			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); +	if (ret < 0) { +		dev_err(gpadc->dev, "calibration failed\n"); +		return ret; +	} + +	/* +	 * Loop to calculate the value needed for returning voltages from +	 * GPADC not values. +	 * +	 * gain is calculated to 3 decimal places fixed point. +	 */ +	for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) { + +		switch (chn) { +		case 0: +		case 1: +		case 2: +		case 3: +		case 4: +		case 5: +		case 6: +		case 11: +		case 14: +			d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, +								0x06, 2); +			d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, +								0x06, 2); +			break; +		case 8: +			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, +								0x06, 2); +			d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6, +								0x18, 0x1E, 1); + +			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F, +								0x06, 2); +			d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7, +								0x1F, 0x06, 2); +			break; +		case 9: +			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, +								0x06, 2); +			d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11, +								0x18, 0x1E, 1); + +			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, +								0x06, 2); +			d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13, +								0x1F, 0x06, 1); +			break; +		case 10: +			d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f, +								0x0E, 3); +			d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f, +								0x0E, 3); +			break; +		case 7: +		case 18: +			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, +								0x06, 2); + +			d1 = (trim_regs[4] & 0x7E) >> 1; +			if (trim_regs[4] & 0x01) +				d1 = -d1; +			d1 += temp; + +			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, +								0x06, 2); + +			d2 = (trim_regs[5] & 0xFE) >> 1; +			if (trim_regs[5] & 0x01) +				d2 = -d2; + +			d2 += temp; +			break; +		default: +			/* No data for other channels */ +			continue; +		} + +		twl6030_calibrate_channel(gpadc, chn, d1, d2); +	} + +	return 0; +} + +#define TWL6030_GPADC_CHAN(chn, _type, chan_info) {	\ +	.type = _type,					\ +	.channel = chn,					\ +	.info_mask_separate = BIT(chan_info),		\ +	.indexed = 1,					\ +} + +static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = { +	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +}; + +static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = { +	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +	TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), +	TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), +}; + +static const struct iio_info twl6030_gpadc_iio_info = { +	.read_raw = &twl6030_gpadc_read_raw, +	.driver_module = THIS_MODULE, +}; + +static const struct twl6030_gpadc_platform_data twl6030_pdata = { +	.iio_channels = twl6030_gpadc_iio_channels, +	.nchannels = TWL6030_GPADC_USED_CHANNELS, +	.ideal = twl6030_ideal, +	.start_conversion = twl6030_start_conversion, +	.channel_to_reg = twl6030_channel_to_reg, +	.calibrate = twl6030_calibration, +}; + +static const struct twl6030_gpadc_platform_data twl6032_pdata = { +	.iio_channels = twl6032_gpadc_iio_channels, +	.nchannels = TWL6032_GPADC_USED_CHANNELS, +	.ideal = twl6032_ideal, +	.start_conversion = twl6032_start_conversion, +	.channel_to_reg = twl6032_channel_to_reg, +	.calibrate = twl6032_calibration, +}; + +static const struct of_device_id of_twl6030_match_tbl[] = { +	{ +		.compatible = "ti,twl6030-gpadc", +		.data = &twl6030_pdata, +	}, +	{ +		.compatible = "ti,twl6032-gpadc", +		.data = &twl6032_pdata, +	}, +	{ /* end */ } +}; + +static int twl6030_gpadc_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct twl6030_gpadc_data *gpadc; +	const struct twl6030_gpadc_platform_data *pdata; +	const struct of_device_id *match; +	struct iio_dev *indio_dev; +	int irq; +	int ret; + +	match = of_match_device(of_twl6030_match_tbl, dev); +	if (!match) +		return -EINVAL; + +	pdata = match->data; + +	indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); +	if (!indio_dev) +		return -ENOMEM; + +	gpadc = iio_priv(indio_dev); + +	gpadc->twl6030_cal_tbl = devm_kzalloc(dev, +					sizeof(*gpadc->twl6030_cal_tbl) * +					pdata->nchannels, GFP_KERNEL); +	if (!gpadc->twl6030_cal_tbl) +		return -ENOMEM; + +	gpadc->dev = dev; +	gpadc->pdata = pdata; + +	platform_set_drvdata(pdev, indio_dev); +	mutex_init(&gpadc->lock); +	init_completion(&gpadc->irq_complete); + +	ret = pdata->calibrate(gpadc); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to read calibration registers\n"); +		return ret; +	} + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "failed to get irq\n"); +		return irq; +	} + +	ret = devm_request_threaded_irq(dev, irq, NULL, +				twl6030_gpadc_irq_handler, +				IRQF_ONESHOT, "twl6030_gpadc", indio_dev); + +	ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to enable GPADC interrupt\n"); +		return ret; +	} + +	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, +					TWL6030_REG_TOGGLE1); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to enable GPADC module\n"); +		return ret; +	} + +	indio_dev->name = DRIVER_NAME; +	indio_dev->dev.parent = dev; +	indio_dev->info = &twl6030_gpadc_iio_info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = pdata->iio_channels; +	indio_dev->num_channels = pdata->nchannels; + +	return iio_device_register(indio_dev); +} + +static int twl6030_gpadc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); + +	twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); +	iio_device_unregister(indio_dev); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int twl6030_gpadc_suspend(struct device *pdev) +{ +	int ret; + +	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR, +				TWL6030_REG_TOGGLE1); +	if (ret) +		dev_err(pdev, "error resetting GPADC (%d)!\n", ret); + +	return 0; +}; + +static int twl6030_gpadc_resume(struct device *pdev) +{ +	int ret; + +	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, +				TWL6030_REG_TOGGLE1); +	if (ret) +		dev_err(pdev, "error setting GPADC (%d)!\n", ret); + +	return 0; +}; +#endif + +static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, +					twl6030_gpadc_resume); + +static struct platform_driver twl6030_gpadc_driver = { +	.probe		= twl6030_gpadc_probe, +	.remove		= twl6030_gpadc_remove, +	.driver		= { +		.name	= DRIVER_NAME, +		.owner	= THIS_MODULE, +		.pm	= &twl6030_gpadc_pm_ops, +		.of_match_table = of_twl6030_match_tbl, +	}, +}; + +module_platform_driver(twl6030_gpadc_driver); + +MODULE_ALIAS("platform: " DRIVER_NAME); +MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); +MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); +MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com"); +MODULE_DESCRIPTION("twl6030 ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c new file mode 100644 index 00000000000..44799eb5930 --- /dev/null +++ b/drivers/iio/adc/vf610_adc.c @@ -0,0 +1,711 @@ +/* + * Freescale Vybrid vf610 ADC driver + * + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/err.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/driver.h> + +/* This will be the driver name the kernel reports */ +#define DRIVER_NAME "vf610-adc" + +/* Vybrid/IMX ADC registers */ +#define VF610_REG_ADC_HC0		0x00 +#define VF610_REG_ADC_HC1		0x04 +#define VF610_REG_ADC_HS		0x08 +#define VF610_REG_ADC_R0		0x0c +#define VF610_REG_ADC_R1		0x10 +#define VF610_REG_ADC_CFG		0x14 +#define VF610_REG_ADC_GC		0x18 +#define VF610_REG_ADC_GS		0x1c +#define VF610_REG_ADC_CV		0x20 +#define VF610_REG_ADC_OFS		0x24 +#define VF610_REG_ADC_CAL		0x28 +#define VF610_REG_ADC_PCTL		0x30 + +/* Configuration register field define */ +#define VF610_ADC_MODE_BIT8		0x00 +#define VF610_ADC_MODE_BIT10		0x04 +#define VF610_ADC_MODE_BIT12		0x08 +#define VF610_ADC_MODE_MASK		0x0c +#define VF610_ADC_BUSCLK2_SEL		0x01 +#define VF610_ADC_ALTCLK_SEL		0x02 +#define VF610_ADC_ADACK_SEL		0x03 +#define VF610_ADC_ADCCLK_MASK		0x03 +#define VF610_ADC_CLK_DIV2		0x20 +#define VF610_ADC_CLK_DIV4		0x40 +#define VF610_ADC_CLK_DIV8		0x60 +#define VF610_ADC_CLK_MASK		0x60 +#define VF610_ADC_ADLSMP_LONG		0x10 +#define VF610_ADC_ADSTS_MASK		0x300 +#define VF610_ADC_ADLPC_EN		0x80 +#define VF610_ADC_ADHSC_EN		0x400 +#define VF610_ADC_REFSEL_VALT		0x100 +#define VF610_ADC_REFSEL_VBG		0x1000 +#define VF610_ADC_ADTRG_HARD		0x2000 +#define VF610_ADC_AVGS_8		0x4000 +#define VF610_ADC_AVGS_16		0x8000 +#define VF610_ADC_AVGS_32		0xC000 +#define VF610_ADC_AVGS_MASK		0xC000 +#define VF610_ADC_OVWREN		0x10000 + +/* General control register field define */ +#define VF610_ADC_ADACKEN		0x1 +#define VF610_ADC_DMAEN			0x2 +#define VF610_ADC_ACREN			0x4 +#define VF610_ADC_ACFGT			0x8 +#define VF610_ADC_ACFE			0x10 +#define VF610_ADC_AVGEN			0x20 +#define VF610_ADC_ADCON			0x40 +#define VF610_ADC_CAL			0x80 + +/* Other field define */ +#define VF610_ADC_ADCHC(x)		((x) & 0xF) +#define VF610_ADC_AIEN			(0x1 << 7) +#define VF610_ADC_CONV_DISABLE		0x1F +#define VF610_ADC_HS_COCO0		0x1 +#define VF610_ADC_CALF			0x2 +#define VF610_ADC_TIMEOUT		msecs_to_jiffies(100) + +enum clk_sel { +	VF610_ADCIOC_BUSCLK_SET, +	VF610_ADCIOC_ALTCLK_SET, +	VF610_ADCIOC_ADACK_SET, +}; + +enum vol_ref { +	VF610_ADCIOC_VR_VREF_SET, +	VF610_ADCIOC_VR_VALT_SET, +	VF610_ADCIOC_VR_VBG_SET, +}; + +enum average_sel { +	VF610_ADC_SAMPLE_1, +	VF610_ADC_SAMPLE_4, +	VF610_ADC_SAMPLE_8, +	VF610_ADC_SAMPLE_16, +	VF610_ADC_SAMPLE_32, +}; + +struct vf610_adc_feature { +	enum clk_sel	clk_sel; +	enum vol_ref	vol_ref; + +	int	clk_div; +	int     sample_rate; +	int	res_mode; + +	bool	lpm; +	bool	calibration; +	bool	ovwren; +}; + +struct vf610_adc { +	struct device *dev; +	void __iomem *regs; +	struct clk *clk; + +	u32 vref_uv; +	u32 value; +	struct regulator *vref; +	struct vf610_adc_feature adc_feature; + +	struct completion completion; +}; + +#define VF610_ADC_CHAN(_idx, _chan_type) {			\ +	.type = (_chan_type),					\ +	.indexed = 1,						\ +	.channel = (_idx),					\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\ +				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\ +} + +static const struct iio_chan_spec vf610_adc_iio_channels[] = { +	VF610_ADC_CHAN(0, IIO_VOLTAGE), +	VF610_ADC_CHAN(1, IIO_VOLTAGE), +	VF610_ADC_CHAN(2, IIO_VOLTAGE), +	VF610_ADC_CHAN(3, IIO_VOLTAGE), +	VF610_ADC_CHAN(4, IIO_VOLTAGE), +	VF610_ADC_CHAN(5, IIO_VOLTAGE), +	VF610_ADC_CHAN(6, IIO_VOLTAGE), +	VF610_ADC_CHAN(7, IIO_VOLTAGE), +	VF610_ADC_CHAN(8, IIO_VOLTAGE), +	VF610_ADC_CHAN(9, IIO_VOLTAGE), +	VF610_ADC_CHAN(10, IIO_VOLTAGE), +	VF610_ADC_CHAN(11, IIO_VOLTAGE), +	VF610_ADC_CHAN(12, IIO_VOLTAGE), +	VF610_ADC_CHAN(13, IIO_VOLTAGE), +	VF610_ADC_CHAN(14, IIO_VOLTAGE), +	VF610_ADC_CHAN(15, IIO_VOLTAGE), +	/* sentinel */ +}; + +/* + * ADC sample frequency, unit is ADCK cycles. + * ADC clk source is ipg clock, which is the same as bus clock. + * + * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder) + * SFCAdder: fixed to 6 ADCK cycles + * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. + * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode + * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * + * By default, enable 12 bit resolution mode, clock source + * set to ipg clock, So get below frequency group: + */ +static const u32 vf610_sample_freq_avail[5] = +{1941176, 559332, 286957, 145374, 73171}; + +static inline void vf610_adc_cfg_init(struct vf610_adc *info) +{ +	/* set default Configuration for ADC controller */ +	info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET; +	info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET; + +	info->adc_feature.calibration = true; +	info->adc_feature.ovwren = true; + +	info->adc_feature.clk_div = 1; +	info->adc_feature.res_mode = 12; +	info->adc_feature.sample_rate = 1; +	info->adc_feature.lpm = true; +} + +static void vf610_adc_cfg_post_set(struct vf610_adc *info) +{ +	struct vf610_adc_feature *adc_feature = &info->adc_feature; +	int cfg_data = 0; +	int gc_data = 0; + +	switch (adc_feature->clk_sel) { +	case VF610_ADCIOC_ALTCLK_SET: +		cfg_data |= VF610_ADC_ALTCLK_SEL; +		break; +	case VF610_ADCIOC_ADACK_SET: +		cfg_data |= VF610_ADC_ADACK_SEL; +		break; +	default: +		break; +	} + +	/* low power set for calibration */ +	cfg_data |= VF610_ADC_ADLPC_EN; + +	/* enable high speed for calibration */ +	cfg_data |= VF610_ADC_ADHSC_EN; + +	/* voltage reference */ +	switch (adc_feature->vol_ref) { +	case VF610_ADCIOC_VR_VREF_SET: +		break; +	case VF610_ADCIOC_VR_VALT_SET: +		cfg_data |= VF610_ADC_REFSEL_VALT; +		break; +	case VF610_ADCIOC_VR_VBG_SET: +		cfg_data |= VF610_ADC_REFSEL_VBG; +		break; +	default: +		dev_err(info->dev, "error voltage reference\n"); +	} + +	/* data overwrite enable */ +	if (adc_feature->ovwren) +		cfg_data |= VF610_ADC_OVWREN; + +	writel(cfg_data, info->regs + VF610_REG_ADC_CFG); +	writel(gc_data, info->regs + VF610_REG_ADC_GC); +} + +static void vf610_adc_calibration(struct vf610_adc *info) +{ +	int adc_gc, hc_cfg; +	int timeout; + +	if (!info->adc_feature.calibration) +		return; + +	/* enable calibration interrupt */ +	hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE; +	writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + +	adc_gc = readl(info->regs + VF610_REG_ADC_GC); +	writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC); + +	timeout = wait_for_completion_timeout +			(&info->completion, VF610_ADC_TIMEOUT); +	if (timeout == 0) +		dev_err(info->dev, "Timeout for adc calibration\n"); + +	adc_gc = readl(info->regs + VF610_REG_ADC_GS); +	if (adc_gc & VF610_ADC_CALF) +		dev_err(info->dev, "ADC calibration failed\n"); + +	info->adc_feature.calibration = false; +} + +static void vf610_adc_cfg_set(struct vf610_adc *info) +{ +	struct vf610_adc_feature *adc_feature = &(info->adc_feature); +	int cfg_data; + +	cfg_data = readl(info->regs + VF610_REG_ADC_CFG); + +	/* low power configuration */ +	cfg_data &= ~VF610_ADC_ADLPC_EN; +	if (adc_feature->lpm) +		cfg_data |= VF610_ADC_ADLPC_EN; + +	/* disable high speed */ +	cfg_data &= ~VF610_ADC_ADHSC_EN; + +	writel(cfg_data, info->regs + VF610_REG_ADC_CFG); +} + +static void vf610_adc_sample_set(struct vf610_adc *info) +{ +	struct vf610_adc_feature *adc_feature = &(info->adc_feature); +	int cfg_data, gc_data; + +	cfg_data = readl(info->regs + VF610_REG_ADC_CFG); +	gc_data = readl(info->regs + VF610_REG_ADC_GC); + +	/* resolution mode */ +	cfg_data &= ~VF610_ADC_MODE_MASK; +	switch (adc_feature->res_mode) { +	case 8: +		cfg_data |= VF610_ADC_MODE_BIT8; +		break; +	case 10: +		cfg_data |= VF610_ADC_MODE_BIT10; +		break; +	case 12: +		cfg_data |= VF610_ADC_MODE_BIT12; +		break; +	default: +		dev_err(info->dev, "error resolution mode\n"); +		break; +	} + +	/* clock select and clock divider */ +	cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK); +	switch (adc_feature->clk_div) { +	case 1: +		break; +	case 2: +		cfg_data |= VF610_ADC_CLK_DIV2; +		break; +	case 4: +		cfg_data |= VF610_ADC_CLK_DIV4; +		break; +	case 8: +		cfg_data |= VF610_ADC_CLK_DIV8; +		break; +	case 16: +		switch (adc_feature->clk_sel) { +		case VF610_ADCIOC_BUSCLK_SET: +			cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8; +			break; +		default: +			dev_err(info->dev, "error clk divider\n"); +			break; +		} +		break; +	} + +	/* Use the short sample mode */ +	cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + +	/* update hardware average selection */ +	cfg_data &= ~VF610_ADC_AVGS_MASK; +	gc_data &= ~VF610_ADC_AVGEN; +	switch (adc_feature->sample_rate) { +	case VF610_ADC_SAMPLE_1: +		break; +	case VF610_ADC_SAMPLE_4: +		gc_data |= VF610_ADC_AVGEN; +		break; +	case VF610_ADC_SAMPLE_8: +		gc_data |= VF610_ADC_AVGEN; +		cfg_data |= VF610_ADC_AVGS_8; +		break; +	case VF610_ADC_SAMPLE_16: +		gc_data |= VF610_ADC_AVGEN; +		cfg_data |= VF610_ADC_AVGS_16; +		break; +	case VF610_ADC_SAMPLE_32: +		gc_data |= VF610_ADC_AVGEN; +		cfg_data |= VF610_ADC_AVGS_32; +		break; +	default: +		dev_err(info->dev, +			"error hardware sample average select\n"); +	} + +	writel(cfg_data, info->regs + VF610_REG_ADC_CFG); +	writel(gc_data, info->regs + VF610_REG_ADC_GC); +} + +static void vf610_adc_hw_init(struct vf610_adc *info) +{ +	/* CFG: Feature set */ +	vf610_adc_cfg_post_set(info); +	vf610_adc_sample_set(info); + +	/* adc calibration */ +	vf610_adc_calibration(info); + +	/* CFG: power and speed set */ +	vf610_adc_cfg_set(info); +} + +static int vf610_adc_read_data(struct vf610_adc *info) +{ +	int result; + +	result = readl(info->regs + VF610_REG_ADC_R0); + +	switch (info->adc_feature.res_mode) { +	case 8: +		result &= 0xFF; +		break; +	case 10: +		result &= 0x3FF; +		break; +	case 12: +		result &= 0xFFF; +		break; +	default: +		break; +	} + +	return result; +} + +static irqreturn_t vf610_adc_isr(int irq, void *dev_id) +{ +	struct vf610_adc *info = (struct vf610_adc *)dev_id; +	int coco; + +	coco = readl(info->regs + VF610_REG_ADC_HS); +	if (coco & VF610_ADC_HS_COCO0) { +		info->value = vf610_adc_read_data(info); +		complete(&info->completion); +	} + +	return IRQ_HANDLED; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171"); + +static struct attribute *vf610_attributes[] = { +	&iio_const_attr_sampling_frequency_available.dev_attr.attr, +	NULL +}; + +static const struct attribute_group vf610_attribute_group = { +	.attrs = vf610_attributes, +}; + +static int vf610_read_raw(struct iio_dev *indio_dev, +			struct iio_chan_spec const *chan, +			int *val, +			int *val2, +			long mask) +{ +	struct vf610_adc *info = iio_priv(indio_dev); +	unsigned int hc_cfg; +	long ret; + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&indio_dev->mlock); +		reinit_completion(&info->completion); + +		hc_cfg = VF610_ADC_ADCHC(chan->channel); +		hc_cfg |= VF610_ADC_AIEN; +		writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); +		ret = wait_for_completion_interruptible_timeout +				(&info->completion, VF610_ADC_TIMEOUT); +		if (ret == 0) { +			mutex_unlock(&indio_dev->mlock); +			return -ETIMEDOUT; +		} +		if (ret < 0) { +			mutex_unlock(&indio_dev->mlock); +			return ret; +		} + +		*val = info->value; +		mutex_unlock(&indio_dev->mlock); +		return IIO_VAL_INT; + +	case IIO_CHAN_INFO_SCALE: +		*val = info->vref_uv / 1000; +		*val2 = info->adc_feature.res_mode; +		return IIO_VAL_FRACTIONAL_LOG2; + +	case IIO_CHAN_INFO_SAMP_FREQ: +		*val = vf610_sample_freq_avail[info->adc_feature.sample_rate]; +		*val2 = 0; +		return IIO_VAL_INT; + +	default: +		break; +	} + +	return -EINVAL; +} + +static int vf610_write_raw(struct iio_dev *indio_dev, +			struct iio_chan_spec const *chan, +			int val, +			int val2, +			long mask) +{ +	struct vf610_adc *info = iio_priv(indio_dev); +	int i; + +	switch (mask) { +		case IIO_CHAN_INFO_SAMP_FREQ: +			for (i = 0; +				i < ARRAY_SIZE(vf610_sample_freq_avail); +				i++) +				if (val == vf610_sample_freq_avail[i]) { +					info->adc_feature.sample_rate = i; +					vf610_adc_sample_set(info); +					return 0; +				} +			break; + +		default: +			break; +	} + +	return -EINVAL; +} + +static int vf610_adc_reg_access(struct iio_dev *indio_dev, +			unsigned reg, unsigned writeval, +			unsigned *readval) +{ +	struct vf610_adc *info = iio_priv(indio_dev); + +	if ((readval == NULL) || +		(!(reg % 4) || (reg > VF610_REG_ADC_PCTL))) +		return -EINVAL; + +	*readval = readl(info->regs + reg); + +	return 0; +} + +static const struct iio_info vf610_adc_iio_info = { +	.driver_module = THIS_MODULE, +	.read_raw = &vf610_read_raw, +	.write_raw = &vf610_write_raw, +	.debugfs_reg_access = &vf610_adc_reg_access, +	.attrs = &vf610_attribute_group, +}; + +static const struct of_device_id vf610_adc_match[] = { +	{ .compatible = "fsl,vf610-adc", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vf610_adc_match); + +static int vf610_adc_probe(struct platform_device *pdev) +{ +	struct vf610_adc *info; +	struct iio_dev *indio_dev; +	struct resource *mem; +	int irq; +	int ret; + +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); +	if (!indio_dev) { +		dev_err(&pdev->dev, "Failed allocating iio device\n"); +		return -ENOMEM; +	} + +	info = iio_priv(indio_dev); +	info->dev = &pdev->dev; + +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	info->regs = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(info->regs)) +		return PTR_ERR(info->regs); + +	irq = platform_get_irq(pdev, 0); +	if (irq <= 0) { +		dev_err(&pdev->dev, "no irq resource?\n"); +		return -EINVAL; +	} + +	ret = devm_request_irq(info->dev, irq, +				vf610_adc_isr, 0, +				dev_name(&pdev->dev), info); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); +		return ret; +	} + +	info->clk = devm_clk_get(&pdev->dev, "adc"); +	if (IS_ERR(info->clk)) { +		dev_err(&pdev->dev, "failed getting clock, err = %ld\n", +						PTR_ERR(info->clk)); +		ret = PTR_ERR(info->clk); +		return ret; +	} + +	info->vref = devm_regulator_get(&pdev->dev, "vref"); +	if (IS_ERR(info->vref)) +		return PTR_ERR(info->vref); + +	ret = regulator_enable(info->vref); +	if (ret) +		return ret; + +	info->vref_uv = regulator_get_voltage(info->vref); + +	platform_set_drvdata(pdev, indio_dev); + +	init_completion(&info->completion); + +	indio_dev->name = dev_name(&pdev->dev); +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->dev.of_node = pdev->dev.of_node; +	indio_dev->info = &vf610_adc_iio_info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = vf610_adc_iio_channels; +	indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels); + +	ret = clk_prepare_enable(info->clk); +	if (ret) { +		dev_err(&pdev->dev, +			"Could not prepare or enable the clock.\n"); +		goto error_adc_clk_enable; +	} + +	vf610_adc_cfg_init(info); +	vf610_adc_hw_init(info); + +	ret = iio_device_register(indio_dev); +	if (ret) { +		dev_err(&pdev->dev, "Couldn't register the device.\n"); +		goto error_iio_device_register; +	} + +	return 0; + + +error_iio_device_register: +	clk_disable_unprepare(info->clk); +error_adc_clk_enable: +	regulator_disable(info->vref); + +	return ret; +} + +static int vf610_adc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); +	struct vf610_adc *info = iio_priv(indio_dev); + +	iio_device_unregister(indio_dev); +	regulator_disable(info->vref); +	clk_disable_unprepare(info->clk); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int vf610_adc_suspend(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct vf610_adc *info = iio_priv(indio_dev); +	int hc_cfg; + +	/* ADC controller enters to stop mode */ +	hc_cfg = readl(info->regs + VF610_REG_ADC_HC0); +	hc_cfg |= VF610_ADC_CONV_DISABLE; +	writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + +	clk_disable_unprepare(info->clk); +	regulator_disable(info->vref); + +	return 0; +} + +static int vf610_adc_resume(struct device *dev) +{ +	struct iio_dev *indio_dev = dev_get_drvdata(dev); +	struct vf610_adc *info = iio_priv(indio_dev); +	int ret; + +	ret = regulator_enable(info->vref); +	if (ret) +		return ret; + +	ret = clk_prepare_enable(info->clk); +	if (ret) +		return ret; + +	vf610_adc_hw_init(info); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, +			vf610_adc_suspend, +			vf610_adc_resume); + +static struct platform_driver vf610_adc_driver = { +	.probe          = vf610_adc_probe, +	.remove         = vf610_adc_remove, +	.driver         = { +		.name   = DRIVER_NAME, +		.owner  = THIS_MODULE, +		.of_match_table = vf610_adc_match, +		.pm     = &vf610_adc_pm_ops, +	}, +}; + +module_platform_driver(vf610_adc_driver); + +MODULE_AUTHOR("Fugang Duan <B38611@freescale.com>"); +MODULE_DESCRIPTION("Freescale VF610 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c new file mode 100644 index 00000000000..9acf6b6d705 --- /dev/null +++ b/drivers/iio/adc/viperboard_adc.c @@ -0,0 +1,158 @@ +/* + *  Nano River Technologies viperboard IIO ADC driver + * + *  (C) 2012 by Lemonage GmbH + *  Author: Lars Poeschel <poeschel@lemonage.de> + *  All rights reserved. + * + *  This program is free software; you can redistribute  it and/or modify it + *  under  the terms of  the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the	License, or (at your + *  option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> + +#include <linux/usb.h> +#include <linux/iio/iio.h> + +#include <linux/mfd/viperboard.h> + +#define VPRBRD_ADC_CMD_GET		0x00 + +struct vprbrd_adc_msg { +	u8 cmd; +	u8 chan; +	u8 val; +} __packed; + +struct vprbrd_adc { +	struct vprbrd *vb; +}; + +#define VPRBRD_ADC_CHANNEL(_index) {			\ +	.type = IIO_VOLTAGE,				\ +	.indexed = 1,					\ +	.channel = _index,				\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\ +} + +static struct iio_chan_spec const vprbrd_adc_iio_channels[] = { +	VPRBRD_ADC_CHANNEL(0), +	VPRBRD_ADC_CHANNEL(1), +	VPRBRD_ADC_CHANNEL(2), +	VPRBRD_ADC_CHANNEL(3), +}; + +static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, +				struct iio_chan_spec const *chan, +				int *val, +				int *val2, +				long info) +{ +	int ret, error = 0; +	struct vprbrd_adc *adc = iio_priv(iio_dev); +	struct vprbrd *vb = adc->vb; +	struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf; + +	switch (info) { +	case IIO_CHAN_INFO_RAW: +		mutex_lock(&vb->lock); + +		admsg->cmd = VPRBRD_ADC_CMD_GET; +		admsg->chan = chan->channel; +		admsg->val = 0x00; + +		ret = usb_control_msg(vb->usb_dev, +			usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC, +			VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg, +			sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS); +		if (ret != sizeof(struct vprbrd_adc_msg)) { +			dev_err(&iio_dev->dev, "usb send error on adc read\n"); +			error = -EREMOTEIO; +		} + +		ret = usb_control_msg(vb->usb_dev, +			usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC, +			VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg, +			sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS); + +		*val = admsg->val; + +		mutex_unlock(&vb->lock); + +		if (ret != sizeof(struct vprbrd_adc_msg)) { +			dev_err(&iio_dev->dev, "usb recv error on adc read\n"); +			error = -EREMOTEIO; +		} + +		if (error) +			goto error; + +		return IIO_VAL_INT; +	default: +		error = -EINVAL; +		break; +	} +error: +	return error; +} + +static const struct iio_info vprbrd_adc_iio_info = { +	.read_raw = &vprbrd_iio_read_raw, +	.driver_module = THIS_MODULE, +}; + +static int vprbrd_adc_probe(struct platform_device *pdev) +{ +	struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); +	struct vprbrd_adc *adc; +	struct iio_dev *indio_dev; +	int ret; + +	/* registering iio */ +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); +	if (!indio_dev) { +		dev_err(&pdev->dev, "failed allocating iio device\n"); +		return -ENOMEM; +	} + +	adc = iio_priv(indio_dev); +	adc->vb = vb; +	indio_dev->name = "viperboard adc"; +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->info = &vprbrd_adc_iio_info; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = vprbrd_adc_iio_channels; +	indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels); + +	ret = devm_iio_device_register(&pdev->dev, indio_dev); +	if (ret) { +		dev_err(&pdev->dev, "could not register iio (adc)"); +		return ret; +	} + +	return 0; +} + +static struct platform_driver vprbrd_adc_driver = { +	.driver = { +		.name	= "viperboard-adc", +		.owner	= THIS_MODULE, +	}, +	.probe		= vprbrd_adc_probe, +}; + +module_platform_driver(vprbrd_adc_driver); + +MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); +MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:viperboard-adc"); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c new file mode 100644 index 00000000000..ab52be29141 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -0,0 +1,1333 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013-2014 Analog Devices Inc. + *  Author: Lars-Peter Clauen <lars@metafoo.de> + * + * Licensed under the GPL-2. + * + * Documentation for the parts can be found at: + *  - XADC hardmacro: Xilinx UG480 + *  - ZYNQ XADC interface: Xilinx UG585 + *  - AXI XADC interface: Xilinx PG019 + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/sysfs.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include "xilinx-xadc.h" + +static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500; + +/* ZYNQ register definitions */ +#define XADC_ZYNQ_REG_CFG	0x00 +#define XADC_ZYNQ_REG_INTSTS	0x04 +#define XADC_ZYNQ_REG_INTMSK	0x08 +#define XADC_ZYNQ_REG_STATUS	0x0c +#define XADC_ZYNQ_REG_CFIFO	0x10 +#define XADC_ZYNQ_REG_DFIFO	0x14 +#define XADC_ZYNQ_REG_CTL		0x18 + +#define XADC_ZYNQ_CFG_ENABLE		BIT(31) +#define XADC_ZYNQ_CFG_CFIFOTH_MASK	(0xf << 20) +#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET	20 +#define XADC_ZYNQ_CFG_DFIFOTH_MASK	(0xf << 16) +#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET	16 +#define XADC_ZYNQ_CFG_WEDGE		BIT(13) +#define XADC_ZYNQ_CFG_REDGE		BIT(12) +#define XADC_ZYNQ_CFG_TCKRATE_MASK	(0x3 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV2	(0x0 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV4	(0x1 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV8	(0x2 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV16	(0x3 << 8) +#define XADC_ZYNQ_CFG_IGAP_MASK		0x1f +#define XADC_ZYNQ_CFG_IGAP(x)		(x) + +#define XADC_ZYNQ_INT_CFIFO_LTH		BIT(9) +#define XADC_ZYNQ_INT_DFIFO_GTH		BIT(8) +#define XADC_ZYNQ_INT_ALARM_MASK	0xff +#define XADC_ZYNQ_INT_ALARM_OFFSET	0 + +#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK	(0xf << 16) +#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET	16 +#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK	(0xf << 12) +#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET	12 +#define XADC_ZYNQ_STATUS_CFIFOF		BIT(11) +#define XADC_ZYNQ_STATUS_CFIFOE		BIT(10) +#define XADC_ZYNQ_STATUS_DFIFOF		BIT(9) +#define XADC_ZYNQ_STATUS_DFIFOE		BIT(8) +#define XADC_ZYNQ_STATUS_OT		BIT(7) +#define XADC_ZYNQ_STATUS_ALM(x)		BIT(x) + +#define XADC_ZYNQ_CTL_RESET		BIT(4) + +#define XADC_ZYNQ_CMD_NOP		0x00 +#define XADC_ZYNQ_CMD_READ		0x01 +#define XADC_ZYNQ_CMD_WRITE		0x02 + +#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (data)) + +/* AXI register definitions */ +#define XADC_AXI_REG_RESET		0x00 +#define XADC_AXI_REG_STATUS		0x04 +#define XADC_AXI_REG_ALARM_STATUS	0x08 +#define XADC_AXI_REG_CONVST		0x0c +#define XADC_AXI_REG_XADC_RESET		0x10 +#define XADC_AXI_REG_GIER		0x5c +#define XADC_AXI_REG_IPISR		0x60 +#define XADC_AXI_REG_IPIER		0x68 +#define XADC_AXI_ADC_REG_OFFSET		0x200 + +#define XADC_AXI_RESET_MAGIC		0xa +#define XADC_AXI_GIER_ENABLE		BIT(31) + +#define XADC_AXI_INT_EOS		BIT(4) +#define XADC_AXI_INT_ALARM_MASK		0x3c0f + +#define XADC_FLAGS_BUFFERED BIT(0) + +static void xadc_write_reg(struct xadc *xadc, unsigned int reg, +	uint32_t val) +{ +	writel(val, xadc->base + reg); +} + +static void xadc_read_reg(struct xadc *xadc, unsigned int reg, +	uint32_t *val) +{ +	*val = readl(xadc->base + reg); +} + +/* + * The ZYNQ interface uses two asynchronous FIFOs for communication with the + * XADC. Reads and writes to the XADC register are performed by submitting a + * request to the command FIFO (CFIFO), once the request has been completed the + * result can be read from the data FIFO (DFIFO). The method currently used in + * this driver is to submit the request for a read/write operation, then go to + * sleep and wait for an interrupt that signals that a response is available in + * the data FIFO. + */ + +static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd, +	unsigned int n) +{ +	unsigned int i; + +	for (i = 0; i < n; i++) +		xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]); +} + +static void xadc_zynq_drain_fifo(struct xadc *xadc) +{ +	uint32_t status, tmp; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); + +	while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) { +		xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); +		xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); +	} +} + +static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask, +	unsigned int val) +{ +	xadc->zynq_intmask &= ~mask; +	xadc->zynq_intmask |= val; + +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, +		xadc->zynq_intmask | xadc->zynq_masked_alarm); +} + +static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t val) +{ +	uint32_t cmd[1]; +	uint32_t tmp; +	int ret; + +	spin_lock_irq(&xadc->lock); +	xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, +			XADC_ZYNQ_INT_DFIFO_GTH); + +	reinit_completion(&xadc->completion); + +	cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val); +	xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); +	xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); +	tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK; +	tmp |= 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; +	xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + +	xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); +	spin_unlock_irq(&xadc->lock); + +	ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ); +	if (ret == 0) +		ret = -EIO; +	else +		ret = 0; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); + +	return ret; +} + +static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t *val) +{ +	uint32_t cmd[2]; +	uint32_t resp, tmp; +	int ret; + +	cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0); +	cmd[1] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0); + +	spin_lock_irq(&xadc->lock); +	xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, +			XADC_ZYNQ_INT_DFIFO_GTH); +	xadc_zynq_drain_fifo(xadc); +	reinit_completion(&xadc->completion); + +	xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); +	xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); +	tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK; +	tmp |= 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; +	xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + +	xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); +	spin_unlock_irq(&xadc->lock); +	ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ); +	if (ret == 0) +		ret = -EIO; +	if (ret < 0) +		return ret; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); +	xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); + +	*val = resp & 0xffff; + +	return 0; +} + +static unsigned int xadc_zynq_transform_alarm(unsigned int alarm) +{ +	return ((alarm & 0x80) >> 4) | +		((alarm & 0x78) << 1) | +		(alarm & 0x07); +} + +/* + * The ZYNQ threshold interrupts are level sensitive. Since we can't make the + * threshold condition go way from within the interrupt handler, this means as + * soon as a threshold condition is present we would enter the interrupt handler + * again and again. To work around this we mask all active thresholds interrupts + * in the interrupt handler and start a timer. In this timer we poll the + * interrupt status and only if the interrupt is inactive we unmask it again. + */ +static void xadc_zynq_unmask_worker(struct work_struct *work) +{ +	struct xadc *xadc = container_of(work, struct xadc, zynq_unmask_work.work); +	unsigned int misc_sts, unmask; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts); + +	misc_sts &= XADC_ZYNQ_INT_ALARM_MASK; + +	spin_lock_irq(&xadc->lock); + +	/* Clear those bits which are not active anymore */ +	unmask = (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm; +	xadc->zynq_masked_alarm &= misc_sts; + +	/* Also clear those which are masked out anyway */ +	xadc->zynq_masked_alarm &= ~xadc->zynq_intmask; + +	/* Clear the interrupts before we unmask them */ +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask); + +	xadc_zynq_update_intmsk(xadc, 0, 0); + +	spin_unlock_irq(&xadc->lock); + +	/* if still pending some alarm re-trigger the timer */ +	if (xadc->zynq_masked_alarm) { +		schedule_delayed_work(&xadc->zynq_unmask_work, +				msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); +	} +} + +static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid) +{ +	struct iio_dev *indio_dev = devid; +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned int alarm; + +	spin_lock_irq(&xadc->lock); +	alarm = xadc->zynq_alarm; +	xadc->zynq_alarm = 0; +	spin_unlock_irq(&xadc->lock); + +	xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm)); + +	/* unmask the required interrupts in timer. */ +	schedule_delayed_work(&xadc->zynq_unmask_work, +			msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); + +	return IRQ_HANDLED; +} + +static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) +{ +	struct iio_dev *indio_dev = devid; +	struct xadc *xadc = iio_priv(indio_dev); +	irqreturn_t ret = IRQ_HANDLED; +	uint32_t status; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); + +	status &= ~(xadc->zynq_intmask | xadc->zynq_masked_alarm); + +	if (!status) +		return IRQ_NONE; + +	spin_lock(&xadc->lock); + +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status); + +	if (status & XADC_ZYNQ_INT_DFIFO_GTH) { +		xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, +			XADC_ZYNQ_INT_DFIFO_GTH); +		complete(&xadc->completion); +	} + +	status &= XADC_ZYNQ_INT_ALARM_MASK; +	if (status) { +		xadc->zynq_alarm |= status; +		xadc->zynq_masked_alarm |= status; +		/* +		 * mask the current event interrupt, +		 * unmask it when the interrupt is no more active. +		 */ +		xadc_zynq_update_intmsk(xadc, 0, 0); +		ret = IRQ_WAKE_THREAD; +	} +	spin_unlock(&xadc->lock); + +	return ret; +} + +#define XADC_ZYNQ_TCK_RATE_MAX 50000000 +#define XADC_ZYNQ_IGAP_DEFAULT 20 + +static int xadc_zynq_setup(struct platform_device *pdev, +	struct iio_dev *indio_dev, int irq) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned long pcap_rate; +	unsigned int tck_div; +	unsigned int div; +	unsigned int igap; +	unsigned int tck_rate; + +	/* TODO: Figure out how to make igap and tck_rate configurable */ +	igap = XADC_ZYNQ_IGAP_DEFAULT; +	tck_rate = XADC_ZYNQ_TCK_RATE_MAX; + +	xadc->zynq_intmask = ~0; + +	pcap_rate = clk_get_rate(xadc->clk); + +	if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) +		tck_rate = XADC_ZYNQ_TCK_RATE_MAX; +	if (tck_rate > pcap_rate / 2) { +		div = 2; +	} else { +		div = pcap_rate / tck_rate; +		if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX) +			div++; +	} + +	if (div <= 3) +		tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV2; +	else if (div <= 7) +		tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV4; +	else if (div <= 15) +		tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV8; +	else +		tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV16; + +	xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET); +	xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0); +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0); +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask); +	xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE | +			XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | +			tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + +	return 0; +} + +static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc) +{ +	unsigned int div; +	uint32_t val; + +	xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val); + +	switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) { +	case XADC_ZYNQ_CFG_TCKRATE_DIV4: +		div = 4; +		break; +	case XADC_ZYNQ_CFG_TCKRATE_DIV8: +		div = 8; +		break; +	case XADC_ZYNQ_CFG_TCKRATE_DIV16: +		div = 16; +		break; +	default: +		div = 2; +		break; +	} + +	return clk_get_rate(xadc->clk) / div; +} + +static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm) +{ +	unsigned long flags; +	uint32_t status; + +	/* Move OT to bit 7 */ +	alarm = ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07); + +	spin_lock_irqsave(&xadc->lock, flags); + +	/* Clear previous interrupts if any. */ +	xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); +	xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm); + +	xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK, +		~alarm & XADC_ZYNQ_INT_ALARM_MASK); + +	spin_unlock_irqrestore(&xadc->lock, flags); +} + +static const struct xadc_ops xadc_zynq_ops = { +	.read = xadc_zynq_read_adc_reg, +	.write = xadc_zynq_write_adc_reg, +	.setup = xadc_zynq_setup, +	.get_dclk_rate = xadc_zynq_get_dclk_rate, +	.interrupt_handler = xadc_zynq_interrupt_handler, +	.threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler, +	.update_alarm = xadc_zynq_update_alarm, +}; + +static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t *val) +{ +	uint32_t val32; + +	xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32); +	*val = val32 & 0xffff; + +	return 0; +} + +static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t val) +{ +	xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val); + +	return 0; +} + +static int xadc_axi_setup(struct platform_device *pdev, +	struct iio_dev *indio_dev, int irq) +{ +	struct xadc *xadc = iio_priv(indio_dev); + +	xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC); +	xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE); + +	return 0; +} + +static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) +{ +	struct iio_dev *indio_dev = devid; +	struct xadc *xadc = iio_priv(indio_dev); +	uint32_t status, mask; +	unsigned int events; + +	xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status); +	xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask); +	status &= mask; + +	if (!status) +		return IRQ_NONE; + +	if ((status & XADC_AXI_INT_EOS) && xadc->trigger) +		iio_trigger_poll(xadc->trigger, 0); + +	if (status & XADC_AXI_INT_ALARM_MASK) { +		/* +		 * The order of the bits in the AXI-XADC status register does +		 * not match the order of the bits in the XADC alarm enable +		 * register. xadc_handle_events() expects the events to be in +		 * the same order as the XADC alarm enable register. +		 */ +		events = (status & 0x000e) >> 1; +		events |= (status & 0x0001) << 3; +		events |= (status & 0x3c00) >> 6; +		xadc_handle_events(indio_dev, events); +	} + +	xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status); + +	return IRQ_HANDLED; +} + +static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm) +{ +	uint32_t val; +	unsigned long flags; + +	/* +	 * The order of the bits in the AXI-XADC status register does not match +	 * the order of the bits in the XADC alarm enable register. We get +	 * passed the alarm mask in the same order as in the XADC alarm enable +	 * register. +	 */ +	alarm = ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) | +			((alarm & 0xf0) << 6); + +	spin_lock_irqsave(&xadc->lock, flags); +	xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); +	val &= ~XADC_AXI_INT_ALARM_MASK; +	val |= alarm; +	xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); +	spin_unlock_irqrestore(&xadc->lock, flags); +} + +static unsigned long xadc_axi_get_dclk(struct xadc *xadc) +{ +	return clk_get_rate(xadc->clk); +} + +static const struct xadc_ops xadc_axi_ops = { +	.read = xadc_axi_read_adc_reg, +	.write = xadc_axi_write_adc_reg, +	.setup = xadc_axi_setup, +	.get_dclk_rate = xadc_axi_get_dclk, +	.update_alarm = xadc_axi_update_alarm, +	.interrupt_handler = xadc_axi_interrupt_handler, +	.flags = XADC_FLAGS_BUFFERED, +}; + +static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t mask, uint16_t val) +{ +	uint16_t tmp; +	int ret; + +	ret = _xadc_read_adc_reg(xadc, reg, &tmp); +	if (ret) +		return ret; + +	return _xadc_write_adc_reg(xadc, reg, (tmp & ~mask) | val); +} + +static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t mask, uint16_t val) +{ +	int ret; + +	mutex_lock(&xadc->mutex); +	ret = _xadc_update_adc_reg(xadc, reg, mask, val); +	mutex_unlock(&xadc->mutex); + +	return ret; +} + +static unsigned long xadc_get_dclk_rate(struct xadc *xadc) +{ +	return xadc->ops->get_dclk_rate(xadc); +} + +static int xadc_update_scan_mode(struct iio_dev *indio_dev, +	const unsigned long *mask) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned int n; + +	n = bitmap_weight(mask, indio_dev->masklength); + +	kfree(xadc->data); +	xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL); +	if (!xadc->data) +		return -ENOMEM; + +	return 0; +} + +static unsigned int xadc_scan_index_to_channel(unsigned int scan_index) +{ +	switch (scan_index) { +	case 5: +		return XADC_REG_VCCPINT; +	case 6: +		return XADC_REG_VCCPAUX; +	case 7: +		return XADC_REG_VCCO_DDR; +	case 8: +		return XADC_REG_TEMP; +	case 9: +		return XADC_REG_VCCINT; +	case 10: +		return XADC_REG_VCCAUX; +	case 11: +		return XADC_REG_VPVN; +	case 12: +		return XADC_REG_VREFP; +	case 13: +		return XADC_REG_VREFN; +	case 14: +		return XADC_REG_VCCBRAM; +	default: +		return XADC_REG_VAUX(scan_index - 16); +	} +} + +static irqreturn_t xadc_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned int chan; +	int i, j; + +	if (!xadc->data) +		goto out; + +	j = 0; +	for_each_set_bit(i, indio_dev->active_scan_mask, +		indio_dev->masklength) { +		chan = xadc_scan_index_to_channel(i); +		xadc_read_adc_reg(xadc, chan, &xadc->data[j]); +		j++; +	} + +	iio_push_to_buffers(indio_dev, xadc->data); + +out: +	iio_trigger_notify_done(indio_dev->trig); + +	return IRQ_HANDLED; +} + +static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state) +{ +	struct xadc *xadc = iio_trigger_get_drvdata(trigger); +	unsigned long flags; +	unsigned int convst; +	unsigned int val; +	int ret = 0; + +	mutex_lock(&xadc->mutex); + +	if (state) { +		/* Only one of the two triggers can be active at the a time. */ +		if (xadc->trigger != NULL) { +			ret = -EBUSY; +			goto err_out; +		} else { +			xadc->trigger = trigger; +			if (trigger == xadc->convst_trigger) +				convst = XADC_CONF0_EC; +			else +				convst = 0; +		} +		ret = _xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF0_EC, +					convst); +		if (ret) +			goto err_out; +	} else { +		xadc->trigger = NULL; +	} + +	spin_lock_irqsave(&xadc->lock, flags); +	xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); +	xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS); +	if (state) +		val |= XADC_AXI_INT_EOS; +	else +		val &= ~XADC_AXI_INT_EOS; +	xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); +	spin_unlock_irqrestore(&xadc->lock, flags); + +err_out: +	mutex_unlock(&xadc->mutex); + +	return ret; +} + +static const struct iio_trigger_ops xadc_trigger_ops = { +	.owner = THIS_MODULE, +	.set_trigger_state = &xadc_trigger_set_state, +}; + +static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, +	const char *name) +{ +	struct iio_trigger *trig; +	int ret; + +	trig = iio_trigger_alloc("%s%d-%s", indio_dev->name, +				indio_dev->id, name); +	if (trig == NULL) +		return ERR_PTR(-ENOMEM); + +	trig->dev.parent = indio_dev->dev.parent; +	trig->ops = &xadc_trigger_ops; +	iio_trigger_set_drvdata(trig, iio_priv(indio_dev)); + +	ret = iio_trigger_register(trig); +	if (ret) +		goto error_free_trig; + +	return trig; + +error_free_trig: +	iio_trigger_free(trig); +	return ERR_PTR(ret); +} + +static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode) +{ +	uint16_t val; + +	switch (seq_mode) { +	case XADC_CONF1_SEQ_SIMULTANEOUS: +	case XADC_CONF1_SEQ_INDEPENDENT: +		val = XADC_CONF2_PD_ADC_B; +		break; +	default: +		val = 0; +		break; +	} + +	return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_PD_MASK, +		val); +} + +static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode) +{ +	unsigned int aux_scan_mode = scan_mode >> 16; + +	if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL) +		return XADC_CONF1_SEQ_SIMULTANEOUS; + +	if ((aux_scan_mode & 0xff00) == 0 || +		(aux_scan_mode & 0x00ff) == 0) +		return XADC_CONF1_SEQ_CONTINUOUS; + +	return XADC_CONF1_SEQ_SIMULTANEOUS; +} + +static int xadc_postdisable(struct iio_dev *indio_dev) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned long scan_mask; +	int ret; +	int i; + +	scan_mask = 1; /* Run calibration as part of the sequence */ +	for (i = 0; i < indio_dev->num_channels; i++) +		scan_mask |= BIT(indio_dev->channels[i].scan_index); + +	/* Enable all channels and calibration */ +	ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff); +	if (ret) +		return ret; + +	ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16); +	if (ret) +		return ret; + +	ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, +		XADC_CONF1_SEQ_CONTINUOUS); +	if (ret) +		return ret; + +	return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS); +} + +static int xadc_preenable(struct iio_dev *indio_dev) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned long scan_mask; +	int seq_mode; +	int ret; + +	ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, +		XADC_CONF1_SEQ_DEFAULT); +	if (ret) +		goto err; + +	scan_mask = *indio_dev->active_scan_mask; +	seq_mode = xadc_get_seq_mode(xadc, scan_mask); + +	ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff); +	if (ret) +		goto err; + +	ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16); +	if (ret) +		goto err; + +	ret = xadc_power_adc_b(xadc, seq_mode); +	if (ret) +		goto err; + +	ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, +		seq_mode); +	if (ret) +		goto err; + +	return 0; +err: +	xadc_postdisable(indio_dev); +	return ret; +} + +static struct iio_buffer_setup_ops xadc_buffer_ops = { +	.preenable = &xadc_preenable, +	.postenable = &iio_triggered_buffer_postenable, +	.predisable = &iio_triggered_buffer_predisable, +	.postdisable = &xadc_postdisable, +}; + +static int xadc_read_raw(struct iio_dev *indio_dev, +	struct iio_chan_spec const *chan, int *val, int *val2, long info) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned int div; +	uint16_t val16; +	int ret; + +	switch (info) { +	case IIO_CHAN_INFO_RAW: +		if (iio_buffer_enabled(indio_dev)) +			return -EBUSY; +		ret = xadc_read_adc_reg(xadc, chan->address, &val16); +		if (ret < 0) +			return ret; + +		val16 >>= 4; +		if (chan->scan_type.sign == 'u') +			*val = val16; +		else +			*val = sign_extend32(val16, 11); + +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		switch (chan->type) { +		case IIO_VOLTAGE: +			/* V = (val * 3.0) / 4096 */ +			switch (chan->address) { +			case XADC_REG_VCCINT: +			case XADC_REG_VCCAUX: +			case XADC_REG_VCCBRAM: +			case XADC_REG_VCCPINT: +			case XADC_REG_VCCPAUX: +			case XADC_REG_VCCO_DDR: +				*val = 3000; +				break; +			default: +				*val = 1000; +				break; +			} +			*val2 = 12; +			return IIO_VAL_FRACTIONAL_LOG2; +		case IIO_TEMP: +			/* Temp in C = (val * 503.975) / 4096 - 273.15 */ +			*val = 503975; +			*val2 = 12; +			return IIO_VAL_FRACTIONAL_LOG2; +		default: +			return -EINVAL; +		} +	case IIO_CHAN_INFO_OFFSET: +		/* Only the temperature channel has an offset */ +		*val = -((273150 << 12) / 503975); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SAMP_FREQ: +		ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16); +		if (ret) +			return ret; + +		div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET; +		if (div < 2) +			div = 2; + +		*val = xadc_get_dclk_rate(xadc) / div / 26; + +		return IIO_VAL_INT; +	default: +		return -EINVAL; +	} +} + +static int xadc_write_raw(struct iio_dev *indio_dev, +	struct iio_chan_spec const *chan, int val, int val2, long info) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	unsigned long clk_rate = xadc_get_dclk_rate(xadc); +	unsigned int div; + +	if (info != IIO_CHAN_INFO_SAMP_FREQ) +		return -EINVAL; + +	if (val <= 0) +		return -EINVAL; + +	/* Max. 150 kSPS */ +	if (val > 150000) +		val = 150000; + +	val *= 26; + +	/* Min 1MHz */ +	if (val < 1000000) +		val = 1000000; + +	/* +	 * We want to round down, but only if we do not exceed the 150 kSPS +	 * limit. +	 */ +	div = clk_rate / val; +	if (clk_rate / div / 26 > 150000) +		div++; +	if (div < 2) +		div = 2; +	else if (div > 0xff) +		div = 0xff; + +	return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_DIV_MASK, +		div << XADC_CONF2_DIV_OFFSET); +} + +static const struct iio_event_spec xadc_temp_events[] = { +	{ +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_RISING, +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) | +				BIT(IIO_EV_INFO_VALUE) | +				BIT(IIO_EV_INFO_HYSTERESIS), +	}, +}; + +/* Separate values for upper and lower thresholds, but only a shared enabled */ +static const struct iio_event_spec xadc_voltage_events[] = { +	{ +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_RISING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE), +	}, { +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_FALLING, +		.mask_separate = BIT(IIO_EV_INFO_VALUE), +	}, { +		.type = IIO_EV_TYPE_THRESH, +		.dir = IIO_EV_DIR_EITHER, +		.mask_separate = BIT(IIO_EV_INFO_ENABLE), +	}, +}; + +#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \ +	.type = IIO_TEMP, \ +	.indexed = 1, \ +	.channel = (_chan), \ +	.address = (_addr), \ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ +		BIT(IIO_CHAN_INFO_SCALE) | \ +		BIT(IIO_CHAN_INFO_OFFSET), \ +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +	.event_spec = xadc_temp_events, \ +	.num_event_specs = ARRAY_SIZE(xadc_temp_events), \ +	.scan_index = (_scan_index), \ +	.scan_type = { \ +		.sign = 'u', \ +		.realbits = 12, \ +		.storagebits = 16, \ +		.shift = 4, \ +		.endianness = IIO_CPU, \ +	}, \ +} + +#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \ +	.type = IIO_VOLTAGE, \ +	.indexed = 1, \ +	.channel = (_chan), \ +	.address = (_addr), \ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ +		BIT(IIO_CHAN_INFO_SCALE), \ +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +	.event_spec = (_alarm) ? xadc_voltage_events : NULL, \ +	.num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \ +	.scan_index = (_scan_index), \ +	.scan_type = { \ +		.sign = 'u', \ +		.realbits = 12, \ +		.storagebits = 16, \ +		.shift = 4, \ +		.endianness = IIO_CPU, \ +	}, \ +	.extend_name = _ext, \ +} + +static const struct iio_chan_spec xadc_channels[] = { +	XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP), +	XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), +	XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true), +	XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), +	XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true), +	XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true), +	XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true), +	XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false), +	XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false), +	XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false), +	XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false), +	XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false), +	XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false), +	XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false), +	XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false), +	XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false), +	XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false), +	XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false), +	XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false), +	XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false), +	XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false), +	XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false), +	XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false), +	XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false), +	XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false), +	XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false), +}; + +static const struct iio_info xadc_info = { +	.read_raw = &xadc_read_raw, +	.write_raw = &xadc_write_raw, +	.read_event_config = &xadc_read_event_config, +	.write_event_config = &xadc_write_event_config, +	.read_event_value = &xadc_read_event_value, +	.write_event_value = &xadc_write_event_value, +	.update_scan_mode = &xadc_update_scan_mode, +	.driver_module = THIS_MODULE, +}; + +static const struct of_device_id xadc_of_match_table[] = { +	{ .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops }, +	{ .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, xadc_of_match_table); + +static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, +	unsigned int *conf) +{ +	struct xadc *xadc = iio_priv(indio_dev); +	struct iio_chan_spec *channels, *chan; +	struct device_node *chan_node, *child; +	unsigned int num_channels; +	const char *external_mux; +	u32 ext_mux_chan; +	int reg; +	int ret; + +	*conf = 0; + +	ret = of_property_read_string(np, "xlnx,external-mux", &external_mux); +	if (ret < 0 || strcasecmp(external_mux, "none") == 0) +		xadc->external_mux_mode = XADC_EXTERNAL_MUX_NONE; +	else if (strcasecmp(external_mux, "single") == 0) +		xadc->external_mux_mode = XADC_EXTERNAL_MUX_SINGLE; +	else if (strcasecmp(external_mux, "dual") == 0) +		xadc->external_mux_mode = XADC_EXTERNAL_MUX_DUAL; +	else +		return -EINVAL; + +	if (xadc->external_mux_mode != XADC_EXTERNAL_MUX_NONE) { +		ret = of_property_read_u32(np, "xlnx,external-mux-channel", +					&ext_mux_chan); +		if (ret < 0) +			return ret; + +		if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_SINGLE) { +			if (ext_mux_chan == 0) +				ext_mux_chan = XADC_REG_VPVN; +			else if (ext_mux_chan <= 16) +				ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1); +			else +				return -EINVAL; +		} else { +			if (ext_mux_chan > 0 && ext_mux_chan <= 8) +				ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1); +			else +				return -EINVAL; +		} + +		*conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan); +	} + +	channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL); +	if (!channels) +		return -ENOMEM; + +	num_channels = 9; +	chan = &channels[9]; + +	chan_node = of_get_child_by_name(np, "xlnx,channels"); +	if (chan_node) { +		for_each_child_of_node(chan_node, child) { +			if (num_channels >= ARRAY_SIZE(xadc_channels)) { +				of_node_put(child); +				break; +			} + +			ret = of_property_read_u32(child, "reg", ®); +			if (ret || reg > 16) +				continue; + +			if (of_property_read_bool(child, "xlnx,bipolar")) +				chan->scan_type.sign = 's'; + +			if (reg == 0) { +				chan->scan_index = 11; +				chan->address = XADC_REG_VPVN; +			} else { +				chan->scan_index = 15 + reg; +				chan->scan_index = XADC_REG_VAUX(reg - 1); +			} +			num_channels++; +			chan++; +		} +	} +	of_node_put(chan_node); + +	indio_dev->num_channels = num_channels; +	indio_dev->channels = krealloc(channels, sizeof(*channels) * +					num_channels, GFP_KERNEL); +	/* If we can't resize the channels array, just use the original */ +	if (!indio_dev->channels) +		indio_dev->channels = channels; + +	return 0; +} + +static int xadc_probe(struct platform_device *pdev) +{ +	const struct of_device_id *id; +	struct iio_dev *indio_dev; +	unsigned int bipolar_mask; +	struct resource *mem; +	unsigned int conf0; +	struct xadc *xadc; +	int ret; +	int irq; +	int i; + +	if (!pdev->dev.of_node) +		return -ENODEV; + +	id = of_match_node(xadc_of_match_table, pdev->dev.of_node); +	if (!id) +		return -EINVAL; + +	irq = platform_get_irq(pdev, 0); +	if (irq <= 0) +		return -ENXIO; + +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc)); +	if (!indio_dev) +		return -ENOMEM; + +	xadc = iio_priv(indio_dev); +	xadc->ops = id->data; +	init_completion(&xadc->completion); +	mutex_init(&xadc->mutex); +	spin_lock_init(&xadc->lock); +	INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker); + +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	xadc->base = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(xadc->base)) +		return PTR_ERR(xadc->base); + +	indio_dev->dev.parent = &pdev->dev; +	indio_dev->dev.of_node = pdev->dev.of_node; +	indio_dev->name = "xadc"; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->info = &xadc_info; + +	ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0); +	if (ret) +		goto err_device_free; + +	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { +		ret = iio_triggered_buffer_setup(indio_dev, +			&iio_pollfunc_store_time, &xadc_trigger_handler, +			&xadc_buffer_ops); +		if (ret) +			goto err_device_free; + +		xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); +		if (IS_ERR(xadc->convst_trigger)) +			goto err_triggered_buffer_cleanup; +		xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev, +			"samplerate"); +		if (IS_ERR(xadc->samplerate_trigger)) +			goto err_free_convst_trigger; +	} + +	xadc->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(xadc->clk)) { +		ret = PTR_ERR(xadc->clk); +		goto err_free_samplerate_trigger; +	} +	clk_prepare_enable(xadc->clk); + +	ret = xadc->ops->setup(pdev, indio_dev, irq); +	if (ret) +		goto err_free_samplerate_trigger; + +	ret = request_threaded_irq(irq, xadc->ops->interrupt_handler, +				xadc->ops->threaded_interrupt_handler, +				0, dev_name(&pdev->dev), indio_dev); +	if (ret) +		goto err_clk_disable_unprepare; + +	for (i = 0; i < 16; i++) +		xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), +			&xadc->threshold[i]); + +	ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); +	if (ret) +		goto err_free_irq; + +	bipolar_mask = 0; +	for (i = 0; i < indio_dev->num_channels; i++) { +		if (indio_dev->channels[i].scan_type.sign == 's') +			bipolar_mask |= BIT(indio_dev->channels[i].scan_index); +	} + +	ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); +	if (ret) +		goto err_free_irq; +	ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), +		bipolar_mask >> 16); +	if (ret) +		goto err_free_irq; + +	/* Disable all alarms */ +	xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, +		XADC_CONF1_ALARM_MASK); + +	/* Set thresholds to min/max */ +	for (i = 0; i < 16; i++) { +		/* +		 * Set max voltage threshold and both temperature thresholds to +		 * 0xffff, min voltage threshold to 0. +		 */ +		if (i % 8 < 4 || i == 7) +			xadc->threshold[i] = 0xffff; +		else +			xadc->threshold[i] = 0; +		xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i), +			xadc->threshold[i]); +	} + +	/* Go to non-buffered mode */ +	xadc_postdisable(indio_dev); + +	ret = iio_device_register(indio_dev); +	if (ret) +		goto err_free_irq; + +	platform_set_drvdata(pdev, indio_dev); + +	return 0; + +err_free_irq: +	free_irq(irq, indio_dev); +err_free_samplerate_trigger: +	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) +		iio_trigger_free(xadc->samplerate_trigger); +err_free_convst_trigger: +	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) +		iio_trigger_free(xadc->convst_trigger); +err_triggered_buffer_cleanup: +	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) +		iio_triggered_buffer_cleanup(indio_dev); +err_clk_disable_unprepare: +	clk_disable_unprepare(xadc->clk); +err_device_free: +	kfree(indio_dev->channels); + +	return ret; +} + +static int xadc_remove(struct platform_device *pdev) +{ +	struct iio_dev *indio_dev = platform_get_drvdata(pdev); +	struct xadc *xadc = iio_priv(indio_dev); +	int irq = platform_get_irq(pdev, 0); + +	iio_device_unregister(indio_dev); +	if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { +		iio_trigger_free(xadc->samplerate_trigger); +		iio_trigger_free(xadc->convst_trigger); +		iio_triggered_buffer_cleanup(indio_dev); +	} +	free_irq(irq, indio_dev); +	clk_disable_unprepare(xadc->clk); +	cancel_delayed_work(&xadc->zynq_unmask_work); +	kfree(xadc->data); +	kfree(indio_dev->channels); + +	return 0; +} + +static struct platform_driver xadc_driver = { +	.probe = xadc_probe, +	.remove = xadc_remove, +	.driver = { +		.name = "xadc", +		.owner = THIS_MODULE, +		.of_match_table = xadc_of_match_table, +	}, +}; +module_platform_driver(xadc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Xilinx XADC IIO driver"); diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c new file mode 100644 index 00000000000..3e7f0d7a80c --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -0,0 +1,254 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013 Analog Devices Inc. + *  Author: Lars-Peter Clauen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/kernel.h> + +#include "xilinx-xadc.h" + +static const struct iio_chan_spec *xadc_event_to_channel( +	struct iio_dev *indio_dev, unsigned int event) +{ +	switch (event) { +	case XADC_THRESHOLD_OT_MAX: +	case XADC_THRESHOLD_TEMP_MAX: +		return &indio_dev->channels[0]; +	case XADC_THRESHOLD_VCCINT_MAX: +	case XADC_THRESHOLD_VCCAUX_MAX: +		return &indio_dev->channels[event]; +	default: +		return &indio_dev->channels[event-1]; +	} +} + +static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) +{ +	const struct iio_chan_spec *chan; +	unsigned int offset; + +	/* Temperature threshold error, we don't handle this yet */ +	if (event == 0) +		return; + +	if (event < 4) +		offset = event; +	else +		offset = event + 4; + +	chan = xadc_event_to_channel(indio_dev, event); + +	if (chan->type == IIO_TEMP) { +		/* +		 * The temperature channel only supports over-temperature +		 * events. +		 */ +		iio_push_event(indio_dev, +			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, +				IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), +			iio_get_time_ns()); +	} else { +		/* +		 * For other channels we don't know whether it is a upper or +		 * lower threshold event. Userspace will have to check the +		 * channel value if it wants to know. +		 */ +		iio_push_event(indio_dev, +			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, +				IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), +			iio_get_time_ns()); +	} +} + +void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events) +{ +	unsigned int i; + +	for_each_set_bit(i, &events, 8) +		xadc_handle_event(indio_dev, i); +} + +static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan, +	enum iio_event_direction dir) +{ +	unsigned int offset; + +	if (chan->type == IIO_TEMP) { +		offset = XADC_THRESHOLD_OT_MAX; +	} else { +		if (chan->channel < 2) +			offset = chan->channel + 1; +		else +			offset = chan->channel + 6; +	} + +	if (dir == IIO_EV_DIR_FALLING) +		offset += 4; + +	return offset; +} + +static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan) +{ +	if (chan->type == IIO_TEMP) { +		return XADC_ALARM_OT_MASK; +	} else { +		switch (chan->channel) { +		case 0: +			return XADC_ALARM_VCCINT_MASK; +		case 1: +			return XADC_ALARM_VCCAUX_MASK; +		case 2: +			return XADC_ALARM_VCCBRAM_MASK; +		case 3: +			return XADC_ALARM_VCCPINT_MASK; +		case 4: +			return XADC_ALARM_VCCPAUX_MASK; +		case 5: +			return XADC_ALARM_VCCODDR_MASK; +		default: +			/* We will never get here */ +			return 0; +		} +	} +} + +int xadc_read_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir) +{ +	struct xadc *xadc = iio_priv(indio_dev); + +	return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan)); +} + +int xadc_write_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, int state) +{ +	unsigned int alarm = xadc_get_alarm_mask(chan); +	struct xadc *xadc = iio_priv(indio_dev); +	uint16_t cfg, old_cfg; +	int ret; + +	mutex_lock(&xadc->mutex); + +	if (state) +		xadc->alarm_mask |= alarm; +	else +		xadc->alarm_mask &= ~alarm; + +	xadc->ops->update_alarm(xadc, xadc->alarm_mask); + +	ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg); +	if (ret) +		goto err_out; + +	old_cfg = cfg; +	cfg |= XADC_CONF1_ALARM_MASK; +	cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */ +	cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */ +	cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */ +	if (old_cfg != cfg) +		ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg); + +err_out: +	mutex_unlock(&xadc->mutex); + +	return ret; +} + +/* Register value is msb aligned, the lower 4 bits are ignored */ +#define XADC_THRESHOLD_VALUE_SHIFT 4 + +int xadc_read_event_value(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, +	int *val, int *val2) +{ +	unsigned int offset = xadc_get_threshold_offset(chan, dir); +	struct xadc *xadc = iio_priv(indio_dev); + +	switch (info) { +	case IIO_EV_INFO_VALUE: +		*val = xadc->threshold[offset]; +		break; +	case IIO_EV_INFO_HYSTERESIS: +		*val = xadc->temp_hysteresis; +		break; +	default: +		return -EINVAL; +	} + +	*val >>= XADC_THRESHOLD_VALUE_SHIFT; + +	return IIO_VAL_INT; +} + +int xadc_write_event_value(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, +	int val, int val2) +{ +	unsigned int offset = xadc_get_threshold_offset(chan, dir); +	struct xadc *xadc = iio_priv(indio_dev); +	int ret = 0; + +	val <<= XADC_THRESHOLD_VALUE_SHIFT; + +	if (val < 0 || val > 0xffff) +		return -EINVAL; + +	mutex_lock(&xadc->mutex); + +	switch (info) { +	case IIO_EV_INFO_VALUE: +		xadc->threshold[offset] = val; +		break; +	case IIO_EV_INFO_HYSTERESIS: +		xadc->temp_hysteresis = val; +		break; +	default: +		mutex_unlock(&xadc->mutex); +		return -EINVAL; +	} + +	if (chan->type == IIO_TEMP) { +		/* +		 * According to the datasheet we need to set the lower 4 bits to +		 * 0x3, otherwise 125 degree celsius will be used as the +		 * threshold. +		 */ +		val |= 0x3; + +		/* +		 * Since we store the hysteresis as relative (to the threshold) +		 * value, but the hardware expects an absolute value we need to +		 * recalcualte this value whenever the hysteresis or the +		 * threshold changes. +		 */ +		if (xadc->threshold[offset] < xadc->temp_hysteresis) +			xadc->threshold[offset + 4] = 0; +		else +			xadc->threshold[offset + 4] = xadc->threshold[offset] - +					xadc->temp_hysteresis; +		ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4), +			xadc->threshold[offset + 4]); +		if (ret) +			goto out_unlock; +	} + +	if (info == IIO_EV_INFO_VALUE) +		ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val); + +out_unlock: +	mutex_unlock(&xadc->mutex); + +	return ret; +} diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h new file mode 100644 index 00000000000..c7487e8d7f8 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc.h @@ -0,0 +1,209 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013 Analog Devices Inc. + *  Author: Lars-Peter Clauen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#ifndef __IIO_XILINX_XADC__ +#define __IIO_XILINX_XADC__ + +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> + +struct iio_dev; +struct clk; +struct xadc_ops; +struct platform_device; + +void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events); + +int xadc_read_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir); +int xadc_write_event_config(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, int state); +int xadc_read_event_value(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, +	int *val, int *val2); +int xadc_write_event_value(struct iio_dev *indio_dev, +	const struct iio_chan_spec *chan, enum iio_event_type type, +	enum iio_event_direction dir, enum iio_event_info info, +	int val, int val2); + +enum xadc_external_mux_mode { +	XADC_EXTERNAL_MUX_NONE, +	XADC_EXTERNAL_MUX_SINGLE, +	XADC_EXTERNAL_MUX_DUAL, +}; + +struct xadc { +	void __iomem *base; +	struct clk *clk; + +	const struct xadc_ops *ops; + +	uint16_t threshold[16]; +	uint16_t temp_hysteresis; +	unsigned int alarm_mask; + +	uint16_t *data; + +	struct iio_trigger *trigger; +	struct iio_trigger *convst_trigger; +	struct iio_trigger *samplerate_trigger; + +	enum xadc_external_mux_mode external_mux_mode; + +	unsigned int zynq_alarm; +	unsigned int zynq_masked_alarm; +	unsigned int zynq_intmask; +	struct delayed_work zynq_unmask_work; + +	struct mutex mutex; +	spinlock_t lock; + +	struct completion completion; +}; + +struct xadc_ops { +	int (*read)(struct xadc *, unsigned int, uint16_t *); +	int (*write)(struct xadc *, unsigned int, uint16_t); +	int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev, +			int irq); +	void (*update_alarm)(struct xadc *, unsigned int); +	unsigned long (*get_dclk_rate)(struct xadc *); +	irqreturn_t (*interrupt_handler)(int, void *); +	irqreturn_t (*threaded_interrupt_handler)(int, void *); + +	unsigned int flags; +}; + +static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t *val) +{ +	lockdep_assert_held(&xadc->mutex); +	return xadc->ops->read(xadc, reg, val); +} + +static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t val) +{ +	lockdep_assert_held(&xadc->mutex); +	return xadc->ops->write(xadc, reg, val); +} + +static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t *val) +{ +	int ret; + +	mutex_lock(&xadc->mutex); +	ret = _xadc_read_adc_reg(xadc, reg, val); +	mutex_unlock(&xadc->mutex); +	return ret; +} + +static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg, +	uint16_t val) +{ +	int ret; + +	mutex_lock(&xadc->mutex); +	ret = _xadc_write_adc_reg(xadc, reg, val); +	mutex_unlock(&xadc->mutex); +	return ret; +} + +/* XADC hardmacro register definitions */ +#define XADC_REG_TEMP		0x00 +#define XADC_REG_VCCINT		0x01 +#define XADC_REG_VCCAUX		0x02 +#define XADC_REG_VPVN		0x03 +#define XADC_REG_VREFP		0x04 +#define XADC_REG_VREFN		0x05 +#define XADC_REG_VCCBRAM	0x06 + +#define XADC_REG_VCCPINT	0x0d +#define XADC_REG_VCCPAUX	0x0e +#define XADC_REG_VCCO_DDR	0x0f +#define XADC_REG_VAUX(x)	(0x10 + (x)) + +#define XADC_REG_MAX_TEMP	0x20 +#define XADC_REG_MAX_VCCINT	0x21 +#define XADC_REG_MAX_VCCAUX	0x22 +#define XADC_REG_MAX_VCCBRAM	0x23 +#define XADC_REG_MIN_TEMP	0x24 +#define XADC_REG_MIN_VCCINT	0x25 +#define XADC_REG_MIN_VCCAUX	0x26 +#define XADC_REG_MIN_VCCBRAM	0x27 +#define XADC_REG_MAX_VCCPINT	0x28 +#define XADC_REG_MAX_VCCPAUX	0x29 +#define XADC_REG_MAX_VCCO_DDR	0x2a +#define XADC_REG_MIN_VCCPINT	0x2b +#define XADC_REG_MIN_VCCPAUX	0x2c +#define XADC_REG_MIN_VCCO_DDR	0x2d + +#define XADC_REG_CONF0		0x40 +#define XADC_REG_CONF1		0x41 +#define XADC_REG_CONF2		0x42 +#define XADC_REG_SEQ(x)		(0x48 + (x)) +#define XADC_REG_INPUT_MODE(x)	(0x4c + (x)) +#define XADC_REG_THRESHOLD(x)	(0x50 + (x)) + +#define XADC_REG_FLAG		0x3f + +#define XADC_CONF0_EC			BIT(9) +#define XADC_CONF0_ACQ			BIT(8) +#define XADC_CONF0_MUX			BIT(11) +#define XADC_CONF0_CHAN(x)		(x) + +#define XADC_CONF1_SEQ_MASK		(0xf << 12) +#define XADC_CONF1_SEQ_DEFAULT		(0 << 12) +#define XADC_CONF1_SEQ_SINGLE_PASS	(1 << 12) +#define XADC_CONF1_SEQ_CONTINUOUS	(2 << 12) +#define XADC_CONF1_SEQ_SINGLE_CHANNEL	(3 << 12) +#define XADC_CONF1_SEQ_SIMULTANEOUS	(4 << 12) +#define XADC_CONF1_SEQ_INDEPENDENT	(8 << 12) +#define XADC_CONF1_ALARM_MASK		0x0f0f + +#define XADC_CONF2_DIV_MASK	0xff00 +#define XADC_CONF2_DIV_OFFSET	8 + +#define XADC_CONF2_PD_MASK	(0x3 << 4) +#define XADC_CONF2_PD_NONE	(0x0 << 4) +#define XADC_CONF2_PD_ADC_B	(0x2 << 4) +#define XADC_CONF2_PD_BOTH	(0x3 << 4) + +#define XADC_ALARM_TEMP_MASK		BIT(0) +#define XADC_ALARM_VCCINT_MASK		BIT(1) +#define XADC_ALARM_VCCAUX_MASK		BIT(2) +#define XADC_ALARM_OT_MASK		BIT(3) +#define XADC_ALARM_VCCBRAM_MASK		BIT(4) +#define XADC_ALARM_VCCPINT_MASK		BIT(5) +#define XADC_ALARM_VCCPAUX_MASK		BIT(6) +#define XADC_ALARM_VCCODDR_MASK		BIT(7) + +#define XADC_THRESHOLD_TEMP_MAX		0x0 +#define XADC_THRESHOLD_VCCINT_MAX	0x1 +#define XADC_THRESHOLD_VCCAUX_MAX	0x2 +#define XADC_THRESHOLD_OT_MAX		0x3 +#define XADC_THRESHOLD_TEMP_MIN		0x4 +#define XADC_THRESHOLD_VCCINT_MIN	0x5 +#define XADC_THRESHOLD_VCCAUX_MIN	0x6 +#define XADC_THRESHOLD_OT_MIN		0x7 +#define XADC_THRESHOLD_VCCBRAM_MAX	0x8 +#define XADC_THRESHOLD_VCCPINT_MAX	0x9 +#define XADC_THRESHOLD_VCCPAUX_MAX	0xa +#define XADC_THRESHOLD_VCCODDR_MAX	0xb +#define XADC_THRESHOLD_VCCBRAM_MIN	0xc +#define XADC_THRESHOLD_VCCPINT_MIN	0xd +#define XADC_THRESHOLD_VCCPAUX_MIN	0xe +#define XADC_THRESHOLD_VCCODDR_MIN	0xf + +#endif  | 
