summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-19 11:44:28 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-19 11:44:28 +0200
commit6bce28cb49320f403ab075ecdc2feb6cee24c416 (patch)
treebf4e29c34eac9e865d891086ef739e184188cd8c /drivers/iio/adc
parentf5245a5fdf757f50a6c905fc16cceb1a6146ccf5 (diff)
parent0336d605daeea142c3ec9b143d0131a137f45108 (diff)
Merge tag 'iio-for-5.16a-split-take4' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: First set of IIO new device and feature support for the 5.16 cycle Counter subsystem changes now sent separately. This has been a busy cycle, so lots here and a few more stragglers to come next week. Big new feature in this cycle is probably output buffer support. This has been in the works for a very long time so it's great to see Mihail pick up the challenge and build upon his predecessors work to finally bring this feature to mainline. New device support ------------------ * adi,adxl313 - New driver and dt bindings for this low power accelerometer. * adi,adxl355 - New driver and dt bindings for this accelerometer. - Later series adds buffer support. * asahi-kasei,ak8975 - Minor additions to driver to support ak09916 * aspeed,aspeed-adc - Substantial rework plus feature additions to add support for the ast2600 including a new dt bindings doc. * atmel,at91_sama5d2 - Rework and support introduced for the sama7g5 parts. * maxim,max31865 - New driver and bindings for this RTD temperature sensor chip. * nxp,imx8qxp - New driver and bindings for the ADC found on the i.MX 8QuadXPlus Soc. * senseair,sunrise - New driver and bindings for this family of carbon dioxide gas sensors. * sensiron,scd4x - New driver and bindings for this carbon dioxide gas sensor. New features ------------ * Output buffer support. Works in a similar fashion to input buffers, but in this case userspace pushes data into the kfifo which is then drained to the device when a trigger occurs. Support added to the ad5766 DAC driver. * Core, devm_iio_map_array_register() to avoid need for devm_add_action_or_reset() based cleanup in fully managed allocation drivers. * Core iio_push_to_buffers_with_ts_unaligned() function to safely handle a few drivers where it really hard to ensure the correct data alignment in an iio_push_to_buffers_with_timestamp() call. Note this uses a bounce buffer so should be avoided whenever possible. Used in the ti,adc108s102, invense,mpu3050 and adi,adis16400. This closes the last known set of drivers with alignment issues at this interface. * maxim,max1027 - Substantial rework to this driver main target of which was supporting use of other triggers than it's own EOC interrupt. - Transfer optimization. * nxp,fxls8962af - Threshold even support including using it as a wakeup source. Cleanups, minor fixes etc ------------------------- Chances of a common type to multiple drivers: * devm_ conversion and drop of .remove() callbacks in: - adi,ad5064 - adi,ad7291 - adi,ad7303 - adi,ad7746 - adi,ad9832 - adi,adis16080 - dialog,da9150-gpadc - intel,mrfld_adc - marvell,berlin2 - maxim,max1363 - maxim,max44000 - nuvoton,nau7802 - st_sensors (includes a lot of rework!) - ti,ads8344 - ti,lp8788 * devm_platform_ioremap_resource() used to reduce boilerplate - cirrus,ep93xx - rockchip,saradc - stm,stm32-dac * Use dev_err_probe() in more places to both not print on deferred probe and ensure a reason for the deferral is available for debug purposes. - adi,ad8801 - capella,cm36651 - linear,ltc1660 - maxim,ds4424 - maxim,max5821 - microchip,mcp4922 - nxp,lpc18xx - onnn,noa1305 - st,lsm9ds0 - st,st_sensors - st,stm32-dac - ti,afe4403 - ti,afe4404 - ti,dac7311 * Drop error returns in SPI and I2C remove() functions as they are ignored and long term plan is to change these all over to returning void. In some cases these patches just make it 'obvious' they always return 0 where it was the case before but not easy to tell. - adi,ad5380 - adi,ad5446 - adi,ad5686 - adi,ad5592r - bosch,bma400 - bosch,bmc150 - fsl,mma7455 - honeywell,hmc5843 - kionix,kxsd9 - maxim,max5487 - meas,ms5611 - ti,afe4403 Driver specific changes * adi,ad5770r - Bring driver inline with documented bindings. * adi,ad7746 - Trivial style fix * adi,ad7949 - Express some magic values as the underlying parts via new #defines. - Make it work with SPI controllers that don't support 14 or 16 bit messages - Support selection of voltage reference from dt including expanding the dt-bindings to cover this new functionality. * adi,ad799x - Implement selection of external reference voltage on AD7991, AD7995 and AD7999. - Add missing dt-bindings doc for devices supported by this driver. * adi,adislib - Move interrupt startup to better location in startup flow. - Handle devices that cannot mask/unmask the drdy pin and must instead mask at the interrupt controller. Applies to the adis16460 and adis16475 from which we then drop equivalent code. * adi,ltc2983 - Add support for optional reset pin. - Fail to probe if no channels specified in dt binding. * asahi-kasei,ak8975 - dt-binding additions of missing vid-supply regulator. * aspeed,aspeed-adc - Typo fix. * fsl,mma7660 - Mark acpi_device_id table __maybe_unused to avoid build warning. * fsl,imx25-gcq - Avoid initializing regulators that aren't used. * invensense,mpu3050 - Drop a dead protection against a clash with the old input driver. * invensense,mpu6050 - Rework code to not use strcpy() and hence avoid possibility of wrong sized buffers. Note this wasn't a bug, but the new code is a lot more readable. - Mark acpi_device_id table __maybe_unused to avoid build warning. * kionix,kxcjk1013 - dt-binding addition to note it supports interrupts. * marvell,berlin2-adc - Enable COMPILE_TEST building. * maxim,max1027 - Avoid returning success in an error path. * nxp,imx8qxp - Fix warning when runtime pm not enabled via __maybe_unused. * ricoh,rn5t618 - Use the new devm_iio_map_array_register() instead of open coding the same. * samsung,exynos_adc - Improve kconfig help text. * st,lsm6dsx - Move max_fifo_size into the fifo_ops structure where the other configuration parameters are found. * st,st_sensors: - Reorder to ensure we turn the power off after removing userspace interfaces. * senseair,sunrise - Add missing I2C dependency. * ti,twl6030 - Small code tidy up. * tag 'iio-for-5.16a-split-take4' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (148 commits) iio: imx8qxp-adc: mark PM functions as __maybe_unused iio: pressure: ms5611: Make ms5611_remove() return void iio: potentiometer: max5487: Don't return an error in .remove() iio: magn: hmc5843: Make hmc5843_common_remove() return void iio: health: afe4403: Don't return an error in .remove() iio: dac: ad5686: Make ad5686_remove() return void iio: dac: ad5592r: Make ad5592r_remove() return void iio: dac: ad5446: Make ad5446_remove() return void iio: dac: ad5380: Make ad5380_remove() return void iio: accel: mma7455: Make mma7455_core_remove() return void iio: accel: kxsd9: Make kxsd9_common_remove() return void iio: accel: bmi088: Make bmi088_accel_core_remove() return void iio: accel: bmc150: Make bmc150_accel_core_remove() return void iio: accel: bma400: Make bma400_remove() return void drivers:iio:dac:ad5766.c: Add trigger buffer iio: triggered-buffer: extend support to configure output buffers iio: kfifo-buffer: Add output buffer support iio: Add output buffer support iio: documentation: Document scd4x calibration use drivers: iio: chemical: Add support for Sensirion SCD4x CO2 sensor ...
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig18
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ad7291.c70
-rw-r--r--drivers/iio/adc/ad7949.c254
-rw-r--r--drivers/iio/adc/ad799x.c68
-rw-r--r--drivers/iio/adc/aspeed_adc.c598
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c598
-rw-r--r--drivers/iio/adc/axp288_adc.c28
-rw-r--r--drivers/iio/adc/berlin2-adc.c34
-rw-r--r--drivers/iio/adc/da9150-gpadc.c27
-rw-r--r--drivers/iio/adc/ep93xx_adc.c4
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c55
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c494
-rw-r--r--drivers/iio/adc/intel_mrfld_adc.c24
-rw-r--r--drivers/iio/adc/lp8788_adc.c31
-rw-r--r--drivers/iio/adc/max1027.c278
-rw-r--r--drivers/iio/adc/max1363.c82
-rw-r--r--drivers/iio/adc/nau7802.c50
-rw-r--r--drivers/iio/adc/rn5t618-adc.c13
-rw-r--r--drivers/iio/adc/rockchip_saradc.c4
-rw-r--r--drivers/iio/adc/ti-adc108s102.c11
-rw-r--r--drivers/iio/adc/ti-ads8344.c27
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c6
23 files changed, 1977 insertions, 798 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index af168e1c9fdb..8bf5b62a73f4 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -354,7 +354,7 @@ config BCM_IPROC_ADC
config BERLIN2_ADC
tristate "Marvell Berlin2 ADC driver"
- depends on ARCH_BERLIN
+ depends on ARCH_BERLIN || COMPILE_TEST
help
Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
temperature measurement.
@@ -430,9 +430,9 @@ config EXYNOS_ADC
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST)
depends on HAS_IOMEM
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.
+ Driver for the ADC block found in the Samsung S3C (S3C2410, S3C2416,
+ S3C2440, S3C2443, S3C6410), S5Pv210 and Exynos SoCs.
+ Choose Y here only if you build for such Samsung SoC.
To compile this driver as a module, choose M here: the module will be
called exynos_adc.
@@ -530,6 +530,16 @@ config IMX7D_ADC
This driver can also be built as a module. If so, the module will be
called imx7d_adc.
+config IMX8QXP_ADC
+ tristate "NXP IMX8QXP ADC driver"
+ depends on ARCH_MXC_ARM64 || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Say yes here to build support for IMX8QXP ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called imx8qxp-adc.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index d68550f493e3..d3f53549720c 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
+obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index 2301a0e27f23..e9129dac762f 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -460,6 +460,11 @@ static const struct iio_info ad7291_info = {
.write_event_value = &ad7291_write_event_value,
};
+static void ad7291_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad7291_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -473,8 +478,6 @@ static int ad7291_probe(struct i2c_client *client,
chip = iio_priv(indio_dev);
mutex_init(&chip->state_lock);
- /* this is only used for device removal purposes */
- i2c_set_clientdata(client, indio_dev);
chip->client = client;
@@ -495,6 +498,11 @@ static int ad7291_probe(struct i2c_client *client,
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, ad7291_reg_disable,
+ chip->reg);
+ if (ret)
+ return ret;
+
chip->command |= AD7291_EXT_REF;
}
@@ -506,58 +514,25 @@ static int ad7291_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, AD7291_RESET);
- if (ret) {
- ret = -EIO;
- goto error_disable_reg;
- }
+ if (ret)
+ return -EIO;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command);
- if (ret) {
- ret = -EIO;
- goto error_disable_reg;
- }
+ if (ret)
+ return -EIO;
if (client->irq > 0) {
- ret = request_threaded_irq(client->irq,
- NULL,
- &ad7291_event_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- id->name,
- indio_dev);
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL,
+ &ad7291_event_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ id->name,
+ indio_dev);
if (ret)
- goto error_disable_reg;
+ return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_unreg_irq;
-
- return 0;
-
-error_unreg_irq:
- if (client->irq)
- free_irq(client->irq, indio_dev);
-error_disable_reg:
- if (chip->reg)
- regulator_disable(chip->reg);
-
- return ret;
-}
-
-static int ad7291_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ad7291_chip_info *chip = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- if (client->irq)
- free_irq(client->irq, indio_dev);
-
- if (chip->reg)
- regulator_disable(chip->reg);
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ad7291_id[] = {
@@ -579,7 +554,6 @@ static struct i2c_driver ad7291_driver = {
.of_match_table = ad7291_of_match,
},
.probe = ad7291_probe,
- .remove = ad7291_remove,
.id_table = ad7291_id,
};
module_i2c_driver(ad7291_driver);
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 1b4b3203e428..44bb5fde83de 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -11,12 +11,41 @@
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/bitfield.h>
-#define AD7949_MASK_CHANNEL_SEL GENMASK(9, 7)
-#define AD7949_MASK_TOTAL GENMASK(13, 0)
-#define AD7949_OFFSET_CHANNEL_SEL 7
-#define AD7949_CFG_READ_BACK 0x1
-#define AD7949_CFG_REG_SIZE_BITS 14
+#define AD7949_CFG_MASK_TOTAL GENMASK(13, 0)
+
+/* CFG: Configuration Update */
+#define AD7949_CFG_MASK_OVERWRITE BIT(13)
+
+/* INCC: Input Channel Configuration */
+#define AD7949_CFG_MASK_INCC GENMASK(12, 10)
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_GND 7
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_COMM 6
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_DIFF 4
+#define AD7949_CFG_VAL_INCC_TEMP 3
+#define AD7949_CFG_VAL_INCC_BIPOLAR 2
+#define AD7949_CFG_VAL_INCC_BIPOLAR_DIFF 0
+
+/* INX: Input channel Selection in a binary fashion */
+#define AD7949_CFG_MASK_INX GENMASK(9, 7)
+
+/* BW: select bandwidth for low-pass filter. Full or Quarter */
+#define AD7949_CFG_MASK_BW_FULL BIT(6)
+
+/* REF: reference/buffer selection */
+#define AD7949_CFG_MASK_REF GENMASK(5, 3)
+#define AD7949_CFG_VAL_REF_EXT_TEMP_BUF 3
+#define AD7949_CFG_VAL_REF_EXT_TEMP 2
+#define AD7949_CFG_VAL_REF_INT_4096 1
+#define AD7949_CFG_VAL_REF_INT_2500 0
+#define AD7949_CFG_VAL_REF_EXTERNAL BIT(1)
+
+/* SEQ: channel sequencer. Allows for scanning channels */
+#define AD7949_CFG_MASK_SEQ GENMASK(2, 1)
+
+/* RB: Read back the CFG register */
+#define AD7949_CFG_MASK_RBN BIT(0)
enum {
ID_AD7949 = 0,
@@ -41,41 +70,51 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
* @vref: regulator generating Vref
* @indio_dev: reference to iio structure
* @spi: reference to spi structure
+ * @refsel: reference selection
* @resolution: resolution of the chip
* @cfg: copy of the configuration register
* @current_channel: current channel in use
* @buffer: buffer to send / receive data to / from device
+ * @buf8b: be16 buffer to exchange data with the device in 8-bit transfers
*/
struct ad7949_adc_chip {
struct mutex lock;
struct regulator *vref;
struct iio_dev *indio_dev;
struct spi_device *spi;
+ u32 refsel;
u8 resolution;
u16 cfg;
unsigned int current_channel;
u16 buffer ____cacheline_aligned;
+ __be16 buf8b;
};
static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
u16 mask)
{
int ret;
- int bits_per_word = ad7949_adc->resolution;
- int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
- struct spi_message msg;
- struct spi_transfer tx[] = {
- {
- .tx_buf = &ad7949_adc->buffer,
- .len = 2,
- .bits_per_word = bits_per_word,
- },
- };
ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
- ad7949_adc->buffer = ad7949_adc->cfg << shift;
- spi_message_init_with_transfers(&msg, tx, 1);
- ret = spi_sync(ad7949_adc->spi, &msg);
+
+ switch (ad7949_adc->spi->bits_per_word) {
+ case 16:
+ ad7949_adc->buffer = ad7949_adc->cfg << 2;
+ ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2);
+ break;
+ case 14:
+ ad7949_adc->buffer = ad7949_adc->cfg;
+ ret = spi_write(ad7949_adc->spi, &ad7949_adc->buffer, 2);
+ break;
+ case 8:
+ /* Here, type is big endian as it must be sent in two transfers */
+ ad7949_adc->buf8b = cpu_to_be16(ad7949_adc->cfg << 2);
+ ret = spi_write(ad7949_adc->spi, &ad7949_adc->buf8b, 2);
+ break;
+ default:
+ dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n");
+ return -EINVAL;
+ }
/*
* This delay is to avoid a new request before the required time to
@@ -90,16 +129,6 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
{
int ret;
int i;
- int bits_per_word = ad7949_adc->resolution;
- int mask = GENMASK(ad7949_adc->resolution - 1, 0);
- struct spi_message msg;
- struct spi_transfer tx[] = {
- {
- .rx_buf = &ad7949_adc->buffer,
- .len = 2,
- .bits_per_word = bits_per_word,
- },
- };
/*
* 1: write CFG for sample N and read old data (sample N-2)
@@ -109,8 +138,8 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
*/
for (i = 0; i < 2; i++) {
ret = ad7949_spi_write_cfg(ad7949_adc,
- channel << AD7949_OFFSET_CHANNEL_SEL,
- AD7949_MASK_CHANNEL_SEL);
+ FIELD_PREP(AD7949_CFG_MASK_INX, channel),
+ AD7949_CFG_MASK_INX);
if (ret)
return ret;
if (channel == ad7949_adc->current_channel)
@@ -118,9 +147,11 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
}
/* 3: write something and read actual data */
- ad7949_adc->buffer = 0;
- spi_message_init_with_transfers(&msg, tx, 1);
- ret = spi_sync(ad7949_adc->spi, &msg);
+ if (ad7949_adc->spi->bits_per_word == 8)
+ ret = spi_read(ad7949_adc->spi, &ad7949_adc->buf8b, 2);
+ else
+ ret = spi_read(ad7949_adc->spi, &ad7949_adc->buffer, 2);
+
if (ret)
return ret;
@@ -132,7 +163,25 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
ad7949_adc->current_channel = channel;
- *val = ad7949_adc->buffer & mask;
+ switch (ad7949_adc->spi->bits_per_word) {
+ case 16:
+ *val = ad7949_adc->buffer;
+ /* Shift-out padding bits */
+ *val >>= 16 - ad7949_adc->resolution;
+ break;
+ case 14:
+ *val = ad7949_adc->buffer & GENMASK(13, 0);
+ break;
+ case 8:
+ /* Here, type is big endian as data was sent in two transfers */
+ *val = be16_to_cpu(ad7949_adc->buf8b);
+ /* Shift-out padding bits */
+ *val >>= 16 - ad7949_adc->resolution;
+ break;
+ default:
+ dev_err(&ad7949_adc->indio_dev->dev, "unsupported BPW\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -178,12 +227,26 @@ static int ad7949_spi_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = regulator_get_voltage(ad7949_adc->vref);
- if (ret < 0)
- return ret;
+ switch (ad7949_adc->refsel) {
+ case AD7949_CFG_VAL_REF_INT_2500:
+ *val = 2500;
+ break;
+ case AD7949_CFG_VAL_REF_INT_4096:
+ *val = 4096;
+ break;
+ case AD7949_CFG_VAL_REF_EXT_TEMP:
+ case AD7949_CFG_VAL_REF_EXT_TEMP_BUF:
+ ret = regulator_get_voltage(ad7949_adc->vref);
+ if (ret < 0)
+ return ret;
+
+ /* convert value back to mV */
+ *val = ret / 1000;
+ break;
+ }
- *val = ret / 5000;
- return IIO_VAL_INT;
+ *val2 = (1 << ad7949_adc->resolution) - 1;
+ return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
@@ -199,8 +262,8 @@ static int ad7949_spi_reg_access(struct iio_dev *indio_dev,
if (readval)
*readval = ad7949_adc->cfg;
else
- ret = ad7949_spi_write_cfg(ad7949_adc,
- writeval & AD7949_MASK_TOTAL, AD7949_MASK_TOTAL);
+ ret = ad7949_spi_write_cfg(ad7949_adc, writeval,
+ AD7949_CFG_MASK_TOTAL);
return ret;
}
@@ -214,10 +277,19 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
{
int ret;
int val;
+ u16 cfg;
- /* Sequencer disabled, CFG readback disabled, IN0 as default channel */
ad7949_adc->current_channel = 0;
- ret = ad7949_spi_write_cfg(ad7949_adc, 0x3C79, AD7949_MASK_TOTAL);
+
+ cfg = FIELD_PREP(AD7949_CFG_MASK_OVERWRITE, 1) |
+ FIELD_PREP(AD7949_CFG_MASK_INCC, AD7949_CFG_VAL_INCC_UNIPOLAR_GND) |
+ FIELD_PREP(AD7949_CFG_MASK_INX, ad7949_adc->current_channel) |
+ FIELD_PREP(AD7949_CFG_MASK_BW_FULL, 1) |
+ FIELD_PREP(AD7949_CFG_MASK_REF, ad7949_adc->refsel) |
+ FIELD_PREP(AD7949_CFG_MASK_SEQ, 0x0) |
+ FIELD_PREP(AD7949_CFG_MASK_RBN, 1);
+
+ ret = ad7949_spi_write_cfg(ad7949_adc, cfg, AD7949_CFG_MASK_TOTAL);
/*
* Do two dummy conversions to apply the first configuration setting.
@@ -229,12 +301,19 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
return ret;
}
+static void ad7949_disable_reg(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad7949_spi_probe(struct spi_device *spi)
{
+ u32 spi_ctrl_mask = spi->controller->bits_per_word_mask;
struct device *dev = &spi->dev;
const struct ad7949_adc_spec *spec;
struct ad7949_adc_chip *ad7949_adc;
struct iio_dev *indio_dev;
+ u32 tmp;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*ad7949_adc));
@@ -257,16 +336,64 @@ static int ad7949_spi_probe(struct spi_device *spi)
indio_dev->num_channels = spec->num_channels;
ad7949_adc->resolution = spec->resolution;
- ad7949_adc->vref = devm_regulator_get(dev, "vref");
+ /* Set SPI bits per word */
+ if (spi_ctrl_mask & SPI_BPW_MASK(ad7949_adc->resolution)) {
+ spi->bits_per_word = ad7949_adc->resolution;
+ } else if (spi_ctrl_mask == SPI_BPW_MASK(16)) {
+ spi->bits_per_word = 16;
+ } else if (spi_ctrl_mask == SPI_BPW_MASK(8)) {
+ spi->bits_per_word = 8;
+ } else {
+ dev_err(dev, "unable to find common BPW with spi controller\n");
+ return -EINVAL;
+ }
+
+ /* Setup internal voltage reference */
+ tmp = 4096000;
+ device_property_read_u32(dev, "adi,internal-ref-microvolt", &tmp);
+
+ switch (tmp) {
+ case 2500000:
+ ad7949_adc->refsel = AD7949_CFG_VAL_REF_INT_2500;
+ break;
+ case 4096000:
+ ad7949_adc->refsel = AD7949_CFG_VAL_REF_INT_4096;
+ break;
+ default:
+ dev_err(dev, "unsupported internal voltage reference\n");
+ return -EINVAL;
+ }
+
+ /* Setup external voltage reference, buffered? */
+ ad7949_adc->vref = devm_regulator_get_optional(dev, "vrefin");
if (IS_ERR(ad7949_adc->vref)) {
- dev_err(dev, "fail to request regulator\n");
- return PTR_ERR(ad7949_adc->vref);
+ ret = PTR_ERR(ad7949_adc->vref);
+ if (ret != -ENODEV)
+ return ret;
+ /* unbuffered? */
+ ad7949_adc->vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(ad7949_adc->vref)) {
+ ret = PTR_ERR(ad7949_adc->vref);
+ if (ret != -ENODEV)
+ return ret;
+ } else {
+ ad7949_adc->refsel = AD7949_CFG_VAL_REF_EXT_TEMP;
+ }
+ } else {
+ ad7949_adc->refsel = AD7949_CFG_VAL_REF_EXT_TEMP_BUF;
}
- ret = regulator_enable(ad7949_adc->vref);
- if (ret < 0) {
- dev_err(dev, "fail to enable regulator\n");
- return ret;
+ if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) {
+ ret = regulator_enable(ad7949_adc->vref);
+ if (ret < 0) {
+ dev_err(dev, "fail to enable regulator\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, ad7949_disable_reg,
+ ad7949_adc->vref);
+ if (ret)
+ return ret;
}
mutex_init(&ad7949_adc->lock);
@@ -274,36 +401,16 @@ static int ad7949_spi_probe(struct spi_device *spi)
ret = ad7949_spi_init(ad7949_adc);
if (ret) {
dev_err(dev, "enable to init this device: %d\n", ret);
- goto err;
+ return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
dev_err(dev, "fail to register iio device: %d\n", ret);
- goto err;
- }
-
- return 0;
-
-err:
- mutex_destroy(&ad7949_adc->lock);
- regulator_disable(ad7949_adc->vref);
return ret;
}
-static int ad7949_spi_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- mutex_destroy(&ad7949_adc->lock);
- regulator_disable(ad7949_adc->vref);
-
- return 0;
-}
-
static const struct of_device_id ad7949_spi_of_id[] = {
{ .compatible = "adi,ad7949" },
{ .compatible = "adi,ad7682" },
@@ -326,7 +433,6 @@ static struct spi_driver ad7949_spi_driver = {
.of_match_table = ad7949_spi_of_id,
},
.probe = ad7949_spi_probe,
- .remove = ad7949_spi_remove,
.id_table = ad7949_spi_id,
};
module_spi_driver(ad7949_spi_driver);
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 18bf8386d50a..220228c375d3 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -299,7 +299,11 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = regulator_get_voltage(st->vref);
+ if (st->vref)
+ ret = regulator_get_voltage(st->vref);
+ else
+ ret = regulator_get_voltage(st->reg);
+
if (ret < 0)
return ret;
*val = ret / 1000;
@@ -770,6 +774,7 @@ static int ad799x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
+ int extra_config = 0;
struct ad799x_state *st;
struct iio_dev *indio_dev;
const struct ad799x_chip_info *chip_info =
@@ -797,14 +802,36 @@ static int ad799x_probe(struct i2c_client *client,
ret = regulator_enable(st->reg);
if (ret)
return ret;
- st->vref = devm_regulator_get(&client->dev, "vref");
+
+ /* check if an external reference is supplied */
+ st->vref = devm_regulator_get_optional(&client->dev, "vref");
+
if (IS_ERR(st->vref)) {
- ret = PTR_ERR(st->vref);
- goto error_disable_reg;
+ if (PTR_ERR(st->vref) == -ENODEV) {
+ st->vref = NULL;
+ dev_info(&client->dev, "Using VCC reference voltage\n");
+ } else {
+ ret = PTR_ERR(st->vref);
+ goto error_disable_reg;
+ }
+ }
+
+ if (st->vref) {
+ /*
+ * Use external reference voltage if supported by hardware.
+ * This is optional if voltage / regulator present, use VCC otherwise.
+ */
+ if ((st->id == ad7991) || (st->id == ad7995) || (st->id == ad7999)) {
+ dev_info(&client->dev, "Using external reference voltage\n");
+ extra_config |= AD7991_REF_SEL;
+ ret = regulator_enable(st->vref);
+ if (ret)
+ goto error_disable_reg;
+ } else {
+ st->vref = NULL;
+ dev_warn(&client->dev, "Supplied reference not supported\n");
+ }
}
- ret = regulator_enable(st->vref);
- if (ret)
- goto error_disable_reg;
st->client = client;
@@ -815,7 +842,7 @@ static int ad799x_probe(struct i2c_client *client,
indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = chip_info->num_channels;
- ret = ad799x_update_config(st, st->chip_config->default_config);
+ ret = ad799x_update_config(st, st->chip_config->default_config | extra_config);
if (ret)
goto error_disable_vref;
@@ -845,7 +872,8 @@ static int ad799x_probe(struct i2c_client *client,
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_vref:
- regulator_disable(st->vref);
+ if (st->vref)
+ regulator_disable(st->vref);
error_disable_reg:
regulator_disable(st->reg);
@@ -860,7 +888,8 @@ static int ad799x_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
- regulator_disable(st->vref);
+ if (st->vref)
+ regulator_disable(st->vref);
regulator_disable(st->reg);
kfree(st->rx_buf);
@@ -872,7 +901,8 @@ static int __maybe_unused ad799x_suspend(struct device *dev)
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ad799x_state *st = iio_priv(indio_dev);
- regulator_disable(st->vref);
+ if (st->vref)
+ regulator_disable(st->vref);
regulator_disable(st->reg);
return 0;
@@ -889,17 +919,21 @@ static int __maybe_unused ad799x_resume(struct device *dev)
dev_err(dev, "Unable to enable vcc regulator\n");
return ret;
}
- ret = regulator_enable(st->vref);
- if (ret) {
- regulator_disable(st->reg);
- dev_err(dev, "Unable to enable vref regulator\n");
- return ret;
+
+ if (st->vref) {
+ ret = regulator_enable(st->vref);
+ if (ret) {
+ regulator_disable(st->reg);
+ dev_err(dev, "Unable to enable vref regulator\n");
+ return ret;
+ }
}
/* resync config */
ret = ad799x_update_config(st, st->config);
if (ret) {
- regulator_disable(st->vref);
+ if (st->vref)
+ regulator_disable(st->vref);
regulator_disable(st->reg);
return ret;
}
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 34ec0c28b2df..e939b84cbb56 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -1,8 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Aspeed AST2400/2500 ADC
+ * Aspeed AST2400/2500/2600 ADC
*
* Copyright (C) 2017 Google, Inc.
+ * Copyright (C) 2021 Aspeed Technology Inc.
+ *
+ * ADC clock formula:
+ * Ast2400/Ast2500:
+ * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
+ * Ast2600:
+ * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1)
*/
#include <linux/clk.h>
@@ -13,9 +20,13 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/types.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
@@ -28,34 +39,87 @@
#define ASPEED_REG_INTERRUPT_CONTROL 0x04
#define ASPEED_REG_VGA_DETECT_CONTROL 0x08
#define ASPEED_REG_CLOCK_CONTROL 0x0C
-#define ASPEED_REG_MAX 0xC0
-
-#define ASPEED_OPERATION_MODE_POWER_DOWN (0x0 << 1)
-#define ASPEED_OPERATION_MODE_STANDBY (0x1 << 1)
-#define ASPEED_OPERATION_MODE_NORMAL (0x7 << 1)
-
-#define ASPEED_ENGINE_ENABLE BIT(0)
-
-#define ASPEED_ADC_CTRL_INIT_RDY BIT(8)
+#define ASPEED_REG_COMPENSATION_TRIM 0xC4
+/*
+ * The register offset between 0xC8~0xCC can be read and won't affect the
+ * hardware logic in each version of ADC.
+ */
+#define ASPEED_REG_MAX 0xD0
+
+#define ASPEED_ADC_ENGINE_ENABLE BIT(0)
+#define ASPEED_ADC_OP_MODE GENMASK(3, 1)
+#define ASPEED_ADC_OP_MODE_PWR_DOWN 0
+#define ASPEED_ADC_OP_MODE_STANDBY 1
+#define ASPEED_ADC_OP_MODE_NORMAL 7
+#define ASPEED_ADC_CTRL_COMPENSATION BIT(4)
+#define ASPEED_ADC_AUTO_COMPENSATION BIT(5)
+/*
+ * Bit 6 determines not only the reference voltage range but also the dividing
+ * circuit for battery sensing.
+ */
+#define ASPEED_ADC_REF_VOLTAGE GENMASK(7, 6)
+#define ASPEED_ADC_REF_VOLTAGE_2500mV 0
+#define ASPEED_ADC_REF_VOLTAGE_1200mV 1
+#define ASPEED_ADC_REF_VOLTAGE_EXT_HIGH 2
+#define ASPEED_ADC_REF_VOLTAGE_EXT_LOW 3
+#define ASPEED_ADC_BAT_SENSING_DIV BIT(6)
+#define ASPEED_ADC_BAT_SENSING_DIV_2_3 0
+#define ASPEED_ADC_BAT_SENSING_DIV_1_3 1
+#define ASPEED_ADC_CTRL_INIT_RDY BIT(8)
+#define ASPEED_ADC_CH7_MODE BIT(12)
+#define ASPEED_ADC_CH7_NORMAL 0
+#define ASPEED_ADC_CH7_BAT 1
+#define ASPEED_ADC_BAT_SENSING_ENABLE BIT(13)
+#define ASPEED_ADC_CTRL_CHANNEL GENMASK(31, 16)
+#define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch))
#define ASPEED_ADC_INIT_POLLING_TIME 500
#define ASPEED_ADC_INIT_TIMEOUT 500000
+/*
+ * When the sampling rate is too high, the ADC may not have enough charging
+ * time, resulting in a low voltage value. Thus, the default uses a slow
+ * sampling rate for most use cases.
+ */
+#define ASPEED_ADC_DEF_SAMPLING_RATE 65000
+
+struct aspeed_adc_trim_locate {
+ const unsigned int offset;
+ const unsigned int field;
+};
struct aspeed_adc_model_data {
const char *model_name;
unsigned int min_sampling_rate; // Hz
unsigned int max_sampling_rate; // Hz
- unsigned int vref_voltage; // mV
+ unsigned int vref_fixed_mv;
bool wait_init_sequence;
+ bool need_prescaler;
+ bool bat_sense_sup;
+ u8 scaler_bit_width;
+ unsigned int num_channels;
+ const struct aspeed_adc_trim_locate *trim_locate;
+};
+
+struct adc_gain {
+ u8 mult;
+ u8 div;
};
struct aspeed_adc_data {
struct device *dev;
+ const struct aspeed_adc_model_data *model_data;
+ struct regulator *regulator;
void __iomem *base;
spinlock_t clk_lock;
+ struct clk_hw *fixed_div_clk;
struct clk_hw *clk_prescaler;
struct clk_hw *clk_scaler;
struct reset_control *rst;
+ int vref_mv;
+ u32 sample_period_ns;
+ int cv;
+ bool battery_sensing;
+ struct adc_gain battery_mode_gain;
};
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
@@ -65,7 +129,8 @@ struct aspeed_adc_data {
.address = (_data_reg_addr), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
@@ -87,21 +152,170 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
ASPEED_CHAN(15, 0x2E),
};
+#define ASPEED_BAT_CHAN(_idx, _data_reg_addr) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .address = (_data_reg_addr), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+static const struct iio_chan_spec aspeed_adc_iio_bat_channels[] = {
+ ASPEED_CHAN(0, 0x10),
+ ASPEED_CHAN(1, 0x12),
+ ASPEED_CHAN(2, 0x14),
+ ASPEED_CHAN(3, 0x16),
+ ASPEED_CHAN(4, 0x18),
+ ASPEED_CHAN(5, 0x1A),
+ ASPEED_CHAN(6, 0x1C),
+ ASPEED_BAT_CHAN(7, 0x1E),
+};
+
+static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
+{
+ struct device_node *syscon;
+ struct regmap *scu;
+ u32 scu_otp, trimming_val;
+ struct aspeed_adc_data *data = iio_priv(indio_dev);
+
+ syscon = of_find_node_by_name(NULL, "syscon");
+ if (syscon == NULL) {
+ dev_warn(data->dev, "Couldn't find syscon node\n");
+ return -EOPNOTSUPP;
+ }
+ scu = syscon_node_to_regmap(syscon);
+ if (IS_ERR(scu)) {
+ dev_warn(data->dev, "Failed to get syscon regmap\n");
+ return -EOPNOTSUPP;
+ }
+ if (data->model_data->trim_locate) {
+ if (regmap_read(scu, data->model_data->trim_locate->offset,
+ &scu_otp)) {
+ dev_warn(data->dev,
+ "Failed to get adc trimming data\n");
+ trimming_val = 0x8;
+ } else {
+ trimming_val =
+ ((scu_otp) &
+ (data->model_data->trim_locate->field)) >>
+ __ffs(data->model_data->trim_locate->field);
+ }
+ dev_dbg(data->dev,
+ "trimming val = %d, offset = %08x, fields = %08x\n",
+ trimming_val, data->model_data->trim_locate->offset,
+ data->model_data->trim_locate->field);
+ writel(trimming_val, data->base + ASPEED_REG_COMPENSATION_TRIM);
+ }
+ return 0;
+}
+
+static int aspeed_adc_compensation(struct iio_dev *indio_dev)
+{
+ struct aspeed_adc_data *data = iio_priv(indio_dev);
+ u32 index, adc_raw = 0;
+ u32 adc_engine_control_reg_val;
+
+ adc_engine_control_reg_val =
+ readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val &= ~ASPEED_ADC_OP_MODE;
+ adc_engine_control_reg_val |=
+ (FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
+ ASPEED_ADC_ENGINE_ENABLE);
+ /*
+ * Enable compensating sensing:
+ * After that, the input voltage of ADC will force to half of the reference
+ * voltage. So the expected reading raw data will become half of the max
+ * value. We can get compensating value = 0x200 - ADC read raw value.
+ * It is recommended to average at least 10 samples to get a final CV.
+ */
+ writel(adc_engine_control_reg_val | ASPEED_ADC_CTRL_COMPENSATION |
+ ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ /*
+ * After enable compensating sensing mode need to wait some time for ADC stable
+ * Experiment result is 1ms.
+ */
+ mdelay(1);
+
+ for (index = 0; index < 16; index++) {
+ /*
+ * Waiting for the sampling period ensures that the value acquired
+ * is fresh each time.
+ */
+ ndelay(data->sample_period_ns);
+ adc_raw += readw(data->base + aspeed_adc_iio_channels[0].address);
+ }
+ adc_raw >>= 4;
+ data->cv = BIT(ASPEED_RESOLUTION_BITS - 1) - adc_raw;
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ dev_dbg(data->dev, "Compensating value = %d\n", data->cv);
+
+ return 0;
+}
+
+static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
+{
+ struct aspeed_adc_data *data = iio_priv(indio_dev);
+
+ if (rate < data->model_data->min_sampling_rate ||
+ rate > data->model_data->max_sampling_rate)
+ return -EINVAL;
+ /* Each sampling needs 12 clocks to convert.*/
+ clk_set_rate(data->clk_scaler->clk, rate * ASPEED_CLOCKS_PER_SAMPLE);
+ rate = clk_get_rate(data->clk_scaler->clk);
+ data->sample_period_ns = DIV_ROUND_UP_ULL(
+ (u64)NSEC_PER_SEC * ASPEED_CLOCKS_PER_SAMPLE, rate);
+ dev_dbg(data->dev, "Adc clock = %d sample period = %d ns", rate,
+ data->sample_period_ns);
+
+ return 0;
+}
+
static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct aspeed_adc_data *data = iio_priv(indio_dev);
- const struct aspeed_adc_model_data *model_data =
- of_device_get_match_data(data->dev);
+ u32 adc_engine_control_reg_val;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- *val = readw(data->base + chan->address);
+ if (data->battery_sensing && chan->channel == 7) {
+ adc_engine_control_reg_val =
+ readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ writel(adc_engine_control_reg_val |
+ FIELD_PREP(ASPEED_ADC_CH7_MODE,
+ ASPEED_ADC_CH7_BAT) |
+ ASPEED_ADC_BAT_SENSING_ENABLE,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ /*
+ * After enable battery sensing mode need to wait some time for adc stable
+ * Experiment result is 1ms.
+ */
+ mdelay(1);
+ *val = readw(data->base + chan->address);
+ *val = (*val * data->battery_mode_gain.mult) /
+ data->battery_mode_gain.div;
+ /* Restore control register value */
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ } else
+ *val = readw(data->base + chan->address);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OFFSET:
+ if (data->battery_sensing && chan->channel == 7)
+ *val = (data->cv * data->battery_mode_gain.mult) /
+ data->battery_mode_gain.div;
+ else
+ *val = data->cv;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = model_data->vref_voltage;
+ *val = data->vref_mv;
*val2 = ASPEED_RESOLUTION_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -119,19 +333,9 @@ static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
- struct aspeed_adc_data *data = iio_priv(indio_dev);
- const struct aspeed_adc_model_data *model_data =
- of_device_get_match_data(data->dev);
-
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- if (val < model_data->min_sampling_rate ||
- val > model_data->max_sampling_rate)
- return -EINVAL;
-
- clk_set_rate(data->clk_scaler->clk,
- val * ASPEED_CLOCKS_PER_SAMPLE);
- return 0;
+ return aspeed_adc_set_sampling_rate(indio_dev, val);
case IIO_CHAN_INFO_SCALE:
case IIO_CHAN_INFO_RAW:
@@ -168,14 +372,119 @@ static const struct iio_info aspeed_adc_iio_info = {
.debugfs_reg_access = aspeed_adc_reg_access,
};
+static void aspeed_adc_unregister_fixed_divider(void *data)
+{
+ struct clk_hw *clk = data;
+
+ clk_hw_unregister_fixed_factor(clk);
+}
+
+static void aspeed_adc_reset_assert(void *data)
+{
+ struct reset_control *rst = data;
+
+ reset_control_assert(rst);
+}
+
+static void aspeed_adc_clk_disable_unprepare(void *data)
+{
+ struct clk *clk = data;
+
+ clk_disable_unprepare(clk);
+}
+
+static void aspeed_adc_power_down(void *data)
+{
+ struct aspeed_adc_data *priv_data = data;
+
+ writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
+ priv_data->base + ASPEED_REG_ENGINE_CONTROL);
+}
+
+static void aspeed_adc_reg_disable(void *data)
+{
+ struct regulator *reg = data;
+
+ regulator_disable(reg);
+}
+
+static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
+{
+ struct aspeed_adc_data *data = iio_priv(indio_dev);
+ int ret;
+ u32 adc_engine_control_reg_val;
+
+ if (data->model_data->vref_fixed_mv) {
+ data->vref_mv = data->model_data->vref_fixed_mv;
+ return 0;
+ }
+ adc_engine_control_reg_val =
+ readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ data->regulator = devm_regulator_get_optional(data->dev, "vref");
+ if (!IS_ERR(data->regulator)) {
+ ret = regulator_enable(data->regulator);
+ if (ret)
+ return ret;
+ ret = devm_add_action_or_reset(
+ data->dev, aspeed_adc_reg_disable, data->regulator);
+ if (ret)
+ return ret;
+ data->vref_mv = regulator_get_voltage(data->regulator);
+ /* Conversion from uV to mV */
+ data->vref_mv /= 1000;
+ if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700))
+ writel(adc_engine_control_reg_val |
+ FIELD_PREP(
+ ASPEED_ADC_REF_VOLTAGE,
+ ASPEED_ADC_REF_VOLTAGE_EXT_HIGH),
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ else if ((data->vref_mv >= 900) && (data->vref_mv <= 1650))
+ writel(adc_engine_control_reg_val |
+ FIELD_PREP(
+ ASPEED_ADC_REF_VOLTAGE,
+ ASPEED_ADC_REF_VOLTAGE_EXT_LOW),
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ else {
+ dev_err(data->dev, "Regulator voltage %d not support",
+ data->vref_mv);
+ return -EOPNOTSUPP;
+ }
+ } else {
+ if (PTR_ERR(data->regulator) != -ENODEV)
+ return PTR_ERR(data->regulator);
+ data->vref_mv = 2500000;
+ of_property_read_u32(data->dev->of_node,
+ "aspeed,int-vref-microvolt",
+ &data->vref_mv);
+ /* Conversion from uV to mV */
+ data->vref_mv /= 1000;
+ if (data->vref_mv == 2500)
+ writel(adc_engine_control_reg_val |
+ FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
+ ASPEED_ADC_REF_VOLTAGE_2500mV),
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ else if (data->vref_mv == 1200)
+ writel(adc_engine_control_reg_val |
+ FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
+ ASPEED_ADC_REF_VOLTAGE_1200mV),
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+ else {
+ dev_err(data->dev, "Voltage %d not support", data->vref_mv);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
static int aspeed_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct aspeed_adc_data *data;
- const struct aspeed_adc_model_data *model_data;
- const char *clk_parent_name;
int ret;
u32 adc_engine_control_reg_val;
+ unsigned long scaler_flags = 0;
+ char clk_name[32], clk_parent_name[32];
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
if (!indio_dev)
@@ -183,6 +492,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
data = iio_priv(indio_dev);
data->dev = &pdev->dev;
+ data->model_data = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, indio_dev);
data->base = devm_platform_ioremap_resource(pdev, 0);
@@ -191,45 +501,117 @@ static int aspeed_adc_probe(struct platform_device *pdev)
/* Register ADC clock prescaler with source specified by device tree. */
spin_lock_init(&data->clk_lock);
- clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-
- data->clk_prescaler = clk_hw_register_divider(
- &pdev->dev, "prescaler", clk_parent_name, 0,
- data->base + ASPEED_REG_CLOCK_CONTROL,
- 17, 15, 0, &data->clk_lock);
- if (IS_ERR(data->clk_prescaler))
- return PTR_ERR(data->clk_prescaler);
-
+ snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s",
+ of_clk_get_parent_name(pdev->dev.of_node, 0));
+ snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div",
+ data->model_data->model_name);
+ data->fixed_div_clk = clk_hw_register_fixed_factor(
+ &pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
+ if (IS_ERR(data->fixed_div_clk))
+ return PTR_ERR(data->fixed_div_clk);
+
+ ret = devm_add_action_or_reset(data->dev,
+ aspeed_adc_unregister_fixed_divider,
+ data->fixed_div_clk);
+ if (ret)
+ return ret;
+ snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), clk_name);
+
+ if (data->model_data->need_prescaler) {
+ snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler",
+ data->model_data->model_name);
+ data->clk_prescaler = devm_clk_hw_register_divider(
+ &pdev->dev, clk_name, clk_parent_name, 0,
+ data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
+ &data->clk_lock);
+ if (IS_ERR(data->clk_prescaler))
+ return PTR_ERR(data->clk_prescaler);
+ snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name),
+ clk_name);
+ scaler_flags = CLK_SET_RATE_PARENT;
+ }
/*
* Register ADC clock scaler downstream from the prescaler. Allow rate
* setting to adjust the prescaler as well.
*/
- data->clk_scaler = clk_hw_register_divider(
- &pdev->dev, "scaler", "prescaler",
- CLK_SET_RATE_PARENT,
- data->base + ASPEED_REG_CLOCK_CONTROL,
- 0, 10, 0, &data->clk_lock);
- if (IS_ERR(data->clk_scaler)) {
- ret = PTR_ERR(data->clk_scaler);
- goto scaler_error;
- }
-
- data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler",
+ data->model_data->model_name);
+ data->clk_scaler = devm_clk_hw_register_divider(
+ &pdev->dev, clk_name, clk_parent_name, scaler_flags,
+ data->base + ASPEED_REG_CLOCK_CONTROL, 0,
+ data->model_data->scaler_bit_width, 0, &data->clk_lock);
+ if (IS_ERR(data->clk_scaler))
+ return PTR_ERR(data->clk_scaler);
+
+ data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
if (IS_ERR(data->rst)) {
dev_err(&pdev->dev,
"invalid or missing reset controller device tree entry");
- ret = PTR_ERR(data->rst);
- goto reset_error;
+ return PTR_ERR(data->rst);
}
reset_control_deassert(data->rst);
- model_data = of_device_get_match_data(&pdev->dev);
+ ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
+ data->rst);
+ if (ret)
+ return ret;
- if (model_data->wait_init_sequence) {
- /* Enable engine in normal mode. */
- writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
- data->base + ASPEED_REG_ENGINE_CONTROL);
+ ret = aspeed_adc_vref_config(indio_dev);
+ if (ret)
+ return ret;
+ if (of_find_property(data->dev->of_node, "aspeed,trim-data-valid",
+ NULL)) {
+ ret = aspeed_adc_set_trim_data(indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
+ NULL)) {
+ if (data->model_data->bat_sense_sup) {
+ data->battery_sensing = 1;
+ if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
+ ASPEED_ADC_BAT_SENSING_DIV) {
+ data->battery_mode_gain.mult = 3;
+ data->battery_mode_gain.div = 1;
+ } else {
+ data->battery_mode_gain.mult = 3;
+ data->battery_mode_gain.div = 2;
+ }
+ } else
+ dev_warn(&pdev->dev,
+ "Failed to enable battery-sensing mode\n");
+ }
+
+ ret = clk_prepare_enable(data->clk_scaler->clk);
+ if (ret)
+ return ret;
+ ret = devm_add_action_or_reset(data->dev,
+ aspeed_adc_clk_disable_unprepare,
+ data->clk_scaler->clk);
+ if (ret)
+ return ret;
+ ret = aspeed_adc_set_sampling_rate(indio_dev,
+ ASPEED_ADC_DEF_SAMPLING_RATE);
+ if (ret)
+ return ret;
+
+ adc_engine_control_reg_val =
+ readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val |=
+ FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
+ ASPEED_ADC_ENGINE_ENABLE;
+ /* Enable engine in normal mode. */
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+
+ ret = devm_add_action_or_reset(data->dev, aspeed_adc_power_down,
+ data);
+ if (ret)
+ return ret;
+
+ if (data->model_data->wait_init_sequence) {
/* Wait for initial sequence complete. */
ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
adc_engine_control_reg_val,
@@ -238,87 +620,99 @@ static int aspeed_adc_probe(struct platform_device *pdev)
ASPEED_ADC_INIT_POLLING_TIME,
ASPEED_ADC_INIT_TIMEOUT);
if (ret)
- goto poll_timeout_error;
+ return ret;
}
+ aspeed_adc_compensation(indio_dev);
/* Start all channels in normal mode. */
- ret = clk_prepare_enable(data->clk_scaler->clk);
- if (ret)
- goto clk_enable_error;
-
- adc_engine_control_reg_val = GENMASK(31, 16) |
- ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+ adc_engine_control_reg_val =
+ readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL;
writel(adc_engine_control_reg_val,
- data->base + ASPEED_REG_ENGINE_CONTROL);
+ data->base + ASPEED_REG_ENGINE_CONTROL);
- model_data = of_device_get_match_data(&pdev->dev);
- indio_dev->name = model_data->model_name;
+ indio_dev->name = data->model_data->model_name;
indio_dev->info = &aspeed_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = aspeed_adc_iio_channels;
- indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels);
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto iio_register_error;
-
- return 0;
+ indio_dev->channels = data->battery_sensing ?
+ aspeed_adc_iio_bat_channels :
+ aspeed_adc_iio_channels;
+ indio_dev->num_channels = data->model_data->num_channels;
-iio_register_error:
- writel(ASPEED_OPERATION_MODE_POWER_DOWN,
- data->base + ASPEED_REG_ENGINE_CONTROL);
- clk_disable_unprepare(data->clk_scaler->clk);
-clk_enable_error:
-poll_timeout_error:
- reset_control_assert(data->rst);
-reset_error:
- clk_hw_unregister_divider(data->clk_scaler);
-scaler_error:
- clk_hw_unregister_divider(data->clk_prescaler);
+ ret = devm_iio_device_register(data->dev, indio_dev);
return ret;
}
-static int aspeed_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct aspeed_adc_data *data = iio_priv(indio_dev);
+static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
+ .offset = 0x154,
+ .field = GENMASK(31, 28),
+};
- iio_device_unregister(indio_dev);
- writel(ASPEED_OPERATION_MODE_POWER_DOWN,
- data->base + ASPEED_REG_ENGINE_CONTROL);
- clk_disable_unprepare(data->clk_scaler->clk);
- reset_control_assert(data->rst);
- clk_hw_unregister_divider(data->clk_scaler);
- clk_hw_unregister_divider(data->clk_prescaler);
+static const struct aspeed_adc_trim_locate ast2600_adc0_trim = {
+ .offset = 0x5d0,
+ .field = GENMASK(3, 0),
+};
- return 0;
-}
+static const struct aspeed_adc_trim_locate ast2600_adc1_trim = {
+ .offset = 0x5d0,
+ .field = GENMASK(7, 4),
+};
static const struct aspeed_adc_model_data ast2400_model_data = {
.model_name = "ast2400-adc",
- .vref_voltage = 2500, // mV
+ .vref_fixed_mv = 2500,
.min_sampling_rate = 10000,
.max_sampling_rate = 500000,
+ .need_prescaler = true,
+ .scaler_bit_width = 10,
+ .num_channels = 16,
};
static const struct aspeed_adc_model_data ast2500_model_data = {
.model_name = "ast2500-adc",
- .vref_voltage = 1800, // mV
+ .vref_fixed_mv = 1800,
.min_sampling_rate = 1,
.max_sampling_rate = 1000000,
.wait_init_sequence = true,
+ .need_prescaler = true,
+ .scaler_bit_width = 10,
+ .num_channels = 16,
+ .trim_locate = &ast2500_adc_trim,
+};
+
+static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
+ .model_name = "ast2600-adc0",
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
+ .wait_init_sequence = true,
+ .bat_sense_sup = true,
+ .scaler_bit_width = 16,
+ .num_channels = 8,
+ .trim_locate = &ast2600_adc0_trim,
+};
+
+static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
+ .model_name = "ast2600-adc1",
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
+ .wait_init_sequence = true,
+ .bat_sense_sup = true,
+ .scaler_bit_width = 16,
+ .num_channels = 8,
+ .trim_locate = &ast2600_adc1_trim,
};
static const struct of_device_id aspeed_adc_matches[] = {
{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
+ { .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
+ { .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
{},
};
MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
static struct platform_driver aspeed_adc_driver = {
.probe = aspeed_adc_probe,
- .remove = aspeed_adc_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = aspeed_adc_matches,
@@ -328,5 +722,5 @@ static struct platform_driver aspeed_adc_driver = {
module_platform_driver(aspeed_adc_driver);
MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
+MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index ea5ca163d879..4c922ef634f8 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -4,6 +4,8 @@
*
* Copyright (C) 2015 Atmel,
* 2015 Ludovic Desroches <ludovic.desroches@atmel.com>
+ * 2021 Microchip Technology, Inc. and its subsidiaries
+ * 2021 Eugen Hristev <eugen.hristev@microchip.com>
*/
#include <linux/bitops.h>
@@ -27,8 +29,9 @@
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
+struct at91_adc_reg_layout {
/* Control Register */
-#define AT91_SAMA5D2_CR 0x00
+ u16 CR;
/* Software Reset */
#define AT91_SAMA5D2_CR_SWRST BIT(0)
/* Start Conversion */
@@ -39,7 +42,7 @@
#define AT91_SAMA5D2_CR_CMPRST BIT(4)
/* Mode Register */
-#define AT91_SAMA5D2_MR 0x04
+ u16 MR;
/* Trigger Selection */
#define AT91_SAMA5D2_MR_TRGSEL(v) ((v) << 1)
/* ADTRG */
@@ -82,19 +85,19 @@
#define AT91_SAMA5D2_MR_USEQ BIT(31)
/* Channel Sequence Register 1 */
-#define AT91_SAMA5D2_SEQR1 0x08
+ u16 SEQR1;
/* Channel Sequence Register 2 */
-#define AT91_SAMA5D2_SEQR2 0x0c
+ u16 SEQR2;
/* Channel Enable Register */
-#define AT91_SAMA5D2_CHER 0x10
+ u16 CHER;
/* Channel Disable Register */
-#define AT91_SAMA5D2_CHDR 0x14
+ u16 CHDR;
/* Channel Status Register */
-#define AT91_SAMA5D2_CHSR 0x18
+ u16 CHSR;
/* Last Converted Data Register */
-#define AT91_SAMA5D2_LCDR 0x20
+ u16 LCDR;
/* Interrupt Enable Register */
-#define AT91_SAMA5D2_IER 0x24
+ u16 IER;
/* Interrupt Enable Register - TS X measurement ready */
#define AT91_SAMA5D2_IER_XRDY BIT(20)
/* Interrupt Enable Register - TS Y measurement ready */
@@ -109,22 +112,31 @@
#define AT91_SAMA5D2_IER_PEN BIT(29)
/* Interrupt Enable Register - No pen detect */
#define AT91_SAMA5D2_IER_NOPEN BIT(30)
+
/* Interrupt Disable Register */
-#define AT91_SAMA5D2_IDR 0x28
+ u16 IDR;
/* Interrupt Mask Register */
-#define AT91_SAMA5D2_IMR 0x2c
+ u16 IMR;
/* Interrupt Status Register */
-#define AT91_SAMA5D2_ISR 0x30
+ u16 ISR;
+/* End of Conversion Interrupt Enable Register */
+ u16 EOC_IER;
+/* End of Conversion Interrupt Disable Register */
+ u16 EOC_IDR;
+/* End of Conversion Interrupt Mask Register */
+ u16 EOC_IMR;
+/* End of Conversion Interrupt Status Register */
+ u16 EOC_ISR;
/* Interrupt Status Register - Pen touching sense status */
#define AT91_SAMA5D2_ISR_PENS BIT(31)
/* Last Channel Trigger Mode Register */
-#define AT91_SAMA5D2_LCTMR 0x34
+ u16 LCTMR;
/* Last Channel Compare Window Register */
-#define AT91_SAMA5D2_LCCWR 0x38
+ u16 LCCWR;
/* Overrun Status Register */
-#define AT91_SAMA5D2_OVER 0x3c
+ u16 OVER;
/* Extended Mode Register */
-#define AT91_SAMA5D2_EMR 0x40
+ u16 EMR;
/* Extended Mode Register - Oversampling rate */
#define AT91_SAMA5D2_EMR_OSR(V) ((V) << 16)
#define AT91_SAMA5D2_EMR_OSR_MASK GENMASK(17, 16)
@@ -134,24 +146,22 @@
/* Extended Mode Register - Averaging on single trigger event */
#define AT91_SAMA5D2_EMR_ASTE(V) ((V) << 20)
+
/* Compare Window Register */
-#define AT91_SAMA5D2_CWR 0x44
+ u16 CWR;
/* Channel Gain Register */
-#define AT91_SAMA5D2_CGR 0x48
-
+ u16 CGR;
/* Channel Offset Register */
-#define AT91_SAMA5D2_COR 0x4c
-#define AT91_SAMA5D2_COR_DIFF_OFFSET 16
-
-/* Channel Data Register 0 */
-#define AT91_SAMA5D2_CDR0 0x50
+ u16 COR;
+/* Channel Offset Register differential offset - constant, not a register */
+ u16 COR_diff_offset;
/* Analog Control Register */
-#define AT91_SAMA5D2_ACR 0x94
+ u16 ACR;
/* Analog Control Register - Pen detect sensitivity mask */
#define AT91_SAMA5D2_ACR_PENDETSENS_MASK GENMASK(1, 0)
/* Touchscreen Mode Register */
-#define AT91_SAMA5D2_TSMR 0xb0
+ u16 TSMR;
/* Touchscreen Mode Register - No touch mode */
#define AT91_SAMA5D2_TSMR_TSMODE_NONE 0
/* Touchscreen Mode Register - 4 wire screen, no pressure measurement */
@@ -180,13 +190,13 @@
#define AT91_SAMA5D2_TSMR_PENDET_ENA BIT(24)
/* Touchscreen X Position Register */
-#define AT91_SAMA5D2_XPOSR 0xb4
+ u16 XPOSR;
/* Touchscreen Y Position Register */
-#define AT91_SAMA5D2_YPOSR 0xb8
+ u16 YPOSR;
/* Touchscreen Pressure Register */
-#define AT91_SAMA5D2_PRESSR 0xbc
+ u16 PRESSR;
/* Trigger Register */
-#define AT91_SAMA5D2_TRGR 0xc0
+ u16 TRGR;
/* Mask for TRGMOD field of TRGR register */
#define AT91_SAMA5D2_TRGR_TRGMOD_MASK GENMASK(2, 0)
/* No trigger, only software trigger can start conversions */
@@ -205,30 +215,85 @@
#define AT91_SAMA5D2_TRGR_TRGPER(x) ((x) << 16)
/* Correction Select Register */
-#define AT91_SAMA5D2_COSR 0xd0
+ u16 COSR;
/* Correction Value Register */
-#define AT91_SAMA5D2_CVR 0xd4
+ u16 CVR;
/* Channel Error Correction Register */
-#define AT91_SAMA5D2_CECR 0xd8
+ u16 CECR;
/* Write Protection Mode Register */
-#define AT91_SAMA5D2_WPMR 0xe4
+ u16 WPMR;
/* Write Protection Status Register */
-#define AT91_SAMA5D2_WPSR 0xe8
+ u16 WPSR;
/* Version Register */
-#define AT91_SAMA5D2_VERSION 0xfc
-
-#define AT91_SAMA5D2_HW_TRIG_CNT 3
-#define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
-#define AT91_SAMA5D2_DIFF_CHAN_CNT 6
+ u16 VERSION;
+};
-#define AT91_SAMA5D2_TIMESTAMP_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
- AT91_SAMA5D2_DIFF_CHAN_CNT + 1)
+static const struct at91_adc_reg_layout sama5d2_layout = {
+ .CR = 0x00,
+ .MR = 0x04,
+ .SEQR1 = 0x08,
+ .SEQR2 = 0x0c,
+ .CHER = 0x10,
+ .CHDR = 0x14,
+ .CHSR = 0x18,
+ .LCDR = 0x20,
+ .IER = 0x24,
+ .IDR = 0x28,
+ .IMR = 0x2c,
+ .ISR = 0x30,
+ .LCTMR = 0x34,
+ .LCCWR = 0x38,
+ .OVER = 0x3c,
+ .EMR = 0x40,
+ .CWR = 0x44,
+ .CGR = 0x48,
+ .COR = 0x4c,
+ .COR_diff_offset = 16,
+ .ACR = 0x94,
+ .TSMR = 0xb0,
+ .XPOSR = 0xb4,
+ .YPOSR = 0xb8,
+ .PRESSR = 0xbc,
+ .TRGR = 0xc0,
+ .COSR = 0xd0,
+ .CVR = 0xd4,
+ .CECR = 0xd8,
+ .WPMR = 0xe4,
+ .WPSR = 0xe8,
+ .VERSION = 0xfc,
+};
-#define AT91_SAMA5D2_TOUCH_X_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
- AT91_SAMA5D2_DIFF_CHAN_CNT * 2)
-#define AT91_SAMA5D2_TOUCH_Y_CHAN_IDX (AT91_SAMA5D2_TOUCH_X_CHAN_IDX + 1)
-#define AT91_SAMA5D2_TOUCH_P_CHAN_IDX (AT91_SAMA5D2_TOUCH_Y_CHAN_IDX + 1)
-#define AT91_SAMA5D2_MAX_CHAN_IDX AT91_SAMA5D2_TOUCH_P_CHAN_IDX
+static const struct at91_adc_reg_layout sama7g5_layout = {
+ .CR = 0x00,
+ .MR = 0x04,
+ .SEQR1 = 0x08,
+ .SEQR2 = 0x0c,
+ .CHER = 0x10,
+ .CHDR = 0x14,
+ .CHSR = 0x18,
+ .LCDR = 0x20,
+ .IER = 0x24,
+ .IDR = 0x28,
+ .IMR = 0x2c,
+ .ISR = 0x30,
+ .EOC_IER = 0x34,
+ .EOC_IDR = 0x38,
+ .EOC_IMR = 0x3c,
+ .EOC_ISR = 0x40,
+ .OVER = 0x4c,
+ .EMR = 0x50,
+ .CWR = 0x54,
+ .COR = 0x5c,
+ .COR_diff_offset = 0,
+ .ACR = 0xe0,
+ .TRGR = 0x100,
+ .COSR = 0x104,
+ .CVR = 0x108,
+ .CECR = 0x10c,
+ .WPMR = 0x118,
+ .WPSR = 0x11c,
+ .VERSION = 0x130,
+};
#define AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
#define AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US 200
@@ -237,18 +302,6 @@
#define AT91_SAMA5D2_MAX_POS_BITS 12
-/*
- * Maximum number of bytes to hold conversion from all channels
- * without the timestamp.
- */
-#define AT91_BUFFER_MAX_CONVERSION_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \
- AT91_SAMA5D2_DIFF_CHAN_CNT) * 2)
-
-/* This total must also include the timestamp */
-#define AT91_BUFFER_MAX_BYTES (AT91_BUFFER_MAX_CONVERSION_BYTES + 8)
-
-#define AT91_BUFFER_MAX_HWORDS (AT91_BUFFER_MAX_BYTES / 2)
-
#define AT91_HWFIFO_MAX_SIZE_STR "128"
#define AT91_HWFIFO_MAX_SIZE 128
@@ -257,12 +310,12 @@
#define AT91_OSR_4SAMPLES 4
#define AT91_OSR_16SAMPLES 16
-#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
+#define AT91_SAMA5D2_CHAN_SINGLE(index, num, addr) \
{ \
.type = IIO_VOLTAGE, \
.channel = num, \
.address = addr, \
- .scan_index = num, \
+ .scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 14, \
@@ -276,14 +329,14 @@
.indexed = 1, \
}
-#define AT91_SAMA5D2_CHAN_DIFF(num, num2, addr) \
+#define AT91_SAMA5D2_CHAN_DIFF(index, num, num2, addr) \
{ \
.type = IIO_VOLTAGE, \
.differential = 1, \
.channel = num, \
.channel2 = num2, \
.address = addr, \
- .scan_index = num + AT91_SAMA5D2_SINGLE_CHAN_CNT, \
+ .scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 14, \
@@ -330,13 +383,51 @@
.datasheet_name = name, \
}
-#define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
-#define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
+#define at91_adc_readl(st, reg) \
+ readl_relaxed((st)->base + (st)->soc_info.platform->layout->reg)
+#define at91_adc_read_chan(st, reg) \
+ readl_relaxed((st)->base + reg)
+#define at91_adc_writel(st, reg, val) \
+ writel_relaxed(val, (st)->base + (st)->soc_info.platform->layout->reg)
+
+/**
+ * struct at91_adc_platform - at91-sama5d2 platform information struct
+ * @layout: pointer to the reg layout struct
+ * @adc_channels: pointer to an array of channels for registering in
+ * the iio subsystem
+ * @nr_channels: number of physical channels available
+ * @touch_chan_x: index of the touchscreen X channel
+ * @touch_chan_y: index of the touchscreen Y channel
+ * @touch_chan_p: index of the touchscreen P channel
+ * @max_channels: number of total channels
+ * @max_index: highest channel index (highest index may be higher
+ * than the total channel number)
+ * @hw_trig_cnt: number of possible hardware triggers
+ */
+struct at91_adc_platform {
+ const struct at91_adc_reg_layout *layout;
+ const struct iio_chan_spec (*adc_channels)[];
+ unsigned int nr_channels;
+ unsigned int touch_chan_x;
+ unsigned int touch_chan_y;
+ unsigned int touch_chan_p;
+ unsigned int max_channels;
+ unsigned int max_index;
+ unsigned int hw_trig_cnt;
+};
+/**
+ * struct at91_adc_soc_info - at91-sama5d2 soc information struct
+ * @startup_time: device startup time
+ * @min_sample_rate: minimum sample rate in Hz
+ * @max_sample_rate: maximum sample rate in Hz
+ * @platform: pointer to the platform structure
+ */
struct at91_adc_soc_info {
unsigned startup_time;
unsigned min_sample_rate;
unsigned max_sample_rate;
+ const struct at91_adc_platform *platform;
};
struct at91_adc_trigger {
@@ -384,6 +475,15 @@ struct at91_adc_touch {
struct work_struct workq;
};
+/*
+ * Buffer size requirements:
+ * No channels * bytes_per_channel(2) + timestamp bytes (8)
+ * Divided by 2 because we need half words.
+ * We assume 32 channels for now, has to be increased if needed.
+ * Nobody minds a buffer being too big.
+ */
+#define AT91_BUFFER_MAX_HWORDS ((32 * 2 + 8) / 2)
+
struct at91_adc_state {
void __iomem *base;
int irq;
@@ -439,29 +539,94 @@ static const struct at91_adc_trigger at91_adc_trigger_list[] = {
},
};
-static const struct iio_chan_spec at91_adc_channels[] = {
- AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
- AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
- AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
- AT91_SAMA5D2_CHAN_SINGLE(3, 0x5c),
- AT91_SAMA5D2_CHAN_SINGLE(4, 0x60),
- AT91_SAMA5D2_CHAN_SINGLE(5, 0x64),
- AT91_SAMA5D2_CHAN_SINGLE(6, 0x68),
- AT91_SAMA5D2_CHAN_SINGLE(7, 0x6c),
- AT91_SAMA5D2_CHAN_SINGLE(8, 0x70),
- AT91_SAMA5D2_CHAN_SINGLE(9, 0x74),
- AT91_SAMA5D2_CHAN_SINGLE(10, 0x78),
- AT91_SAMA5D2_CHAN_SINGLE(11, 0x7c),
- AT91_SAMA5D2_CHAN_DIFF(0, 1, 0x50),
- AT91_SAMA5D2_CHAN_DIFF(2, 3, 0x58),
- AT91_SAMA5D2_CHAN_DIFF(4, 5, 0x60),
- AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
- AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
- AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
- IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_TIMESTAMP_CHAN_IDX),
- AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_X_CHAN_IDX, "x", IIO_MOD_X),
- AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, "y", IIO_MOD_Y),
- AT91_SAMA5D2_CHAN_PRESSURE(AT91_SAMA5D2_TOUCH_P_CHAN_IDX, "pressure"),
+static const struct iio_chan_spec at91_sama5d2_adc_channels[] = {
+ AT91_SAMA5D2_CHAN_SINGLE(0, 0, 0x50),
+ AT91_SAMA5D2_CHAN_SINGLE(1, 1, 0x54),
+ AT91_SAMA5D2_CHAN_SINGLE(2, 2, 0x58),
+ AT91_SAMA5D2_CHAN_SINGLE(3, 3, 0x5c),
+ AT91_SAMA5D2_CHAN_SINGLE(4, 4, 0x60),
+ AT91_SAMA5D2_CHAN_SINGLE(5, 5, 0x64),
+ AT91_SAMA5D2_CHAN_SINGLE(6, 6, 0x68),
+ AT91_SAMA5D2_CHAN_SINGLE(7, 7, 0x6c),
+ AT91_SAMA5D2_CHAN_SINGLE(8, 8, 0x70),
+ AT91_SAMA5D2_CHAN_SINGLE(9, 9, 0x74),
+ AT91_SAMA5D2_CHAN_SINGLE(10, 10, 0x78),
+ AT91_SAMA5D2_CHAN_SINGLE(11, 11, 0x7c),
+ /* original ABI has the differential channels with a gap in between */
+ AT91_SAMA5D2_CHAN_DIFF(12, 0, 1, 0x50),
+ AT91_SAMA5D2_CHAN_DIFF(14, 2, 3, 0x58),
+ AT91_SAMA5D2_CHAN_DIFF(16, 4, 5, 0x60),
+ AT91_SAMA5D2_CHAN_DIFF(18, 6, 7, 0x68),
+ AT91_SAMA5D2_CHAN_DIFF(20, 8, 9, 0x70),
+ AT91_SAMA5D2_CHAN_DIFF(22, 10, 11, 0x78),
+ IIO_CHAN_SOFT_TIMESTAMP(23),
+ AT91_SAMA5D2_CHAN_TOUCH(24, "x", IIO_MOD_X),
+ AT91_SAMA5D2_CHAN_TOUCH(25, "y", IIO_MOD_Y),
+ AT91_SAMA5D2_CHAN_PRESSURE(26, "pressure"),
+};
+
+static const struct iio_chan_spec at91_sama7g5_adc_channels[] = {
+ AT91_SAMA5D2_CHAN_SINGLE(0, 0, 0x60),
+ AT91_SAMA5D2_CHAN_SINGLE(1, 1, 0x64),
+ AT91_SAMA5D2_CHAN_SINGLE(2, 2, 0x68),
+ AT91_SAMA5D2_CHAN_SINGLE(3, 3, 0x6c),
+ AT91_SAMA5D2_CHAN_SINGLE(4, 4, 0x70),
+ AT91_SAMA5D2_CHAN_SINGLE(5, 5, 0x74),
+ AT91_SAMA5D2_CHAN_SINGLE(6, 6, 0x78),
+ AT91_SAMA5D2_CHAN_SINGLE(7, 7, 0x7c),
+ AT91_SAMA5D2_CHAN_SINGLE(8, 8, 0x80),
+ AT91_SAMA5D2_CHAN_SINGLE(9, 9, 0x84),
+ AT91_SAMA5D2_CHAN_SINGLE(10, 10, 0x88),
+ AT91_SAMA5D2_CHAN_SINGLE(11, 11, 0x8c),
+ AT91_SAMA5D2_CHAN_SINGLE(12, 12, 0x90),
+ AT91_SAMA5D2_CHAN_SINGLE(13, 13, 0x94),
+ AT91_SAMA5D2_CHAN_SINGLE(14, 14, 0x98),
+ AT91_SAMA5D2_CHAN_SINGLE(15, 15, 0x9c),
+ AT91_SAMA5D2_CHAN_DIFF(16, 0, 1, 0x60),
+ AT91_SAMA5D2_CHAN_DIFF(17, 2, 3, 0x68),
+ AT91_SAMA5D2_CHAN_DIFF(18, 4, 5, 0x70),
+ AT91_SAMA5D2_CHAN_DIFF(19, 6, 7, 0x78),
+ AT91_SAMA5D2_CHAN_DIFF(20, 8, 9, 0x80),
+ AT91_SAMA5D2_CHAN_DIFF(21, 10, 11, 0x88),
+ AT91_SAMA5D2_CHAN_DIFF(22, 12, 13, 0x90),
+ AT91_SAMA5D2_CHAN_DIFF(23, 14, 15, 0x98),
+ IIO_CHAN_SOFT_TIMESTAMP(24),
+};
+
+static const struct at91_adc_platform sama5d2_platform = {
+ .layout = &sama5d2_layout,
+ .adc_channels = &at91_sama5d2_adc_channels,
+#define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
+#define AT91_SAMA5D2_DIFF_CHAN_CNT 6
+ .nr_channels = AT91_SAMA5D2_SINGLE_CHAN_CNT +
+ AT91_SAMA5D2_DIFF_CHAN_CNT,
+#define AT91_SAMA5D2_TOUCH_X_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
+ AT91_SAMA5D2_DIFF_CHAN_CNT * 2)
+ .touch_chan_x = AT91_SAMA5D2_TOUCH_X_CHAN_IDX,
+#define AT91_SAMA5D2_TOUCH_Y_CHAN_IDX (AT91_SAMA5D2_TOUCH_X_CHAN_IDX + 1)
+ .touch_chan_y = AT91_SAMA5D2_TOUCH_Y_CHAN_IDX,
+#define AT91_SAMA5D2_TOUCH_P_CHAN_IDX (AT91_SAMA5D2_TOUCH_Y_CHAN_IDX + 1)
+ .touch_chan_p = AT91_SAMA5D2_TOUCH_P_CHAN_IDX,
+#define AT91_SAMA5D2_MAX_CHAN_IDX AT91_SAMA5D2_TOUCH_P_CHAN_IDX
+ .max_channels = ARRAY_SIZE(at91_sama5d2_adc_channels),
+ .max_index = AT91_SAMA5D2_MAX_CHAN_IDX,
+#define AT91_SAMA5D2_HW_TRIG_CNT 3
+ .hw_trig_cnt = AT91_SAMA5D2_HW_TRIG_CNT,
+};
+
+static const struct at91_adc_platform sama7g5_platform = {
+ .layout = &sama7g5_layout,
+ .adc_channels = &at91_sama7g5_adc_channels,
+#define AT91_SAMA7G5_SINGLE_CHAN_CNT 16
+#define AT91_SAMA7G5_DIFF_CHAN_CNT 8
+ .nr_channels = AT91_SAMA7G5_SINGLE_CHAN_CNT +
+ AT91_SAMA7G5_DIFF_CHAN_CNT,
+#define AT91_SAMA7G5_MAX_CHAN_IDX (AT91_SAMA7G5_SINGLE_CHAN_CNT + \
+ AT91_SAMA7G5_DIFF_CHAN_CNT)
+ .max_channels = ARRAY_SIZE(at91_sama7g5_adc_channels),
+ .max_index = AT91_SAMA7G5_MAX_CHAN_IDX,
+#define AT91_SAMA7G5_HW_TRIG_CNT 3
+ .hw_trig_cnt = AT91_SAMA7G5_HW_TRIG_CNT,
};
static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
@@ -495,6 +660,7 @@ static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
{
u32 mask = 0;
u8 bit;
+ struct at91_adc_state *st = iio_priv(indio_dev);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
@@ -503,13 +669,66 @@ static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
mask |= BIT(chan->channel);
}
- return mask & GENMASK(11, 0);
+ return mask & GENMASK(st->soc_info.platform->nr_channels, 0);
+}
+
+static void at91_adc_cor(struct at91_adc_state *st,
+ struct iio_chan_spec const *chan)
+{
+ u32 cor, cur_cor;
+
+ cor = BIT(chan->channel) | BIT(chan->channel2);
+
+ cur_cor = at91_adc_readl(st, COR);
+ cor <<= st->soc_info.platform->layout->COR_diff_offset;
+ if (chan->differential)
+ at91_adc_writel(st, COR, cur_cor | cor);
+ else
+ at91_adc_writel(st, COR, cur_cor & ~cor);
+}
+
+static void at91_adc_irq_status(struct at91_adc_state *st, u32 *status,
+ u32 *eoc)
+{
+ *status = at91_adc_readl(st, ISR);
+ if (st->soc_info.platform->layout->EOC_ISR)
+ *eoc = at91_adc_readl(st, EOC_ISR);
+ else
+ *eoc = *status;
+}
+
+static void at91_adc_irq_mask(struct at91_adc_state *st, u32 *status, u32 *eoc)
+{
+ *status = at91_adc_readl(st, IMR);
+ if (st->soc_info.platform->layout->EOC_IMR)
+ *eoc = at91_adc_readl(st, EOC_IMR);
+ else
+ *eoc = *status;
+}
+
+static void at91_adc_eoc_dis(struct at91_adc_state *st, unsigned int channel)
+{
+ /*
+ * On some products having the EOC bits in a separate register,
+ * errata recommends not writing this register (EOC_IDR).
+ * On products having the EOC bits in the IDR register, it's fine to write it.
+ */
+ if (!st->soc_info.platform->layout->EOC_IDR)
+ at91_adc_writel(st, IDR, BIT(channel));
+}
+
+static void at91_adc_eoc_ena(struct at91_adc_state *st, unsigned int channel)
+{
+ if (!st->soc_info.platform->layout->EOC_IDR)
+ at91_adc_writel(st, IER, BIT(channel));
+ else
+ at91_adc_writel(st, EOC_IER, BIT(channel));
}
static void at91_adc_config_emr(struct at91_adc_state *st)
{
/* configure the extended mode register */
- unsigned int emr = at91_adc_readl(st, AT91_SAMA5D2_EMR);
+ unsigned int emr = at91_adc_readl(st, EMR);
/* select oversampling per single trigger event */
emr |= AT91_SAMA5D2_EMR_ASTE(1);
@@ -533,7 +752,7 @@ static void at91_adc_config_emr(struct at91_adc_state *st)
break;
}
- at91_adc_writel(st, AT91_SAMA5D2_EMR, emr);
+ at91_adc_writel(st, EMR, emr);
}
static int at91_adc_adjust_val_osr(struct at91_adc_state *st, int *val)
@@ -586,9 +805,9 @@ static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
if (!state) {
/* disabling touch IRQs and setting mode to no touch enabled */
- at91_adc_writel(st, AT91_SAMA5D2_IDR,
+ at91_adc_writel(st, IDR,
AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN);
- at91_adc_writel(st, AT91_SAMA5D2_TSMR, 0);
+ at91_adc_writel(st, TSMR, 0);
return 0;
}
/*
@@ -614,26 +833,26 @@ static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
tsmr |= AT91_SAMA5D2_TSMR_PENDET_ENA;
tsmr |= AT91_SAMA5D2_TSMR_TSFREQ(2) & AT91_SAMA5D2_TSMR_TSFREQ_MASK;
- at91_adc_writel(st, AT91_SAMA5D2_TSMR, tsmr);
+ at91_adc_writel(st, TSMR, tsmr);
- acr = at91_adc_readl(st, AT91_SAMA5D2_ACR);
+ acr = at91_adc_readl(st, ACR);
acr &= ~AT91_SAMA5D2_ACR_PENDETSENS_MASK;
acr |= 0x02 & AT91_SAMA5D2_ACR_PENDETSENS_MASK;
- at91_adc_writel(st, AT91_SAMA5D2_ACR, acr);
+ at91_adc_writel(st, ACR, acr);
/* Sample Period Time = (TRGPER + 1) / ADCClock */
st->touch_st.sample_period_val =
round_up((AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US *
clk_khz / 1000) - 1, 1);
/* enable pen detect IRQ */
- at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
+ at91_adc_writel(st, IER, AT91_SAMA5D2_IER_PEN);
return 0;
}
static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg)
{
- u32 val;
+ u32 val = 0;
u32 scale, result, pos;
/*
@@ -642,7 +861,11 @@ static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg)
* max = 2^AT91_SAMA5D2_MAX_POS_BITS - 1
*/
/* first half of register is the x or y, second half is the scale */
- val = at91_adc_readl(st, reg);
+ if (reg == st->soc_info.platform->layout->XPOSR)
+ val = at91_adc_readl(st, XPOSR);
+ else if (reg == st->soc_info.platform->layout->YPOSR)
+ val = at91_adc_readl(st, YPOSR);
+
if (!val)
dev_dbg(&st->indio_dev->dev, "pos is 0\n");
@@ -660,13 +883,13 @@ static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg)
static u16 at91_adc_touch_x_pos(struct at91_adc_state *st)
{
- st->touch_st.x_pos = at91_adc_touch_pos(st, AT91_SAMA5D2_XPOSR);
+ st->touch_st.x_pos = at91_adc_touch_pos(st, st->soc_info.platform->layout->XPOSR);
return st->touch_st.x_pos;
}
static u16 at91_adc_touch_y_pos(struct at91_adc_state *st)
{
- return at91_adc_touch_pos(st, AT91_SAMA5D2_YPOSR);
+ return at91_adc_touch_pos(st, st->soc_info.platform->layout->YPOSR);
}
static u16 at91_adc_touch_pressure(struct at91_adc_state *st)
@@ -678,7 +901,7 @@ static u16 at91_adc_touch_pressure(struct at91_adc_state *st)
u32 factor = 1000;
/* calculate the pressure */
- val = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
+ val = at91_adc_readl(st, PRESSR);
z1 = val & AT91_SAMA5D2_XYZ_MASK;
z2 = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
@@ -702,9 +925,9 @@ static int at91_adc_read_position(struct at91_adc_state *st, int chan, u16 *val)
*val = 0;
if (!st->touch_st.touching)
return -ENODATA;
- if (chan == AT91_SAMA5D2_TOUCH_X_CHAN_IDX)
+ if (chan == st->soc_info.platform->touch_chan_x)
*val = at91_adc_touch_x_pos(st);
- else if (chan == AT91_SAMA5D2_TOUCH_Y_CHAN_IDX)
+ else if (chan == st->soc_info.platform->touch_chan_y)
*val = at91_adc_touch_y_pos(st);
else
return -ENODATA;
@@ -717,7 +940,7 @@ static int at91_adc_read_pressure(struct at91_adc_state *st, int chan, u16 *val)
*val = 0;
if (!st->touch_st.touching)
return -ENODATA;
- if (chan == AT91_SAMA5D2_TOUCH_P_CHAN_IDX)
+ if (chan == st->soc_info.platform->touch_chan_p)
*val = at91_adc_touch_pressure(st);
else
return -ENODATA;
@@ -729,7 +952,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio);
- u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
+ u32 status = at91_adc_readl(st, TRGR);
/* clear TRGMOD */
status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
@@ -738,7 +961,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
status |= st->selected_trig->trgmod_value;
/* set/unset hw trigger */
- at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
+ at91_adc_writel(st, TRGR, status);
return 0;
}
@@ -755,7 +978,7 @@ static void at91_adc_reenable_trigger(struct iio_trigger *trig)
enable_irq(st->irq);
/* Needed to ACK the DRDY interruption */
- at91_adc_readl(st, AT91_SAMA5D2_LCDR);
+ at91_adc_readl(st, LCDR);
}
static const struct iio_trigger_ops at91_adc_trigger_ops = {
@@ -850,7 +1073,7 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
}
/* enable general overrun error signaling */
- at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_GOVRE);
+ at91_adc_writel(st, IER, AT91_SAMA5D2_IER_GOVRE);
/* Issue pending DMA requests */
dma_async_issue_pending(st->dma_st.dma_chan);
@@ -880,7 +1103,7 @@ static bool at91_adc_current_chan_is_touch(struct iio_dev *indio_dev)
return !!bitmap_subset(indio_dev->active_scan_mask,
&st->touch_st.channels_bitmask,
- AT91_SAMA5D2_MAX_CHAN_IDX + 1);
+ st->soc_info.platform->max_index + 1);
}
static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
@@ -908,8 +1131,6 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
indio_dev->num_channels) {
struct iio_chan_spec const *chan =
at91_adc_chan_get(indio_dev, bit);
- u32 cor;
-
if (!chan)
continue;
/* these channel types cannot be handled by this trigger */
@@ -917,22 +1138,13 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
chan->type == IIO_PRESSURE)
continue;
- cor = at91_adc_readl(st, AT91_SAMA5D2_COR);
-
- if (chan->differential)
- cor |= (BIT(chan->channel) | BIT(chan->channel2)) <<
- AT91_SAMA5D2_COR_DIFF_OFFSET;
- else
- cor &= ~(BIT(chan->channel) <<
- AT91_SAMA5D2_COR_DIFF_OFFSET);
-
- at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
+ at91_adc_cor(st, chan);
- at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
+ at91_adc_writel(st, CHER, BIT(chan->channel));
}
if (at91_adc_buffer_check_use_irq(indio_dev, st))
- at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_DRDY);
+ at91_adc_writel(st, IER, AT91_SAMA5D2_IER_DRDY);
return 0;
}
@@ -968,17 +1180,17 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
chan->type == IIO_PRESSURE)
continue;
- at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
+ at91_adc_writel(st, CHDR, BIT(chan->channel));
if (st->dma_st.dma_chan)
- at91_adc_readl(st, chan->address);
+ at91_adc_read_chan(st, chan->address);
}
if (at91_adc_buffer_check_use_irq(indio_dev, st))
- at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_DRDY);
+ at91_adc_writel(st, IDR, AT91_SAMA5D2_IER_DRDY);
/* read overflow register to clear possible overflow status */
- at91_adc_readl(st, AT91_SAMA5D2_OVER);
+ at91_adc_readl(st, OVER);
/* if we are using DMA we must clear registers and end DMA */
if (st->dma_st.dma_chan)
@@ -1021,13 +1233,15 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
u8 bit;
u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev);
unsigned int timeout = 50;
+ u32 status, imr, eoc = 0, eoc_imr;
/*
* Check if the conversion is ready. If not, wait a little bit, and
* in case of timeout exit with an error.
*/
- while ((at91_adc_readl(st, AT91_SAMA5D2_ISR) & mask) != mask &&
- timeout) {
+ while (((eoc & mask) != mask) && timeout) {
+ at91_adc_irq_status(st, &status, &eoc);
+ at91_adc_irq_mask(st, &imr, &eoc_imr);
usleep_range(50, 100);
timeout--;
}
@@ -1054,7 +1268,7 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
* Thus, emit a warning.
*/
if (chan->type == IIO_VOLTAGE) {
- val = at91_adc_readl(st, chan->address);
+ val = at91_adc_read_chan(st, chan->address);
at91_adc_adjust_val_osr(st, &val);
st->buffer[i] = val;
} else {
@@ -1075,7 +1289,7 @@ static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
s64 interval;
int sample_index = 0, sample_count, sample_size;
- u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
+ u32 status = at91_adc_readl(st, ISR);
/* if we reached this point, we cannot sample faster */
if (status & AT91_SAMA5D2_IER_GOVRE)
pr_info_ratelimited("%s: conversion overrun detected\n",
@@ -1127,7 +1341,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
* actually polling the trigger now.
*/
if (iio_trigger_validate_own_device(indio_dev->trig, indio_dev))
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
+ at91_adc_writel(st, CR, AT91_SAMA5D2_CR_START);
if (st->dma_st.dma_chan)
at91_adc_trigger_handler_dma(indio_dev);
@@ -1174,11 +1388,11 @@ static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq)
startup = at91_adc_startup_time(st->soc_info.startup_time,
freq / 1000);
- mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
+ mr = at91_adc_readl(st, MR);
mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
mr |= AT91_SAMA5D2_MR_STARTUP(startup);
mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
- at91_adc_writel(st, AT91_SAMA5D2_MR, mr);
+ at91_adc_writel(st, MR, mr);
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
freq, startup, prescal);
@@ -1198,7 +1412,7 @@ static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
int i = 0;
for_each_set_bit(bit, indio_dev->active_scan_mask,
- AT91_SAMA5D2_MAX_CHAN_IDX + 1) {
+ st->soc_info.platform->max_index + 1) {
struct iio_chan_spec const *chan =
at91_adc_chan_get(indio_dev, bit);
@@ -1224,12 +1438,11 @@ static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
static void at91_adc_pen_detect_interrupt(struct at91_adc_state *st)
{
- at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_PEN);
- at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_NOPEN |
+ at91_adc_writel(st, IDR, AT91_SAMA5D2_IER_PEN);
+ at91_adc_writel(st, IER, AT91_SAMA5D2_IER_NOPEN |
AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
AT91_SAMA5D2_IER_PRDY);
- at91_adc_writel(st, AT91_SAMA5D2_TRGR,
- AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC |
+ at91_adc_writel(st, TRGR, AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC |
AT91_SAMA5D2_TRGR_TRGPER(st->touch_st.sample_period_val));
st->touch_st.touching = true;
}
@@ -1238,16 +1451,15 @@ static void at91_adc_no_pen_detect_interrupt(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
- at91_adc_writel(st, AT91_SAMA5D2_TRGR,
- AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
- at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_NOPEN |
+ at91_adc_writel(st, TRGR, AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
+ at91_adc_writel(st, IDR, AT91_SAMA5D2_IER_NOPEN |
AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
AT91_SAMA5D2_IER_PRDY);
st->touch_st.touching = false;
at91_adc_touch_data_handler(indio_dev);
- at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
+ at91_adc_writel(st, IER, AT91_SAMA5D2_IER_PEN);
}
static void at91_adc_workq_handler(struct work_struct *workq)
@@ -1265,12 +1477,14 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
{
struct iio_dev *indio = private;
struct at91_adc_state *st = iio_priv(indio);
- u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
- u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
+ u32 status, eoc, imr, eoc_imr;
u32 rdy_mask = AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
AT91_SAMA5D2_IER_PRDY;
- if (!(status & imr))
+ at91_adc_irq_status(st, &status, &eoc);
+ at91_adc_irq_mask(st, &imr, &eoc_imr);
+
+ if (!(status & imr) && !(eoc & eoc_imr))
return IRQ_NONE;
if (status & AT91_SAMA5D2_IER_PEN) {
/* pen detected IRQ */
@@ -1287,9 +1501,9 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
* touching, but the measurements are not ready yet.
* read and ignore.
*/
- status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR);
- status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
- status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
+ status = at91_adc_readl(st, XPOSR);
+ status = at91_adc_readl(st, YPOSR);
+ status = at91_adc_readl(st, PRESSR);
} else if (iio_buffer_enabled(indio) &&
(status & AT91_SAMA5D2_IER_DRDY)) {
/* triggered buffer without DMA */
@@ -1301,7 +1515,7 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
WARN(true, "Unexpected irq occurred\n");
} else if (!iio_buffer_enabled(indio)) {
/* software requested conversion */
- st->conversion_value = at91_adc_readl(st, st->chan->address);
+ st->conversion_value = at91_adc_read_chan(st, st->chan->address);
st->conversion_done = true;
wake_up_interruptible(&st->wq_data_available);
}
@@ -1312,7 +1526,6 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct at91_adc_state *st = iio_priv(indio_dev);
- u32 cor = 0;
u16 tmp_val;
int ret;
@@ -1358,14 +1571,10 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
st->chan = chan;
- if (chan->differential)
- cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
- AT91_SAMA5D2_COR_DIFF_OFFSET;
-
- at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
- at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
+ at91_adc_cor(st, chan);
+ at91_adc_writel(st, CHER, BIT(chan->channel));
+ at91_adc_eoc_ena(st, chan->channel);
+ at91_adc_writel(st, CR, AT91_SAMA5D2_CR_START);
ret = wait_event_interruptible_timeout(st->wq_data_available,
st->conversion_done,
@@ -1381,11 +1590,11 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
st->conversion_done = false;
}
- at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
+ at91_adc_eoc_dis(st, st->chan->channel);
+ at91_adc_writel(st, CHDR, BIT(chan->channel));
/* Needed to ACK the DRDY interruption */
- at91_adc_readl(st, AT91_SAMA5D2_LCDR);
+ at91_adc_readl(st, LCDR);
mutex_unlock(&st->lock);
@@ -1457,14 +1666,15 @@ static void at91_adc_dma_init(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
struct dma_slave_config config = {0};
+ /* we have 2 bytes for each channel */
+ unsigned int sample_size = st->soc_info.platform->nr_channels * 2;
/*
* We make the buffer double the size of the fifo,
* such that DMA uses one half of the buffer (full fifo size)
* and the software uses the other half to read/write.
*/
unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE *
- AT91_BUFFER_MAX_CONVERSION_BYTES * 2,
- PAGE_SIZE);
+ sample_size * 2, PAGE_SIZE);
if (st->dma_st.dma_chan)
return;
@@ -1488,7 +1698,7 @@ static void at91_adc_dma_init(struct platform_device *pdev)
/* Configure DMA channel to read data register */
config.direction = DMA_DEV_TO_MEM;
config.src_addr = (phys_addr_t)(st->dma_st.phys_addr
- + AT91_SAMA5D2_LCDR);
+ + st->soc_info.platform->layout->LCDR);
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
config.src_maxburst = 1;
config.dst_maxburst = 1;
@@ -1517,9 +1727,10 @@ static void at91_adc_dma_disable(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
+ /* we have 2 bytes for each channel */
+ unsigned int sample_size = st->soc_info.platform->nr_channels * 2;
unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE *
- AT91_BUFFER_MAX_CONVERSION_BYTES * 2,
- PAGE_SIZE);
+ sample_size * 2, PAGE_SIZE);
/* if we are not using DMA, just return */
if (!st->dma_st.dma_chan)
@@ -1580,14 +1791,14 @@ static int at91_adc_update_scan_mode(struct iio_dev *indio_dev,
struct at91_adc_state *st = iio_priv(indio_dev);
if (bitmap_subset(scan_mask, &st->touch_st.channels_bitmask,
- AT91_SAMA5D2_MAX_CHAN_IDX + 1))
+ st->soc_info.platform->max_index + 1))
return 0;
/*
* if the new bitmap is a combination of touchscreen and regular
* channels, then we are not fine
*/
if (bitmap_intersects(&st->touch_st.channels_bitmask, scan_mask,
- AT91_SAMA5D2_MAX_CHAN_IDX + 1))
+ st->soc_info.platform->max_index + 1))
return -EINVAL;
return 0;
}
@@ -1596,13 +1807,15 @@ static void at91_adc_hw_init(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
- at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
+ at91_adc_writel(st, CR, AT91_SAMA5D2_CR_SWRST);
+ if (st->soc_info.platform->layout->EOC_IDR)
+ at91_adc_writel(st, EOC_IDR, 0xffffffff);
+ at91_adc_writel(st, IDR, 0xffffffff);
/*
* Transfer field must be set to 2 according to the datasheet and
* allows different analog settings for each channel.
*/
- at91_adc_writel(st, AT91_SAMA5D2_MR,
+ at91_adc_writel(st, MR,
AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
at91_adc_setup_samp_freq(indio_dev, st->soc_info.min_sample_rate);
@@ -1681,8 +1894,8 @@ static int at91_adc_buffer_and_trigger_init(struct device *dev,
fifo_attrs = NULL;
ret = devm_iio_triggered_buffer_setup_ext(&indio->dev, indio,
- &iio_pollfunc_store_time,
- &at91_adc_trigger_handler, &at91_buffer_setup_ops, fifo_attrs);
+ &iio_pollfunc_store_time, &at91_adc_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN, &at91_buffer_setup_ops, fifo_attrs);
if (ret < 0) {
dev_err(dev, "couldn't initialize the buffer.\n");
return ret;
@@ -1718,21 +1931,23 @@ static int at91_adc_probe(struct platform_device *pdev)
if (!indio_dev)
return -ENOMEM;
+ st = iio_priv(indio_dev);
+ st->indio_dev = indio_dev;
+
+ st->soc_info.platform = of_device_get_match_data(&pdev->dev);
+
indio_dev->name = dev_name(&pdev->dev);
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->info = &at91_adc_info;
- indio_dev->channels = at91_adc_channels;
- indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
-
- st = iio_priv(indio_dev);
- st->indio_dev = indio_dev;
+ indio_dev->channels = *st->soc_info.platform->adc_channels;
+ indio_dev->num_channels = st->soc_info.platform->max_channels;
bitmap_set(&st->touch_st.channels_bitmask,
- AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
+ st->soc_info.platform->touch_chan_x, 1);
bitmap_set(&st->touch_st.channels_bitmask,
- AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1);
+ st->soc_info.platform->touch_chan_y, 1);
bitmap_set(&st->touch_st.channels_bitmask,
- AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
+ st->soc_info.platform->touch_chan_p, 1);
st->oversampling_ratio = AT91_OSR_1SAMPLES;
@@ -1772,7 +1987,7 @@ static int at91_adc_probe(struct platform_device *pdev)
st->selected_trig = NULL;
/* find the right trigger, or no trigger at all */
- for (i = 0; i < AT91_SAMA5D2_HW_TRIG_CNT + 1; i++)
+ for (i = 0; i < st->soc_info.platform->hw_trig_cnt + 1; i++)
if (at91_adc_trigger_list[i].edge_type == edge_type) {
st->selected_trig = &at91_adc_trigger_list[i];
break;
@@ -1833,12 +2048,12 @@ static int at91_adc_probe(struct platform_device *pdev)
goto vref_disable;
}
- at91_adc_hw_init(indio_dev);
-
ret = clk_prepare_enable(st->per_clk);
if (ret)
goto vref_disable;
+ at91_adc_hw_init(indio_dev);
+
platform_set_drvdata(pdev, indio_dev);
ret = at91_adc_buffer_and_trigger_init(&pdev->dev, indio_dev);
@@ -1857,7 +2072,7 @@ static int at91_adc_probe(struct platform_device *pdev)
st->selected_trig->name);
dev_info(&pdev->dev, "version: %x\n",
- readl_relaxed(st->base + AT91_SAMA5D2_VERSION));
+ readl_relaxed(st->base + st->soc_info.platform->layout->VERSION));
return 0;
@@ -1900,7 +2115,7 @@ static __maybe_unused int at91_adc_suspend(struct device *dev)
* and can be used by for other devices.
* Otherwise, ADC will hog them and we can't go to suspend mode.
*/
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
+ at91_adc_writel(st, CR, AT91_SAMA5D2_CR_SWRST);
clk_disable_unprepare(st->per_clk);
regulator_disable(st->vref);
@@ -1960,6 +2175,10 @@ static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
static const struct of_device_id at91_adc_dt_match[] = {
{
.compatible = "atmel,sama5d2-adc",
+ .data = (const void *)&sama5d2_platform,
+ }, {
+ .compatible = "microchip,sama7g5-adc",
+ .data = (const void *)&sama7g5_platform,
}, {
/* sentinel */
}
@@ -1977,6 +2196,7 @@ static struct platform_driver at91_adc_driver = {
};
module_platform_driver(at91_adc_driver)
-MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@atmel.com>");
+MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@microchip.com>");
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com");
MODULE_DESCRIPTION("Atmel AT91 SAMA5D2 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
index 5f5e8b39e4d2..a4b8be5b8f88 100644
--- a/drivers/iio/adc/axp288_adc.c
+++ b/drivers/iio/adc/axp288_adc.c
@@ -259,7 +259,7 @@ static int axp288_adc_probe(struct platform_device *pdev)
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0)
return info->irq;
- platform_set_drvdata(pdev, indio_dev);
+
info->regmap = axp20x->regmap;
/*
* Set ADC to enabled state at all time, including system suspend.
@@ -276,31 +276,12 @@ static int axp288_adc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
indio_dev->info = &axp288_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
+
+ ret = devm_iio_map_array_register(&pdev->dev, indio_dev, axp288_adc_default_maps);
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to register iio device\n");
- goto err_array_unregister;
- }
- return 0;
-
-err_array_unregister:
- iio_map_array_unregister(indio_dev);
-
- return ret;
-}
-
-static int axp288_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;
+ return devm_iio_device_register(&pdev->dev, indio_dev);
}
static const struct platform_device_id axp288_adc_id_table[] = {
@@ -310,7 +291,6 @@ static const struct platform_device_id axp288_adc_id_table[] = {
static struct platform_driver axp288_adc_driver = {
.probe = axp288_adc_probe,
- .remove = axp288_adc_remove,
.id_table = axp288_adc_id_table,
.driver = {
.name = "axp288_adc",
diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c
index 8b04b95b7b7a..03987d7e6b3d 100644
--- a/drivers/iio/adc/berlin2-adc.c
+++ b/drivers/iio/adc/berlin2-adc.c
@@ -280,6 +280,13 @@ static const struct iio_info berlin2_adc_info = {
.read_raw = berlin2_adc_read_raw,
};
+static void berlin2_adc_powerdown(void *regmap)
+{
+ regmap_update_bits(regmap, BERLIN2_SM_CTRL,
+ BERLIN2_SM_CTRL_ADC_POWER, 0);
+
+}
+
static int berlin2_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
@@ -293,7 +300,6 @@ static int berlin2_adc_probe(struct platform_device *pdev)
return -ENOMEM;
priv = iio_priv(indio_dev);
- platform_set_drvdata(pdev, indio_dev);
priv->regmap = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
@@ -333,29 +339,12 @@ static int berlin2_adc_probe(struct platform_device *pdev)
BERLIN2_SM_CTRL_ADC_POWER,
BERLIN2_SM_CTRL_ADC_POWER);
- ret = iio_device_register(indio_dev);
- if (ret) {
- /* Power down the ADC */
- regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, 0);
+ ret = devm_add_action_or_reset(&pdev->dev, berlin2_adc_powerdown,
+ priv->regmap);
+ if (ret)
return ret;
- }
-
- return 0;
-}
-
-static int berlin2_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct berlin2_adc_priv *priv = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- /* Power down the ADC */
- regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, 0);
- return 0;
+ return devm_iio_device_register(&pdev->dev, indio_dev);
}
static const struct of_device_id berlin2_adc_match[] = {
@@ -370,7 +359,6 @@ static struct platform_driver berlin2_adc_driver = {
.of_match_table = berlin2_adc_match,
},
.probe = berlin2_adc_probe,
- .remove = berlin2_adc_remove,
};
module_platform_driver(berlin2_adc_driver);
diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
index 7a7a54a7ed76..8f0d3fb63b67 100644
--- a/drivers/iio/adc/da9150-gpadc.c
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -330,7 +330,6 @@ static int da9150_gpadc_probe(struct platform_device *pdev)
}
gpadc = iio_priv(indio_dev);
- platform_set_drvdata(pdev, indio_dev);
gpadc->da9150 = da9150;
gpadc->dev = dev;
mutex_init(&gpadc->lock);
@@ -347,7 +346,7 @@ static int da9150_gpadc_probe(struct platform_device *pdev)
return ret;
}
- ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
+ ret = devm_iio_map_array_register(&pdev->dev, indio_dev, da9150_gpadc_default_maps);
if (ret) {
dev_err(dev, "Failed to register IIO maps: %d\n", ret);
return ret;
@@ -359,28 +358,7 @@ static int da9150_gpadc_probe(struct platform_device *pdev)
indio_dev->channels = da9150_gpadc_channels;
indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(dev, "Failed to register IIO device: %d\n", ret);
- goto iio_map_unreg;
- }
-
- return 0;
-
-iio_map_unreg:
- iio_map_array_unregister(indio_dev);
-
- return ret;
-}
-
-static int da9150_gpadc_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;
+ return devm_iio_device_register(&pdev->dev, indio_dev);
}
static struct platform_driver da9150_gpadc_driver = {
@@ -388,7 +366,6 @@ static struct platform_driver da9150_gpadc_driver = {
.name = "da9150-gpadc",
},
.probe = da9150_gpadc_probe,
- .remove = da9150_gpadc_remove,
};
module_platform_driver(da9150_gpadc_driver);
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index 8edd6407b7c3..fd5a9404c8dc 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -156,15 +156,13 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
struct iio_dev *iiodev;
struct ep93xx_adc_priv *priv;
struct clk *pclk;
- struct resource *res;
iiodev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
if (!iiodev)
return -ENOMEM;
priv = iio_priv(iiodev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(&pdev->dev, res);
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index 329c555b55cc..551e83ae573c 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -172,13 +172,35 @@ static const struct regmap_config mx25_gcq_regconfig = {
.reg_stride = 4,
};
+static int mx25_gcq_ext_regulator_setup(struct device *dev,
+ struct mx25_gcq_priv *priv, u32 refp)
+{
+ char reg_name[12];
+ int ret;
+
+ if (priv->vref[refp])
+ return 0;
+
+ ret = snprintf(reg_name, sizeof(reg_name), "vref-%s",
+ mx25_gcq_refp_names[refp]);
+ if (ret < 0)
+ return ret;
+
+ priv->vref[refp] = devm_regulator_get_optional(dev, reg_name);
+ if (IS_ERR(priv->vref[refp]))
+ return dev_err_probe(dev, PTR_ERR(priv->vref[refp]),
+ "Error, trying to use external voltage reference without a %s regulator.",
+ reg_name);
+
+ return 0;
+}
+
static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
struct mx25_gcq_priv *priv)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
struct device *dev = &pdev->dev;
- unsigned int refp_used[4] = {};
int ret, i;
/*
@@ -194,19 +216,6 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
MX25_ADCQ_CFG_IN(i) |
MX25_ADCQ_CFG_REFN_NGND2);
- /*
- * First get all regulators to store them in channel_vref_mv if
- * necessary. Later we use that information for proper IIO scale
- * information.
- */
- priv->vref[MX25_ADC_REFP_INT] = NULL;
- priv->vref[MX25_ADC_REFP_EXT] =
- devm_regulator_get_optional(dev, "vref-ext");
- priv->vref[MX25_ADC_REFP_XP] =
- devm_regulator_get_optional(dev, "vref-xp");
- priv->vref[MX25_ADC_REFP_YP] =
- devm_regulator_get_optional(dev, "vref-yp");
-
for_each_child_of_node(np, child) {
u32 reg;
u32 refp = MX25_ADCQ_CFG_REFP_INT;
@@ -233,11 +242,10 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
case MX25_ADC_REFP_EXT:
case MX25_ADC_REFP_XP:
case MX25_ADC_REFP_YP:
- if (IS_ERR(priv->vref[refp])) {
- dev_err(dev, "Error, trying to use external voltage reference without a vref-%s regulator.",
- mx25_gcq_refp_names[refp]);
+ ret = mx25_gcq_ext_regulator_setup(&pdev->dev, priv, refp);
+ if (ret) {
of_node_put(child);
- return PTR_ERR(priv->vref[refp]);
+ return ret;
}
priv->channel_vref_mv[reg] =
regulator_get_voltage(priv->vref[refp]);
@@ -253,8 +261,6 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
return -EINVAL;
}
- ++refp_used[refp];
-
/*
* Shift the read values to the correct positions within the
* register.
@@ -285,15 +291,6 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
regmap_write(priv->regs, MX25_ADCQ_CR,
MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS);
- /* Remove unused regulators */
- for (i = 0; i != 4; ++i) {
- if (!refp_used[i]) {
- if (!IS_ERR_OR_NULL(priv->vref[i]))
- devm_regulator_put(priv->vref[i]);
- priv->vref[i] = NULL;
- }
- }
-
return 0;
}
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
new file mode 100644
index 000000000000..901dd8e1b32f
--- /dev/null
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NXP i.MX8QXP ADC driver
+ *
+ * Based on the work of Haibo Chen <haibo.chen@nxp.com>
+ * The initial developer of the original code is Haibo Chen.
+ * Portions created by Haibo Chen are Copyright (C) 2018 NXP.
+ * All Rights Reserved.
+ *
+ * Copyright (C) 2018 NXP
+ * Copyright (C) 2021 Cai Huoqing
+ */
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+
+#define ADC_DRIVER_NAME "imx8qxp-adc"
+
+/* Register map definition */
+#define IMX8QXP_ADR_ADC_CTRL 0x10
+#define IMX8QXP_ADR_ADC_STAT 0x14
+#define IMX8QXP_ADR_ADC_IE 0x18
+#define IMX8QXP_ADR_ADC_DE 0x1c
+#define IMX8QXP_ADR_ADC_CFG 0x20
+#define IMX8QXP_ADR_ADC_FCTRL 0x30
+#define IMX8QXP_ADR_ADC_SWTRIG 0x34
+#define IMX8QXP_ADR_ADC_TCTRL(tid) (0xc0 + (tid) * 4)
+#define IMX8QXP_ADR_ADC_CMDH(cid) (0x100 + (cid) * 8)
+#define IMX8QXP_ADR_ADC_CMDL(cid) (0x104 + (cid) * 8)
+#define IMX8QXP_ADR_ADC_RESFIFO 0x300
+#define IMX8QXP_ADR_ADC_TST 0xffc
+
+/* ADC bit shift */
+#define IMX8QXP_ADC_IE_FWMIE_MASK GENMASK(1, 0)
+#define IMX8QXP_ADC_CTRL_FIFO_RESET_MASK BIT(8)
+#define IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK BIT(1)
+#define IMX8QXP_ADC_CTRL_ADC_EN_MASK BIT(0)
+#define IMX8QXP_ADC_TCTRL_TCMD_MASK GENMASK(31, 24)
+#define IMX8QXP_ADC_TCTRL_TDLY_MASK GENMASK(23, 16)
+#define IMX8QXP_ADC_TCTRL_TPRI_MASK GENMASK(15, 8)
+#define IMX8QXP_ADC_TCTRL_HTEN_MASK GENMASK(7, 0)
+#define IMX8QXP_ADC_CMDL_CSCALE_MASK GENMASK(13, 8)
+#define IMX8QXP_ADC_CMDL_MODE_MASK BIT(7)
+#define IMX8QXP_ADC_CMDL_DIFF_MASK BIT(6)
+#define IMX8QXP_ADC_CMDL_ABSEL_MASK BIT(5)
+#define IMX8QXP_ADC_CMDL_ADCH_MASK GENMASK(2, 0)
+#define IMX8QXP_ADC_CMDH_NEXT_MASK GENMASK(31, 24)
+#define IMX8QXP_ADC_CMDH_LOOP_MASK GENMASK(23, 16)
+#define IMX8QXP_ADC_CMDH_AVGS_MASK GENMASK(15, 12)
+#define IMX8QXP_ADC_CMDH_STS_MASK BIT(8)
+#define IMX8QXP_ADC_CMDH_LWI_MASK GENMASK(7, 7)
+#define IMX8QXP_ADC_CMDH_CMPEN_MASK GENMASK(0, 0)
+#define IMX8QXP_ADC_CFG_PWREN_MASK BIT(28)
+#define IMX8QXP_ADC_CFG_PUDLY_MASK GENMASK(23, 16)
+#define IMX8QXP_ADC_CFG_REFSEL_MASK GENMASK(7, 6)
+#define IMX8QXP_ADC_CFG_PWRSEL_MASK GENMASK(5, 4)
+#define IMX8QXP_ADC_CFG_TPRICTRL_MASK GENMASK(3, 0)
+#define IMX8QXP_ADC_FCTRL_FWMARK_MASK GENMASK(20, 16)
+#define IMX8QXP_ADC_FCTRL_FCOUNT_MASK GENMASK(4, 0)
+#define IMX8QXP_ADC_RESFIFO_VAL_MASK GENMASK(18, 3)
+
+/* ADC PARAMETER*/
+#define IMX8QXP_ADC_CMDL_CHANNEL_SCALE_FULL GENMASK(5, 0)
+#define IMX8QXP_ADC_CMDL_SEL_A_A_B_CHANNEL 0
+#define IMX8QXP_ADC_CMDL_STANDARD_RESOLUTION 0
+#define IMX8QXP_ADC_CMDL_MODE_SINGLE 0
+#define IMX8QXP_ADC_CMDH_LWI_INCREMENT_DIS 0
+#define IMX8QXP_ADC_CMDH_CMPEN_DIS 0
+#define IMX8QXP_ADC_PAUSE_EN BIT(31)
+#define IMX8QXP_ADC_TCTRL_TPRI_PRIORITY_HIGH 0
+
+#define IMX8QXP_ADC_TCTRL_HTEN_HW_TIRG_DIS 0
+
+#define IMX8QXP_ADC_TIMEOUT msecs_to_jiffies(100)
+
+struct imx8qxp_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ struct clk *ipg_clk;
+ struct regulator *vref;
+ /* Serialise ADC channel reads */
+ struct mutex lock;
+ struct completion completion;
+};
+
+#define IMX8QXP_ADC_CHAN(_idx) { \
+ .type = IIO_VOLTAGE, \
+ .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 imx8qxp_adc_iio_channels[] = {
+ IMX8QXP_ADC_CHAN(0),
+ IMX8QXP_ADC_CHAN(1),
+ IMX8QXP_ADC_CHAN(2),
+ IMX8QXP_ADC_CHAN(3),
+ IMX8QXP_ADC_CHAN(4),
+ IMX8QXP_ADC_CHAN(5),
+ IMX8QXP_ADC_CHAN(6),
+ IMX8QXP_ADC_CHAN(7),
+};
+
+static void imx8qxp_adc_reset(struct imx8qxp_adc *adc)
+{
+ u32 ctrl;
+
+ /*software reset, need to clear the set bit*/
+ ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);
+ ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);
+ writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
+ udelay(10);
+ ctrl &= ~FIELD_PREP(IMX8QXP_ADC_CTRL_SOFTWARE_RESET_MASK, 1);
+ writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
+
+ /* reset the fifo */
+ ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_FIFO_RESET_MASK, 1);
+ writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
+}
+
+static void imx8qxp_adc_reg_config(struct imx8qxp_adc *adc, int channel)
+{
+ u32 adc_cfg, adc_tctrl, adc_cmdl, adc_cmdh;
+
+ /* ADC configuration */
+ adc_cfg = FIELD_PREP(IMX8QXP_ADC_CFG_PWREN_MASK, 1) |
+ FIELD_PREP(IMX8QXP_ADC_CFG_PUDLY_MASK, 0x80)|
+ FIELD_PREP(IMX8QXP_ADC_CFG_REFSEL_MASK, 0) |
+ FIELD_PREP(IMX8QXP_ADC_CFG_PWRSEL_MASK, 3) |
+ FIELD_PREP(IMX8QXP_ADC_CFG_TPRICTRL_MASK, 0);
+ writel(adc_cfg, adc->regs + IMX8QXP_ADR_ADC_CFG);
+
+ /* config the trigger control */
+ adc_tctrl = FIELD_PREP(IMX8QXP_ADC_TCTRL_TCMD_MASK, 1) |
+ FIELD_PREP(IMX8QXP_ADC_TCTRL_TDLY_MASK, 0) |
+ FIELD_PREP(IMX8QXP_ADC_TCTRL_TPRI_MASK, IMX8QXP_ADC_TCTRL_TPRI_PRIORITY_HIGH) |
+ FIELD_PREP(IMX8QXP_ADC_TCTRL_HTEN_MASK, IMX8QXP_ADC_TCTRL_HTEN_HW_TIRG_DIS);
+ writel(adc_tctrl, adc->regs + IMX8QXP_ADR_ADC_TCTRL(0));
+
+ /* config the cmd */
+ adc_cmdl = FIELD_PREP(IMX8QXP_ADC_CMDL_CSCALE_MASK, IMX8QXP_ADC_CMDL_CHANNEL_SCALE_FULL) |
+ FIELD_PREP(IMX8QXP_ADC_CMDL_MODE_MASK, IMX8QXP_ADC_CMDL_STANDARD_RESOLUTION) |
+ FIELD_PREP(IMX8QXP_ADC_CMDL_DIFF_MASK, IMX8QXP_ADC_CMDL_MODE_SINGLE) |
+ FIELD_PREP(IMX8QXP_ADC_CMDL_ABSEL_MASK, IMX8QXP_ADC_CMDL_SEL_A_A_B_CHANNEL) |
+ FIELD_PREP(IMX8QXP_ADC_CMDL_ADCH_MASK, channel);
+ writel(adc_cmdl, adc->regs + IMX8QXP_ADR_ADC_CMDL(0));
+
+ adc_cmdh = FIELD_PREP(IMX8QXP_ADC_CMDH_NEXT_MASK, 0) |
+ FIELD_PREP(IMX8QXP_ADC_CMDH_LOOP_MASK, 0) |
+ FIELD_PREP(IMX8QXP_ADC_CMDH_AVGS_MASK, 7) |
+ FIELD_PREP(IMX8QXP_ADC_CMDH_STS_MASK, 0) |
+ FIELD_PREP(IMX8QXP_ADC_CMDH_LWI_MASK, IMX8QXP_ADC_CMDH_LWI_INCREMENT_DIS) |
+ FIELD_PREP(IMX8QXP_ADC_CMDH_CMPEN_MASK, IMX8QXP_ADC_CMDH_CMPEN_DIS);
+ writel(adc_cmdh, adc->regs + IMX8QXP_ADR_ADC_CMDH(0));
+}
+
+static void imx8qxp_adc_fifo_config(struct imx8qxp_adc *adc)
+{
+ u32 fifo_ctrl, interrupt_en;
+
+ fifo_ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL);
+ fifo_ctrl &= ~IMX8QXP_ADC_FCTRL_FWMARK_MASK;
+ /* set the watermark level to 1 */
+ fifo_ctrl |= FIELD_PREP(IMX8QXP_ADC_FCTRL_FWMARK_MASK, 0);
+ writel(fifo_ctrl, adc->regs + IMX8QXP_ADR_ADC_FCTRL);
+
+ /* FIFO Watermark Interrupt Enable */
+ interrupt_en = readl(adc->regs + IMX8QXP_ADR_ADC_IE);
+ interrupt_en |= FIELD_PREP(IMX8QXP_ADC_IE_FWMIE_MASK, 1);
+ writel(interrupt_en, adc->regs + IMX8QXP_ADR_ADC_IE);
+}
+
+static void imx8qxp_adc_disable(struct imx8qxp_adc *adc)
+{
+ u32 ctrl;
+
+ ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);
+ ctrl &= ~FIELD_PREP(IMX8QXP_ADC_CTRL_ADC_EN_MASK, 1);
+ writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
+}
+
+static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+
+ u32 ctrl, vref_uv;
+ long ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ pm_runtime_get_sync(dev);
+
+ mutex_lock(&adc->lock);
+ reinit_completion(&adc->completion);
+
+ imx8qxp_adc_reg_config(adc, chan->channel);
+
+ imx8qxp_adc_fifo_config(adc);
+
+ /* adc enable */
+ ctrl = readl(adc->regs + IMX8QXP_ADR_ADC_CTRL);
+ ctrl |= FIELD_PREP(IMX8QXP_ADC_CTRL_ADC_EN_MASK, 1);
+ writel(ctrl, adc->regs + IMX8QXP_ADR_ADC_CTRL);
+ /* adc start */
+ writel(1, adc->regs + IMX8QXP_ADR_ADC_SWTRIG);
+
+ ret = wait_for_completion_interruptible_timeout(&adc->completion,
+ IMX8QXP_ADC_TIMEOUT);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+
+ if (ret == 0) {
+ mutex_unlock(&adc->lock);
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ mutex_unlock(&adc->lock);
+ return ret;
+ }
+
+ *val = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK,
+ readl(adc->regs + IMX8QXP_ADR_ADC_RESFIFO));
+
+ mutex_unlock(&adc->lock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ vref_uv = regulator_get_voltage(adc->vref);
+ *val = vref_uv / 1000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = clk_get_rate(adc->clk) / 3;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t imx8qxp_adc_isr(int irq, void *dev_id)
+{
+ struct imx8qxp_adc *adc = dev_id;
+ u32 fifo_count;
+
+ fifo_count = FIELD_GET(IMX8QXP_ADC_FCTRL_FCOUNT_MASK,
+ readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL));
+
+ if (fifo_count)
+ complete(&adc->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int imx8qxp_adc_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+
+ if (!readval || reg % 4 || reg > IMX8QXP_ADR_ADC_TST)
+ return -EINVAL;
+
+ pm_runtime_get_sync(dev);
+
+ *readval = readl(adc->regs + reg);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+
+ return 0;
+}
+
+static const struct iio_info imx8qxp_adc_iio_info = {
+ .read_raw = &imx8qxp_adc_read_raw,
+ .debugfs_reg_access = &imx8qxp_adc_reg_access,
+};
+
+static int imx8qxp_adc_probe(struct platform_device *pdev)
+{
+ struct imx8qxp_adc *adc;
+ struct iio_dev *indio_dev;
+ struct device *dev = &pdev->dev;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev) {
+ dev_err(dev, "Failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ adc = iio_priv(indio_dev);
+ adc->dev = dev;
+
+ mutex_init(&adc->lock);
+ adc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(adc->regs))
+ return PTR_ERR(adc->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ adc->clk = devm_clk_get(dev, "per");
+ if (IS_ERR(adc->clk))
+ return dev_err_probe(dev, PTR_ERR(adc->clk), "Failed getting clock\n");
+
+ adc->ipg_clk = devm_clk_get(dev, "ipg");
+ if (IS_ERR(adc->ipg_clk))
+ return dev_err_probe(dev, PTR_ERR(adc->ipg_clk), "Failed getting clock\n");
+
+ adc->vref = devm_regulator_get(dev, "vref");
+ if (IS_ERR(adc->vref))
+ return dev_err_probe(dev, PTR_ERR(adc->vref), "Failed getting reference voltage\n");
+
+ ret = regulator_enable(adc->vref);
+ if (ret) {
+ dev_err(dev, "Can't enable adc reference top voltage\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&adc->completion);
+
+ indio_dev->name = ADC_DRIVER_NAME;
+ indio_dev->info = &imx8qxp_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = imx8qxp_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(imx8qxp_adc_iio_channels);
+
+ ret = clk_prepare_enable(adc->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare or enable the clock.\n");
+ goto error_regulator_disable;
+ }
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare or enable the clock.\n");
+ goto error_adc_clk_disable;
+ }
+
+ ret = devm_request_irq(dev, irq, imx8qxp_adc_isr, 0, ADC_DRIVER_NAME, adc);
+ if (ret < 0) {
+ dev_err(dev, "Failed requesting irq, irq = %d\n", irq);
+ goto error_ipg_clk_disable;
+ }
+
+ imx8qxp_adc_reset(adc);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ imx8qxp_adc_disable(adc);
+ dev_err(dev, "Couldn't register the device.\n");
+ goto error_ipg_clk_disable;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+error_ipg_clk_disable:
+ clk_disable_unprepare(adc->ipg_clk);
+error_adc_clk_disable:
+ clk_disable_unprepare(adc->clk);
+error_regulator_disable:
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static int imx8qxp_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+
+ pm_runtime_get_sync(dev);
+
+ iio_device_unregister(indio_dev);
+
+ imx8qxp_adc_disable(adc);
+
+ clk_disable_unprepare(adc->clk);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+
+ return 0;
+}
+
+static __maybe_unused int imx8qxp_adc_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+
+ imx8qxp_adc_disable(adc);
+
+ clk_disable_unprepare(adc->clk);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ return 0;
+}
+
+static __maybe_unused int imx8qxp_adc_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(adc->vref);
+ if (ret) {
+ dev_err(dev, "Can't enable adc reference top voltage, err = %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(adc->clk);
+ if (ret) {
+ dev_err(dev, "Could not prepare or enable clock.\n");
+ goto err_disable_reg;
+ }
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err(dev, "Could not prepare or enable clock.\n");
+ goto err_unprepare_clk;
+ }
+
+ imx8qxp_adc_reset(adc);
+
+ return 0;
+
+err_unprepare_clk:
+ clk_disable_unprepare(adc->clk);
+
+err_disable_reg:
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static const struct dev_pm_ops imx8qxp_adc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(imx8qxp_adc_runtime_suspend, imx8qxp_adc_runtime_resume, NULL)
+};
+
+static const struct of_device_id imx8qxp_adc_match[] = {
+ { .compatible = "nxp,imx8qxp-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
+
+static struct platform_driver imx8qxp_adc_driver = {
+ .probe = imx8qxp_adc_probe,
+ .remove = imx8qxp_adc_remove,
+ .driver = {
+ .name = ADC_DRIVER_NAME,
+ .of_match_table = imx8qxp_adc_match,
+ .pm = &imx8qxp_adc_pm_ops,
+ },
+};
+
+module_platform_driver(imx8qxp_adc_driver);
+
+MODULE_DESCRIPTION("i.MX8QuadXPlus ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c
index 75394350eb4c..616de0c3a049 100644
--- a/drivers/iio/adc/intel_mrfld_adc.c
+++ b/drivers/iio/adc/intel_mrfld_adc.c
@@ -205,8 +205,6 @@ static int mrfld_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- platform_set_drvdata(pdev, indio_dev);
-
indio_dev->name = pdev->name;
indio_dev->channels = mrfld_adc_channels;
@@ -214,28 +212,11 @@ static int mrfld_adc_probe(struct platform_device *pdev)
indio_dev->info = &mrfld_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_map_array_register(indio_dev, iio_maps);
+ ret = devm_iio_map_array_register(dev, indio_dev, iio_maps);
if (ret)
return ret;
- ret = devm_iio_device_register(dev, indio_dev);
- if (ret < 0)
- goto err_array_unregister;
-
- return 0;
-
-err_array_unregister:
- iio_map_array_unregister(indio_dev);
- return ret;
-}
-
-static int mrfld_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-
- iio_map_array_unregister(indio_dev);
-
- return 0;
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct platform_device_id mrfld_adc_id_table[] = {
@@ -249,7 +230,6 @@ static struct platform_driver mrfld_adc_driver = {
.name = "mrfld_bcove_adc",
},
.probe = mrfld_adc_probe,
- .remove = mrfld_adc_remove,
.id_table = mrfld_adc_id_table,
};
module_platform_driver(mrfld_adc_driver);
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 8fb57e375529..6d9b354bc705 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -163,7 +163,8 @@ static struct iio_map lp8788_default_iio_maps[] = {
{ }
};
-static int lp8788_iio_map_register(struct iio_dev *indio_dev,
+static int lp8788_iio_map_register(struct device *dev,
+ struct iio_dev *indio_dev,
struct lp8788_platform_data *pdata,
struct lp8788_adc *adc)
{
@@ -173,7 +174,7 @@ static int lp8788_iio_map_register(struct iio_dev *indio_dev,
map = (!pdata || !pdata->adc_pdata) ?
lp8788_default_iio_maps : pdata->adc_pdata;
- ret = iio_map_array_register(indio_dev, map);
+ ret = devm_iio_map_array_register(dev, indio_dev, map);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
return ret;
@@ -196,9 +197,8 @@ static int lp8788_adc_probe(struct platform_device *pdev)
adc = iio_priv(indio_dev);
adc->lp = lp;
- platform_set_drvdata(pdev, indio_dev);
- ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
+ ret = lp8788_iio_map_register(&pdev->dev, indio_dev, lp->pdata, adc);
if (ret)
return ret;
@@ -210,32 +210,11 @@ static int lp8788_adc_probe(struct platform_device *pdev)
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;
+ return devm_iio_device_register(&pdev->dev, indio_dev);
}
static struct platform_driver lp8788_adc_driver = {
.probe = lp8788_adc_probe,
- .remove = lp8788_adc_remove,
.driver = {
.name = LP8788_DEV_ADC,
},
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index b753658bb41e..4daf1d576c4e 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -60,6 +60,9 @@
#define MAX1027_NAVG_32 (0x03 << 2)
#define MAX1027_AVG_EN BIT(4)
+/* Device can achieve 300ksps so we assume a 3.33us conversion delay */
+#define MAX1027_CONVERSION_UDELAY 4
+
enum max1027_id {
max1027,
max1029,
@@ -172,18 +175,53 @@ static const struct iio_chan_spec max1231_channels[] = {
MAX1X31_CHANNELS(12),
};
+/*
+ * These devices are able to scan from 0 to N, N being the highest voltage
+ * channel requested by the user. The temperature can be included or not,
+ * but cannot be retrieved alone. Based on the below
+ * ->available_scan_masks, the core will select the most appropriate
+ * ->active_scan_mask and the "minimum" number of channels will be
+ * scanned and pushed to the buffers.
+ *
+ * For example, if the user wants channels 1, 4 and 5, all channels from
+ * 0 to 5 will be scanned and pushed to the IIO buffers. The core will then
+ * filter out the unneeded samples based on the ->active_scan_mask that has
+ * been selected and only channels 1, 4 and 5 will be available to the user
+ * in the shared buffer.
+ */
+#define MAX1X27_SCAN_MASK_TEMP BIT(0)
+
+#define MAX1X27_SCAN_MASKS(temp) \
+ GENMASK(1, 1 - (temp)), GENMASK(2, 1 - (temp)), \
+ GENMASK(3, 1 - (temp)), GENMASK(4, 1 - (temp)), \
+ GENMASK(5, 1 - (temp)), GENMASK(6, 1 - (temp)), \
+ GENMASK(7, 1 - (temp)), GENMASK(8, 1 - (temp))
+
+#define MAX1X29_SCAN_MASKS(temp) \
+ MAX1X27_SCAN_MASKS(temp), \
+ GENMASK(9, 1 - (temp)), GENMASK(10, 1 - (temp)), \
+ GENMASK(11, 1 - (temp)), GENMASK(12, 1 - (temp))
+
+#define MAX1X31_SCAN_MASKS(temp) \
+ MAX1X29_SCAN_MASKS(temp), \
+ GENMASK(13, 1 - (temp)), GENMASK(14, 1 - (temp)), \
+ GENMASK(15, 1 - (temp)), GENMASK(16, 1 - (temp))
+
static const unsigned long max1027_available_scan_masks[] = {
- 0x000001ff,
+ MAX1X27_SCAN_MASKS(0),
+ MAX1X27_SCAN_MASKS(1),
0x00000000,
};
static const unsigned long max1029_available_scan_masks[] = {
- 0x00001fff,
+ MAX1X29_SCAN_MASKS(0),
+ MAX1X29_SCAN_MASKS(1),
0x00000000,
};
static const unsigned long max1031_available_scan_masks[] = {
- 0x0001ffff,
+ MAX1X31_SCAN_MASKS(0),
+ MAX1X31_SCAN_MASKS(1),
0x00000000,
};
@@ -232,10 +270,65 @@ struct max1027_state {
struct iio_trigger *trig;
__be16 *buffer;
struct mutex lock;
+ struct completion complete;
u8 reg ____cacheline_aligned;
};
+static int max1027_wait_eoc(struct iio_dev *indio_dev)
+{
+ struct max1027_state *st = iio_priv(indio_dev);
+ unsigned int conversion_time = MAX1027_CONVERSION_UDELAY;
+ int ret;
+
+ if (st->spi->irq) {
+ ret = wait_for_completion_timeout(&st->complete,
+ msecs_to_jiffies(1000));
+ reinit_completion(&st->complete);
+ if (!ret)
+ return -ETIMEDOUT;
+ } else {
+ if (indio_dev->active_scan_mask)
+ conversion_time *= hweight32(*indio_dev->active_scan_mask);
+
+ usleep_range(conversion_time, conversion_time * 2);
+ }
+
+ return 0;
+}
+
+/* Scan from chan 0 to the highest requested channel. Include temperature on demand. */
+static int max1027_configure_chans_and_start(struct iio_dev *indio_dev)
+{
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ st->reg = MAX1027_CONV_REG | MAX1027_SCAN_0_N;
+ st->reg |= MAX1027_CHAN(fls(*indio_dev->active_scan_mask) - 2);
+ if (*indio_dev->active_scan_mask & MAX1X27_SCAN_MASK_TEMP)
+ st->reg |= MAX1027_TEMP;
+
+ return spi_write(st->spi, &st->reg, 1);
+}
+
+static int max1027_enable_trigger(struct iio_dev *indio_dev, bool enable)
+{
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2;
+
+ /*
+ * Start acquisition on:
+ * MODE0: external hardware trigger wired to the cnvst input pin
+ * MODE2: conversion register write
+ */
+ if (enable)
+ st->reg |= MAX1027_CKS_MODE0;
+ else
+ st->reg |= MAX1027_CKS_MODE2;
+
+ return spi_write(st->spi, &st->reg, 1);
+}
+
static int max1027_read_single_value(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
@@ -243,19 +336,9 @@ static int max1027_read_single_value(struct iio_dev *indio_dev,
int ret;
struct max1027_state *st = iio_priv(indio_dev);
- if (iio_buffer_enabled(indio_dev)) {
- dev_warn(&indio_dev->dev, "trigger mode already enabled");
- return -EBUSY;
- }
-
- /* Start acquisition on conversion register write */
- st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2;
- ret = spi_write(st->spi, &st->reg, 1);
- if (ret < 0) {
- dev_err(&indio_dev->dev,
- "Failed to configure setup register\n");
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
return ret;
- }
/* Configure conversion register with the requested chan */
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) |
@@ -266,18 +349,24 @@ static int max1027_read_single_value(struct iio_dev *indio_dev,
if (ret < 0) {
dev_err(&indio_dev->dev,
"Failed to configure conversion register\n");
+ iio_device_release_direct_mode(indio_dev);
return ret;
}
/*
* For an unknown reason, when we use the mode "10" (write
* conversion register), the interrupt doesn't occur every time.
- * So we just wait 1 ms.
+ * So we just wait the maximum conversion time and deliver the value.
*/
- mdelay(1);
+ ret = max1027_wait_eoc(indio_dev);
+ if (ret)
+ return ret;
/* Read result */
ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2);
+
+ iio_device_release_direct_mode(indio_dev);
+
if (ret < 0)
return ret;
@@ -327,8 +416,8 @@ static int max1027_read_raw(struct iio_dev *indio_dev,
}
static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
- unsigned reg, unsigned writeval,
- unsigned *readval)
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
{
struct max1027_state *st = iio_priv(indio_dev);
u8 *val = (u8 *)st->buffer;
@@ -343,61 +432,96 @@ static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
return spi_write(st->spi, val, 1);
}
-static int max1027_validate_trigger(struct iio_dev *indio_dev,
- struct iio_trigger *trig)
+static int max1027_set_cnvst_trigger_state(struct iio_trigger *trig, bool state)
{
- struct max1027_state *st = iio_priv(indio_dev);
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ int ret;
+
+ /*
+ * In order to disable the convst trigger, start acquisition on
+ * conversion register write, which basically disables triggering
+ * conversions upon cnvst changes and thus has the effect of disabling
+ * the external hardware trigger.
+ */
+ ret = max1027_enable_trigger(indio_dev, state);
+ if (ret)
+ return ret;
- if (st->trig != trig)
- return -EINVAL;
+ if (state) {
+ ret = max1027_configure_chans_and_start(indio_dev);
+ if (ret)
+ return ret;
+ }
return 0;
}
-static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
+static int max1027_read_scan(struct iio_dev *indio_dev)
{
- struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct max1027_state *st = iio_priv(indio_dev);
+ unsigned int scanned_chans;
int ret;
- if (state) {
- /* Start acquisition on cnvst */
- st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 |
- MAX1027_REF_MODE2;
- ret = spi_write(st->spi, &st->reg, 1);
- if (ret < 0)
- return ret;
+ scanned_chans = fls(*indio_dev->active_scan_mask) - 1;
+ if (*indio_dev->active_scan_mask & MAX1X27_SCAN_MASK_TEMP)
+ scanned_chans++;
- /* Scan from 0 to max */
- st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) |
- MAX1027_SCAN_N_M | MAX1027_TEMP;
- ret = spi_write(st->spi, &st->reg, 1);
- if (ret < 0)
- return ret;
- } else {
- /* Start acquisition on conversion register write */
- st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 |
- MAX1027_REF_MODE2;
- ret = spi_write(st->spi, &st->reg, 1);
- if (ret < 0)
- return ret;
- }
+ /* fill buffer with all channel */
+ ret = spi_read(st->spi, st->buffer, scanned_chans * 2);
+ if (ret < 0)
+ return ret;
+
+ iio_push_to_buffers(indio_dev, st->buffer);
return 0;
}
+static irqreturn_t max1027_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct max1027_state *st = iio_priv(indio_dev);
+
+ /*
+ * If buffers are disabled (raw read) or when using external triggers,
+ * we just need to unlock the waiters which will then handle the data.
+ *
+ * When using the internal trigger, we must hand-off the choice of the
+ * handler to the core which will then lookup through the interrupt tree
+ * for the right handler registered with iio_triggered_buffer_setup()
+ * to execute, as this trigger might very well be used in conjunction
+ * with another device. The core will then call the relevant handler to
+ * perform the data processing step.
+ */
+ if (!iio_buffer_enabled(indio_dev))
+ complete(&st->complete);
+ else
+ iio_trigger_poll(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t max1027_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
- struct max1027_state *st = iio_priv(indio_dev);
+ int ret;
- pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private);
+ if (!iio_trigger_using_own(indio_dev)) {
+ ret = max1027_configure_chans_and_start(indio_dev);
+ if (ret)
+ goto out;
- /* fill buffer with all channel */
- spi_read(st->spi, st->buffer, indio_dev->masklength * 2);
+ /* This is a threaded handler, it is fine to wait for an IRQ */
+ ret = max1027_wait_eoc(indio_dev);
+ if (ret)
+ goto out;
+ }
- iio_push_to_buffers(indio_dev, st->buffer);
+ ret = max1027_read_scan(indio_dev);
+out:
+ if (ret)
+ dev_err(&indio_dev->dev,
+ "Cannot read scanned values (%d)\n", ret);
iio_trigger_notify_done(indio_dev->trig);
@@ -406,12 +530,11 @@ static irqreturn_t max1027_trigger_handler(int irq, void *private)
static const struct iio_trigger_ops max1027_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
- .set_trigger_state = &max1027_set_trigger_state,
+ .set_trigger_state = &max1027_set_cnvst_trigger_state,
};
static const struct iio_info max1027_info = {
.read_raw = &max1027_read_raw,
- .validate_trigger = &max1027_validate_trigger,
.debugfs_reg_access = &max1027_debugfs_reg_access,
};
@@ -421,10 +544,8 @@ static int max1027_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct max1027_state *st;
- pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi);
-
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (indio_dev == NULL) {
+ if (!indio_dev) {
pr_err("Can't allocate iio device\n");
return -ENOMEM;
}
@@ -434,6 +555,7 @@ static int max1027_probe(struct spi_device *spi)
st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
mutex_init(&st->lock);
+ init_completion(&st->complete);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &max1027_info;
@@ -443,26 +565,26 @@ static int max1027_probe(struct spi_device *spi)
indio_dev->available_scan_masks = st->info->available_scan_masks;
st->buffer = devm_kmalloc_array(&indio_dev->dev,
- indio_dev->num_channels, 2,
- GFP_KERNEL);
- if (st->buffer == NULL) {
- dev_err(&indio_dev->dev, "Can't allocate buffer\n");
+ indio_dev->num_channels, 2,
+ GFP_KERNEL);
+ if (!st->buffer)
return -ENOMEM;
+
+ /* Enable triggered buffers */
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &max1027_trigger_handler,
+ NULL);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Failed to setup buffer\n");
+ return ret;
}
+ /* If there is an EOC interrupt, register the cnvst hardware trigger */
if (spi->irq) {
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
- &iio_pollfunc_store_time,
- &max1027_trigger_handler,
- NULL);
- if (ret < 0) {
- dev_err(&indio_dev->dev, "Failed to setup buffer\n");
- return ret;
- }
-
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
indio_dev->name);
- if (st->trig == NULL) {
+ if (!st->trig) {
ret = -ENOMEM;
dev_err(&indio_dev->dev,
"Failed to allocate iio trigger\n");
@@ -479,12 +601,9 @@ static int max1027_probe(struct spi_device *spi)
return ret;
}
- ret = devm_request_threaded_irq(&spi->dev, spi->irq,
- iio_trigger_generic_data_rdy_poll,
- NULL,
- IRQF_TRIGGER_FALLING,
- spi->dev.driver->name,
- st->trig);
+ ret = devm_request_irq(&spi->dev, spi->irq, max1027_handler,
+ IRQF_TRIGGER_FALLING,
+ spi->dev.driver->name, indio_dev);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
return ret;
@@ -507,6 +626,11 @@ static int max1027_probe(struct spi_device *spi)
return ret;
}
+ /* Assume conversion on register write for now */
+ ret = max1027_enable_trigger(indio_dev, false);
+ if (ret)
+ return ret;
+
return devm_iio_device_register(&spi->dev, indio_dev);
}
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index f2b576c69949..eef55ed4814a 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1577,6 +1577,11 @@ static const struct of_device_id max1363_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max1363_of_match);
+static void max1363_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int max1363_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1590,7 +1595,8 @@ static int max1363_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
- ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+ ret = devm_iio_map_array_register(&client->dev, indio_dev,
+ client->dev.platform_data);
if (ret < 0)
return ret;
@@ -1598,17 +1604,16 @@ static int max1363_probe(struct i2c_client *client,
mutex_init(&st->lock);
st->reg = devm_regulator_get(&client->dev, "vcc");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_unregister_map;
- }
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
- goto error_unregister_map;
+ return ret;
- /* this is only used for device removal purposes */
- i2c_set_clientdata(client, indio_dev);
+ ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, st->reg);
+ if (ret)
+ return ret;
st->chip_info = device_get_match_data(&client->dev);
if (!st->chip_info)
@@ -1622,13 +1627,17 @@ static int max1363_probe(struct i2c_client *client,
ret = regulator_enable(vref);
if (ret)
- goto error_disable_reg;
+ return ret;
+
+ ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, vref);
+ if (ret)
+ return ret;
+
st->vref = vref;
vref_uv = regulator_get_voltage(vref);
- if (vref_uv <= 0) {
- ret = -EINVAL;
- goto error_disable_reg;
- }
+ if (vref_uv <= 0)
+ return -EINVAL;
+
st->vref_uv = vref_uv;
}
@@ -1640,13 +1649,12 @@ static int max1363_probe(struct i2c_client *client,
st->send = max1363_smbus_send;
st->recv = max1363_smbus_recv;
} else {
- ret = -EOPNOTSUPP;
- goto error_disable_reg;
+ return -EOPNOTSUPP;
}
ret = max1363_alloc_scan_masks(indio_dev);
if (ret)
- goto error_disable_reg;
+ return ret;
indio_dev->name = id->name;
indio_dev->channels = st->chip_info->channels;
@@ -1655,12 +1663,12 @@ static int max1363_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
ret = max1363_initial_setup(st);
if (ret < 0)
- goto error_disable_reg;
+ return ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- &max1363_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ &max1363_trigger_handler, NULL);
if (ret)
- goto error_disable_reg;
+ return ret;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, st->client->irq,
@@ -1671,39 +1679,10 @@ static int max1363_probe(struct i2c_client *client,
indio_dev);
if (ret)
- goto error_uninit_buffer;
+ return ret;
}
- 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;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id max1363_id[] = {
@@ -1756,7 +1735,6 @@ static struct i2c_driver max1363_driver = {
.of_match_table = max1363_of_match,
},
.probe = max1363_probe,
- .remove = max1363_remove,
.id_table = max1363_id,
};
module_i2c_driver(max1363_driver);
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
index bb70b51d25b1..976c235f3079 100644
--- a/drivers/iio/adc/nau7802.c
+++ b/drivers/iio/adc/nau7802.c
@@ -428,8 +428,6 @@ static int nau7802_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
-
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &nau7802_info;
@@ -495,13 +493,13 @@ static int nau7802_probe(struct i2c_client *client,
* 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 |
- IRQF_NO_AUTOEN,
- client->dev.driver->name,
- indio_dev);
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL,
+ nau7802_eoc_trigger,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT |
+ IRQF_NO_AUTOEN,
+ client->dev.driver->name,
+ indio_dev);
if (ret) {
/*
* What may happen here is that our IRQ controller is
@@ -526,7 +524,7 @@ static int nau7802_probe(struct i2c_client *client,
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2,
NAU7802_CTRL2_CRS(st->sample_rate));
if (ret)
- goto error_free_irq;
+ return ret;
}
/* Setup the ADC channels available on the board */
@@ -536,36 +534,7 @@ static int nau7802_probe(struct i2c_client *client,
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;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id nau7802_i2c_id[] = {
@@ -582,7 +551,6 @@ 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",
diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c
index c56fccb2c8e1..7d891b4ea461 100644
--- a/drivers/iio/adc/rn5t618-adc.c
+++ b/drivers/iio/adc/rn5t618-adc.c
@@ -197,13 +197,6 @@ static struct iio_map rn5t618_maps[] = {
{ /* sentinel */ }
};
-static void unregister_map(void *data)
-{
- struct iio_dev *iio_dev = (struct iio_dev *) data;
-
- iio_map_array_unregister(iio_dev);
-}
-
static int rn5t618_adc_probe(struct platform_device *pdev)
{
int ret;
@@ -254,11 +247,7 @@ static int rn5t618_adc_probe(struct platform_device *pdev)
return ret;
}
- ret = iio_map_array_register(iio_dev, rn5t618_maps);
- if (ret < 0)
- return ret;
-
- ret = devm_add_action_or_reset(adc->dev, unregister_map, iio_dev);
+ ret = devm_iio_map_array_register(adc->dev, iio_dev, rn5t618_maps);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index a237fe469a30..a56a0d7337ca 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -319,7 +319,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
struct rockchip_saradc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
- struct resource *mem;
const struct of_device_id *match;
int ret;
int irq;
@@ -348,8 +347,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
return -EINVAL;
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- info->regs = devm_ioremap_resource(&pdev->dev, mem);
+ info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
index db902aef2abe..c8e48881c37f 100644
--- a/drivers/iio/adc/ti-adc108s102.c
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -75,9 +75,9 @@ struct adc108s102_state {
* rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt|
*
* tx_buf: 8 channel read commands, plus 1 dummy command
- * rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp
+ * rx_buf: 1 dummy response, 8 channel responses
*/
- __be16 rx_buf[13] ____cacheline_aligned;
+ __be16 rx_buf[9] ____cacheline_aligned;
__be16 tx_buf[9] ____cacheline_aligned;
};
@@ -149,9 +149,10 @@ static irqreturn_t adc108s102_trigger_handler(int irq, void *p)
goto out_notify;
/* Skip the dummy response in the first slot */
- iio_push_to_buffers_with_timestamp(indio_dev,
- (u8 *)&st->rx_buf[1],
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts_unaligned(indio_dev,
+ &st->rx_buf[1],
+ st->ring_xfer.len - sizeof(st->rx_buf[1]),
+ iio_get_time_ns(indio_dev));
out_notify:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-ads8344.c b/drivers/iio/adc/ti-ads8344.c
index a345a30d74fa..c96d2a9ba924 100644
--- a/drivers/iio/adc/ti-ads8344.c
+++ b/drivers/iio/adc/ti-ads8344.c
@@ -133,6 +133,11 @@ static const struct iio_info ads8344_info = {
.read_raw = ads8344_read_raw,
};
+static void ads8344_reg_disable(void *data)
+{
+ regulator_disable(data);
+}
+
static int ads8344_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -161,26 +166,11 @@ static int ads8344_probe(struct spi_device *spi)
if (ret)
return ret;
- spi_set_drvdata(spi, indio_dev);
-
- ret = iio_device_register(indio_dev);
- if (ret) {
- regulator_disable(adc->reg);
+ ret = devm_add_action_or_reset(&spi->dev, ads8344_reg_disable, adc->reg);
+ if (ret)
return ret;
- }
-
- return 0;
-}
-
-static int ads8344_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ads8344 *adc = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- regulator_disable(adc->reg);
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ads8344_of_match[] = {
@@ -195,7 +185,6 @@ static struct spi_driver ads8344_driver = {
.of_match_table = ads8344_of_match,
},
.probe = ads8344_probe,
- .remove = ads8344_remove,
};
module_spi_driver(ads8344_driver);
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index c6416ad795ca..afdb59e0b526 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -900,7 +900,7 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
ret = pdata->calibrate(gpadc);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to read calibration registers\n");
+ dev_err(dev, "failed to read calibration registers\n");
return ret;
}
@@ -914,14 +914,14 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
+ dev_err(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");
+ dev_err(dev, "failed to enable GPADC module\n");
return ret;
}