diff options
29 files changed, 1225 insertions, 472 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 731146c3b138..c7353030670a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -197,6 +197,18 @@ Description: Angle of rotation. Units after application of scale and offset are radians. +What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_x_raw +What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_y_raw +KernelVersion: 4.18 +Contact: linux-iio@vger.kernel.org +Description: + Relative position in direction x or y on a pad (may be + arbitrarily assigned but should match other such assignments on + device). + Units after application of scale and offset are milli percents + from the pad's size in both directions. Should be calibrated by + the consumer. + What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw diff --git a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt index 6469a4cd2a6d..4a3c1d496e1a 100644 --- a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt @@ -21,6 +21,14 @@ Optional properties: - dmas: Phandle to dma channel for the ADC. - dma-names: Must be "rx" when dmas property is being used. See ../../dma/dma.txt for details. + - #io-channel-cells: in case consumer drivers are attached, this must be 1. + See <Documentation/devicetree/bindings/iio/iio-bindings.txt> for details. + +Properties for consumer drivers: + - Consumer drivers can be connected to this producer device, as specified + in <Documentation/devicetree/bindings/iio/iio-bindings.txt> + - Channels exposed are specified in: + <dt-bindings/iio/adc/at91-sama5d2_adc.txt> Example: @@ -38,4 +46,5 @@ adc: adc@fc030000 { atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>; dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>; dma-names = "rx"; + #io-channel-cells = <1>; } diff --git a/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt new file mode 100644 index 000000000000..51456c0e9a27 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt @@ -0,0 +1,30 @@ +Generic resistive touchscreen ADC + +Required properties: + + - compatible: must be "resistive-adc-touch" +The device must be connected to an ADC device that provides channels for +position measurement and optional pressure. +Refer to ../iio/iio-bindings.txt for details + - iio-channels: must have at least two channels connected to an ADC device. +These should correspond to the channels exposed by the ADC device and should +have the right index as the ADC device registers them. These channels +represent the relative position on the "x" and "y" axes. + - iio-channel-names: must have all the channels' names. Mandatory channels +are "x" and "y". + +Optional properties: + - iio-channels: The third channel named "pressure" is optional and can be +used if the ADC device also measures pressure besides position. +If this channel is missing, pressure will be ignored and the touchscreen +will only report position. + - iio-channel-names: optional channel named "pressure". + +Example: + + resistive_touch: resistive_touch { + compatible = "resistive-adc-touch"; + touchscreen-min-pressure = <50000>; + io-channels = <&adc 24>, <&adc 25>, <&adc 26>; + io-channel-names = "x", "y", "pressure"; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt index 537643e86f61..d092d5d033a0 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt @@ -7,6 +7,9 @@ Optional properties for Touchscreens: (in pixels) - touchscreen-max-pressure : maximum reported pressure (arbitrary range dependent on the controller) + - touchscreen-min-pressure : minimum pressure on the touchscreen to be + achieved in order for the touchscreen + driver to report a touch event. - touchscreen-fuzz-x : horizontal noise value of the absolute input device (in pixels) - touchscreen-fuzz-y : vertical noise value of the absolute input diff --git a/MAINTAINERS b/MAINTAINERS index 9d5eeff51b5f..a21cadbf39e7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2547,6 +2547,13 @@ S: Maintained F: drivers/auxdisplay/ F: include/linux/cfag12864b.h +AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER +M: Andreas Klinger <ak@it-klinger.de> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/avia-hx711.txt +F: drivers/iio/adc/hx711.c + AX.25 NETWORK LAYER M: Ralf Baechle <ralf@linux-mips.org> L: linux-hams@vger.kernel.org @@ -6006,6 +6013,12 @@ F: drivers/base/power/domain*.c F: include/linux/pm_domain.h F: Documentation/devicetree/bindings/power/power_domain.txt +GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER +M: Eugen Hristev <eugen.hristev@microchip.com> +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/input/touchscreen/resistive-adc-touch.c + GENERIC UIO DRIVER FOR PCI DEVICES M: "Michael S. Tsirkin" <mst@redhat.com> L: kvm@vger.kernel.org diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9da79070357c..084638e4ddf2 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 @@ -647,7 +646,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 +715,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/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 8729d6524b4d..e02f7d1c86bc 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,97 @@ 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; 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, + (u16 *)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, + (u16 *)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 +1393,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 +1408,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 +1545,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 +1575,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 +1608,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 +1630,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 +1653,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 +1718,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 +1778,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 +1891,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/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index b56985078d8c..92be8d0f7735 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -59,6 +59,39 @@ struct quad8_iio { unsigned int base; }; +#define QUAD8_REG_CHAN_OP 0x11 +#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 +/* Borrow Toggle flip-flop */ +#define QUAD8_FLAG_BT BIT(0) +/* Carry Toggle flip-flop */ +#define QUAD8_FLAG_CT BIT(1) +/* Error flag */ +#define QUAD8_FLAG_E BIT(4) +/* Up/Down flag */ +#define QUAD8_FLAG_UD BIT(5) +/* Reset and Load Signal Decoders */ +#define QUAD8_CTR_RLD 0x00 +/* Counter Mode Register */ +#define QUAD8_CTR_CMR 0x20 +/* Input / Output Control Register */ +#define QUAD8_CTR_IOR 0x40 +/* Index Control Register */ +#define QUAD8_CTR_IDR 0x60 +/* Reset Byte Pointer (three byte data pointer) */ +#define QUAD8_RLD_RESET_BP 0x01 +/* Reset Counter */ +#define QUAD8_RLD_RESET_CNTR 0x02 +/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */ +#define QUAD8_RLD_RESET_FLAGS 0x04 +/* Reset Error flag */ +#define QUAD8_RLD_RESET_E 0x06 +/* Preset Register to Counter */ +#define QUAD8_RLD_PRESET_CNTR 0x08 +/* Transfer Counter to Output Latch */ +#define QUAD8_RLD_CNTR_OUT 0x10 +#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00 +#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 + static int quad8_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -72,19 +105,21 @@ static int quad8_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type == IIO_INDEX) { - *val = !!(inb(priv->base + 0x16) & BIT(chan->channel)); + *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) + & BIT(chan->channel)); return IIO_VAL_INT; } flags = inb(base_offset + 1); - borrow = flags & BIT(0); - carry = !!(flags & BIT(1)); + borrow = flags & QUAD8_FLAG_BT; + carry = !!(flags & QUAD8_FLAG_CT); /* Borrow XOR Carry effectively doubles count range */ *val = (borrow ^ carry) << 24; /* Reset Byte Pointer; transfer Counter to Output Latch */ - outb(0x11, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, + base_offset + 1); for (i = 0; i < 3; i++) *val |= (unsigned int)inb(base_offset) << (8 * i); @@ -120,17 +155,17 @@ static int quad8_write_raw(struct iio_dev *indio_dev, return -EINVAL; /* Reset Byte Pointer */ - outb(0x01, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Counter can only be set via Preset Register */ for (i = 0; i < 3; i++) outb(val >> (8 * i), base_offset); /* Transfer Preset Register to Counter */ - outb(0x08, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); /* Reset Byte Pointer */ - outb(0x01, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Set Preset Register back to original value */ val = priv->preset[chan->channel]; @@ -138,9 +173,9 @@ static int quad8_write_raw(struct iio_dev *indio_dev, outb(val >> (8 * i), base_offset); /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(0x02, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); /* Reset Error flag */ - outb(0x06, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); return 0; case IIO_CHAN_INFO_ENABLE: @@ -153,7 +188,7 @@ static int quad8_write_raw(struct iio_dev *indio_dev, ior_cfg = val | priv->preset_enable[chan->channel] << 1; /* Load I/O control configuration */ - outb(0x40 | ior_cfg, base_offset + 1); + outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); return 0; case IIO_CHAN_INFO_SCALE: @@ -217,7 +252,7 @@ static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, priv->preset[chan->channel] = preset; /* Reset Byte Pointer */ - outb(0x01, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Set Preset Register */ for (i = 0; i < 3; i++) @@ -258,7 +293,7 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, (unsigned int)preset_enable << 1; /* Load I/O control configuration to Input / Output Control Register */ - outb(0x40 | ior_cfg, base_offset); + outb(QUAD8_CTR_IOR | ior_cfg, base_offset); return len; } @@ -274,7 +309,7 @@ static int quad8_get_noise_error(struct iio_dev *indio_dev, struct quad8_iio *const priv = iio_priv(indio_dev); const int base_offset = priv->base + 2 * chan->channel + 1; - return !!(inb(base_offset) & BIT(4)); + return !!(inb(base_offset) & QUAD8_FLAG_E); } static const struct iio_enum quad8_noise_error_enum = { @@ -294,7 +329,7 @@ static int quad8_get_count_direction(struct iio_dev *indio_dev, struct quad8_iio *const priv = iio_priv(indio_dev); const int base_offset = priv->base + 2 * chan->channel + 1; - return !!(inb(base_offset) & BIT(5)); + return !!(inb(base_offset) & QUAD8_FLAG_UD); } static const struct iio_enum quad8_count_direction_enum = { @@ -324,7 +359,7 @@ static int quad8_set_count_mode(struct iio_dev *indio_dev, mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; /* Load mode configuration to Counter Mode Register */ - outb(0x20 | mode_cfg, base_offset); + outb(QUAD8_CTR_CMR | mode_cfg, base_offset); return 0; } @@ -364,7 +399,7 @@ static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, priv->synchronous_mode[chan->channel] = synchronous_mode; /* Load Index Control configuration to Index Control Register */ - outb(0x60 | idr_cfg, base_offset); + outb(QUAD8_CTR_IDR | idr_cfg, base_offset); return 0; } @@ -410,7 +445,7 @@ static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, priv->quadrature_mode[chan->channel] = quadrature_mode; /* Load mode configuration to Counter Mode Register */ - outb(0x20 | mode_cfg, base_offset); + outb(QUAD8_CTR_CMR | mode_cfg, base_offset); return 0; } @@ -446,7 +481,7 @@ static int quad8_set_index_polarity(struct iio_dev *indio_dev, priv->index_polarity[chan->channel] = index_polarity; /* Load Index Control configuration to Index Control Register */ - outb(0x60 | idr_cfg, base_offset); + outb(QUAD8_CTR_IDR | idr_cfg, base_offset); return 0; } @@ -556,28 +591,28 @@ static int quad8_probe(struct device *dev, unsigned int id) priv->base = base[id]; /* Reset all counters and disable interrupt function */ - outb(0x01, base[id] + 0x11); + outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); /* Set initial configuration for all counters */ for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { base_offset = base[id] + 2 * i; /* Reset Byte Pointer */ - outb(0x01, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Reset Preset Register */ for (j = 0; j < 3; j++) outb(0x00, base_offset); /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(0x04, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); /* Reset Error flag */ - outb(0x06, base_offset + 1); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); /* Binary encoding; Normal count; non-quadrature mode */ - outb(0x20, base_offset + 1); + outb(QUAD8_CTR_CMR, base_offset + 1); /* Disable A and B inputs; preset on index; FLG1 as Carry */ - outb(0x40, base_offset + 1); + outb(QUAD8_CTR_IOR, base_offset + 1); /* Disable index function; negative index polarity */ - outb(0x60, base_offset + 1); + outb(QUAD8_CTR_IDR, base_offset + 1); } /* Enable all counters */ - outb(0x00, base[id] + 0x11); + outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index e136f0fd38f0..2ddbfc3fdbae 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -221,6 +221,7 @@ static struct iio_chan_spec name[] = { \ AD5868_CHANNEL(7, 7, bits, _shift), \ } +DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); @@ -231,6 +232,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2); DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4); static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { + [ID_AD5311R] = { + .channels = ad5311r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5693_REGMAP, + }, [ID_AD5671R] = { .channels = ad5672_channels, .int_vref_mv = 2500, diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index d05cda9f1edd..57b3c61bfb91 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -45,6 +45,7 @@ * ad5686_supported_device_ids: */ enum ad5686_supported_device_ids { + ID_AD5311R, ID_AD5671R, ID_AD5672R, ID_AD5675R, diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index d18735d7d938..7350d9806a11 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -71,6 +71,7 @@ static int ad5686_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id ad5686_i2c_id[] = { + {"ad5311r", ID_AD5311R}, {"ad5671r", ID_AD5671R}, {"ad5675r", ID_AD5675R}, {"ad5691r", ID_AD5691R}, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index f9c0624505a2..de68e83fc52d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -20,8 +20,6 @@ #include <linux/jiffies.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/kfifo.h> -#include <linux/spinlock.h> #include <linux/iio/iio.h> #include <linux/acpi.h> #include <linux/platform_device.h> @@ -84,7 +82,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = { static const struct inv_mpu6050_chip_config chip_config_6050 = { .fsr = INV_MPU6050_FSR_2000DPS, .lpf = INV_MPU6050_FILTER_20HZ, - .fifo_rate = INV_MPU6050_INIT_FIFO_RATE, + .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE), .gyro_fifo_enable = false, .accl_fifo_enable = false, .accl_fs = INV_MPU6050_FS_02G, @@ -280,7 +278,7 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) if (result) goto error_power_off; - d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; + d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE); result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) goto error_power_off; @@ -297,6 +295,13 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) memcpy(&st->chip_config, hw_info[st->chip_type].config, sizeof(struct inv_mpu6050_chip_config)); + /* + * Internal chip period is 1ms (1kHz). + * Let's use at the beginning the theorical value before measuring + * with interrupt timestamps. + */ + st->chip_period = NSEC_PER_MSEC; + return inv_mpu6050_set_power_itg(st, false); error_power_off: @@ -630,7 +635,7 @@ static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - s32 fifo_rate; + int fifo_rate; u8 d; int result; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -646,8 +651,13 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, if (result) return result; + /* compute the chip sample rate divider */ + d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate); + /* compute back the fifo rate to handle truncation cases */ + fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(d); + mutex_lock(&st->lock); - if (fifo_rate == st->chip_config.fifo_rate) { + if (d == st->chip_config.divider) { result = 0; goto fifo_rate_fail_unlock; } @@ -655,11 +665,10 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, if (result) goto fifo_rate_fail_unlock; - d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) goto fifo_rate_fail_power_off; - st->chip_config.fifo_rate = fifo_rate; + st->chip_config.divider = d; result = inv_mpu6050_set_lpf(st, fifo_rate); if (result) @@ -687,7 +696,7 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr, unsigned fifo_rate; mutex_lock(&st->lock); - fifo_rate = st->chip_config.fifo_rate; + fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider); mutex_unlock(&st->lock); return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate); @@ -1003,7 +1012,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, indio_dev->modes = INDIO_BUFFER_TRIGGERED; result = devm_iio_triggered_buffer_setup(dev, indio_dev, - inv_mpu6050_irq_handler, + iio_pollfunc_store_time, inv_mpu6050_read_fifo, NULL); if (result) { @@ -1016,8 +1025,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return result; } - INIT_KFIFO(st->timestamps); - spin_lock_init(&st->time_stamp_lock); result = devm_iio_device_register(dev, indio_dev); if (result) { dev_err(dev, "IIO register fail %d\n", result); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index c54da777945d..de8391693e17 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -12,8 +12,6 @@ */ #include <linux/i2c.h> #include <linux/i2c-mux.h> -#include <linux/kfifo.h> -#include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -88,7 +86,7 @@ enum inv_devices { * @accl_fs: accel full scale range. * @accl_fifo_enable: enable accel data output * @gyro_fifo_enable: enable gyro data output - * @fifo_rate: FIFO update rate. + * @divider: chip sample rate divider (sample rate divider - 1) */ struct inv_mpu6050_chip_config { unsigned int fsr:2; @@ -96,7 +94,7 @@ struct inv_mpu6050_chip_config { unsigned int accl_fs:2; unsigned int accl_fifo_enable:1; unsigned int gyro_fifo_enable:1; - u16 fifo_rate; + u8 divider; u8 user_ctrl; }; @@ -116,40 +114,40 @@ struct inv_mpu6050_hw { /* * struct inv_mpu6050_state - Driver state variables. - * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. * @lock: Chip access lock. * @trig: IIO trigger. * @chip_config: Cached attribute information. * @reg: Map of important registers. * @hw: Other hardware-specific information. * @chip_type: chip type. - * @time_stamp_lock: spin lock to time stamp. * @plat_data: platform data (deprecated in favor of @orientation). * @orientation: sensor chip orientation relative to main hardware. - * @timestamps: kfifo queue to store time stamp. * @map regmap pointer. * @irq interrupt number. * @irq_mask the int_pin_cfg mask to configure interrupt type. + * @chip_period: chip internal period estimation (~1kHz). + * @it_timestamp: timestamp from previous interrupt. + * @data_timestamp: timestamp for next data sample. */ struct inv_mpu6050_state { -#define TIMESTAMP_FIFO_SIZE 16 struct mutex lock; struct iio_trigger *trig; struct inv_mpu6050_chip_config chip_config; const struct inv_mpu6050_reg_map *reg; const struct inv_mpu6050_hw *hw; enum inv_devices chip_type; - spinlock_t time_stamp_lock; struct i2c_mux_core *muxc; struct i2c_client *mux_client; unsigned int powerup_count; struct inv_mpu6050_platform_data plat_data; struct iio_mount_matrix orientation; - DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); struct regmap *map; int irq; u8 irq_mask; unsigned skip_samples; + s64 chip_period; + s64 it_timestamp; + s64 data_timestamp; }; /*register and associated bit definition*/ @@ -174,6 +172,7 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_RAW_GYRO 0x43 #define INV_MPU6050_REG_INT_STATUS 0x3A +#define INV_MPU6050_BIT_FIFO_OVERFLOW_INT 0x10 #define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01 #define INV_MPU6050_REG_USER_CTRL 0x6A @@ -198,7 +197,6 @@ struct inv_mpu6050_state { #define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 #define INV_MPU6050_FIFO_COUNT_BYTE 2 -#define INV_MPU6050_FIFO_THRESHOLD 500 /* mpu6500 registers */ #define INV_MPU6500_REG_ACCEL_CONFIG_2 0x1D @@ -231,13 +229,24 @@ struct inv_mpu6050_state { #define INV_MPU6050_LATCH_INT_EN 0x20 #define INV_MPU6050_BIT_BYPASS_EN 0x2 +/* Allowed timestamp period jitter in percent */ +#define INV_MPU6050_TS_PERIOD_JITTER 4 /* init parameters */ #define INV_MPU6050_INIT_FIFO_RATE 50 -#define INV_MPU6050_TIME_STAMP_TOR 5 #define INV_MPU6050_MAX_FIFO_RATE 1000 #define INV_MPU6050_MIN_FIFO_RATE 4 -#define INV_MPU6050_ONE_K_HZ 1000 + +/* chip internal frequency: 1KHz */ +#define INV_MPU6050_INTERNAL_FREQ_HZ 1000 +/* return the frequency divider (chip sample rate divider + 1) */ +#define INV_MPU6050_FREQ_DIVIDER(st) \ + ((st)->chip_config.divider + 1) +/* chip sample rate divider to fifo rate */ +#define INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate) \ + ((INV_MPU6050_INTERNAL_FREQ_HZ / (fifo_rate)) - 1) +#define INV_MPU6050_DIVIDER_TO_FIFO_RATE(divider) \ + (INV_MPU6050_INTERNAL_FREQ_HZ / ((divider) + 1)) #define INV_MPU6050_REG_WHOAMI 117 @@ -300,7 +309,6 @@ enum inv_mpu6050_clock_sel_e { NUM_CLK }; -irqreturn_t inv_mpu6050_irq_handler(int irq, void *p); irqreturn_t inv_mpu6050_read_fifo(int irq, void *p); int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type); int inv_reset_fifo(struct iio_dev *indio_dev); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 1795418438e4..548e042f7b5b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -19,18 +19,83 @@ #include <linux/jiffies.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/kfifo.h> #include <linux/poll.h> +#include <linux/math64.h> +#include <asm/unaligned.h> #include "inv_mpu_iio.h" -static void inv_clear_kfifo(struct inv_mpu6050_state *st) +/** + * inv_mpu6050_update_period() - Update chip internal period estimation + * + * @st: driver state + * @timestamp: the interrupt timestamp + * @nb: number of data set in the fifo + * + * This function uses interrupt timestamps to estimate the chip period and + * to choose the data timestamp to come. + */ +static void inv_mpu6050_update_period(struct inv_mpu6050_state *st, + s64 timestamp, size_t nb) { - unsigned long flags; + /* Period boundaries for accepting timestamp */ + const s64 period_min = + (NSEC_PER_MSEC * (100 - INV_MPU6050_TS_PERIOD_JITTER)) / 100; + const s64 period_max = + (NSEC_PER_MSEC * (100 + INV_MPU6050_TS_PERIOD_JITTER)) / 100; + const s32 divider = INV_MPU6050_FREQ_DIVIDER(st); + s64 delta, interval; + bool use_it_timestamp = false; + + if (st->it_timestamp == 0) { + /* not initialized, forced to use it_timestamp */ + use_it_timestamp = true; + } else if (nb == 1) { + /* + * Validate the use of it timestamp by checking if interrupt + * has been delayed. + * nb > 1 means interrupt was delayed for more than 1 sample, + * so it's obviously not good. + * Compute the chip period between 2 interrupts for validating. + */ + delta = div_s64(timestamp - st->it_timestamp, divider); + if (delta > period_min && delta < period_max) { + /* update chip period and use it timestamp */ + st->chip_period = (st->chip_period + delta) / 2; + use_it_timestamp = true; + } + } + + if (use_it_timestamp) { + /* + * Manage case of multiple samples in the fifo (nb > 1): + * compute timestamp corresponding to the first sample using + * estimated chip period. + */ + interval = (nb - 1) * st->chip_period * divider; + st->data_timestamp = timestamp - interval; + } - /* take the spin lock sem to avoid interrupt kick in */ - spin_lock_irqsave(&st->time_stamp_lock, flags); - kfifo_reset(&st->timestamps); - spin_unlock_irqrestore(&st->time_stamp_lock, flags); + /* save it timestamp */ + st->it_timestamp = timestamp; +} + +/** + * inv_mpu6050_get_timestamp() - Return the current data timestamp + * + * @st: driver state + * @return: current data timestamp + * + * This function returns the current data timestamp and prepares for next one. + */ +static s64 inv_mpu6050_get_timestamp(struct inv_mpu6050_state *st) +{ + s64 ts; + + /* return current data timestamp and increment */ + ts = st->data_timestamp; + st->data_timestamp += st->chip_period * INV_MPU6050_FREQ_DIVIDER(st); + + return ts; } int inv_reset_fifo(struct iio_dev *indio_dev) @@ -39,6 +104,9 @@ int inv_reset_fifo(struct iio_dev *indio_dev) u8 d; struct inv_mpu6050_state *st = iio_priv(indio_dev); + /* reset it timestamp validation */ + st->it_timestamp = 0; + /* disable interrupt */ result = regmap_write(st->map, st->reg->int_enable, 0); if (result) { @@ -62,9 +130,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev) if (result) goto reset_fifo_fail; - /* clear timestamps fifo */ - inv_clear_kfifo(st); - /* enable interrupt */ if (st->chip_config.accl_fifo_enable || st->chip_config.gyro_fifo_enable) { @@ -99,23 +164,6 @@ reset_fifo_fail: } /** - * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. - */ -irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - s64 timestamp; - - timestamp = iio_get_time_ns(indio_dev); - kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, - &st->time_stamp_lock); - - return IRQ_WAKE_THREAD; -} - -/** * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO. */ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) @@ -129,6 +177,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u16 fifo_count; s64 timestamp; int int_status; + size_t i, nb; mutex_lock(&st->lock); @@ -139,6 +188,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) "failed to ack interrupt\n"); goto flush_fifo; } + /* handle fifo overflow by reseting fifo */ + if (int_status & INV_MPU6050_BIT_FIFO_OVERFLOW_INT) + goto flush_fifo; if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) { dev_warn(regmap_get_device(st->map), "spurious interrupt with status 0x%x\n", int_status); @@ -163,38 +215,23 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) INV_MPU6050_FIFO_COUNT_BYTE); if (result) goto end_session; - fifo_count = be16_to_cpup((__be16 *)(&data[0])); - if (fifo_count < bytes_per_datum) - goto end_session; - /* fifo count can't be an odd number. If it is odd, reset the FIFO. */ - if (fifo_count & 1) - goto flush_fifo; - if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) - goto flush_fifo; - /* Timestamp mismatch. */ - if (kfifo_len(&st->timestamps) > - fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) - goto flush_fifo; - do { + fifo_count = get_unaligned_be16(&data[0]); + /* compute and process all complete datum */ + nb = fifo_count / bytes_per_datum; + inv_mpu6050_update_period(st, pf->timestamp, nb); + for (i = 0; i < nb; ++i) { result = regmap_bulk_read(st->map, st->reg->fifo_r_w, data, bytes_per_datum); if (result) goto flush_fifo; - - result = kfifo_out(&st->timestamps, ×tamp, 1); - /* when there is no timestamp, put timestamp as 0 */ - if (result == 0) - timestamp = 0; - /* skip first samples if needed */ - if (st->skip_samples) + if (st->skip_samples) { st->skip_samples--; - else - iio_push_to_buffers_with_timestamp(indio_dev, data, - timestamp); - - fifo_count -= bytes_per_datum; - } while (fifo_count >= bytes_per_datum); + continue; + } + timestamp = inv_mpu6050_get_timestamp(st); + iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); + } end_session: mutex_unlock(&st->lock); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 19bdf3d2962a..ed1b3ebade94 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -85,6 +85,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_COUNT] = "count", [IIO_INDEX] = "index", [IIO_GRAVITY] = "gravity", + [IIO_POSITIONRELATIVE] = "positionrelative", }; static const char * const iio_modifier_names[] = { @@ -207,35 +208,27 @@ static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) */ s64 iio_get_time_ns(const struct iio_dev *indio_dev) { - struct timespec tp; + struct timespec64 tp; switch (iio_device_get_clock(indio_dev)) { case CLOCK_REALTIME: - ktime_get_real_ts(&tp); - break; + return ktime_get_real_ns(); case CLOCK_MONOTONIC: - ktime_get_ts(&tp); - break; + return ktime_get_ns(); case CLOCK_MONOTONIC_RAW: - getrawmonotonic(&tp); - break; + return ktime_get_raw_ns(); case CLOCK_REALTIME_COARSE: - tp = current_kernel_time(); - break; + return ktime_to_ns(ktime_get_coarse_real()); case CLOCK_MONOTONIC_COARSE: - tp = get_monotonic_coarse(); - break; + ktime_get_coarse_ts64(&tp); + return timespec64_to_ns(&tp); case CLOCK_BOOTTIME: - get_monotonic_boottime(&tp); - break; + return ktime_get_boot_ns(); case CLOCK_TAI: - timekeeping_clocktai(&tp); - break; + return ktime_get_tai_ns(); default: BUG(); } - - return timespec_to_ns(&tp); } EXPORT_SYMBOL(iio_get_time_ns); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 32267c1afebc..66d1a220726a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -92,6 +92,19 @@ config TOUCHSCREEN_AD7879_SPI To compile this driver as a module, choose M here: the module will be called ad7879-spi. +config TOUCHSCREEN_ADC + tristate "Generic ADC based resistive touchscreen" + depends on IIO + select IIO_BUFFER_CB + help + Say Y here if you want to use the generic ADC + resistive touchscreen driver. + + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called resistive-adc-touch.ko. + config TOUCHSCREEN_AR1021_I2C tristate "Microchip AR1020/1021 i2c touchscreen" depends on I2C && OF diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index fd4fd32fb73f..35bd0619edf1 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o +obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c new file mode 100644 index 000000000000..cfc8bb4553f7 --- /dev/null +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADC generic resistive touchscreen (GRTS) + * This is a generic input driver that connects to an ADC + * given the channels in device tree, and reports events to the input + * subsystem. + * + * Copyright (C) 2017,2018 Microchip Technology, + * Author: Eugen Hristev <eugen.hristev@microchip.com> + * + */ +#include <linux/input.h> +#include <linux/input/touchscreen.h> +#include <linux/iio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#define DRIVER_NAME "resistive-adc-touch" +#define GRTS_DEFAULT_PRESSURE_MIN 50000 +#define GRTS_MAX_POS_MASK GENMASK(11, 0) + +/** + * grts_state - generic resistive touch screen information struct + * @pressure_min: number representing the minimum for the pressure + * @pressure: are we getting pressure info or not + * @iio_chans: list of channels acquired + * @iio_cb: iio_callback buffer for the data + * @input: the input device structure that we register + * @prop: touchscreen properties struct + */ +struct grts_state { + u32 pressure_min; + bool pressure; + struct iio_channel *iio_chans; + struct iio_cb_buffer *iio_cb; + struct input_dev *input; + struct touchscreen_properties prop; +}; + +static int grts_cb(const void *data, void *private) +{ + const u16 *touch_info = data; + struct grts_state *st = private; + unsigned int x, y, press = 0x0; + + /* channel data coming in buffer in the order below */ + x = touch_info[0]; + y = touch_info[1]; + if (st->pressure) + press = touch_info[2]; + + if ((!x && !y) || (st->pressure && (press < st->pressure_min))) { + /* report end of touch */ + input_report_key(st->input, BTN_TOUCH, 0); + input_sync(st->input); + return 0; + } + + /* report proper touch to subsystem*/ + touchscreen_report_pos(st->input, &st->prop, x, y, false); + if (st->pressure) + input_report_abs(st->input, ABS_PRESSURE, press); + input_report_key(st->input, BTN_TOUCH, 1); + input_sync(st->input); + + return 0; +} + +static int grts_open(struct input_dev *dev) +{ + int error; + struct grts_state *st = input_get_drvdata(dev); + + error = iio_channel_start_all_cb(st->iio_cb); + if (error) { + dev_err(dev->dev.parent, "failed to start callback buffer.\n"); + return error; + } + return 0; +} + +static void grts_close(struct input_dev *dev) +{ + struct grts_state *st = input_get_drvdata(dev); + + iio_channel_stop_all_cb(st->iio_cb); +} + +static void grts_disable(void *data) +{ + iio_channel_release_all_cb(data); +} + +static int grts_probe(struct platform_device *pdev) +{ + struct grts_state *st; + struct input_dev *input; + struct device *dev = &pdev->dev; + struct iio_channel *chan; + int error; + + st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL); + if (!st) + return -ENOMEM; + + /* get the channels from IIO device */ + st->iio_chans = devm_iio_channel_get_all(dev); + if (IS_ERR(st->iio_chans)) { + error = PTR_ERR(st->iio_chans); + if (error != -EPROBE_DEFER) + dev_err(dev, "can't get iio channels.\n"); + return error; + } + + chan = &st->iio_chans[0]; + st->pressure = false; + while (chan && chan->indio_dev) { + if (!strcmp(chan->channel->datasheet_name, "pressure")) + st->pressure = true; + chan++; + } + + if (st->pressure) { + error = device_property_read_u32(dev, + "touchscreen-min-pressure", + &st->pressure_min); + if (error) { + dev_dbg(dev, "can't get touchscreen-min-pressure property.\n"); + st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN; + } + } + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "failed to allocate input device.\n"); + return -ENOMEM; + } + + input->name = DRIVER_NAME; + input->id.bustype = BUS_HOST; + input->open = grts_open; + input->close = grts_close; + + input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0); + input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0); + if (st->pressure) + input_set_abs_params(input, ABS_PRESSURE, st->pressure_min, + 0xffff, 0, 0); + + input_set_capability(input, EV_KEY, BTN_TOUCH); + + /* parse optional device tree properties */ + touchscreen_parse_properties(input, false, &st->prop); + + st->input = input; + input_set_drvdata(input, st); + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to register input device."); + return error; + } + + st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st); + if (IS_ERR(st->iio_cb)) { + dev_err(dev, "failed to allocate callback buffer.\n"); + return PTR_ERR(st->iio_cb); + } + + error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb); + if (error) { + dev_err(dev, "failed to add disable action.\n"); + return error; + } + + return 0; +} + +static const struct of_device_id grts_of_match[] = { + { + .compatible = "resistive-adc-touch", + }, { + /* sentinel */ + }, +}; + +MODULE_DEVICE_TABLE(of, grts_of_match); + +static struct platform_driver grts_driver = { + .probe = grts_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(grts_of_match), + }, +}; + +module_platform_driver(grts_driver); + +MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>"); +MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index aee2335a25a1..e86ac9e47867 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -9,7 +9,6 @@ source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/frequency/Kconfig" -source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" source "drivers/staging/iio/meter/Kconfig" source "drivers/staging/iio/resolver/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index c28d657497de..b15904b99581 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -8,7 +8,6 @@ obj-y += adc/ obj-y += addac/ obj-y += cdc/ obj-y += frequency/ -obj-y += gyro/ obj-y += impedance-analyzer/ obj-y += meter/ obj-y += resolver/ diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c index b3e4571340ab..5cc96c8086b5 100644 --- a/drivers/staging/iio/accel/adis16203.c +++ b/drivers/staging/iio/accel/adis16203.c @@ -168,7 +168,6 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, { struct adis *st = iio_priv(indio_dev); int ret; - int bits; u8 addr; s16 val16; @@ -202,14 +201,11 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, *val = 25000 / -470 - 1278; /* 25 C = 1278 */ return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: - bits = 14; addr = adis16203_addresses[chan->scan_index]; ret = adis_read_reg_16(st, addr, &val16); if (ret) return ret; - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; + *val = sign_extend32(val16, 13); return IIO_VAL_INT; default: return -EINVAL; diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c index fff6d99089cc..24e525f1ef25 100644 --- a/drivers/staging/iio/accel/adis16240.c +++ b/drivers/staging/iio/accel/adis16240.c @@ -250,7 +250,6 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, { struct adis *st = iio_priv(indio_dev); int ret; - int bits; u8 addr; s16 val16; @@ -287,24 +286,18 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, *val = 25000 / 244 - 0x133; /* 25 C = 0x133 */ return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: - bits = 10; addr = adis16240_addresses[chan->scan_index][0]; ret = adis_read_reg_16(st, addr, &val16); if (ret) return ret; - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; + *val = sign_extend32(val16, 9); return IIO_VAL_INT; case IIO_CHAN_INFO_PEAK: - bits = 10; addr = adis16240_addresses[chan->scan_index][1]; ret = adis_read_reg_16(st, addr, &val16); if (ret) return ret; - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; + *val = sign_extend32(val16, 9); return IIO_VAL_INT; } return -EINVAL; diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index acaed8d5379c..9716ee9d94a7 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -57,7 +57,7 @@ struct ad7606_state { struct ad7606_bus_ops { /* more methods added in future? */ - int (*read_block)(struct device *, int, void *); + int (*read_block)(struct device *dev, int num, void *data); }; int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig deleted file mode 100644 index f62f68fd6f3f..000000000000 --- a/drivers/staging/iio/gyro/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# IIO Digital Gyroscope Sensor drivers configuration -# -menu "Digital gyroscope sensors" - -config ADIS16060 - tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver" - depends on SPI - help - Say Y (yes) here to build support for Analog Devices adis16060 wide bandwidth - yaw rate gyroscope with SPI. - - To compile this driver as a module, say M here: the module will be - called adis16060. If unsure, say N. - -endmenu diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile deleted file mode 100644 index cf22d6d55e27..000000000000 --- a/drivers/staging/iio/gyro/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for digital gyroscope sensor drivers -# - -adis16060-y := adis16060_core.o -obj-$(CONFIG_ADIS16060) += adis16060.o diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c deleted file mode 100644 index 4e7630caf7d3..000000000000 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */ -#define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */ -#define ADIS16060_AIN2 0x80 /* Measure AIN2 */ -#define ADIS16060_AIN1 0x40 /* Measure AIN1 */ - -/** - * struct adis16060_state - device instance specific data - * @us_w: actual spi_device to write config - * @us_r: actual spi_device to read back data - * @buf: transmit or receive buffer - * @buf_lock: mutex to protect tx and rx - **/ -struct adis16060_state { - struct spi_device *us_w; - struct spi_device *us_r; - struct mutex buf_lock; - - u8 buf[3] ____cacheline_aligned; -}; - -static struct iio_dev *adis16060_iio_dev; - -static int adis16060_spi_write_then_read(struct iio_dev *indio_dev, - u8 conf, u16 *val) -{ - int ret; - struct adis16060_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->buf[2] = conf; /* The last 8 bits clocked in are latched */ - ret = spi_write(st->us_w, st->buf, 3); - - if (ret < 0) { - mutex_unlock(&st->buf_lock); - return ret; - } - - ret = spi_read(st->us_r, st->buf, 3); - - /* The internal successive approximation ADC begins the - * conversion process on the falling edge of MSEL1 and - * starts to place data MSB first on the DOUT line at - * the 6th falling edge of SCLK - */ - if (!ret) - *val = ((st->buf[0] & 0x3) << 12) | - (st->buf[1] << 4) | - ((st->buf[2] >> 4) & 0xF); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int adis16060_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - u16 tval = 0; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = adis16060_spi_write_then_read(indio_dev, - chan->address, &tval); - if (ret < 0) - return ret; - - *val = tval; - return IIO_VAL_INT; - case IIO_CHAN_INFO_OFFSET: - *val = -7; - *val2 = 461117; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = 34000; - return IIO_VAL_INT_PLUS_MICRO; - } - - return -EINVAL; -} - -static const struct iio_info adis16060_info = { - .read_raw = adis16060_read_raw, -}; - -static const struct iio_chan_spec adis16060_channels[] = { - { - .type = IIO_ANGL_VEL, - .modified = 1, - .channel2 = IIO_MOD_Z, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .address = ADIS16060_GYRO, - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .address = ADIS16060_AIN1, - }, { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .address = ADIS16060_AIN2, - }, { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), - .address = ADIS16060_TEMP_OUT, - } -}; - -static int adis16060_r_probe(struct spi_device *spi) -{ - int ret; - struct adis16060_state *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - st = iio_priv(indio_dev); - st->us_r = spi; - mutex_init(&st->buf_lock); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16060_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = adis16060_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16060_channels); - - ret = devm_iio_device_register(&spi->dev, indio_dev); - if (ret) - return ret; - - adis16060_iio_dev = indio_dev; - return 0; -} - -static int adis16060_w_probe(struct spi_device *spi) -{ - int ret; - struct iio_dev *indio_dev = adis16060_iio_dev; - struct adis16060_state *st; - - if (!indio_dev) { - ret = -ENODEV; - goto error_ret; - } - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->us_w = spi; - return 0; - -error_ret: - return ret; -} - -static int adis16060_w_remove(struct spi_device *spi) -{ - return 0; -} - -static struct spi_driver adis16060_r_driver = { - .driver = { - .name = "adis16060_r", - }, - .probe = adis16060_r_probe, -}; - -static struct spi_driver adis16060_w_driver = { - .driver = { - .name = "adis16060_w", - }, - .probe = adis16060_w_probe, - .remove = adis16060_w_remove, -}; - -static __init int adis16060_init(void) -{ - int ret; - - ret = spi_register_driver(&adis16060_r_driver); - if (ret < 0) - return ret; - - ret = spi_register_driver(&adis16060_w_driver); - if (ret < 0) { - spi_unregister_driver(&adis16060_r_driver); - return ret; - } - - return 0; -} -module_init(adis16060_init); - -static __exit void adis16060_exit(void) -{ - spi_unregister_driver(&adis16060_w_driver); - spi_unregister_driver(&adis16060_r_driver); -} -module_exit(adis16060_exit); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/iio/adc/at91-sama5d2_adc.h b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h new file mode 100644 index 000000000000..70f99dbdbb42 --- /dev/null +++ b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for configuring the AT91 SAMA5D2 ADC + */ + +#ifndef _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H +#define _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H + +/* X relative position channel index */ +#define AT91_SAMA5D2_ADC_X_CHANNEL 24 +/* Y relative position channel index */ +#define AT91_SAMA5D2_ADC_Y_CHANNEL 25 +/* pressure channel index */ +#define AT91_SAMA5D2_ADC_P_CHANNEL 26 + +#endif diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 4213cdf88e3c..033c7d28924e 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -44,6 +44,7 @@ enum iio_chan_type { IIO_COUNT, IIO_INDEX, IIO_GRAVITY, + IIO_POSITIONRELATIVE, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index b61245e1181d..148f69dfae75 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -58,6 +58,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", [IIO_GRAVITY] = "gravity", + [IIO_POSITIONRELATIVE] = "positionrelative", }; static const char * const iio_ev_type_text[] = { @@ -151,6 +152,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_PH: case IIO_UVINDEX: case IIO_GRAVITY: + case IIO_POSITIONRELATIVE: break; default: return false; |