diff options
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r-- | drivers/iio/adc/Kconfig | 13 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/adc/ad_sigma_delta.c | 5 | ||||
-rw-r--r-- | drivers/iio/adc/at91-sama5d2_adc.c | 783 | ||||
-rw-r--r-- | drivers/iio/adc/hx711.c | 39 | ||||
-rw-r--r-- | drivers/iio/adc/ina2xx-adc.c | 17 | ||||
-rw-r--r-- | drivers/iio/adc/max1363.c | 8 | ||||
-rw-r--r-- | drivers/iio/adc/meson_saradc.c | 9 | ||||
-rw-r--r-- | drivers/iio/adc/sc27xx_adc.c | 522 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads7950.c | 43 | ||||
-rw-r--r-- | drivers/iio/adc/xilinx-xadc-core.c | 44 | ||||
-rw-r--r-- | drivers/iio/adc/xilinx-xadc.h | 1 |
12 files changed, 1361 insertions, 124 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9da79070357c..4a754921fb6f 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -157,7 +157,6 @@ config AT91_SAMA5D2_ADC tristate "Atmel AT91 SAMA5D2 ADC" depends on ARCH_AT91 || COMPILE_TEST depends on HAS_IOMEM - depends on HAS_DMA select IIO_BUFFER select IIO_TRIGGERED_BUFFER help @@ -621,6 +620,16 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config SC27XX_ADC + tristate "Spreadtrum SC27xx series PMICs ADC" + depends on MFD_SC27XX_PMIC || COMPILE_TEST + help + Say yes here to build support for the integrated ADC inside the + Spreadtrum SC27xx series PMICs. + + This driver can also be built as a module. If so, the module + will be called sc27xx_adc. + config SPEAR_ADC tristate "ST SPEAr ADC" depends on PLAT_SPEAR || COMPILE_TEST @@ -647,7 +656,6 @@ config SD_ADC_MODULATOR config STM32_ADC_CORE tristate "STMicroelectronics STM32 adc core" depends on ARCH_STM32 || COMPILE_TEST - depends on HAS_DMA depends on OF depends on REGULATOR select IIO_BUFFER @@ -717,6 +725,7 @@ config SUN4I_GPADC depends on IIO depends on MFD_SUN4I_GPADC || MACH_SUN8I depends on THERMAL || !THERMAL_OF + select REGMAP_IRQ help Say yes here to build support for Allwinner (A10, A13 and A31) SoCs GPADC. This ADC provides 4 channels which can be used as an ADC or as diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 28a9423997f3..03db7b578f9c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index cf1b048b0665..fc9510716ac7 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -209,6 +209,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) { int ret; + unsigned long timeout; ret = ad_sigma_delta_set_channel(sigma_delta, channel); if (ret) @@ -224,8 +225,8 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, sigma_delta->irq_dis = false; enable_irq(sigma_delta->spi->irq); - ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ); - if (ret == 0) { + timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); + if (timeout == 0) { sigma_delta->irq_dis = true; disable_irq_nosync(sigma_delta->spi->irq); ret = -EIO; diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 8729d6524b4d..d5ea84cf6460 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -102,14 +102,26 @@ #define AT91_SAMA5D2_LCDR 0x20 /* Interrupt Enable Register */ #define AT91_SAMA5D2_IER 0x24 +/* Interrupt Enable Register - TS X measurement ready */ +#define AT91_SAMA5D2_IER_XRDY BIT(20) +/* Interrupt Enable Register - TS Y measurement ready */ +#define AT91_SAMA5D2_IER_YRDY BIT(21) +/* Interrupt Enable Register - TS pressure measurement ready */ +#define AT91_SAMA5D2_IER_PRDY BIT(22) /* Interrupt Enable Register - general overrun error */ #define AT91_SAMA5D2_IER_GOVRE BIT(25) +/* Interrupt Enable Register - Pen detect */ +#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 /* Interrupt Mask Register */ #define AT91_SAMA5D2_IMR 0x2c /* Interrupt Status Register */ #define AT91_SAMA5D2_ISR 0x30 +/* Interrupt Status Register - Pen touching sense status */ +#define AT91_SAMA5D2_ISR_PENS BIT(31) /* Last Channel Trigger Mode Register */ #define AT91_SAMA5D2_LCTMR 0x34 /* Last Channel Compare Window Register */ @@ -118,6 +130,15 @@ #define AT91_SAMA5D2_OVER 0x3c /* Extended Mode Register */ #define AT91_SAMA5D2_EMR 0x40 +/* Extended Mode Register - Oversampling rate */ +#define AT91_SAMA5D2_EMR_OSR(V) ((V) << 16) +#define AT91_SAMA5D2_EMR_OSR_MASK GENMASK(17, 16) +#define AT91_SAMA5D2_EMR_OSR_1SAMPLES 0 +#define AT91_SAMA5D2_EMR_OSR_4SAMPLES 1 +#define AT91_SAMA5D2_EMR_OSR_16SAMPLES 2 + +/* Extended Mode Register - Averaging on single trigger event */ +#define AT91_SAMA5D2_EMR_ASTE(V) ((V) << 20) /* Compare Window Register */ #define AT91_SAMA5D2_CWR 0x44 /* Channel Gain Register */ @@ -131,8 +152,38 @@ #define AT91_SAMA5D2_CDR0 0x50 /* Analog Control Register */ #define AT91_SAMA5D2_ACR 0x94 +/* Analog Control Register - Pen detect sensitivity mask */ +#define AT91_SAMA5D2_ACR_PENDETSENS_MASK GENMASK(1, 0) + /* Touchscreen Mode Register */ #define AT91_SAMA5D2_TSMR 0xb0 +/* Touchscreen Mode Register - No touch mode */ +#define AT91_SAMA5D2_TSMR_TSMODE_NONE 0 +/* Touchscreen Mode Register - 4 wire screen, no pressure measurement */ +#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_NO_PRESS 1 +/* Touchscreen Mode Register - 4 wire screen, pressure measurement */ +#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS 2 +/* Touchscreen Mode Register - 5 wire screen */ +#define AT91_SAMA5D2_TSMR_TSMODE_5WIRE 3 +/* Touchscreen Mode Register - Average samples mask */ +#define AT91_SAMA5D2_TSMR_TSAV_MASK GENMASK(5, 4) +/* Touchscreen Mode Register - Average samples */ +#define AT91_SAMA5D2_TSMR_TSAV(x) ((x) << 4) +/* Touchscreen Mode Register - Touch/trigger frequency ratio mask */ +#define AT91_SAMA5D2_TSMR_TSFREQ_MASK GENMASK(11, 8) +/* Touchscreen Mode Register - Touch/trigger frequency ratio */ +#define AT91_SAMA5D2_TSMR_TSFREQ(x) ((x) << 8) +/* Touchscreen Mode Register - Pen Debounce Time mask */ +#define AT91_SAMA5D2_TSMR_PENDBC_MASK GENMASK(31, 28) +/* Touchscreen Mode Register - Pen Debounce Time */ +#define AT91_SAMA5D2_TSMR_PENDBC(x) ((x) << 28) +/* Touchscreen Mode Register - No DMA for touch measurements */ +#define AT91_SAMA5D2_TSMR_NOTSDMA BIT(22) +/* Touchscreen Mode Register - Disable pen detection */ +#define AT91_SAMA5D2_TSMR_PENDET_DIS (0 << 24) +/* Touchscreen Mode Register - Enable pen detection */ +#define AT91_SAMA5D2_TSMR_PENDET_ENA BIT(24) + /* Touchscreen X Position Register */ #define AT91_SAMA5D2_XPOSR 0xb4 /* Touchscreen Y Position Register */ @@ -151,6 +202,12 @@ #define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL 2 /* Trigger Mode external trigger any edge */ #define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY 3 +/* Trigger Mode internal periodic */ +#define AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC 5 +/* Trigger Mode - trigger period mask */ +#define AT91_SAMA5D2_TRGR_TRGPER_MASK GENMASK(31, 16) +/* Trigger Mode - trigger period */ +#define AT91_SAMA5D2_TRGR_TRGPER(x) ((x) << 16) /* Correction Select Register */ #define AT91_SAMA5D2_COSR 0xd0 @@ -169,6 +226,22 @@ #define AT91_SAMA5D2_SINGLE_CHAN_CNT 12 #define AT91_SAMA5D2_DIFF_CHAN_CNT 6 +#define AT91_SAMA5D2_TIMESTAMP_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \ + AT91_SAMA5D2_DIFF_CHAN_CNT + 1) + +#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 + +#define AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ +#define AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US 200 + +#define AT91_SAMA5D2_XYZ_MASK GENMASK(11, 0) + +#define AT91_SAMA5D2_MAX_POS_BITS 12 + /* * Maximum number of bytes to hold conversion from all channels * without the timestamp. @@ -184,6 +257,11 @@ #define AT91_HWFIFO_MAX_SIZE_STR "128" #define AT91_HWFIFO_MAX_SIZE 128 +/* Possible values for oversampling ratio */ +#define AT91_OSR_1SAMPLES 1 +#define AT91_OSR_4SAMPLES 4 +#define AT91_OSR_16SAMPLES 16 + #define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \ { \ .type = IIO_VOLTAGE, \ @@ -192,12 +270,13 @@ .scan_index = num, \ .scan_type = { \ .sign = 'u', \ - .realbits = 12, \ + .realbits = 14, \ .storagebits = 16, \ }, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .datasheet_name = "CH"#num, \ .indexed = 1, \ } @@ -212,16 +291,50 @@ .scan_index = num + AT91_SAMA5D2_SINGLE_CHAN_CNT, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = 14, \ .storagebits = 16, \ }, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .datasheet_name = "CH"#num"-CH"#num2, \ .indexed = 1, \ } +#define AT91_SAMA5D2_CHAN_TOUCH(num, name, mod) \ + { \ + .type = IIO_POSITIONRELATIVE, \ + .modified = 1, \ + .channel = num, \ + .channel2 = mod, \ + .scan_index = num, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .datasheet_name = name, \ + } +#define AT91_SAMA5D2_CHAN_PRESSURE(num, name) \ + { \ + .type = IIO_PRESSURE, \ + .channel = num, \ + .scan_index = num, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .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) @@ -260,6 +373,22 @@ struct at91_adc_dma { s64 dma_ts; }; +/** + * at91_adc_touch - at91-sama5d2 touchscreen information struct + * @sample_period_val: the value for periodic trigger interval + * @touching: is the pen touching the screen or not + * @x_pos: temporary placeholder for pressure computation + * @channels_bitmask: bitmask with the touchscreen channels enabled + * @workq: workqueue for buffer data pushing + */ +struct at91_adc_touch { + u16 sample_period_val; + bool touching; + u16 x_pos; + unsigned long channels_bitmask; + struct work_struct workq; +}; + struct at91_adc_state { void __iomem *base; int irq; @@ -267,14 +396,17 @@ struct at91_adc_state { struct regulator *reg; struct regulator *vref; int vref_uv; + unsigned int current_sample_rate; struct iio_trigger *trig; const struct at91_adc_trigger *selected_trig; const struct iio_chan_spec *chan; bool conversion_done; u32 conversion_value; + unsigned int oversampling_ratio; struct at91_adc_soc_info soc_info; wait_queue_head_t wq_data_available; struct at91_adc_dma dma_st; + struct at91_adc_touch touch_st; u16 buffer[AT91_BUFFER_MAX_HWORDS]; /* * lock to prevent concurrent 'single conversion' requests through @@ -329,8 +461,10 @@ static const struct iio_chan_spec at91_adc_channels[] = { 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_SINGLE_CHAN_CNT - + AT91_SAMA5D2_DIFF_CHAN_CNT + 1), + 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 int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan) @@ -354,6 +488,231 @@ at91_adc_chan_get(struct iio_dev *indio_dev, int chan) return indio_dev->channels + index; } +static inline int at91_adc_of_xlate(struct iio_dev *indio_dev, + const struct of_phandle_args *iiospec) +{ + return at91_adc_chan_xlate(indio_dev, iiospec->args[0]); +} + +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); + + /* select oversampling per single trigger event */ + emr |= AT91_SAMA5D2_EMR_ASTE(1); + + /* delete leftover content if it's the case */ + emr &= ~AT91_SAMA5D2_EMR_OSR_MASK; + + /* select oversampling ratio from configuration */ + switch (st->oversampling_ratio) { + case AT91_OSR_1SAMPLES: + emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_1SAMPLES) & + AT91_SAMA5D2_EMR_OSR_MASK; + break; + case AT91_OSR_4SAMPLES: + emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_4SAMPLES) & + AT91_SAMA5D2_EMR_OSR_MASK; + break; + case AT91_OSR_16SAMPLES: + emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_16SAMPLES) & + AT91_SAMA5D2_EMR_OSR_MASK; + break; + } + + at91_adc_writel(st, AT91_SAMA5D2_EMR, emr); +} + +static int at91_adc_adjust_val_osr(struct at91_adc_state *st, int *val) +{ + if (st->oversampling_ratio == AT91_OSR_1SAMPLES) { + /* + * in this case we only have 12 bits of real data, but channel + * is registered as 14 bits, so shift left two bits + */ + *val <<= 2; + } else if (st->oversampling_ratio == AT91_OSR_4SAMPLES) { + /* + * in this case we have 13 bits of real data, but channel + * is registered as 14 bits, so left shift one bit + */ + *val <<= 1; + } + + return IIO_VAL_INT; +} + +static void at91_adc_adjust_val_osr_array(struct at91_adc_state *st, void *buf, + int len) +{ + int i = 0, val; + u16 *buf_u16 = (u16 *) buf; + + /* + * We are converting each two bytes (each sample). + * First convert the byte based array to u16, and convert each sample + * separately. + * Each value is two bytes in an array of chars, so to not shift + * more than we need, save the value separately. + * len is in bytes, so divide by two to get number of samples. + */ + while (i < len / 2) { + val = buf_u16[i]; + at91_adc_adjust_val_osr(st, &val); + buf_u16[i] = val; + i++; + } +} + +static int at91_adc_configure_touch(struct at91_adc_state *st, bool state) +{ + u32 clk_khz = st->current_sample_rate / 1000; + int i = 0; + u16 pendbc; + u32 tsmr, acr; + + if (!state) { + /* disabling touch IRQs and setting mode to no touch enabled */ + at91_adc_writel(st, AT91_SAMA5D2_IDR, + AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN); + at91_adc_writel(st, AT91_SAMA5D2_TSMR, 0); + return 0; + } + /* + * debounce time is in microseconds, we need it in milliseconds to + * multiply with kilohertz, so, divide by 1000, but after the multiply. + * round up to make sure pendbc is at least 1 + */ + pendbc = round_up(AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US * + clk_khz / 1000, 1); + + /* get the required exponent */ + while (pendbc >> i++) + ; + + pendbc = i; + + tsmr = AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS; + + tsmr |= AT91_SAMA5D2_TSMR_TSAV(2) & AT91_SAMA5D2_TSMR_TSAV_MASK; + tsmr |= AT91_SAMA5D2_TSMR_PENDBC(pendbc) & + AT91_SAMA5D2_TSMR_PENDBC_MASK; + tsmr |= AT91_SAMA5D2_TSMR_NOTSDMA; + 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); + + acr = at91_adc_readl(st, AT91_SAMA5D2_ACR); + acr &= ~AT91_SAMA5D2_ACR_PENDETSENS_MASK; + acr |= 0x02 & AT91_SAMA5D2_ACR_PENDETSENS_MASK; + at91_adc_writel(st, AT91_SAMA5D2_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); + + return 0; +} + +static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg) +{ + u32 val; + u32 scale, result, pos; + + /* + * to obtain the actual position we must divide by scale + * and multiply with max, where + * 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 (!val) + dev_dbg(&iio_priv_to_dev(st)->dev, "pos is 0\n"); + + pos = val & AT91_SAMA5D2_XYZ_MASK; + result = (pos << AT91_SAMA5D2_MAX_POS_BITS) - pos; + scale = (val >> 16) & AT91_SAMA5D2_XYZ_MASK; + if (scale == 0) { + dev_err(&iio_priv_to_dev(st)->dev, "scale is 0\n"); + return 0; + } + result /= scale; + + return result; +} + +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); + 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); +} + +static u16 at91_adc_touch_pressure(struct at91_adc_state *st) +{ + u32 val; + u32 z1, z2; + u32 pres; + u32 rxp = 1; + u32 factor = 1000; + + /* calculate the pressure */ + val = at91_adc_readl(st, AT91_SAMA5D2_PRESSR); + z1 = val & AT91_SAMA5D2_XYZ_MASK; + z2 = (val >> 16) & AT91_SAMA5D2_XYZ_MASK; + + if (z1 != 0) + pres = rxp * (st->touch_st.x_pos * factor / 1024) * + (z2 * factor / z1 - factor) / + factor; + else + pres = 0xFFFF; /* no pen contact */ + + /* + * The pressure from device grows down, minimum is 0xFFFF, maximum 0x0. + * We compute it this way, but let's return it in the expected way, + * growing from 0 to 0xFFFF. + */ + return 0xFFFF - pres; +} + +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) + *val = at91_adc_touch_x_pos(st); + else if (chan == AT91_SAMA5D2_TOUCH_Y_CHAN_IDX) + *val = at91_adc_touch_y_pos(st); + else + return -ENODATA; + + return IIO_VAL_INT; +} + +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) + *val = at91_adc_touch_pressure(st); + else + return -ENODATA; + + return IIO_VAL_INT; +} + static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *indio = iio_trigger_get_drvdata(trig); @@ -375,6 +734,11 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) if (!chan) continue; + /* these channel types cannot be handled by this trigger */ + if (chan->type == IIO_POSITIONRELATIVE || + chan->type == IIO_PRESSURE) + continue; + if (state) { at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel)); @@ -520,7 +884,20 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev) static int at91_adc_buffer_postenable(struct iio_dev *indio_dev) { int ret; + struct at91_adc_state *st = iio_priv(indio_dev); + /* check if we are enabling triggered buffer or the touchscreen */ + if (bitmap_subset(indio_dev->active_scan_mask, + &st->touch_st.channels_bitmask, + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { + /* touchscreen enabling */ + return at91_adc_configure_touch(st, true); + } + /* if we are not in triggered mode, we cannot enable the buffer. */ + if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) + return -EINVAL; + + /* we continue with the triggered buffer */ ret = at91_adc_dma_start(indio_dev); if (ret) { dev_err(&indio_dev->dev, "buffer postenable failed\n"); @@ -536,6 +913,18 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) int ret; u8 bit; + /* check if we are disabling triggered buffer or the touchscreen */ + if (bitmap_subset(indio_dev->active_scan_mask, + &st->touch_st.channels_bitmask, + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { + /* touchscreen disable */ + return at91_adc_configure_touch(st, false); + } + /* if we are not in triggered mode, nothing to do here */ + if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) + return -EINVAL; + + /* continue with the triggered buffer */ ret = iio_triggered_buffer_predisable(indio_dev); if (ret < 0) dev_err(&indio_dev->dev, "buffer predisable failed\n"); @@ -558,6 +947,10 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) if (!chan) continue; + /* these channel types are virtual, no need to do anything */ + if (chan->type == IIO_POSITIONRELATIVE || + chan->type == IIO_PRESSURE) + continue; if (st->dma_st.dma_chan) at91_adc_readl(st, chan->address); } @@ -613,6 +1006,7 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, { struct at91_adc_state *st = iio_priv(indio_dev); int i = 0; + int val; u8 bit; for_each_set_bit(bit, indio_dev->active_scan_mask, @@ -622,7 +1016,24 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, if (!chan) continue; - st->buffer[i] = at91_adc_readl(st, chan->address); + /* + * Our external trigger only supports the voltage channels. + * In case someone requested a different type of channel + * just put zeroes to buffer. + * This should not happen because we check the scan mode + * and scan mask when we enable the buffer, and we don't allow + * the buffer to start with a mixed mask (voltage and something + * else). + * Thus, emit a warning. + */ + if (chan->type == IIO_VOLTAGE) { + val = at91_adc_readl(st, chan->address); + at91_adc_adjust_val_osr(st, &val); + st->buffer[i] = val; + } else { + st->buffer[i] = 0; + WARN(true, "This trigger cannot handle this type of channel"); + } i++; } iio_push_to_buffers_with_timestamp(indio_dev, st->buffer, @@ -654,6 +1065,14 @@ static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev) interval = div_s64((ns - st->dma_st.dma_ts), sample_count); while (transferred_len >= sample_size) { + /* + * for all the values in the current sample, + * adjust the values inside the buffer for oversampling + */ + at91_adc_adjust_val_osr_array(st, + &st->dma_st.rx_buf[st->dma_st.buf_idx], + sample_size); + iio_push_to_buffers_with_timestamp(indio_dev, (st->dma_st.rx_buf + st->dma_st.buf_idx), (st->dma_st.dma_ts + interval * sample_index)); @@ -688,9 +1107,20 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) static int at91_adc_buffer_init(struct iio_dev *indio) { - return devm_iio_triggered_buffer_setup(&indio->dev, indio, + struct at91_adc_state *st = iio_priv(indio); + + if (st->selected_trig->hw_trig) { + return devm_iio_triggered_buffer_setup(&indio->dev, indio, &iio_pollfunc_store_time, &at91_adc_trigger_handler, &at91_buffer_setup_ops); + } + /* + * we need to prepare the buffer ops in case we will get + * another buffer attached (like a callback buffer for the touchscreen) + */ + indio->setup_ops = &at91_buffer_setup_ops; + + return 0; } static unsigned at91_adc_startup_time(unsigned startup_time_min, @@ -736,19 +1166,83 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq) dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n", freq, startup, prescal); + st->current_sample_rate = freq; } -static unsigned at91_adc_get_sample_freq(struct at91_adc_state *st) +static inline unsigned at91_adc_get_sample_freq(struct at91_adc_state *st) { - unsigned f_adc, f_per = clk_get_rate(st->per_clk); - unsigned mr, prescal; + return st->current_sample_rate; +} - mr = at91_adc_readl(st, AT91_SAMA5D2_MR); - prescal = (mr >> AT91_SAMA5D2_MR_PRESCAL_OFFSET) - & AT91_SAMA5D2_MR_PRESCAL_MAX; - f_adc = f_per / (2 * (prescal + 1)); +static void at91_adc_touch_data_handler(struct iio_dev *indio_dev) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + u8 bit; + u16 val; + int i = 0; + + for_each_set_bit(bit, indio_dev->active_scan_mask, + AT91_SAMA5D2_MAX_CHAN_IDX + 1) { + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + + if (chan->type == IIO_POSITIONRELATIVE) + at91_adc_read_position(st, chan->channel, &val); + else if (chan->type == IIO_PRESSURE) + at91_adc_read_pressure(st, chan->channel, &val); + else + continue; + st->buffer[i] = val; + i++; + } + /* + * Schedule work to push to buffers. + * This is intended to push to the callback buffer that another driver + * registered. We are still in a handler from our IRQ. If we push + * directly, it means the other driver has it's callback called + * from our IRQ context. Which is something we better avoid. + * Let's schedule it after our IRQ is completed. + */ + schedule_work(&st->touch_st.workq); +} + +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_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY | + AT91_SAMA5D2_IER_PRDY); + at91_adc_writel(st, AT91_SAMA5D2_TRGR, + AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC | + AT91_SAMA5D2_TRGR_TRGPER(st->touch_st.sample_period_val)); + st->touch_st.touching = true; +} + +static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st) +{ + struct iio_dev *indio_dev = iio_priv_to_dev(st); + + 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_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); +} + +static void at91_adc_workq_handler(struct work_struct *workq) +{ + struct at91_adc_touch *touch_st = container_of(workq, + struct at91_adc_touch, workq); + struct at91_adc_state *st = container_of(touch_st, + struct at91_adc_state, touch_st); + struct iio_dev *indio_dev = iio_priv_to_dev(st); - return f_adc; + iio_push_to_buffers(indio_dev, st->buffer); } static irqreturn_t at91_adc_interrupt(int irq, void *private) @@ -757,17 +1251,39 @@ static irqreturn_t at91_adc_interrupt(int irq, void *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 rdy_mask = AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY | + AT91_SAMA5D2_IER_PRDY; if (!(status & imr)) return IRQ_NONE; - - if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) { + if (status & AT91_SAMA5D2_IER_PEN) { + /* pen detected IRQ */ + at91_adc_pen_detect_interrupt(st); + } else if ((status & AT91_SAMA5D2_IER_NOPEN)) { + /* nopen detected IRQ */ + at91_adc_no_pen_detect_interrupt(st); + } else if ((status & AT91_SAMA5D2_ISR_PENS) && + ((status & rdy_mask) == rdy_mask)) { + /* periodic trigger IRQ - during pen sense */ + at91_adc_touch_data_handler(indio); + } else if (status & AT91_SAMA5D2_ISR_PENS) { + /* + * 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); + } else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) { + /* triggered buffer without DMA */ disable_irq_nosync(irq); iio_trigger_poll(indio->trig); } else if (iio_buffer_enabled(indio) && st->dma_st.dma_chan) { + /* triggered buffer with DMA - should not happen */ disable_irq_nosync(irq); 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_done = true; wake_up_interruptible(&st->wq_data_available); @@ -775,58 +1291,100 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private) return IRQ_HANDLED; } -static int at91_adc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) +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; - switch (mask) { - case IIO_CHAN_INFO_RAW: - /* we cannot use software trigger if hw trigger enabled */ + /* + * Keep in mind that we cannot use software trigger or touchscreen + * if external trigger is enabled + */ + if (chan->type == IIO_POSITIONRELATIVE) { ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; mutex_lock(&st->lock); - st->chan = chan; + ret = at91_adc_read_position(st, chan->channel, + &tmp_val); + *val = tmp_val; + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); - 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); - - ret = wait_event_interruptible_timeout(st->wq_data_available, - st->conversion_done, - msecs_to_jiffies(1000)); - if (ret == 0) - ret = -ETIMEDOUT; - - if (ret > 0) { - *val = st->conversion_value; - if (chan->scan_type.sign == 's') - *val = sign_extend32(*val, 11); - ret = IIO_VAL_INT; - st->conversion_done = false; - } + return at91_adc_adjust_val_osr(st, val); + } + if (chan->type == IIO_PRESSURE) { + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&st->lock); - at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel)); - at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel)); + ret = at91_adc_read_pressure(st, chan->channel, + &tmp_val); + *val = tmp_val; + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); - /* Needed to ACK the DRDY interruption */ - at91_adc_readl(st, AT91_SAMA5D2_LCDR); + return at91_adc_adjust_val_osr(st, val); + } - mutex_unlock(&st->lock); + /* in this case we have a voltage channel */ - iio_device_release_direct_mode(indio_dev); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) return ret; + mutex_lock(&st->lock); + + 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); + + ret = wait_event_interruptible_timeout(st->wq_data_available, + st->conversion_done, + msecs_to_jiffies(1000)); + if (ret == 0) + ret = -ETIMEDOUT; + + if (ret > 0) { + *val = st->conversion_value; + ret = at91_adc_adjust_val_osr(st, val); + if (chan->scan_type.sign == 's') + *val = sign_extend32(*val, 11); + st->conversion_done = false; + } + at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel)); + at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel)); + + /* Needed to ACK the DRDY interruption */ + at91_adc_readl(st, AT91_SAMA5D2_LCDR); + + mutex_unlock(&st->lock); + + iio_device_release_direct_mode(indio_dev); + return ret; +} + +static int at91_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return at91_adc_read_info_raw(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: *val = st->vref_uv / 1000; if (chan->differential) @@ -838,6 +1396,10 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev, *val = at91_adc_get_sample_freq(st); return IIO_VAL_INT; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling_ratio; + return IIO_VAL_INT; + default: return -EINVAL; } @@ -849,16 +1411,28 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev, { struct at91_adc_state *st = iio_priv(indio_dev); - if (mask != IIO_CHAN_INFO_SAMP_FREQ) - return -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if ((val != AT91_OSR_1SAMPLES) && (val != AT91_OSR_4SAMPLES) && + (val != AT91_OSR_16SAMPLES)) + return -EINVAL; + /* if no change, optimize out */ + if (val == st->oversampling_ratio) + return 0; + st->oversampling_ratio = val; + /* update ratio */ + at91_adc_config_emr(st); + return 0; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < st->soc_info.min_sample_rate || + val > st->soc_info.max_sample_rate) + return -EINVAL; - if (val < st->soc_info.min_sample_rate || - val > st->soc_info.max_sample_rate) + at91_adc_setup_samp_freq(st, val); + return 0; + default: return -EINVAL; - - at91_adc_setup_samp_freq(st, val); - - return 0; + }; } static void at91_adc_dma_init(struct platform_device *pdev) @@ -974,11 +1548,23 @@ static int at91_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) return 0; } -static const struct iio_info at91_adc_info = { - .read_raw = &at91_adc_read_raw, - .write_raw = &at91_adc_write_raw, - .hwfifo_set_watermark = &at91_adc_set_watermark, -}; +static int at91_adc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + 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)) + 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)) + return -EINVAL; + return 0; +} static void at91_adc_hw_init(struct at91_adc_state *st) { @@ -992,6 +1578,9 @@ static void at91_adc_hw_init(struct at91_adc_state *st) AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH); at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate); + + /* configure extended mode register */ + at91_adc_config_emr(st); } static ssize_t at91_adc_get_fifo_state(struct device *dev, @@ -1022,6 +1611,20 @@ static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, static IIO_CONST_ATTR(hwfifo_watermark_min, "2"); static IIO_CONST_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR); +static IIO_CONST_ATTR(oversampling_ratio_available, + __stringify(AT91_OSR_1SAMPLES) " " + __stringify(AT91_OSR_4SAMPLES) " " + __stringify(AT91_OSR_16SAMPLES)); + +static struct attribute *at91_adc_attributes[] = { + &iio_const_attr_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group at91_adc_attribute_group = { + .attrs = at91_adc_attributes, +}; + static const struct attribute *at91_adc_fifo_attributes[] = { &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, @@ -1030,6 +1633,15 @@ static const struct attribute *at91_adc_fifo_attributes[] = { NULL, }; +static const struct iio_info at91_adc_info = { + .attrs = &at91_adc_attribute_group, + .read_raw = &at91_adc_read_raw, + .write_raw = &at91_adc_write_raw, + .update_scan_mode = &at91_adc_update_scan_mode, + .of_xlate = &at91_adc_of_xlate, + .hwfifo_set_watermark = &at91_adc_set_watermark, +}; + static int at91_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -1044,13 +1656,22 @@ static int at91_adc_probe(struct platform_device *pdev) indio_dev->dev.parent = &pdev->dev; indio_dev->name = dev_name(&pdev->dev); - indio_dev->modes = INDIO_DIRECT_MODE; + 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); + bitmap_set(&st->touch_st.channels_bitmask, + AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1); + bitmap_set(&st->touch_st.channels_bitmask, + AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1); + bitmap_set(&st->touch_st.channels_bitmask, + AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1); + + st->oversampling_ratio = AT91_OSR_1SAMPLES; + ret = of_property_read_u32(pdev->dev.of_node, "atmel,min-sample-rate-hz", &st->soc_info.min_sample_rate); @@ -1100,6 +1721,7 @@ static int at91_adc_probe(struct platform_device *pdev) init_waitqueue_head(&st->wq_data_available); mutex_init(&st->lock); + INIT_WORK(&st->touch_st.workq, at91_adc_workq_handler); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -1159,13 +1781,13 @@ static int at91_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); - if (st->selected_trig->hw_trig) { - ret = at91_adc_buffer_init(indio_dev); - if (ret < 0) { - dev_err(&pdev->dev, "couldn't initialize the buffer.\n"); - goto per_clk_disable_unprepare; - } + ret = at91_adc_buffer_init(indio_dev); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't initialize the buffer.\n"); + goto per_clk_disable_unprepare; + } + if (st->selected_trig->hw_trig) { ret = at91_adc_trigger_init(indio_dev); if (ret < 0) { dev_err(&pdev->dev, "couldn't setup the triggers.\n"); @@ -1272,9 +1894,20 @@ static __maybe_unused int at91_adc_resume(struct device *dev) at91_adc_hw_init(st); /* reconfiguring trigger hardware state */ - if (iio_buffer_enabled(indio_dev)) - at91_adc_configure_trigger(st->trig, true); + if (!iio_buffer_enabled(indio_dev)) + return 0; + + /* check if we are enabling triggered buffer or the touchscreen */ + if (bitmap_subset(indio_dev->active_scan_mask, + &st->touch_st.channels_bitmask, + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { + /* touchscreen enabling */ + return at91_adc_configure_touch(st, true); + } else { + return at91_adc_configure_trigger(st->trig, true); + } + /* not needed but more explicit */ return 0; vref_disable_resume: diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 9430b54121e0..36b59d8957fb 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -97,6 +97,14 @@ struct hx711_data { * 2x32-bit channel + 64-bit timestamp */ u32 buffer[4]; + /* + * delay after a rising edge on SCK until the data is ready DOUT + * this is dependent on the hx711 where the datasheet tells a + * maximum value of 100 ns + * but also on potential parasitic capacities on the wiring + */ + u32 data_ready_delay_ns; + u32 clock_frequency; }; static int hx711_cycle(struct hx711_data *hx711_data) @@ -110,6 +118,14 @@ static int hx711_cycle(struct hx711_data *hx711_data) */ preempt_disable(); gpiod_set_value(hx711_data->gpiod_pd_sck, 1); + + /* + * wait until DOUT is ready + * it turned out that parasitic capacities are extending the time + * until DOUT has reached it's value + */ + ndelay(hx711_data->data_ready_delay_ns); + val = gpiod_get_value(hx711_data->gpiod_dout); /* * here we are not waiting for 0.2 us as suggested by the datasheet, @@ -120,6 +136,12 @@ static int hx711_cycle(struct hx711_data *hx711_data) gpiod_set_value(hx711_data->gpiod_pd_sck, 0); preempt_enable(); + /* + * make it a square wave for addressing cases with capacitance on + * PC_SCK + */ + ndelay(hx711_data->data_ready_delay_ns); + return val; } @@ -458,6 +480,7 @@ static const struct iio_chan_spec hx711_chan_spec[] = { static int hx711_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct hx711_data *hx711_data; struct iio_dev *indio_dev; int ret; @@ -530,6 +553,22 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->gain_set = 128; hx711_data->gain_chan_a = 128; + hx711_data->clock_frequency = 400000; + ret = of_property_read_u32(np, "clock-frequency", + &hx711_data->clock_frequency); + + /* + * datasheet says the high level of PD_SCK has a maximum duration + * of 50 microseconds + */ + if (hx711_data->clock_frequency < 20000) { + dev_warn(dev, "clock-frequency too low - assuming 400 kHz\n"); + hx711_data->clock_frequency = 400000; + } + + hx711_data->data_ready_delay_ns = + 1000000000 / hx711_data->clock_frequency; + platform_set_drvdata(pdev, indio_dev); indio_dev->name = "hx711"; diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 0635a79864bf..d1239624187d 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -30,6 +30,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/regmap.h> +#include <linux/sched/task.h> #include <linux/util_macros.h> #include <linux/platform_data/ina2xx.h> @@ -826,6 +827,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) { struct ina2xx_chip_info *chip = iio_priv(indio_dev); unsigned int sampling_us = SAMPLING_PERIOD(chip); + struct task_struct *task; dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n", (unsigned int)(*indio_dev->active_scan_mask), @@ -835,11 +837,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", chip->allow_async_readout); - chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, - "%s:%d-%uus", indio_dev->name, indio_dev->id, - sampling_us); + task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, + "%s:%d-%uus", indio_dev->name, indio_dev->id, + sampling_us); + if (IS_ERR(task)) + return PTR_ERR(task); + + get_task_struct(task); + wake_up_process(task); + chip->task = task; - return PTR_ERR_OR_ZERO(chip->task); + return 0; } static int ina2xx_buffer_disable(struct iio_dev *indio_dev) @@ -848,6 +856,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev) if (chip->task) { kthread_stop(chip->task); + put_task_struct(chip->task); chip->task = NULL; } diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 7fb4f525714a..a8d35aebee80 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1577,7 +1577,6 @@ static int max1363_probe(struct i2c_client *client, struct max1363_state *st; struct iio_dev *indio_dev; struct regulator *vref; - const struct of_device_id *match; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct max1363_state)); @@ -1604,11 +1603,8 @@ static int max1363_probe(struct i2c_client *client, /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); - match = of_match_device(of_match_ptr(max1363_of_match), - &client->dev); - if (match) - st->chip_info = of_device_get_match_data(&client->dev); - else + st->chip_info = of_device_get_match_data(&client->dev); + if (!st->chip_info) st->chip_info = &max1363_chip_info_tbl[id->driver_data]; st->client = client; diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 2948909f3ee3..da2d16dfa63e 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -922,6 +922,11 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { .name = "meson-meson8b-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = { + .param = &meson_sar_adc_meson8_param, + .name = "meson-meson8m2-saradc", +}; + static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { .param = &meson_sar_adc_gxbb_param, .name = "meson-gxbb-saradc", @@ -952,6 +957,10 @@ static const struct of_device_id meson_sar_adc_of_match[] = { .data = &meson_sar_adc_meson8b_data, }, { + .compatible = "amlogic,meson8m2-saradc", + .data = &meson_sar_adc_meson8m2_data, + }, + { .compatible = "amlogic,meson-gxbb-saradc", .data = &meson_sar_adc_gxbb_data, }, { diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c new file mode 100644 index 000000000000..2b60efea0c39 --- /dev/null +++ b/drivers/iio/adc/sc27xx_adc.c @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Spreadtrum Communications Inc. + +#include <linux/hwspinlock.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* PMIC global registers definition */ +#define SC27XX_MODULE_EN 0xc08 +#define SC27XX_MODULE_ADC_EN BIT(5) +#define SC27XX_ARM_CLK_EN 0xc10 +#define SC27XX_CLK_ADC_EN BIT(5) +#define SC27XX_CLK_ADC_CLK_EN BIT(6) + +/* ADC controller registers definition */ +#define SC27XX_ADC_CTL 0x0 +#define SC27XX_ADC_CH_CFG 0x4 +#define SC27XX_ADC_DATA 0x4c +#define SC27XX_ADC_INT_EN 0x50 +#define SC27XX_ADC_INT_CLR 0x54 +#define SC27XX_ADC_INT_STS 0x58 +#define SC27XX_ADC_INT_RAW 0x5c + +/* Bits and mask definition for SC27XX_ADC_CTL register */ +#define SC27XX_ADC_EN BIT(0) +#define SC27XX_ADC_CHN_RUN BIT(1) +#define SC27XX_ADC_12BIT_MODE BIT(2) +#define SC27XX_ADC_RUN_NUM_MASK GENMASK(7, 4) +#define SC27XX_ADC_RUN_NUM_SHIFT 4 + +/* Bits and mask definition for SC27XX_ADC_CH_CFG register */ +#define SC27XX_ADC_CHN_ID_MASK GENMASK(4, 0) +#define SC27XX_ADC_SCALE_MASK GENMASK(10, 8) +#define SC27XX_ADC_SCALE_SHIFT 8 + +/* Bits definitions for SC27XX_ADC_INT_EN registers */ +#define SC27XX_ADC_IRQ_EN BIT(0) + +/* Bits definitions for SC27XX_ADC_INT_CLR registers */ +#define SC27XX_ADC_IRQ_CLR BIT(0) + +/* Mask definition for SC27XX_ADC_DATA register */ +#define SC27XX_ADC_DATA_MASK GENMASK(11, 0) + +/* Timeout (ms) for the trylock of hardware spinlocks */ +#define SC27XX_ADC_HWLOCK_TIMEOUT 5000 + +/* Maximum ADC channel number */ +#define SC27XX_ADC_CHANNEL_MAX 32 + +/* ADC voltage ratio definition */ +#define SC27XX_VOLT_RATIO(n, d) \ + (((n) << SC27XX_RATIO_NUMERATOR_OFFSET) | (d)) +#define SC27XX_RATIO_NUMERATOR_OFFSET 16 +#define SC27XX_RATIO_DENOMINATOR_MASK GENMASK(15, 0) + +struct sc27xx_adc_data { + struct device *dev; + struct regmap *regmap; + /* + * One hardware spinlock to synchronize between the multiple + * subsystems which will access the unique ADC controller. + */ + struct hwspinlock *hwlock; + struct completion completion; + int channel_scale[SC27XX_ADC_CHANNEL_MAX]; + u32 base; + int value; + int irq; +}; + +struct sc27xx_adc_linear_graph { + int volt0; + int adc0; + int volt1; + int adc1; +}; + +/* + * According to the datasheet, we can convert one ADC value to one voltage value + * through 2 points in the linear graph. If the voltage is less than 1.2v, we + * should use the small-scale graph, and if more than 1.2v, we should use the + * big-scale graph. + */ +static const struct sc27xx_adc_linear_graph big_scale_graph = { + 4200, 3310, + 3600, 2832, +}; + +static const struct sc27xx_adc_linear_graph small_scale_graph = { + 1000, 3413, + 100, 341, +}; + +static int sc27xx_adc_get_ratio(int channel, int scale) +{ + switch (channel) { + case 1: + case 2: + case 3: + case 4: + return scale ? SC27XX_VOLT_RATIO(400, 1025) : + SC27XX_VOLT_RATIO(1, 1); + case 5: + return SC27XX_VOLT_RATIO(7, 29); + case 6: + return SC27XX_VOLT_RATIO(375, 9000); + case 7: + case 8: + return scale ? SC27XX_VOLT_RATIO(100, 125) : + SC27XX_VOLT_RATIO(1, 1); + case 19: + return SC27XX_VOLT_RATIO(1, 3); + default: + return SC27XX_VOLT_RATIO(1, 1); + } + return SC27XX_VOLT_RATIO(1, 1); +} + +static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, + int scale, int *val) +{ + int ret; + u32 tmp; + + reinit_completion(&data->completion); + + ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT); + if (ret) { + dev_err(data->dev, "timeout to get the hwspinlock\n"); + return ret; + } + + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN, SC27XX_ADC_EN); + if (ret) + goto unlock_adc; + + /* Configure the channel id and scale */ + tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK; + tmp |= channel & SC27XX_ADC_CHN_ID_MASK; + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CH_CFG, + SC27XX_ADC_CHN_ID_MASK | SC27XX_ADC_SCALE_MASK, + tmp); + if (ret) + goto disable_adc; + + /* Select 12bit conversion mode, and only sample 1 time */ + tmp = SC27XX_ADC_12BIT_MODE; + tmp |= (0 << SC27XX_ADC_RUN_NUM_SHIFT) & SC27XX_ADC_RUN_NUM_MASK; + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_RUN_NUM_MASK | SC27XX_ADC_12BIT_MODE, + tmp); + if (ret) + goto disable_adc; + + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN); + if (ret) + goto disable_adc; + + wait_for_completion(&data->completion); + +disable_adc: + regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, + SC27XX_ADC_EN, 0); +unlock_adc: + hwspin_unlock_raw(data->hwlock); + + if (!ret) + *val = data->value; + + return ret; +} + +static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id) +{ + struct sc27xx_adc_data *data = dev_id; + int ret; + + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, + SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); + if (ret) + return IRQ_RETVAL(ret); + + ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, + &data->value); + if (ret) + return IRQ_RETVAL(ret); + + data->value &= SC27XX_ADC_DATA_MASK; + complete(&data->completion); + + return IRQ_HANDLED; +} + +static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data, + int channel, int scale, + u32 *div_numerator, u32 *div_denominator) +{ + u32 ratio = sc27xx_adc_get_ratio(channel, scale); + + *div_numerator = ratio >> SC27XX_RATIO_NUMERATOR_OFFSET; + *div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK; +} + +static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph, + int raw_adc) +{ + int tmp; + + tmp = (graph->volt0 - graph->volt1) * (raw_adc - graph->adc1); + tmp /= (graph->adc0 - graph->adc1); + tmp += graph->volt1; + + return tmp < 0 ? 0 : tmp; +} + +static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel, + int scale, int raw_adc) +{ + u32 numerator, denominator; + u32 volt; + + /* + * Convert ADC values to voltage values according to the linear graph, + * and channel 5 and channel 1 has been calibrated, so we can just + * return the voltage values calculated by the linear graph. But other + * channels need be calculated to the real voltage values with the + * voltage ratio. + */ + switch (channel) { + case 5: + return sc27xx_adc_to_volt(&big_scale_graph, raw_adc); + + case 1: + return sc27xx_adc_to_volt(&small_scale_graph, raw_adc); + + default: + volt = sc27xx_adc_to_volt(&small_scale_graph, raw_adc); + break; + } + + sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator); + + return (volt * denominator + numerator / 2) / numerator; +} + +static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data, + int channel, int scale, int *val) +{ + int ret, raw_adc; + + ret = sc27xx_adc_read(data, channel, scale, &raw_adc); + if (ret) + return ret; + + *val = sc27xx_adc_convert_volt(data, channel, scale, raw_adc); + return 0; +} + +static int sc27xx_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sc27xx_adc_data *data = iio_priv(indio_dev); + int scale = data->channel_scale[chan->channel]; + int ret, tmp; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + mutex_lock(&indio_dev->mlock); + ret = sc27xx_adc_read_processed(data, chan->channel, scale, + &tmp); + mutex_unlock(&indio_dev->mlock); + + if (ret) + return ret; + + *val = tmp; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = scale; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int sc27xx_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sc27xx_adc_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + data->channel_scale[chan->channel] = val; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static const struct iio_info sc27xx_info = { + .read_raw = &sc27xx_adc_read_raw, + .write_raw = &sc27xx_adc_write_raw, +}; + +#define SC27XX_ADC_CHANNEL(index) { \ + .type = IIO_VOLTAGE, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = "CH##index", \ + .indexed = 1, \ +} + +static const struct iio_chan_spec sc27xx_channels[] = { + SC27XX_ADC_CHANNEL(0), + SC27XX_ADC_CHANNEL(1), + SC27XX_ADC_CHANNEL(2), + SC27XX_ADC_CHANNEL(3), + SC27XX_ADC_CHANNEL(4), + SC27XX_ADC_CHANNEL(5), + SC27XX_ADC_CHANNEL(6), + SC27XX_ADC_CHANNEL(7), + SC27XX_ADC_CHANNEL(8), + SC27XX_ADC_CHANNEL(9), + SC27XX_ADC_CHANNEL(10), + SC27XX_ADC_CHANNEL(11), + SC27XX_ADC_CHANNEL(12), + SC27XX_ADC_CHANNEL(13), + SC27XX_ADC_CHANNEL(14), + SC27XX_ADC_CHANNEL(15), + SC27XX_ADC_CHANNEL(16), + SC27XX_ADC_CHANNEL(17), + SC27XX_ADC_CHANNEL(18), + SC27XX_ADC_CHANNEL(19), + SC27XX_ADC_CHANNEL(20), + SC27XX_ADC_CHANNEL(21), + SC27XX_ADC_CHANNEL(22), + SC27XX_ADC_CHANNEL(23), + SC27XX_ADC_CHANNEL(24), + SC27XX_ADC_CHANNEL(25), + SC27XX_ADC_CHANNEL(26), + SC27XX_ADC_CHANNEL(27), + SC27XX_ADC_CHANNEL(28), + SC27XX_ADC_CHANNEL(29), + SC27XX_ADC_CHANNEL(30), + SC27XX_ADC_CHANNEL(31), +}; + +static int sc27xx_adc_enable(struct sc27xx_adc_data *data) +{ + int ret; + + ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN, + SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN); + if (ret) + return ret; + + /* Enable ADC work clock and controller clock */ + ret = regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); + if (ret) + goto disable_adc; + + ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, + SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN); + if (ret) + goto disable_clk; + + return 0; + +disable_clk: + regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); +disable_adc: + regmap_update_bits(data->regmap, SC27XX_MODULE_EN, + SC27XX_MODULE_ADC_EN, 0); + + return ret; +} + +static void sc27xx_adc_disable(void *_data) +{ + struct sc27xx_adc_data *data = _data; + + regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, + SC27XX_ADC_IRQ_EN, 0); + + /* Disable ADC work clock and controller clock */ + regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, + SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); + + regmap_update_bits(data->regmap, SC27XX_MODULE_EN, + SC27XX_MODULE_ADC_EN, 0); +} + +static void sc27xx_adc_free_hwlock(void *_data) +{ + struct hwspinlock *hwlock = _data; + + hwspin_lock_free(hwlock); +} + +static int sc27xx_adc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct sc27xx_adc_data *sc27xx_data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data)); + if (!indio_dev) + return -ENOMEM; + + sc27xx_data = iio_priv(indio_dev); + + sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!sc27xx_data->regmap) { + dev_err(&pdev->dev, "failed to get ADC regmap\n"); + return -ENODEV; + } + + ret = of_property_read_u32(np, "reg", &sc27xx_data->base); + if (ret) { + dev_err(&pdev->dev, "failed to get ADC base address\n"); + return ret; + } + + sc27xx_data->irq = platform_get_irq(pdev, 0); + if (sc27xx_data->irq < 0) { + dev_err(&pdev->dev, "failed to get ADC irq number\n"); + return sc27xx_data->irq; + } + + ret = of_hwspin_lock_get_id(np, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get hwspinlock id\n"); + return ret; + } + + sc27xx_data->hwlock = hwspin_lock_request_specific(ret); + if (!sc27xx_data->hwlock) { + dev_err(&pdev->dev, "failed to request hwspinlock\n"); + return -ENXIO; + } + + ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock, + sc27xx_data->hwlock); + if (ret) { + sc27xx_adc_free_hwlock(sc27xx_data->hwlock); + dev_err(&pdev->dev, "failed to add hwspinlock action\n"); + return ret; + } + + init_completion(&sc27xx_data->completion); + sc27xx_data->dev = &pdev->dev; + + ret = sc27xx_adc_enable(sc27xx_data); + if (ret) { + dev_err(&pdev->dev, "failed to enable ADC module\n"); + return ret; + } + + ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data); + if (ret) { + sc27xx_adc_disable(sc27xx_data); + dev_err(&pdev->dev, "failed to add ADC disable action\n"); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL, + sc27xx_adc_isr, IRQF_ONESHOT, + pdev->name, sc27xx_data); + if (ret) { + dev_err(&pdev->dev, "failed to request ADC irq\n"); + return ret; + } + + indio_dev->dev.parent = &pdev->dev; + indio_dev->name = dev_name(&pdev->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &sc27xx_info; + indio_dev->channels = sc27xx_channels; + indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels); + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) + dev_err(&pdev->dev, "could not register iio (ADC)"); + + return ret; +} + +static const struct of_device_id sc27xx_adc_of_match[] = { + { .compatible = "sprd,sc2731-adc", }, + { } +}; + +static struct platform_driver sc27xx_adc_driver = { + .probe = sc27xx_adc_probe, + .driver = { + .name = "sc27xx-adc", + .of_match_table = sc27xx_adc_of_match, + }, +}; + +module_platform_driver(sc27xx_adc_driver); + +MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>"); +MODULE_DESCRIPTION("Spreadtrum SC27XX ADC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 0225c1b333ab..a5bd5944bc66 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Texas Instruments ADS7950 SPI ADC driver * @@ -10,15 +11,6 @@ * And also on hwmon/ads79xx.c * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * Nishanth Menon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/acpi.h> @@ -76,6 +68,9 @@ struct ti_ads7950_state { __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE] ____cacheline_aligned; __be16 tx_buf[TI_ADS7950_MAX_CHAN]; + __be16 single_tx; + __be16 single_rx; + }; struct ti_ads7950_chip_info { @@ -295,18 +290,26 @@ out: return IRQ_HANDLED; } -static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch) +static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) { + struct ti_ads7950_state *st = iio_priv(indio_dev); int ret, cmd; + mutex_lock(&indio_dev->mlock); + cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; - st->tx_buf[0] = cpu_to_be16(cmd); + st->single_tx = cpu_to_be16(cmd); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - return ret; + goto out; + + ret = be16_to_cpu(st->single_rx); - return be16_to_cpu(st->rx_buf[0]); +out: + mutex_unlock(&indio_dev->mlock); + + return ret; } static int ti_ads7950_get_range(struct ti_ads7950_state *st) @@ -338,13 +341,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret < 0) - return ret; - - ret = ti_ads7950_scan_direct(st, chan->address); - iio_device_release_direct_mode(indio_dev); + ret = ti_ads7950_scan_direct(indio_dev, chan->address); if (ret < 0) return ret; @@ -410,13 +407,13 @@ static int ti_ads7950_probe(struct spi_device *spi) * was read at the end of the first transfer. */ - st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; + st->scan_single_xfer[0].tx_buf = &st->single_tx; st->scan_single_xfer[0].len = 2; st->scan_single_xfer[0].cs_change = 1; - st->scan_single_xfer[1].tx_buf = &st->tx_buf[0]; + st->scan_single_xfer[1].tx_buf = &st->single_tx; st->scan_single_xfer[1].len = 2; st->scan_single_xfer[1].cs_change = 1; - st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; + st->scan_single_xfer[2].rx_buf = &st->single_rx; st->scan_single_xfer[2].len = 2; spi_message_init_with_transfers(&st->scan_single_msg, diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index d4f21d1be6c8..3f6be5ac049a 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -322,6 +322,7 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) #define XADC_ZYNQ_TCK_RATE_MAX 50000000 #define XADC_ZYNQ_IGAP_DEFAULT 20 +#define XADC_ZYNQ_PCAP_RATE_MAX 200000000 static int xadc_zynq_setup(struct platform_device *pdev, struct iio_dev *indio_dev, int irq) @@ -332,6 +333,7 @@ static int xadc_zynq_setup(struct platform_device *pdev, unsigned int div; unsigned int igap; unsigned int tck_rate; + int ret; /* TODO: Figure out how to make igap and tck_rate configurable */ igap = XADC_ZYNQ_IGAP_DEFAULT; @@ -340,9 +342,16 @@ static int xadc_zynq_setup(struct platform_device *pdev, xadc->zynq_intmask = ~0; pcap_rate = clk_get_rate(xadc->clk); + if (!pcap_rate) + return -EINVAL; + + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, + (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); + if (ret) + return ret; + } - if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) - tck_rate = XADC_ZYNQ_TCK_RATE_MAX; if (tck_rate > pcap_rate / 2) { div = 2; } else { @@ -368,6 +377,12 @@ static int xadc_zynq_setup(struct platform_device *pdev, XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, pcap_rate); + if (ret) + return ret; + } + return 0; } @@ -889,6 +904,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev, unsigned long clk_rate = xadc_get_dclk_rate(xadc); unsigned int div; + if (!clk_rate) + return -EINVAL; + if (info != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; @@ -1045,7 +1063,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, unsigned int num_channels; const char *external_mux; u32 ext_mux_chan; - int reg; + u32 reg; int ret; *conf = 0; @@ -1157,6 +1175,7 @@ static int xadc_probe(struct platform_device *pdev) xadc = iio_priv(indio_dev); xadc->ops = id->data; + xadc->irq = irq; init_completion(&xadc->completion); mutex_init(&xadc->mutex); spin_lock_init(&xadc->lock); @@ -1207,14 +1226,14 @@ static int xadc_probe(struct platform_device *pdev) if (ret) goto err_free_samplerate_trigger; - ret = xadc->ops->setup(pdev, indio_dev, irq); + ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0, + dev_name(&pdev->dev), indio_dev); if (ret) goto err_clk_disable_unprepare; - ret = request_irq(irq, xadc->ops->interrupt_handler, 0, - dev_name(&pdev->dev), indio_dev); + ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); if (ret) - goto err_clk_disable_unprepare; + goto err_free_irq; for (i = 0; i < 16; i++) xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), @@ -1239,8 +1258,10 @@ static int xadc_probe(struct platform_device *pdev) goto err_free_irq; /* Disable all alarms */ - xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, - XADC_CONF1_ALARM_MASK); + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, + XADC_CONF1_ALARM_MASK); + if (ret) + goto err_free_irq; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { @@ -1268,7 +1289,7 @@ static int xadc_probe(struct platform_device *pdev) return 0; err_free_irq: - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); err_clk_disable_unprepare: clk_disable_unprepare(xadc->clk); err_free_samplerate_trigger: @@ -1290,7 +1311,6 @@ static int xadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct xadc *xadc = iio_priv(indio_dev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(indio_dev); if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { @@ -1298,7 +1318,7 @@ static int xadc_remove(struct platform_device *pdev) iio_trigger_free(xadc->convst_trigger); iio_triggered_buffer_cleanup(indio_dev); } - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); clk_disable_unprepare(xadc->clk); cancel_delayed_work(&xadc->zynq_unmask_work); kfree(xadc->data); diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 62edbdae1244..8c0009585c16 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -68,6 +68,7 @@ struct xadc { spinlock_t lock; struct completion completion; + int irq; }; struct xadc_ops { |