diff options
21 files changed, 2537 insertions, 33 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 new file mode 100644 index 000000000000..da9822309f07 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 | |||
@@ -0,0 +1,16 @@ | |||
1 | What: /sys/bus/iio/devices/iio:deviceX/in_voltage_spi_clk_freq | ||
2 | KernelVersion: 4.14 | ||
3 | Contact: arnaud.pouliquen@st.com | ||
4 | Description: | ||
5 | For audio purpose only. | ||
6 | Used by audio driver to set/get the spi input frequency. | ||
7 | This is mandatory if DFSDM is slave on SPI bus, to | ||
8 | provide information on the SPI clock frequency during runtime | ||
9 | Notice that the SPI frequency should be a multiple of sample | ||
10 | frequency to ensure the precision. | ||
11 | if DFSDM input is SPI master | ||
12 | Reading SPI clkout frequency, | ||
13 | error on writing | ||
14 | If DFSDM input is SPI Slave: | ||
15 | Reading returns value previously set. | ||
16 | Writing value before starting conversions. \ No newline at end of file | ||
diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt new file mode 100644 index 000000000000..e9ebb8a20e0d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt | |||
@@ -0,0 +1,13 @@ | |||
1 | Device-Tree bindings for sigma delta modulator | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use | ||
5 | as a generic SD modulator if modulator not specified in compatible list. | ||
6 | - #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". | ||
7 | |||
8 | Example node: | ||
9 | |||
10 | ads1202: adc@0 { | ||
11 | compatible = "sd-modulator"; | ||
12 | #io-channel-cells = <1>; | ||
13 | }; | ||
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt new file mode 100644 index 000000000000..911492da48f3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt | |||
@@ -0,0 +1,128 @@ | |||
1 | STMicroelectronics STM32 DFSDM ADC device driver | ||
2 | |||
3 | |||
4 | STM32 DFSDM ADC is a sigma delta analog-to-digital converter dedicated to | ||
5 | interface external sigma delta modulators to STM32 micro controllers. | ||
6 | It is mainly targeted for: | ||
7 | - Sigma delta modulators (motor control, metering...) | ||
8 | - PDM microphones (audio digital microphone) | ||
9 | |||
10 | It features up to 8 serial digital interfaces (SPI or Manchester) and | ||
11 | up to 4 filters on stm32h7. | ||
12 | |||
13 | Each child node match with a filter instance. | ||
14 | |||
15 | Contents of a STM32 DFSDM root node: | ||
16 | ------------------------------------ | ||
17 | Required properties: | ||
18 | - compatible: Should be "st,stm32h7-dfsdm". | ||
19 | - reg: Offset and length of the DFSDM block register set. | ||
20 | - clocks: IP and serial interfaces clocking. Should be set according | ||
21 | to rcc clock ID and "clock-names". | ||
22 | - clock-names: Input clock name "dfsdm" must be defined, | ||
23 | "audio" is optional. If defined CLKOUT is based on the audio | ||
24 | clock, else "dfsdm" is used. | ||
25 | - #interrupt-cells = <1>; | ||
26 | - #address-cells = <1>; | ||
27 | - #size-cells = <0>; | ||
28 | |||
29 | Optional properties: | ||
30 | - spi-max-frequency: Requested only for SPI master mode. | ||
31 | SPI clock OUT frequency (Hz). This clock must be set according | ||
32 | to "clock" property. Frequency must be a multiple of the rcc | ||
33 | clock frequency. If not, SPI CLKOUT frequency will not be | ||
34 | accurate. | ||
35 | |||
36 | Contents of a STM32 DFSDM child nodes: | ||
37 | -------------------------------------- | ||
38 | |||
39 | Required properties: | ||
40 | - compatible: Must be: | ||
41 | "st,stm32-dfsdm-adc" for sigma delta ADCs | ||
42 | "st,stm32-dfsdm-dmic" for audio digital microphone. | ||
43 | - reg: Specifies the DFSDM filter instance used. | ||
44 | - interrupts: IRQ lines connected to each DFSDM filter instance. | ||
45 | - st,adc-channels: List of single-ended channels muxed for this ADC. | ||
46 | valid values: | ||
47 | "st,stm32h7-dfsdm" compatibility: 0 to 7. | ||
48 | - st,adc-channel-names: List of single-ended channel names. | ||
49 | - st,filter-order: SinC filter order from 0 to 5. | ||
50 | 0: FastSinC | ||
51 | [1-5]: order 1 to 5. | ||
52 | For audio purpose it is recommended to use order 3 to 5. | ||
53 | - #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". | ||
54 | |||
55 | Required properties for "st,stm32-dfsdm-adc" compatibility: | ||
56 | - io-channels: From common IIO binding. Used to pipe external sigma delta | ||
57 | modulator or internal ADC output to DFSDM channel. | ||
58 | This is not required for "st,stm32-dfsdm-pdm" compatibility as | ||
59 | PDM microphone is binded in Audio DT node. | ||
60 | |||
61 | Required properties for "st,stm32-dfsdm-pdm" compatibility: | ||
62 | - #sound-dai-cells: Must be set to 0. | ||
63 | - dma: DMA controller phandle and DMA request line associated to the | ||
64 | filter instance (specified by the field "reg") | ||
65 | - dma-names: Must be "rx" | ||
66 | |||
67 | Optional properties: | ||
68 | - st,adc-channel-types: Single-ended channel input type. | ||
69 | - "SPI_R": SPI with data on rising edge (default) | ||
70 | - "SPI_F": SPI with data on falling edge | ||
71 | - "MANCH_R": manchester codec, rising edge = logic 0 | ||
72 | - "MANCH_F": manchester codec, falling edge = logic 1 | ||
73 | - st,adc-channel-clk-src: Conversion clock source. | ||
74 | - "CLKIN": external SPI clock (CLKIN x) | ||
75 | - "CLKOUT": internal SPI clock (CLKOUT) (default) | ||
76 | - "CLKOUT_F": internal SPI clock divided by 2 (falling edge). | ||
77 | - "CLKOUT_R": internal SPI clock divided by 2 (rising edge). | ||
78 | |||
79 | - st,adc-alt-channel: Must be defined if two sigma delta modulator are | ||
80 | connected on same SPI input. | ||
81 | If not set, channel n is connected to SPI input n. | ||
82 | If set, channel n is connected to SPI input n + 1. | ||
83 | |||
84 | - st,filter0-sync: Set to 1 to synchronize with DFSDM filter instance 0. | ||
85 | Used for multi microphones synchronization. | ||
86 | |||
87 | Example of a sigma delta adc connected on DFSDM SPI port 0 | ||
88 | and a pdm microphone connected on DFSDM SPI port 1: | ||
89 | |||
90 | ads1202: simple_sd_adc@0 { | ||
91 | compatible = "ads1202"; | ||
92 | #io-channel-cells = <1>; | ||
93 | }; | ||
94 | |||
95 | dfsdm: dfsdm@40017000 { | ||
96 | compatible = "st,stm32h7-dfsdm"; | ||
97 | reg = <0x40017000 0x400>; | ||
98 | clocks = <&rcc DFSDM1_CK>; | ||
99 | clock-names = "dfsdm"; | ||
100 | #interrupt-cells = <1>; | ||
101 | #address-cells = <1>; | ||
102 | #size-cells = <0>; | ||
103 | |||
104 | dfsdm_adc0: filter@0 { | ||
105 | compatible = "st,stm32-dfsdm-adc"; | ||
106 | #io-channel-cells = <1>; | ||
107 | reg = <0>; | ||
108 | interrupts = <110>; | ||
109 | st,adc-channels = <0>; | ||
110 | st,adc-channel-names = "sd_adc0"; | ||
111 | st,adc-channel-types = "SPI_F"; | ||
112 | st,adc-channel-clk-src = "CLKOUT"; | ||
113 | io-channels = <&ads1202 0>; | ||
114 | st,filter-order = <3>; | ||
115 | }; | ||
116 | dfsdm_pdm1: filter@1 { | ||
117 | compatible = "st,stm32-dfsdm-dmic"; | ||
118 | reg = <1>; | ||
119 | interrupts = <111>; | ||
120 | dmas = <&dmamux1 102 0x400 0x00>; | ||
121 | dma-names = "rx"; | ||
122 | st,adc-channels = <1>; | ||
123 | st,adc-channel-names = "dmic1"; | ||
124 | st,adc-channel-types = "SPI_R"; | ||
125 | st,adc-channel-clk-src = "CLKOUT"; | ||
126 | st,filter-order = <5>; | ||
127 | }; | ||
128 | } | ||
diff --git a/Documentation/driver-api/iio/hw-consumer.rst b/Documentation/driver-api/iio/hw-consumer.rst new file mode 100644 index 000000000000..8facce6a6733 --- /dev/null +++ b/Documentation/driver-api/iio/hw-consumer.rst | |||
@@ -0,0 +1,51 @@ | |||
1 | =========== | ||
2 | HW consumer | ||
3 | =========== | ||
4 | An IIO device can be directly connected to another device in hardware. in this | ||
5 | case the buffers between IIO provider and IIO consumer are handled by hardware. | ||
6 | The Industrial I/O HW consumer offers a way to bond these IIO devices without | ||
7 | software buffer for data. The implementation can be found under | ||
8 | :file:`drivers/iio/buffer/hw-consumer.c` | ||
9 | |||
10 | |||
11 | * struct :c:type:`iio_hw_consumer` — Hardware consumer structure | ||
12 | * :c:func:`iio_hw_consumer_alloc` — Allocate IIO hardware consumer | ||
13 | * :c:func:`iio_hw_consumer_free` — Free IIO hardware consumer | ||
14 | * :c:func:`iio_hw_consumer_enable` — Enable IIO hardware consumer | ||
15 | * :c:func:`iio_hw_consumer_disable` — Disable IIO hardware consumer | ||
16 | |||
17 | |||
18 | HW consumer setup | ||
19 | ================= | ||
20 | |||
21 | As standard IIO device the implementation is based on IIO provider/consumer. | ||
22 | A typical IIO HW consumer setup looks like this:: | ||
23 | |||
24 | static struct iio_hw_consumer *hwc; | ||
25 | |||
26 | static const struct iio_info adc_info = { | ||
27 | .read_raw = adc_read_raw, | ||
28 | }; | ||
29 | |||
30 | static int adc_read_raw(struct iio_dev *indio_dev, | ||
31 | struct iio_chan_spec const *chan, int *val, | ||
32 | int *val2, long mask) | ||
33 | { | ||
34 | ret = iio_hw_consumer_enable(hwc); | ||
35 | |||
36 | /* Acquire data */ | ||
37 | |||
38 | ret = iio_hw_consumer_disable(hwc); | ||
39 | } | ||
40 | |||
41 | static int adc_probe(struct platform_device *pdev) | ||
42 | { | ||
43 | hwc = devm_iio_hw_consumer_alloc(&iio->dev); | ||
44 | } | ||
45 | |||
46 | More details | ||
47 | ============ | ||
48 | .. kernel-doc:: include/linux/iio/hw-consumer.h | ||
49 | .. kernel-doc:: drivers/iio/buffer/industrialio-hw-consumer.c | ||
50 | :export: | ||
51 | |||
diff --git a/Documentation/driver-api/iio/index.rst b/Documentation/driver-api/iio/index.rst index e5c3922d1b6f..7fba341bd8b2 100644 --- a/Documentation/driver-api/iio/index.rst +++ b/Documentation/driver-api/iio/index.rst | |||
@@ -15,3 +15,4 @@ Contents: | |||
15 | buffers | 15 | buffers |
16 | triggers | 16 | triggers |
17 | triggered-buffers | 17 | triggered-buffers |
18 | hw-consumer | ||
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ef86296b8b0d..39e3b345a6c8 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig | |||
@@ -629,6 +629,18 @@ config SPEAR_ADC | |||
629 | To compile this driver as a module, choose M here: the | 629 | To compile this driver as a module, choose M here: the |
630 | module will be called spear_adc. | 630 | module will be called spear_adc. |
631 | 631 | ||
632 | config SD_ADC_MODULATOR | ||
633 | tristate "Generic sigma delta modulator" | ||
634 | depends on OF | ||
635 | select IIO_BUFFER | ||
636 | select IIO_TRIGGERED_BUFFER | ||
637 | help | ||
638 | Select this option to enables sigma delta modulator. This driver can | ||
639 | support generic sigma delta modulators. | ||
640 | |||
641 | This driver can also be built as a module. If so, the module | ||
642 | will be called sd_adc_modulator. | ||
643 | |||
632 | config STM32_ADC_CORE | 644 | config STM32_ADC_CORE |
633 | tristate "STMicroelectronics STM32 adc core" | 645 | tristate "STMicroelectronics STM32 adc core" |
634 | depends on ARCH_STM32 || COMPILE_TEST | 646 | depends on ARCH_STM32 || COMPILE_TEST |
@@ -656,6 +668,31 @@ config STM32_ADC | |||
656 | This driver can also be built as a module. If so, the module | 668 | This driver can also be built as a module. If so, the module |
657 | will be called stm32-adc. | 669 | will be called stm32-adc. |
658 | 670 | ||
671 | config STM32_DFSDM_CORE | ||
672 | tristate "STMicroelectronics STM32 DFSDM core" | ||
673 | depends on (ARCH_STM32 && OF) || COMPILE_TEST | ||
674 | select REGMAP | ||
675 | select REGMAP_MMIO | ||
676 | help | ||
677 | Select this option to enable the driver for STMicroelectronics | ||
678 | STM32 digital filter for sigma delta converter. | ||
679 | |||
680 | This driver can also be built as a module. If so, the module | ||
681 | will be called stm32-dfsdm-core. | ||
682 | |||
683 | config STM32_DFSDM_ADC | ||
684 | tristate "STMicroelectronics STM32 dfsdm adc" | ||
685 | depends on (ARCH_STM32 && OF) || COMPILE_TEST | ||
686 | select STM32_DFSDM_CORE | ||
687 | select REGMAP_MMIO | ||
688 | select IIO_BUFFER_HW_CONSUMER | ||
689 | help | ||
690 | Select this option to support ADCSigma delta modulator for | ||
691 | STMicroelectronics STM32 digital filter for sigma delta converter. | ||
692 | |||
693 | This driver can also be built as a module. If so, the module | ||
694 | will be called stm32-dfsdm-adc. | ||
695 | |||
659 | config STX104 | 696 | config STX104 |
660 | tristate "Apex Embedded Systems STX104 driver" | 697 | tristate "Apex Embedded Systems STX104 driver" |
661 | depends on PC104 && X86 && ISA_BUS_API | 698 | depends on PC104 && X86 && ISA_BUS_API |
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9572c1090f35..28a9423997f3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile | |||
@@ -64,6 +64,8 @@ obj-$(CONFIG_STX104) += stx104.o | |||
64 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o | 64 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o |
65 | obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o | 65 | obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o |
66 | obj-$(CONFIG_STM32_ADC) += stm32-adc.o | 66 | obj-$(CONFIG_STM32_ADC) += stm32-adc.o |
67 | obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o | ||
68 | obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o | ||
67 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o | 69 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o |
68 | obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o | 70 | obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o |
69 | obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o | 71 | obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o |
@@ -82,3 +84,4 @@ obj-$(CONFIG_VF610_ADC) += vf610_adc.o | |||
82 | obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o | 84 | obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o |
83 | xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o | 85 | xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o |
84 | obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o | 86 | obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o |
87 | obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o | ||
diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c new file mode 100644 index 000000000000..560d8c7d9d86 --- /dev/null +++ b/drivers/iio/adc/sd_adc_modulator.c | |||
@@ -0,0 +1,68 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Generic sigma delta modulator driver | ||
4 | * | ||
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
6 | * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>. | ||
7 | */ | ||
8 | |||
9 | #include <linux/iio/iio.h> | ||
10 | #include <linux/iio/triggered_buffer.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of_device.h> | ||
13 | |||
14 | static const struct iio_info iio_sd_mod_iio_info; | ||
15 | |||
16 | static const struct iio_chan_spec iio_sd_mod_ch = { | ||
17 | .type = IIO_VOLTAGE, | ||
18 | .indexed = 1, | ||
19 | .scan_type = { | ||
20 | .sign = 'u', | ||
21 | .realbits = 1, | ||
22 | .shift = 0, | ||
23 | }, | ||
24 | }; | ||
25 | |||
26 | static int iio_sd_mod_probe(struct platform_device *pdev) | ||
27 | { | ||
28 | struct device *dev = &pdev->dev; | ||
29 | struct iio_dev *iio; | ||
30 | |||
31 | iio = devm_iio_device_alloc(dev, 0); | ||
32 | if (!iio) | ||
33 | return -ENOMEM; | ||
34 | |||
35 | iio->dev.parent = dev; | ||
36 | iio->dev.of_node = dev->of_node; | ||
37 | iio->name = dev_name(dev); | ||
38 | iio->info = &iio_sd_mod_iio_info; | ||
39 | iio->modes = INDIO_BUFFER_HARDWARE; | ||
40 | |||
41 | iio->num_channels = 1; | ||
42 | iio->channels = &iio_sd_mod_ch; | ||
43 | |||
44 | platform_set_drvdata(pdev, iio); | ||
45 | |||
46 | return devm_iio_device_register(&pdev->dev, iio); | ||
47 | } | ||
48 | |||
49 | static const struct of_device_id sd_adc_of_match[] = { | ||
50 | { .compatible = "sd-modulator" }, | ||
51 | { .compatible = "ads1201" }, | ||
52 | { } | ||
53 | }; | ||
54 | MODULE_DEVICE_TABLE(of, sd_adc_of_match); | ||
55 | |||
56 | static struct platform_driver iio_sd_mod_adc = { | ||
57 | .driver = { | ||
58 | .name = "iio_sd_adc_mod", | ||
59 | .of_match_table = of_match_ptr(sd_adc_of_match), | ||
60 | }, | ||
61 | .probe = iio_sd_mod_probe, | ||
62 | }; | ||
63 | |||
64 | module_platform_driver(iio_sd_mod_adc); | ||
65 | |||
66 | MODULE_DESCRIPTION("Basic sigma delta modulator"); | ||
67 | MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); | ||
68 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c new file mode 100644 index 000000000000..e628d04d5c77 --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm-adc.c | |||
@@ -0,0 +1,1216 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * This file is the ADC part of the STM32 DFSDM driver | ||
4 | * | ||
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
6 | * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>. | ||
7 | */ | ||
8 | |||
9 | #include <linux/dmaengine.h> | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/iio/buffer.h> | ||
13 | #include <linux/iio/hw-consumer.h> | ||
14 | #include <linux/iio/iio.h> | ||
15 | #include <linux/iio/sysfs.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include "stm32-dfsdm.h" | ||
23 | |||
24 | #define DFSDM_DMA_BUFFER_SIZE (4 * PAGE_SIZE) | ||
25 | |||
26 | /* Conversion timeout */ | ||
27 | #define DFSDM_TIMEOUT_US 100000 | ||
28 | #define DFSDM_TIMEOUT (msecs_to_jiffies(DFSDM_TIMEOUT_US / 1000)) | ||
29 | |||
30 | /* Oversampling attribute default */ | ||
31 | #define DFSDM_DEFAULT_OVERSAMPLING 100 | ||
32 | |||
33 | /* Oversampling max values */ | ||
34 | #define DFSDM_MAX_INT_OVERSAMPLING 256 | ||
35 | #define DFSDM_MAX_FL_OVERSAMPLING 1024 | ||
36 | |||
37 | /* Max sample resolutions */ | ||
38 | #define DFSDM_MAX_RES BIT(31) | ||
39 | #define DFSDM_DATA_RES BIT(23) | ||
40 | |||
41 | enum sd_converter_type { | ||
42 | DFSDM_AUDIO, | ||
43 | DFSDM_IIO, | ||
44 | }; | ||
45 | |||
46 | struct stm32_dfsdm_dev_data { | ||
47 | int type; | ||
48 | int (*init)(struct iio_dev *indio_dev); | ||
49 | unsigned int num_channels; | ||
50 | const struct regmap_config *regmap_cfg; | ||
51 | }; | ||
52 | |||
53 | struct stm32_dfsdm_adc { | ||
54 | struct stm32_dfsdm *dfsdm; | ||
55 | const struct stm32_dfsdm_dev_data *dev_data; | ||
56 | unsigned int fl_id; | ||
57 | unsigned int ch_id; | ||
58 | |||
59 | /* ADC specific */ | ||
60 | unsigned int oversamp; | ||
61 | struct iio_hw_consumer *hwc; | ||
62 | struct completion completion; | ||
63 | u32 *buffer; | ||
64 | |||
65 | /* Audio specific */ | ||
66 | unsigned int spi_freq; /* SPI bus clock frequency */ | ||
67 | unsigned int sample_freq; /* Sample frequency after filter decimation */ | ||
68 | int (*cb)(const void *data, size_t size, void *cb_priv); | ||
69 | void *cb_priv; | ||
70 | |||
71 | /* DMA */ | ||
72 | u8 *rx_buf; | ||
73 | unsigned int bufi; /* Buffer current position */ | ||
74 | unsigned int buf_sz; /* Buffer size */ | ||
75 | struct dma_chan *dma_chan; | ||
76 | dma_addr_t dma_buf; | ||
77 | }; | ||
78 | |||
79 | struct stm32_dfsdm_str2field { | ||
80 | const char *name; | ||
81 | unsigned int val; | ||
82 | }; | ||
83 | |||
84 | /* DFSDM channel serial interface type */ | ||
85 | static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_type[] = { | ||
86 | { "SPI_R", 0 }, /* SPI with data on rising edge */ | ||
87 | { "SPI_F", 1 }, /* SPI with data on falling edge */ | ||
88 | { "MANCH_R", 2 }, /* Manchester codec, rising edge = logic 0 */ | ||
89 | { "MANCH_F", 3 }, /* Manchester codec, falling edge = logic 1 */ | ||
90 | {}, | ||
91 | }; | ||
92 | |||
93 | /* DFSDM channel clock source */ | ||
94 | static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_src[] = { | ||
95 | /* External SPI clock (CLKIN x) */ | ||
96 | { "CLKIN", DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL }, | ||
97 | /* Internal SPI clock (CLKOUT) */ | ||
98 | { "CLKOUT", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL }, | ||
99 | /* Internal SPI clock divided by 2 (falling edge) */ | ||
100 | { "CLKOUT_F", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING }, | ||
101 | /* Internal SPI clock divided by 2 (falling edge) */ | ||
102 | { "CLKOUT_R", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING }, | ||
103 | {}, | ||
104 | }; | ||
105 | |||
106 | static int stm32_dfsdm_str2val(const char *str, | ||
107 | const struct stm32_dfsdm_str2field *list) | ||
108 | { | ||
109 | const struct stm32_dfsdm_str2field *p = list; | ||
110 | |||
111 | for (p = list; p && p->name; p++) | ||
112 | if (!strcmp(p->name, str)) | ||
113 | return p->val; | ||
114 | |||
115 | return -EINVAL; | ||
116 | } | ||
117 | |||
118 | static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, | ||
119 | unsigned int fast, unsigned int oversamp) | ||
120 | { | ||
121 | unsigned int i, d, fosr, iosr; | ||
122 | u64 res; | ||
123 | s64 delta; | ||
124 | unsigned int m = 1; /* multiplication factor */ | ||
125 | unsigned int p = fl->ford; /* filter order (ford) */ | ||
126 | |||
127 | pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp); | ||
128 | /* | ||
129 | * This function tries to compute filter oversampling and integrator | ||
130 | * oversampling, base on oversampling ratio requested by user. | ||
131 | * | ||
132 | * Decimation d depends on the filter order and the oversampling ratios. | ||
133 | * ford: filter order | ||
134 | * fosr: filter over sampling ratio | ||
135 | * iosr: integrator over sampling ratio | ||
136 | */ | ||
137 | if (fl->ford == DFSDM_FASTSINC_ORDER) { | ||
138 | m = 2; | ||
139 | p = 2; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Look for filter and integrator oversampling ratios which allows | ||
144 | * to reach 24 bits data output resolution. | ||
145 | * Leave as soon as if exact resolution if reached. | ||
146 | * Otherwise the higher resolution below 32 bits is kept. | ||
147 | */ | ||
148 | for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) { | ||
149 | for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) { | ||
150 | if (fast) | ||
151 | d = fosr * iosr; | ||
152 | else if (fl->ford == DFSDM_FASTSINC_ORDER) | ||
153 | d = fosr * (iosr + 3) + 2; | ||
154 | else | ||
155 | d = fosr * (iosr - 1 + p) + p; | ||
156 | |||
157 | if (d > oversamp) | ||
158 | break; | ||
159 | else if (d != oversamp) | ||
160 | continue; | ||
161 | /* | ||
162 | * Check resolution (limited to signed 32 bits) | ||
163 | * res <= 2^31 | ||
164 | * Sincx filters: | ||
165 | * res = m * fosr^p x iosr (with m=1, p=ford) | ||
166 | * FastSinc filter | ||
167 | * res = m * fosr^p x iosr (with m=2, p=2) | ||
168 | */ | ||
169 | res = fosr; | ||
170 | for (i = p - 1; i > 0; i--) { | ||
171 | res = res * (u64)fosr; | ||
172 | if (res > DFSDM_MAX_RES) | ||
173 | break; | ||
174 | } | ||
175 | if (res > DFSDM_MAX_RES) | ||
176 | continue; | ||
177 | res = res * (u64)m * (u64)iosr; | ||
178 | if (res > DFSDM_MAX_RES) | ||
179 | continue; | ||
180 | |||
181 | delta = res - DFSDM_DATA_RES; | ||
182 | |||
183 | if (res >= fl->res) { | ||
184 | fl->res = res; | ||
185 | fl->fosr = fosr; | ||
186 | fl->iosr = iosr; | ||
187 | fl->fast = fast; | ||
188 | pr_debug("%s: fosr = %d, iosr = %d\n", | ||
189 | __func__, fl->fosr, fl->iosr); | ||
190 | } | ||
191 | |||
192 | if (!delta) | ||
193 | return 0; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | if (!fl->fosr) | ||
198 | return -EINVAL; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm, | ||
204 | unsigned int ch_id) | ||
205 | { | ||
206 | return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), | ||
207 | DFSDM_CHCFGR1_CHEN_MASK, | ||
208 | DFSDM_CHCFGR1_CHEN(1)); | ||
209 | } | ||
210 | |||
211 | static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, | ||
212 | unsigned int ch_id) | ||
213 | { | ||
214 | regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), | ||
215 | DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0)); | ||
216 | } | ||
217 | |||
218 | static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, | ||
219 | struct stm32_dfsdm_channel *ch) | ||
220 | { | ||
221 | unsigned int id = ch->id; | ||
222 | struct regmap *regmap = dfsdm->regmap; | ||
223 | int ret; | ||
224 | |||
225 | ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id), | ||
226 | DFSDM_CHCFGR1_SITP_MASK, | ||
227 | DFSDM_CHCFGR1_SITP(ch->type)); | ||
228 | if (ret < 0) | ||
229 | return ret; | ||
230 | ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id), | ||
231 | DFSDM_CHCFGR1_SPICKSEL_MASK, | ||
232 | DFSDM_CHCFGR1_SPICKSEL(ch->src)); | ||
233 | if (ret < 0) | ||
234 | return ret; | ||
235 | return regmap_update_bits(regmap, DFSDM_CHCFGR1(id), | ||
236 | DFSDM_CHCFGR1_CHINSEL_MASK, | ||
237 | DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); | ||
238 | } | ||
239 | |||
240 | static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, | ||
241 | unsigned int fl_id) | ||
242 | { | ||
243 | int ret; | ||
244 | |||
245 | /* Enable filter */ | ||
246 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), | ||
247 | DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(1)); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | /* Start conversion */ | ||
252 | return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), | ||
253 | DFSDM_CR1_RSWSTART_MASK, | ||
254 | DFSDM_CR1_RSWSTART(1)); | ||
255 | } | ||
256 | |||
257 | static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) | ||
258 | { | ||
259 | /* Disable conversion */ | ||
260 | regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), | ||
261 | DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); | ||
262 | } | ||
263 | |||
264 | static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, | ||
265 | unsigned int fl_id, unsigned int ch_id) | ||
266 | { | ||
267 | struct regmap *regmap = dfsdm->regmap; | ||
268 | struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id]; | ||
269 | int ret; | ||
270 | |||
271 | /* Average integrator oversampling */ | ||
272 | ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK, | ||
273 | DFSDM_FCR_IOSR(fl->iosr - 1)); | ||
274 | if (ret) | ||
275 | return ret; | ||
276 | |||
277 | /* Filter order and Oversampling */ | ||
278 | ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK, | ||
279 | DFSDM_FCR_FOSR(fl->fosr - 1)); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FORD_MASK, | ||
284 | DFSDM_FCR_FORD(fl->ford)); | ||
285 | if (ret) | ||
286 | return ret; | ||
287 | |||
288 | /* No scan mode supported for the moment */ | ||
289 | ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, | ||
290 | DFSDM_CR1_RCH(ch_id)); | ||
291 | if (ret) | ||
292 | return ret; | ||
293 | |||
294 | return regmap_update_bits(regmap, DFSDM_CR1(fl_id), | ||
295 | DFSDM_CR1_RSYNC_MASK, | ||
296 | DFSDM_CR1_RSYNC(fl->sync_mode)); | ||
297 | } | ||
298 | |||
299 | static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, | ||
300 | struct iio_dev *indio_dev, | ||
301 | struct iio_chan_spec *ch) | ||
302 | { | ||
303 | struct stm32_dfsdm_channel *df_ch; | ||
304 | const char *of_str; | ||
305 | int chan_idx = ch->scan_index; | ||
306 | int ret, val; | ||
307 | |||
308 | ret = of_property_read_u32_index(indio_dev->dev.of_node, | ||
309 | "st,adc-channels", chan_idx, | ||
310 | &ch->channel); | ||
311 | if (ret < 0) { | ||
312 | dev_err(&indio_dev->dev, | ||
313 | " Error parsing 'st,adc-channels' for idx %d\n", | ||
314 | chan_idx); | ||
315 | return ret; | ||
316 | } | ||
317 | if (ch->channel >= dfsdm->num_chs) { | ||
318 | dev_err(&indio_dev->dev, | ||
319 | " Error bad channel number %d (max = %d)\n", | ||
320 | ch->channel, dfsdm->num_chs); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | ret = of_property_read_string_index(indio_dev->dev.of_node, | ||
325 | "st,adc-channel-names", chan_idx, | ||
326 | &ch->datasheet_name); | ||
327 | if (ret < 0) { | ||
328 | dev_err(&indio_dev->dev, | ||
329 | " Error parsing 'st,adc-channel-names' for idx %d\n", | ||
330 | chan_idx); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | df_ch = &dfsdm->ch_list[ch->channel]; | ||
335 | df_ch->id = ch->channel; | ||
336 | |||
337 | ret = of_property_read_string_index(indio_dev->dev.of_node, | ||
338 | "st,adc-channel-types", chan_idx, | ||
339 | &of_str); | ||
340 | if (!ret) { | ||
341 | val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); | ||
342 | if (val < 0) | ||
343 | return val; | ||
344 | } else { | ||
345 | val = 0; | ||
346 | } | ||
347 | df_ch->type = val; | ||
348 | |||
349 | ret = of_property_read_string_index(indio_dev->dev.of_node, | ||
350 | "st,adc-channel-clk-src", chan_idx, | ||
351 | &of_str); | ||
352 | if (!ret) { | ||
353 | val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); | ||
354 | if (val < 0) | ||
355 | return val; | ||
356 | } else { | ||
357 | val = 0; | ||
358 | } | ||
359 | df_ch->src = val; | ||
360 | |||
361 | ret = of_property_read_u32_index(indio_dev->dev.of_node, | ||
362 | "st,adc-alt-channel", chan_idx, | ||
363 | &df_ch->alt_si); | ||
364 | if (ret < 0) | ||
365 | df_ch->alt_si = 0; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, | ||
371 | uintptr_t priv, | ||
372 | const struct iio_chan_spec *chan, | ||
373 | char *buf) | ||
374 | { | ||
375 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
376 | |||
377 | return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); | ||
378 | } | ||
379 | |||
380 | static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, | ||
381 | uintptr_t priv, | ||
382 | const struct iio_chan_spec *chan, | ||
383 | const char *buf, size_t len) | ||
384 | { | ||
385 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
386 | struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; | ||
387 | struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; | ||
388 | unsigned int sample_freq = adc->sample_freq; | ||
389 | unsigned int spi_freq; | ||
390 | int ret; | ||
391 | |||
392 | dev_err(&indio_dev->dev, "enter %s\n", __func__); | ||
393 | /* If DFSDM is master on SPI, SPI freq can not be updated */ | ||
394 | if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) | ||
395 | return -EPERM; | ||
396 | |||
397 | ret = kstrtoint(buf, 0, &spi_freq); | ||
398 | if (ret) | ||
399 | return ret; | ||
400 | |||
401 | if (!spi_freq) | ||
402 | return -EINVAL; | ||
403 | |||
404 | if (sample_freq) { | ||
405 | if (spi_freq % sample_freq) | ||
406 | dev_warn(&indio_dev->dev, | ||
407 | "Sampling rate not accurate (%d)\n", | ||
408 | spi_freq / (spi_freq / sample_freq)); | ||
409 | |||
410 | ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq)); | ||
411 | if (ret < 0) { | ||
412 | dev_err(&indio_dev->dev, | ||
413 | "No filter parameters that match!\n"); | ||
414 | return ret; | ||
415 | } | ||
416 | } | ||
417 | adc->spi_freq = spi_freq; | ||
418 | |||
419 | return len; | ||
420 | } | ||
421 | |||
422 | static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma) | ||
423 | { | ||
424 | struct regmap *regmap = adc->dfsdm->regmap; | ||
425 | int ret; | ||
426 | unsigned int dma_en = 0, cont_en = 0; | ||
427 | |||
428 | ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id); | ||
429 | if (ret < 0) | ||
430 | return ret; | ||
431 | |||
432 | ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, | ||
433 | adc->ch_id); | ||
434 | if (ret < 0) | ||
435 | goto stop_channels; | ||
436 | |||
437 | if (dma) { | ||
438 | /* Enable DMA transfer*/ | ||
439 | dma_en = DFSDM_CR1_RDMAEN(1); | ||
440 | /* Enable conversion triggered by SPI clock*/ | ||
441 | cont_en = DFSDM_CR1_RCONT(1); | ||
442 | } | ||
443 | /* Enable DMA transfer*/ | ||
444 | ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
445 | DFSDM_CR1_RDMAEN_MASK, dma_en); | ||
446 | if (ret < 0) | ||
447 | goto stop_channels; | ||
448 | |||
449 | /* Enable conversion triggered by SPI clock*/ | ||
450 | ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
451 | DFSDM_CR1_RCONT_MASK, cont_en); | ||
452 | if (ret < 0) | ||
453 | goto stop_channels; | ||
454 | |||
455 | ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); | ||
456 | if (ret < 0) | ||
457 | goto stop_channels; | ||
458 | |||
459 | return 0; | ||
460 | |||
461 | stop_channels: | ||
462 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
463 | DFSDM_CR1_RDMAEN_MASK, 0); | ||
464 | |||
465 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
466 | DFSDM_CR1_RCONT_MASK, 0); | ||
467 | stm32_dfsdm_stop_channel(adc->dfsdm, adc->fl_id); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) | ||
473 | { | ||
474 | struct regmap *regmap = adc->dfsdm->regmap; | ||
475 | |||
476 | stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); | ||
477 | |||
478 | /* Clean conversion options */ | ||
479 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
480 | DFSDM_CR1_RDMAEN_MASK, 0); | ||
481 | |||
482 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
483 | DFSDM_CR1_RCONT_MASK, 0); | ||
484 | |||
485 | stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); | ||
486 | } | ||
487 | |||
488 | static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, | ||
489 | unsigned int val) | ||
490 | { | ||
491 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
492 | unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; | ||
493 | |||
494 | /* | ||
495 | * DMA cyclic transfers are used, buffer is split into two periods. | ||
496 | * There should be : | ||
497 | * - always one buffer (period) DMA is working on | ||
498 | * - one buffer (period) driver pushed to ASoC side. | ||
499 | */ | ||
500 | watermark = min(watermark, val * (unsigned int)(sizeof(u32))); | ||
501 | adc->buf_sz = watermark * 2; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) | ||
507 | { | ||
508 | struct dma_tx_state state; | ||
509 | enum dma_status status; | ||
510 | |||
511 | status = dmaengine_tx_status(adc->dma_chan, | ||
512 | adc->dma_chan->cookie, | ||
513 | &state); | ||
514 | if (status == DMA_IN_PROGRESS) { | ||
515 | /* Residue is size in bytes from end of buffer */ | ||
516 | unsigned int i = adc->buf_sz - state.residue; | ||
517 | unsigned int size; | ||
518 | |||
519 | /* Return available bytes */ | ||
520 | if (i >= adc->bufi) | ||
521 | size = i - adc->bufi; | ||
522 | else | ||
523 | size = adc->buf_sz + i - adc->bufi; | ||
524 | |||
525 | return size; | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static void stm32_dfsdm_audio_dma_buffer_done(void *data) | ||
532 | { | ||
533 | struct iio_dev *indio_dev = data; | ||
534 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
535 | int available = stm32_dfsdm_adc_dma_residue(adc); | ||
536 | size_t old_pos; | ||
537 | |||
538 | /* | ||
539 | * FIXME: In Kernel interface does not support cyclic DMA buffer,and | ||
540 | * offers only an interface to push data samples per samples. | ||
541 | * For this reason IIO buffer interface is not used and interface is | ||
542 | * bypassed using a private callback registered by ASoC. | ||
543 | * This should be a temporary solution waiting a cyclic DMA engine | ||
544 | * support in IIO. | ||
545 | */ | ||
546 | |||
547 | dev_dbg(&indio_dev->dev, "%s: pos = %d, available = %d\n", __func__, | ||
548 | adc->bufi, available); | ||
549 | old_pos = adc->bufi; | ||
550 | |||
551 | while (available >= indio_dev->scan_bytes) { | ||
552 | u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi]; | ||
553 | |||
554 | /* Mask 8 LSB that contains the channel ID */ | ||
555 | *buffer = (*buffer & 0xFFFFFF00) << 8; | ||
556 | available -= indio_dev->scan_bytes; | ||
557 | adc->bufi += indio_dev->scan_bytes; | ||
558 | if (adc->bufi >= adc->buf_sz) { | ||
559 | if (adc->cb) | ||
560 | adc->cb(&adc->rx_buf[old_pos], | ||
561 | adc->buf_sz - old_pos, adc->cb_priv); | ||
562 | adc->bufi = 0; | ||
563 | old_pos = 0; | ||
564 | } | ||
565 | } | ||
566 | if (adc->cb) | ||
567 | adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, | ||
568 | adc->cb_priv); | ||
569 | } | ||
570 | |||
571 | static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) | ||
572 | { | ||
573 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
574 | struct dma_async_tx_descriptor *desc; | ||
575 | dma_cookie_t cookie; | ||
576 | int ret; | ||
577 | |||
578 | if (!adc->dma_chan) | ||
579 | return -EINVAL; | ||
580 | |||
581 | dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, | ||
582 | adc->buf_sz, adc->buf_sz / 2); | ||
583 | |||
584 | /* Prepare a DMA cyclic transaction */ | ||
585 | desc = dmaengine_prep_dma_cyclic(adc->dma_chan, | ||
586 | adc->dma_buf, | ||
587 | adc->buf_sz, adc->buf_sz / 2, | ||
588 | DMA_DEV_TO_MEM, | ||
589 | DMA_PREP_INTERRUPT); | ||
590 | if (!desc) | ||
591 | return -EBUSY; | ||
592 | |||
593 | desc->callback = stm32_dfsdm_audio_dma_buffer_done; | ||
594 | desc->callback_param = indio_dev; | ||
595 | |||
596 | cookie = dmaengine_submit(desc); | ||
597 | ret = dma_submit_error(cookie); | ||
598 | if (ret) { | ||
599 | dmaengine_terminate_all(adc->dma_chan); | ||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | /* Issue pending DMA requests */ | ||
604 | dma_async_issue_pending(adc->dma_chan); | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) | ||
610 | { | ||
611 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
612 | int ret; | ||
613 | |||
614 | /* Reset adc buffer index */ | ||
615 | adc->bufi = 0; | ||
616 | |||
617 | ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); | ||
618 | if (ret < 0) | ||
619 | return ret; | ||
620 | |||
621 | ret = stm32_dfsdm_start_conv(adc, true); | ||
622 | if (ret) { | ||
623 | dev_err(&indio_dev->dev, "Can't start conversion\n"); | ||
624 | goto stop_dfsdm; | ||
625 | } | ||
626 | |||
627 | if (adc->dma_chan) { | ||
628 | ret = stm32_dfsdm_adc_dma_start(indio_dev); | ||
629 | if (ret) { | ||
630 | dev_err(&indio_dev->dev, "Can't start DMA\n"); | ||
631 | goto err_stop_conv; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | |||
637 | err_stop_conv: | ||
638 | stm32_dfsdm_stop_conv(adc); | ||
639 | stop_dfsdm: | ||
640 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | ||
641 | |||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) | ||
646 | { | ||
647 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
648 | |||
649 | if (adc->dma_chan) | ||
650 | dmaengine_terminate_all(adc->dma_chan); | ||
651 | |||
652 | stm32_dfsdm_stop_conv(adc); | ||
653 | |||
654 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | static const struct iio_buffer_setup_ops stm32_dfsdm_buffer_setup_ops = { | ||
660 | .postenable = &stm32_dfsdm_postenable, | ||
661 | .predisable = &stm32_dfsdm_predisable, | ||
662 | }; | ||
663 | |||
664 | /** | ||
665 | * stm32_dfsdm_get_buff_cb() - register a callback that will be called when | ||
666 | * DMA transfer period is achieved. | ||
667 | * | ||
668 | * @iio_dev: Handle to IIO device. | ||
669 | * @cb: Pointer to callback function: | ||
670 | * - data: pointer to data buffer | ||
671 | * - size: size in byte of the data buffer | ||
672 | * - private: pointer to consumer private structure. | ||
673 | * @private: Pointer to consumer private structure. | ||
674 | */ | ||
675 | int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev, | ||
676 | int (*cb)(const void *data, size_t size, | ||
677 | void *private), | ||
678 | void *private) | ||
679 | { | ||
680 | struct stm32_dfsdm_adc *adc; | ||
681 | |||
682 | if (!iio_dev) | ||
683 | return -EINVAL; | ||
684 | adc = iio_priv(iio_dev); | ||
685 | |||
686 | adc->cb = cb; | ||
687 | adc->cb_priv = private; | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | EXPORT_SYMBOL_GPL(stm32_dfsdm_get_buff_cb); | ||
692 | |||
693 | /** | ||
694 | * stm32_dfsdm_release_buff_cb - unregister buffer callback | ||
695 | * | ||
696 | * @iio_dev: Handle to IIO device. | ||
697 | */ | ||
698 | int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev) | ||
699 | { | ||
700 | struct stm32_dfsdm_adc *adc; | ||
701 | |||
702 | if (!iio_dev) | ||
703 | return -EINVAL; | ||
704 | adc = iio_priv(iio_dev); | ||
705 | |||
706 | adc->cb = NULL; | ||
707 | adc->cb_priv = NULL; | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | EXPORT_SYMBOL_GPL(stm32_dfsdm_release_buff_cb); | ||
712 | |||
713 | static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, | ||
714 | const struct iio_chan_spec *chan, int *res) | ||
715 | { | ||
716 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
717 | long timeout; | ||
718 | int ret; | ||
719 | |||
720 | reinit_completion(&adc->completion); | ||
721 | |||
722 | adc->buffer = res; | ||
723 | |||
724 | ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); | ||
725 | if (ret < 0) | ||
726 | return ret; | ||
727 | |||
728 | ret = regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), | ||
729 | DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(1)); | ||
730 | if (ret < 0) | ||
731 | goto stop_dfsdm; | ||
732 | |||
733 | ret = stm32_dfsdm_start_conv(adc, false); | ||
734 | if (ret < 0) { | ||
735 | regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), | ||
736 | DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); | ||
737 | goto stop_dfsdm; | ||
738 | } | ||
739 | |||
740 | timeout = wait_for_completion_interruptible_timeout(&adc->completion, | ||
741 | DFSDM_TIMEOUT); | ||
742 | |||
743 | /* Mask IRQ for regular conversion achievement*/ | ||
744 | regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), | ||
745 | DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); | ||
746 | |||
747 | if (timeout == 0) | ||
748 | ret = -ETIMEDOUT; | ||
749 | else if (timeout < 0) | ||
750 | ret = timeout; | ||
751 | else | ||
752 | ret = IIO_VAL_INT; | ||
753 | |||
754 | stm32_dfsdm_stop_conv(adc); | ||
755 | |||
756 | stop_dfsdm: | ||
757 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | ||
758 | |||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, | ||
763 | struct iio_chan_spec const *chan, | ||
764 | int val, int val2, long mask) | ||
765 | { | ||
766 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
767 | struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; | ||
768 | struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; | ||
769 | unsigned int spi_freq = adc->spi_freq; | ||
770 | int ret = -EINVAL; | ||
771 | |||
772 | switch (mask) { | ||
773 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | ||
774 | ret = stm32_dfsdm_set_osrs(fl, 0, val); | ||
775 | if (!ret) | ||
776 | adc->oversamp = val; | ||
777 | |||
778 | return ret; | ||
779 | |||
780 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
781 | if (!val) | ||
782 | return -EINVAL; | ||
783 | if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) | ||
784 | spi_freq = adc->dfsdm->spi_master_freq; | ||
785 | |||
786 | if (spi_freq % val) | ||
787 | dev_warn(&indio_dev->dev, | ||
788 | "Sampling rate not accurate (%d)\n", | ||
789 | spi_freq / (spi_freq / val)); | ||
790 | |||
791 | ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val)); | ||
792 | if (ret < 0) { | ||
793 | dev_err(&indio_dev->dev, | ||
794 | "Not able to find parameter that match!\n"); | ||
795 | return ret; | ||
796 | } | ||
797 | adc->sample_freq = val; | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | return -EINVAL; | ||
803 | } | ||
804 | |||
805 | static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, | ||
806 | struct iio_chan_spec const *chan, int *val, | ||
807 | int *val2, long mask) | ||
808 | { | ||
809 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
810 | int ret; | ||
811 | |||
812 | switch (mask) { | ||
813 | case IIO_CHAN_INFO_RAW: | ||
814 | ret = iio_hw_consumer_enable(adc->hwc); | ||
815 | if (ret < 0) { | ||
816 | dev_err(&indio_dev->dev, | ||
817 | "%s: IIO enable failed (channel %d)\n", | ||
818 | __func__, chan->channel); | ||
819 | return ret; | ||
820 | } | ||
821 | ret = stm32_dfsdm_single_conv(indio_dev, chan, val); | ||
822 | iio_hw_consumer_disable(adc->hwc); | ||
823 | if (ret < 0) { | ||
824 | dev_err(&indio_dev->dev, | ||
825 | "%s: Conversion failed (channel %d)\n", | ||
826 | __func__, chan->channel); | ||
827 | return ret; | ||
828 | } | ||
829 | return IIO_VAL_INT; | ||
830 | |||
831 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | ||
832 | *val = adc->oversamp; | ||
833 | |||
834 | return IIO_VAL_INT; | ||
835 | |||
836 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
837 | *val = adc->sample_freq; | ||
838 | |||
839 | return IIO_VAL_INT; | ||
840 | } | ||
841 | |||
842 | return -EINVAL; | ||
843 | } | ||
844 | |||
845 | static const struct iio_info stm32_dfsdm_info_audio = { | ||
846 | .hwfifo_set_watermark = stm32_dfsdm_set_watermark, | ||
847 | .read_raw = stm32_dfsdm_read_raw, | ||
848 | .write_raw = stm32_dfsdm_write_raw, | ||
849 | }; | ||
850 | |||
851 | static const struct iio_info stm32_dfsdm_info_adc = { | ||
852 | .read_raw = stm32_dfsdm_read_raw, | ||
853 | .write_raw = stm32_dfsdm_write_raw, | ||
854 | }; | ||
855 | |||
856 | static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) | ||
857 | { | ||
858 | struct stm32_dfsdm_adc *adc = arg; | ||
859 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); | ||
860 | struct regmap *regmap = adc->dfsdm->regmap; | ||
861 | unsigned int status, int_en; | ||
862 | |||
863 | regmap_read(regmap, DFSDM_ISR(adc->fl_id), &status); | ||
864 | regmap_read(regmap, DFSDM_CR2(adc->fl_id), &int_en); | ||
865 | |||
866 | if (status & DFSDM_ISR_REOCF_MASK) { | ||
867 | /* Read the data register clean the IRQ status */ | ||
868 | regmap_read(regmap, DFSDM_RDATAR(adc->fl_id), adc->buffer); | ||
869 | complete(&adc->completion); | ||
870 | } | ||
871 | |||
872 | if (status & DFSDM_ISR_ROVRF_MASK) { | ||
873 | if (int_en & DFSDM_CR2_ROVRIE_MASK) | ||
874 | dev_warn(&indio_dev->dev, "Overrun detected\n"); | ||
875 | regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id), | ||
876 | DFSDM_ICR_CLRROVRF_MASK, | ||
877 | DFSDM_ICR_CLRROVRF_MASK); | ||
878 | } | ||
879 | |||
880 | return IRQ_HANDLED; | ||
881 | } | ||
882 | |||
883 | /* | ||
884 | * Define external info for SPI Frequency and audio sampling rate that can be | ||
885 | * configured by ASoC driver through consumer.h API | ||
886 | */ | ||
887 | static const struct iio_chan_spec_ext_info dfsdm_adc_audio_ext_info[] = { | ||
888 | /* spi_clk_freq : clock freq on SPI/manchester bus used by channel */ | ||
889 | { | ||
890 | .name = "spi_clk_freq", | ||
891 | .shared = IIO_SHARED_BY_TYPE, | ||
892 | .read = dfsdm_adc_audio_get_spiclk, | ||
893 | .write = dfsdm_adc_audio_set_spiclk, | ||
894 | }, | ||
895 | {}, | ||
896 | }; | ||
897 | |||
898 | static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) | ||
899 | { | ||
900 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
901 | |||
902 | if (adc->dma_chan) { | ||
903 | dma_free_coherent(adc->dma_chan->device->dev, | ||
904 | DFSDM_DMA_BUFFER_SIZE, | ||
905 | adc->rx_buf, adc->dma_buf); | ||
906 | dma_release_channel(adc->dma_chan); | ||
907 | } | ||
908 | } | ||
909 | |||
910 | static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) | ||
911 | { | ||
912 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
913 | struct dma_slave_config config = { | ||
914 | .src_addr = (dma_addr_t)adc->dfsdm->phys_base + | ||
915 | DFSDM_RDATAR(adc->fl_id), | ||
916 | .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, | ||
917 | }; | ||
918 | int ret; | ||
919 | |||
920 | adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); | ||
921 | if (!adc->dma_chan) | ||
922 | return -EINVAL; | ||
923 | |||
924 | adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, | ||
925 | DFSDM_DMA_BUFFER_SIZE, | ||
926 | &adc->dma_buf, GFP_KERNEL); | ||
927 | if (!adc->rx_buf) { | ||
928 | ret = -ENOMEM; | ||
929 | goto err_release; | ||
930 | } | ||
931 | |||
932 | ret = dmaengine_slave_config(adc->dma_chan, &config); | ||
933 | if (ret) | ||
934 | goto err_free; | ||
935 | |||
936 | return 0; | ||
937 | |||
938 | err_free: | ||
939 | dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE, | ||
940 | adc->rx_buf, adc->dma_buf); | ||
941 | err_release: | ||
942 | dma_release_channel(adc->dma_chan); | ||
943 | |||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, | ||
948 | struct iio_chan_spec *ch) | ||
949 | { | ||
950 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
951 | int ret; | ||
952 | |||
953 | ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch); | ||
954 | if (ret < 0) | ||
955 | return ret; | ||
956 | |||
957 | ch->type = IIO_VOLTAGE; | ||
958 | ch->indexed = 1; | ||
959 | |||
960 | /* | ||
961 | * IIO_CHAN_INFO_RAW: used to compute regular conversion | ||
962 | * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling | ||
963 | */ | ||
964 | ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); | ||
965 | ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); | ||
966 | |||
967 | if (adc->dev_data->type == DFSDM_AUDIO) { | ||
968 | ch->scan_type.sign = 's'; | ||
969 | ch->ext_info = dfsdm_adc_audio_ext_info; | ||
970 | } else { | ||
971 | ch->scan_type.sign = 'u'; | ||
972 | } | ||
973 | ch->scan_type.realbits = 24; | ||
974 | ch->scan_type.storagebits = 32; | ||
975 | adc->ch_id = ch->channel; | ||
976 | |||
977 | return stm32_dfsdm_chan_configure(adc->dfsdm, | ||
978 | &adc->dfsdm->ch_list[ch->channel]); | ||
979 | } | ||
980 | |||
981 | static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) | ||
982 | { | ||
983 | struct iio_chan_spec *ch; | ||
984 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
985 | struct stm32_dfsdm_channel *d_ch; | ||
986 | int ret; | ||
987 | |||
988 | indio_dev->modes |= INDIO_BUFFER_SOFTWARE; | ||
989 | indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; | ||
990 | |||
991 | ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); | ||
992 | if (!ch) | ||
993 | return -ENOMEM; | ||
994 | |||
995 | ch->scan_index = 0; | ||
996 | |||
997 | ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch); | ||
998 | if (ret < 0) { | ||
999 | dev_err(&indio_dev->dev, "Channels init failed\n"); | ||
1000 | return ret; | ||
1001 | } | ||
1002 | ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ); | ||
1003 | |||
1004 | d_ch = &adc->dfsdm->ch_list[adc->ch_id]; | ||
1005 | if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) | ||
1006 | adc->spi_freq = adc->dfsdm->spi_master_freq; | ||
1007 | |||
1008 | indio_dev->num_channels = 1; | ||
1009 | indio_dev->channels = ch; | ||
1010 | |||
1011 | return stm32_dfsdm_dma_request(indio_dev); | ||
1012 | } | ||
1013 | |||
1014 | static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) | ||
1015 | { | ||
1016 | struct iio_chan_spec *ch; | ||
1017 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
1018 | int num_ch; | ||
1019 | int ret, chan_idx; | ||
1020 | |||
1021 | adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; | ||
1022 | ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0, | ||
1023 | adc->oversamp); | ||
1024 | if (ret < 0) | ||
1025 | return ret; | ||
1026 | |||
1027 | num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, | ||
1028 | "st,adc-channels"); | ||
1029 | if (num_ch < 0 || num_ch > adc->dfsdm->num_chs) { | ||
1030 | dev_err(&indio_dev->dev, "Bad st,adc-channels\n"); | ||
1031 | return num_ch < 0 ? num_ch : -EINVAL; | ||
1032 | } | ||
1033 | |||
1034 | /* Bind to SD modulator IIO device */ | ||
1035 | adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev); | ||
1036 | if (IS_ERR(adc->hwc)) | ||
1037 | return -EPROBE_DEFER; | ||
1038 | |||
1039 | ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch), | ||
1040 | GFP_KERNEL); | ||
1041 | if (!ch) | ||
1042 | return -ENOMEM; | ||
1043 | |||
1044 | for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { | ||
1045 | ch->scan_index = chan_idx; | ||
1046 | ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch); | ||
1047 | if (ret < 0) { | ||
1048 | dev_err(&indio_dev->dev, "Channels init failed\n"); | ||
1049 | return ret; | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | indio_dev->num_channels = num_ch; | ||
1054 | indio_dev->channels = ch; | ||
1055 | |||
1056 | init_completion(&adc->completion); | ||
1057 | |||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_adc_data = { | ||
1062 | .type = DFSDM_IIO, | ||
1063 | .init = stm32_dfsdm_adc_init, | ||
1064 | }; | ||
1065 | |||
1066 | static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_audio_data = { | ||
1067 | .type = DFSDM_AUDIO, | ||
1068 | .init = stm32_dfsdm_audio_init, | ||
1069 | }; | ||
1070 | |||
1071 | static const struct of_device_id stm32_dfsdm_adc_match[] = { | ||
1072 | { | ||
1073 | .compatible = "st,stm32-dfsdm-adc", | ||
1074 | .data = &stm32h7_dfsdm_adc_data, | ||
1075 | }, | ||
1076 | { | ||
1077 | .compatible = "st,stm32-dfsdm-dmic", | ||
1078 | .data = &stm32h7_dfsdm_audio_data, | ||
1079 | }, | ||
1080 | {} | ||
1081 | }; | ||
1082 | |||
1083 | static int stm32_dfsdm_adc_probe(struct platform_device *pdev) | ||
1084 | { | ||
1085 | struct device *dev = &pdev->dev; | ||
1086 | struct stm32_dfsdm_adc *adc; | ||
1087 | struct device_node *np = dev->of_node; | ||
1088 | const struct stm32_dfsdm_dev_data *dev_data; | ||
1089 | struct iio_dev *iio; | ||
1090 | const struct of_device_id *of_id; | ||
1091 | char *name; | ||
1092 | int ret, irq, val; | ||
1093 | |||
1094 | of_id = of_match_node(stm32_dfsdm_adc_match, np); | ||
1095 | if (!of_id->data) { | ||
1096 | dev_err(&pdev->dev, "Data associated to device is missing\n"); | ||
1097 | return -EINVAL; | ||
1098 | } | ||
1099 | |||
1100 | dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; | ||
1101 | |||
1102 | iio = devm_iio_device_alloc(dev, sizeof(*adc)); | ||
1103 | if (IS_ERR(iio)) { | ||
1104 | dev_err(dev, "%s: Failed to allocate IIO\n", __func__); | ||
1105 | return PTR_ERR(iio); | ||
1106 | } | ||
1107 | |||
1108 | adc = iio_priv(iio); | ||
1109 | if (IS_ERR(adc)) { | ||
1110 | dev_err(dev, "%s: Failed to allocate ADC\n", __func__); | ||
1111 | return PTR_ERR(adc); | ||
1112 | } | ||
1113 | adc->dfsdm = dev_get_drvdata(dev->parent); | ||
1114 | |||
1115 | iio->dev.parent = dev; | ||
1116 | iio->dev.of_node = np; | ||
1117 | iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; | ||
1118 | |||
1119 | platform_set_drvdata(pdev, adc); | ||
1120 | |||
1121 | ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id); | ||
1122 | if (ret != 0) { | ||
1123 | dev_err(dev, "Missing reg property\n"); | ||
1124 | return -EINVAL; | ||
1125 | } | ||
1126 | |||
1127 | name = devm_kzalloc(dev, sizeof("dfsdm-adc0"), GFP_KERNEL); | ||
1128 | if (!name) | ||
1129 | return -ENOMEM; | ||
1130 | if (dev_data->type == DFSDM_AUDIO) { | ||
1131 | iio->info = &stm32_dfsdm_info_audio; | ||
1132 | snprintf(name, sizeof("dfsdm-pdm0"), "dfsdm-pdm%d", adc->fl_id); | ||
1133 | } else { | ||
1134 | iio->info = &stm32_dfsdm_info_adc; | ||
1135 | snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id); | ||
1136 | } | ||
1137 | iio->name = name; | ||
1138 | |||
1139 | /* | ||
1140 | * In a first step IRQs generated for channels are not treated. | ||
1141 | * So IRQ associated to filter instance 0 is dedicated to the Filter 0. | ||
1142 | */ | ||
1143 | irq = platform_get_irq(pdev, 0); | ||
1144 | ret = devm_request_irq(dev, irq, stm32_dfsdm_irq, | ||
1145 | 0, pdev->name, adc); | ||
1146 | if (ret < 0) { | ||
1147 | dev_err(dev, "Failed to request IRQ\n"); | ||
1148 | return ret; | ||
1149 | } | ||
1150 | |||
1151 | ret = of_property_read_u32(dev->of_node, "st,filter-order", &val); | ||
1152 | if (ret < 0) { | ||
1153 | dev_err(dev, "Failed to set filter order\n"); | ||
1154 | return ret; | ||
1155 | } | ||
1156 | |||
1157 | adc->dfsdm->fl_list[adc->fl_id].ford = val; | ||
1158 | |||
1159 | ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val); | ||
1160 | if (!ret) | ||
1161 | adc->dfsdm->fl_list[adc->fl_id].sync_mode = val; | ||
1162 | |||
1163 | adc->dev_data = dev_data; | ||
1164 | ret = dev_data->init(iio); | ||
1165 | if (ret < 0) | ||
1166 | return ret; | ||
1167 | |||
1168 | ret = iio_device_register(iio); | ||
1169 | if (ret < 0) | ||
1170 | goto err_cleanup; | ||
1171 | |||
1172 | dev_err(dev, "of_platform_populate\n"); | ||
1173 | if (dev_data->type == DFSDM_AUDIO) { | ||
1174 | ret = of_platform_populate(np, NULL, NULL, dev); | ||
1175 | if (ret < 0) { | ||
1176 | dev_err(dev, "Failed to find an audio DAI\n"); | ||
1177 | goto err_unregister; | ||
1178 | } | ||
1179 | } | ||
1180 | |||
1181 | return 0; | ||
1182 | |||
1183 | err_unregister: | ||
1184 | iio_device_unregister(iio); | ||
1185 | err_cleanup: | ||
1186 | stm32_dfsdm_dma_release(iio); | ||
1187 | |||
1188 | return ret; | ||
1189 | } | ||
1190 | |||
1191 | static int stm32_dfsdm_adc_remove(struct platform_device *pdev) | ||
1192 | { | ||
1193 | struct stm32_dfsdm_adc *adc = platform_get_drvdata(pdev); | ||
1194 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); | ||
1195 | |||
1196 | if (adc->dev_data->type == DFSDM_AUDIO) | ||
1197 | of_platform_depopulate(&pdev->dev); | ||
1198 | iio_device_unregister(indio_dev); | ||
1199 | stm32_dfsdm_dma_release(indio_dev); | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static struct platform_driver stm32_dfsdm_adc_driver = { | ||
1205 | .driver = { | ||
1206 | .name = "stm32-dfsdm-adc", | ||
1207 | .of_match_table = stm32_dfsdm_adc_match, | ||
1208 | }, | ||
1209 | .probe = stm32_dfsdm_adc_probe, | ||
1210 | .remove = stm32_dfsdm_adc_remove, | ||
1211 | }; | ||
1212 | module_platform_driver(stm32_dfsdm_adc_driver); | ||
1213 | |||
1214 | MODULE_DESCRIPTION("STM32 sigma delta ADC"); | ||
1215 | MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); | ||
1216 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c new file mode 100644 index 000000000000..72427414db7f --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm-core.c | |||
@@ -0,0 +1,309 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * This file is part the core part STM32 DFSDM driver | ||
4 | * | ||
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
6 | * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics. | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/iio/iio.h> | ||
11 | #include <linux/iio/sysfs.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of_device.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include "stm32-dfsdm.h" | ||
19 | |||
20 | struct stm32_dfsdm_dev_data { | ||
21 | unsigned int num_filters; | ||
22 | unsigned int num_channels; | ||
23 | const struct regmap_config *regmap_cfg; | ||
24 | }; | ||
25 | |||
26 | #define STM32H7_DFSDM_NUM_FILTERS 4 | ||
27 | #define STM32H7_DFSDM_NUM_CHANNELS 8 | ||
28 | |||
29 | static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) | ||
30 | { | ||
31 | if (reg < DFSDM_FILTER_BASE_ADR) | ||
32 | return false; | ||
33 | |||
34 | /* | ||
35 | * Mask is done on register to avoid to list registers of all | ||
36 | * filter instances. | ||
37 | */ | ||
38 | switch (reg & DFSDM_FILTER_REG_MASK) { | ||
39 | case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: | ||
40 | case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: | ||
41 | case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: | ||
42 | case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | return false; | ||
47 | } | ||
48 | |||
49 | static const struct regmap_config stm32h7_dfsdm_regmap_cfg = { | ||
50 | .reg_bits = 32, | ||
51 | .val_bits = 32, | ||
52 | .reg_stride = sizeof(u32), | ||
53 | .max_register = 0x2B8, | ||
54 | .volatile_reg = stm32_dfsdm_volatile_reg, | ||
55 | .fast_io = true, | ||
56 | }; | ||
57 | |||
58 | static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { | ||
59 | .num_filters = STM32H7_DFSDM_NUM_FILTERS, | ||
60 | .num_channels = STM32H7_DFSDM_NUM_CHANNELS, | ||
61 | .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, | ||
62 | }; | ||
63 | |||
64 | struct dfsdm_priv { | ||
65 | struct platform_device *pdev; /* platform device */ | ||
66 | |||
67 | struct stm32_dfsdm dfsdm; /* common data exported for all instances */ | ||
68 | |||
69 | unsigned int spi_clk_out_div; /* SPI clkout divider value */ | ||
70 | atomic_t n_active_ch; /* number of current active channels */ | ||
71 | |||
72 | struct clk *clk; /* DFSDM clock */ | ||
73 | struct clk *aclk; /* audio clock */ | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * stm32_dfsdm_start_dfsdm - start global dfsdm interface. | ||
78 | * | ||
79 | * Enable interface if n_active_ch is not null. | ||
80 | * @dfsdm: Handle used to retrieve dfsdm context. | ||
81 | */ | ||
82 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) | ||
83 | { | ||
84 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | ||
85 | struct device *dev = &priv->pdev->dev; | ||
86 | unsigned int clk_div = priv->spi_clk_out_div; | ||
87 | int ret; | ||
88 | |||
89 | if (atomic_inc_return(&priv->n_active_ch) == 1) { | ||
90 | ret = clk_prepare_enable(priv->clk); | ||
91 | if (ret < 0) { | ||
92 | dev_err(dev, "Failed to start clock\n"); | ||
93 | goto error_ret; | ||
94 | } | ||
95 | if (priv->aclk) { | ||
96 | ret = clk_prepare_enable(priv->aclk); | ||
97 | if (ret < 0) { | ||
98 | dev_err(dev, "Failed to start audio clock\n"); | ||
99 | goto disable_clk; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ | ||
104 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
105 | DFSDM_CHCFGR1_CKOUTDIV_MASK, | ||
106 | DFSDM_CHCFGR1_CKOUTDIV(clk_div)); | ||
107 | if (ret < 0) | ||
108 | goto disable_aclk; | ||
109 | |||
110 | /* Global enable of DFSDM interface */ | ||
111 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
112 | DFSDM_CHCFGR1_DFSDMEN_MASK, | ||
113 | DFSDM_CHCFGR1_DFSDMEN(1)); | ||
114 | if (ret < 0) | ||
115 | goto disable_aclk; | ||
116 | } | ||
117 | |||
118 | dev_dbg(dev, "%s: n_active_ch %d\n", __func__, | ||
119 | atomic_read(&priv->n_active_ch)); | ||
120 | |||
121 | return 0; | ||
122 | |||
123 | disable_aclk: | ||
124 | clk_disable_unprepare(priv->aclk); | ||
125 | disable_clk: | ||
126 | clk_disable_unprepare(priv->clk); | ||
127 | |||
128 | error_ret: | ||
129 | atomic_dec(&priv->n_active_ch); | ||
130 | |||
131 | return ret; | ||
132 | } | ||
133 | EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); | ||
134 | |||
135 | /** | ||
136 | * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. | ||
137 | * | ||
138 | * Disable interface if n_active_ch is null | ||
139 | * @dfsdm: Handle used to retrieve dfsdm context. | ||
140 | */ | ||
141 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) | ||
142 | { | ||
143 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | ||
144 | int ret; | ||
145 | |||
146 | if (atomic_dec_and_test(&priv->n_active_ch)) { | ||
147 | /* Global disable of DFSDM interface */ | ||
148 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
149 | DFSDM_CHCFGR1_DFSDMEN_MASK, | ||
150 | DFSDM_CHCFGR1_DFSDMEN(0)); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | |||
154 | /* Stop SPI CLKOUT */ | ||
155 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
156 | DFSDM_CHCFGR1_CKOUTDIV_MASK, | ||
157 | DFSDM_CHCFGR1_CKOUTDIV(0)); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | |||
161 | clk_disable_unprepare(priv->clk); | ||
162 | if (priv->aclk) | ||
163 | clk_disable_unprepare(priv->aclk); | ||
164 | } | ||
165 | dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, | ||
166 | atomic_read(&priv->n_active_ch)); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(stm32_dfsdm_stop_dfsdm); | ||
171 | |||
172 | static int stm32_dfsdm_parse_of(struct platform_device *pdev, | ||
173 | struct dfsdm_priv *priv) | ||
174 | { | ||
175 | struct device_node *node = pdev->dev.of_node; | ||
176 | struct resource *res; | ||
177 | unsigned long clk_freq; | ||
178 | unsigned int spi_freq, rem; | ||
179 | int ret; | ||
180 | |||
181 | if (!node) | ||
182 | return -EINVAL; | ||
183 | |||
184 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
185 | if (!res) { | ||
186 | dev_err(&pdev->dev, "Failed to get memory resource\n"); | ||
187 | return -ENODEV; | ||
188 | } | ||
189 | priv->dfsdm.phys_base = res->start; | ||
190 | priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res); | ||
191 | |||
192 | /* | ||
193 | * "dfsdm" clock is mandatory for DFSDM peripheral clocking. | ||
194 | * "dfsdm" or "audio" clocks can be used as source clock for | ||
195 | * the SPI clock out signal and internal processing, depending | ||
196 | * on use case. | ||
197 | */ | ||
198 | priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); | ||
199 | if (IS_ERR(priv->clk)) { | ||
200 | dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | priv->aclk = devm_clk_get(&pdev->dev, "audio"); | ||
205 | if (IS_ERR(priv->aclk)) | ||
206 | priv->aclk = NULL; | ||
207 | |||
208 | if (priv->aclk) | ||
209 | clk_freq = clk_get_rate(priv->aclk); | ||
210 | else | ||
211 | clk_freq = clk_get_rate(priv->clk); | ||
212 | |||
213 | /* SPI clock out frequency */ | ||
214 | ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", | ||
215 | &spi_freq); | ||
216 | if (ret < 0) { | ||
217 | /* No SPI master mode */ | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; | ||
222 | priv->dfsdm.spi_master_freq = spi_freq; | ||
223 | |||
224 | if (rem) { | ||
225 | dev_warn(&pdev->dev, "SPI clock not accurate\n"); | ||
226 | dev_warn(&pdev->dev, "%ld = %d * %d + %d\n", | ||
227 | clk_freq, spi_freq, priv->spi_clk_out_div + 1, rem); | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | }; | ||
232 | |||
233 | static const struct of_device_id stm32_dfsdm_of_match[] = { | ||
234 | { | ||
235 | .compatible = "st,stm32h7-dfsdm", | ||
236 | .data = &stm32h7_dfsdm_data, | ||
237 | }, | ||
238 | {} | ||
239 | }; | ||
240 | MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); | ||
241 | |||
242 | static int stm32_dfsdm_probe(struct platform_device *pdev) | ||
243 | { | ||
244 | struct dfsdm_priv *priv; | ||
245 | struct device_node *pnode = pdev->dev.of_node; | ||
246 | const struct of_device_id *of_id; | ||
247 | const struct stm32_dfsdm_dev_data *dev_data; | ||
248 | struct stm32_dfsdm *dfsdm; | ||
249 | int ret; | ||
250 | |||
251 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
252 | if (!priv) | ||
253 | return -ENOMEM; | ||
254 | |||
255 | priv->pdev = pdev; | ||
256 | |||
257 | of_id = of_match_node(stm32_dfsdm_of_match, pnode); | ||
258 | if (!of_id->data) { | ||
259 | dev_err(&pdev->dev, "Data associated to device is missing\n"); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; | ||
264 | dfsdm = &priv->dfsdm; | ||
265 | dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, | ||
266 | sizeof(*dfsdm->fl_list), GFP_KERNEL); | ||
267 | if (!dfsdm->fl_list) | ||
268 | return -ENOMEM; | ||
269 | |||
270 | dfsdm->num_fls = dev_data->num_filters; | ||
271 | dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, | ||
272 | sizeof(*dfsdm->ch_list), | ||
273 | GFP_KERNEL); | ||
274 | if (!dfsdm->ch_list) | ||
275 | return -ENOMEM; | ||
276 | dfsdm->num_chs = dev_data->num_channels; | ||
277 | |||
278 | ret = stm32_dfsdm_parse_of(pdev, priv); | ||
279 | if (ret < 0) | ||
280 | return ret; | ||
281 | |||
282 | dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", | ||
283 | dfsdm->base, | ||
284 | &stm32h7_dfsdm_regmap_cfg); | ||
285 | if (IS_ERR(dfsdm->regmap)) { | ||
286 | ret = PTR_ERR(dfsdm->regmap); | ||
287 | dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", | ||
288 | __func__, ret); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | platform_set_drvdata(pdev, dfsdm); | ||
293 | |||
294 | return devm_of_platform_populate(&pdev->dev); | ||
295 | } | ||
296 | |||
297 | static struct platform_driver stm32_dfsdm_driver = { | ||
298 | .probe = stm32_dfsdm_probe, | ||
299 | .driver = { | ||
300 | .name = "stm32-dfsdm", | ||
301 | .of_match_table = stm32_dfsdm_of_match, | ||
302 | }, | ||
303 | }; | ||
304 | |||
305 | module_platform_driver(stm32_dfsdm_driver); | ||
306 | |||
307 | MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); | ||
308 | MODULE_DESCRIPTION("STMicroelectronics STM32 dfsdm driver"); | ||
309 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h new file mode 100644 index 000000000000..8708394b0725 --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm.h | |||
@@ -0,0 +1,310 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * This file is part of STM32 DFSDM driver | ||
4 | * | ||
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
6 | * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com>. | ||
7 | */ | ||
8 | |||
9 | #ifndef MDF_STM32_DFSDM__H | ||
10 | #define MDF_STM32_DFSDM__H | ||
11 | |||
12 | #include <linux/bitfield.h> | ||
13 | |||
14 | /* | ||
15 | * STM32 DFSDM - global register map | ||
16 | * ________________________________________________________ | ||
17 | * | Offset | Registers block | | ||
18 | * -------------------------------------------------------- | ||
19 | * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | | ||
20 | * -------------------------------------------------------- | ||
21 | * | 0x020 | CHANNEL 1 | | ||
22 | * -------------------------------------------------------- | ||
23 | * | ... | ..... | | ||
24 | * -------------------------------------------------------- | ||
25 | * | 0x0E0 | CHANNEL 7 | | ||
26 | * -------------------------------------------------------- | ||
27 | * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | | ||
28 | * -------------------------------------------------------- | ||
29 | * | 0x200 | FILTER 1 | | ||
30 | * -------------------------------------------------------- | ||
31 | * | 0x300 | FILTER 2 | | ||
32 | * -------------------------------------------------------- | ||
33 | * | 0x400 | FILTER 3 | | ||
34 | * -------------------------------------------------------- | ||
35 | */ | ||
36 | |||
37 | /* | ||
38 | * Channels register definitions | ||
39 | */ | ||
40 | #define DFSDM_CHCFGR1(y) ((y) * 0x20 + 0x00) | ||
41 | #define DFSDM_CHCFGR2(y) ((y) * 0x20 + 0x04) | ||
42 | #define DFSDM_AWSCDR(y) ((y) * 0x20 + 0x08) | ||
43 | #define DFSDM_CHWDATR(y) ((y) * 0x20 + 0x0C) | ||
44 | #define DFSDM_CHDATINR(y) ((y) * 0x20 + 0x10) | ||
45 | |||
46 | /* CHCFGR1: Channel configuration register 1 */ | ||
47 | #define DFSDM_CHCFGR1_SITP_MASK GENMASK(1, 0) | ||
48 | #define DFSDM_CHCFGR1_SITP(v) FIELD_PREP(DFSDM_CHCFGR1_SITP_MASK, v) | ||
49 | #define DFSDM_CHCFGR1_SPICKSEL_MASK GENMASK(3, 2) | ||
50 | #define DFSDM_CHCFGR1_SPICKSEL(v) FIELD_PREP(DFSDM_CHCFGR1_SPICKSEL_MASK, v) | ||
51 | #define DFSDM_CHCFGR1_SCDEN_MASK BIT(5) | ||
52 | #define DFSDM_CHCFGR1_SCDEN(v) FIELD_PREP(DFSDM_CHCFGR1_SCDEN_MASK, v) | ||
53 | #define DFSDM_CHCFGR1_CKABEN_MASK BIT(6) | ||
54 | #define DFSDM_CHCFGR1_CKABEN(v) FIELD_PREP(DFSDM_CHCFGR1_CKABEN_MASK, v) | ||
55 | #define DFSDM_CHCFGR1_CHEN_MASK BIT(7) | ||
56 | #define DFSDM_CHCFGR1_CHEN(v) FIELD_PREP(DFSDM_CHCFGR1_CHEN_MASK, v) | ||
57 | #define DFSDM_CHCFGR1_CHINSEL_MASK BIT(8) | ||
58 | #define DFSDM_CHCFGR1_CHINSEL(v) FIELD_PREP(DFSDM_CHCFGR1_CHINSEL_MASK, v) | ||
59 | #define DFSDM_CHCFGR1_DATMPX_MASK GENMASK(13, 12) | ||
60 | #define DFSDM_CHCFGR1_DATMPX(v) FIELD_PREP(DFSDM_CHCFGR1_DATMPX_MASK, v) | ||
61 | #define DFSDM_CHCFGR1_DATPACK_MASK GENMASK(15, 14) | ||
62 | #define DFSDM_CHCFGR1_DATPACK(v) FIELD_PREP(DFSDM_CHCFGR1_DATPACK_MASK, v) | ||
63 | #define DFSDM_CHCFGR1_CKOUTDIV_MASK GENMASK(23, 16) | ||
64 | #define DFSDM_CHCFGR1_CKOUTDIV(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTDIV_MASK, v) | ||
65 | #define DFSDM_CHCFGR1_CKOUTSRC_MASK BIT(30) | ||
66 | #define DFSDM_CHCFGR1_CKOUTSRC(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTSRC_MASK, v) | ||
67 | #define DFSDM_CHCFGR1_DFSDMEN_MASK BIT(31) | ||
68 | #define DFSDM_CHCFGR1_DFSDMEN(v) FIELD_PREP(DFSDM_CHCFGR1_DFSDMEN_MASK, v) | ||
69 | |||
70 | /* CHCFGR2: Channel configuration register 2 */ | ||
71 | #define DFSDM_CHCFGR2_DTRBS_MASK GENMASK(7, 3) | ||
72 | #define DFSDM_CHCFGR2_DTRBS(v) FIELD_PREP(DFSDM_CHCFGR2_DTRBS_MASK, v) | ||
73 | #define DFSDM_CHCFGR2_OFFSET_MASK GENMASK(31, 8) | ||
74 | #define DFSDM_CHCFGR2_OFFSET(v) FIELD_PREP(DFSDM_CHCFGR2_OFFSET_MASK, v) | ||
75 | |||
76 | /* AWSCDR: Channel analog watchdog and short circuit detector */ | ||
77 | #define DFSDM_AWSCDR_SCDT_MASK GENMASK(7, 0) | ||
78 | #define DFSDM_AWSCDR_SCDT(v) FIELD_PREP(DFSDM_AWSCDR_SCDT_MASK, v) | ||
79 | #define DFSDM_AWSCDR_BKSCD_MASK GENMASK(15, 12) | ||
80 | #define DFSDM_AWSCDR_BKSCD(v) FIELD_PREP(DFSDM_AWSCDR_BKSCD_MASK, v) | ||
81 | #define DFSDM_AWSCDR_AWFOSR_MASK GENMASK(20, 16) | ||
82 | #define DFSDM_AWSCDR_AWFOSR(v) FIELD_PREP(DFSDM_AWSCDR_AWFOSR_MASK, v) | ||
83 | #define DFSDM_AWSCDR_AWFORD_MASK GENMASK(23, 22) | ||
84 | #define DFSDM_AWSCDR_AWFORD(v) FIELD_PREP(DFSDM_AWSCDR_AWFORD_MASK, v) | ||
85 | |||
86 | /* | ||
87 | * Filters register definitions | ||
88 | */ | ||
89 | #define DFSDM_FILTER_BASE_ADR 0x100 | ||
90 | #define DFSDM_FILTER_REG_MASK 0x7F | ||
91 | #define DFSDM_FILTER_X_BASE_ADR(x) ((x) * 0x80 + DFSDM_FILTER_BASE_ADR) | ||
92 | |||
93 | #define DFSDM_CR1(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x00) | ||
94 | #define DFSDM_CR2(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x04) | ||
95 | #define DFSDM_ISR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x08) | ||
96 | #define DFSDM_ICR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x0C) | ||
97 | #define DFSDM_JCHGR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x10) | ||
98 | #define DFSDM_FCR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x14) | ||
99 | #define DFSDM_JDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x18) | ||
100 | #define DFSDM_RDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x1C) | ||
101 | #define DFSDM_AWHTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x20) | ||
102 | #define DFSDM_AWLTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x24) | ||
103 | #define DFSDM_AWSR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x28) | ||
104 | #define DFSDM_AWCFR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x2C) | ||
105 | #define DFSDM_EXMAX(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x30) | ||
106 | #define DFSDM_EXMIN(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x34) | ||
107 | #define DFSDM_CNVTIMR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x38) | ||
108 | |||
109 | /* CR1 Control register 1 */ | ||
110 | #define DFSDM_CR1_DFEN_MASK BIT(0) | ||
111 | #define DFSDM_CR1_DFEN(v) FIELD_PREP(DFSDM_CR1_DFEN_MASK, v) | ||
112 | #define DFSDM_CR1_JSWSTART_MASK BIT(1) | ||
113 | #define DFSDM_CR1_JSWSTART(v) FIELD_PREP(DFSDM_CR1_JSWSTART_MASK, v) | ||
114 | #define DFSDM_CR1_JSYNC_MASK BIT(3) | ||
115 | #define DFSDM_CR1_JSYNC(v) FIELD_PREP(DFSDM_CR1_JSYNC_MASK, v) | ||
116 | #define DFSDM_CR1_JSCAN_MASK BIT(4) | ||
117 | #define DFSDM_CR1_JSCAN(v) FIELD_PREP(DFSDM_CR1_JSCAN_MASK, v) | ||
118 | #define DFSDM_CR1_JDMAEN_MASK BIT(5) | ||
119 | #define DFSDM_CR1_JDMAEN(v) FIELD_PREP(DFSDM_CR1_JDMAEN_MASK, v) | ||
120 | #define DFSDM_CR1_JEXTSEL_MASK GENMASK(12, 8) | ||
121 | #define DFSDM_CR1_JEXTSEL(v) FIELD_PREP(DFSDM_CR1_JEXTSEL_MASK, v) | ||
122 | #define DFSDM_CR1_JEXTEN_MASK GENMASK(14, 13) | ||
123 | #define DFSDM_CR1_JEXTEN(v) FIELD_PREP(DFSDM_CR1_JEXTEN_MASK, v) | ||
124 | #define DFSDM_CR1_RSWSTART_MASK BIT(17) | ||
125 | #define DFSDM_CR1_RSWSTART(v) FIELD_PREP(DFSDM_CR1_RSWSTART_MASK, v) | ||
126 | #define DFSDM_CR1_RCONT_MASK BIT(18) | ||
127 | #define DFSDM_CR1_RCONT(v) FIELD_PREP(DFSDM_CR1_RCONT_MASK, v) | ||
128 | #define DFSDM_CR1_RSYNC_MASK BIT(19) | ||
129 | #define DFSDM_CR1_RSYNC(v) FIELD_PREP(DFSDM_CR1_RSYNC_MASK, v) | ||
130 | #define DFSDM_CR1_RDMAEN_MASK BIT(21) | ||
131 | #define DFSDM_CR1_RDMAEN(v) FIELD_PREP(DFSDM_CR1_RDMAEN_MASK, v) | ||
132 | #define DFSDM_CR1_RCH_MASK GENMASK(26, 24) | ||
133 | #define DFSDM_CR1_RCH(v) FIELD_PREP(DFSDM_CR1_RCH_MASK, v) | ||
134 | #define DFSDM_CR1_FAST_MASK BIT(29) | ||
135 | #define DFSDM_CR1_FAST(v) FIELD_PREP(DFSDM_CR1_FAST_MASK, v) | ||
136 | #define DFSDM_CR1_AWFSEL_MASK BIT(30) | ||
137 | #define DFSDM_CR1_AWFSEL(v) FIELD_PREP(DFSDM_CR1_AWFSEL_MASK, v) | ||
138 | |||
139 | /* CR2: Control register 2 */ | ||
140 | #define DFSDM_CR2_IE_MASK GENMASK(6, 0) | ||
141 | #define DFSDM_CR2_IE(v) FIELD_PREP(DFSDM_CR2_IE_MASK, v) | ||
142 | #define DFSDM_CR2_JEOCIE_MASK BIT(0) | ||
143 | #define DFSDM_CR2_JEOCIE(v) FIELD_PREP(DFSDM_CR2_JEOCIE_MASK, v) | ||
144 | #define DFSDM_CR2_REOCIE_MASK BIT(1) | ||
145 | #define DFSDM_CR2_REOCIE(v) FIELD_PREP(DFSDM_CR2_REOCIE_MASK, v) | ||
146 | #define DFSDM_CR2_JOVRIE_MASK BIT(2) | ||
147 | #define DFSDM_CR2_JOVRIE(v) FIELD_PREP(DFSDM_CR2_JOVRIE_MASK, v) | ||
148 | #define DFSDM_CR2_ROVRIE_MASK BIT(3) | ||
149 | #define DFSDM_CR2_ROVRIE(v) FIELD_PREP(DFSDM_CR2_ROVRIE_MASK, v) | ||
150 | #define DFSDM_CR2_AWDIE_MASK BIT(4) | ||
151 | #define DFSDM_CR2_AWDIE(v) FIELD_PREP(DFSDM_CR2_AWDIE_MASK, v) | ||
152 | #define DFSDM_CR2_SCDIE_MASK BIT(5) | ||
153 | #define DFSDM_CR2_SCDIE(v) FIELD_PREP(DFSDM_CR2_SCDIE_MASK, v) | ||
154 | #define DFSDM_CR2_CKABIE_MASK BIT(6) | ||
155 | #define DFSDM_CR2_CKABIE(v) FIELD_PREP(DFSDM_CR2_CKABIE_MASK, v) | ||
156 | #define DFSDM_CR2_EXCH_MASK GENMASK(15, 8) | ||
157 | #define DFSDM_CR2_EXCH(v) FIELD_PREP(DFSDM_CR2_EXCH_MASK, v) | ||
158 | #define DFSDM_CR2_AWDCH_MASK GENMASK(23, 16) | ||
159 | #define DFSDM_CR2_AWDCH(v) FIELD_PREP(DFSDM_CR2_AWDCH_MASK, v) | ||
160 | |||
161 | /* ISR: Interrupt status register */ | ||
162 | #define DFSDM_ISR_JEOCF_MASK BIT(0) | ||
163 | #define DFSDM_ISR_JEOCF(v) FIELD_PREP(DFSDM_ISR_JEOCF_MASK, v) | ||
164 | #define DFSDM_ISR_REOCF_MASK BIT(1) | ||
165 | #define DFSDM_ISR_REOCF(v) FIELD_PREP(DFSDM_ISR_REOCF_MASK, v) | ||
166 | #define DFSDM_ISR_JOVRF_MASK BIT(2) | ||
167 | #define DFSDM_ISR_JOVRF(v) FIELD_PREP(DFSDM_ISR_JOVRF_MASK, v) | ||
168 | #define DFSDM_ISR_ROVRF_MASK BIT(3) | ||
169 | #define DFSDM_ISR_ROVRF(v) FIELD_PREP(DFSDM_ISR_ROVRF_MASK, v) | ||
170 | #define DFSDM_ISR_AWDF_MASK BIT(4) | ||
171 | #define DFSDM_ISR_AWDF(v) FIELD_PREP(DFSDM_ISR_AWDF_MASK, v) | ||
172 | #define DFSDM_ISR_JCIP_MASK BIT(13) | ||
173 | #define DFSDM_ISR_JCIP(v) FIELD_PREP(DFSDM_ISR_JCIP_MASK, v) | ||
174 | #define DFSDM_ISR_RCIP_MASK BIT(14) | ||
175 | #define DFSDM_ISR_RCIP(v) FIELD_PREP(DFSDM_ISR_RCIP, v) | ||
176 | #define DFSDM_ISR_CKABF_MASK GENMASK(23, 16) | ||
177 | #define DFSDM_ISR_CKABF(v) FIELD_PREP(DFSDM_ISR_CKABF_MASK, v) | ||
178 | #define DFSDM_ISR_SCDF_MASK GENMASK(31, 24) | ||
179 | #define DFSDM_ISR_SCDF(v) FIELD_PREP(DFSDM_ISR_SCDF_MASK, v) | ||
180 | |||
181 | /* ICR: Interrupt flag clear register */ | ||
182 | #define DFSDM_ICR_CLRJOVRF_MASK BIT(2) | ||
183 | #define DFSDM_ICR_CLRJOVRF(v) FIELD_PREP(DFSDM_ICR_CLRJOVRF_MASK, v) | ||
184 | #define DFSDM_ICR_CLRROVRF_MASK BIT(3) | ||
185 | #define DFSDM_ICR_CLRROVRF(v) FIELD_PREP(DFSDM_ICR_CLRROVRF_MASK, v) | ||
186 | #define DFSDM_ICR_CLRCKABF_MASK GENMASK(23, 16) | ||
187 | #define DFSDM_ICR_CLRCKABF(v) FIELD_PREP(DFSDM_ICR_CLRCKABF_MASK, v) | ||
188 | #define DFSDM_ICR_CLRCKABF_CH_MASK(y) BIT(16 + (y)) | ||
189 | #define DFSDM_ICR_CLRCKABF_CH(v, y) \ | ||
190 | (((v) << (16 + (y))) & DFSDM_ICR_CLRCKABF_CH_MASK(y)) | ||
191 | #define DFSDM_ICR_CLRSCDF_MASK GENMASK(31, 24) | ||
192 | #define DFSDM_ICR_CLRSCDF(v) FIELD_PREP(DFSDM_ICR_CLRSCDF_MASK, v) | ||
193 | #define DFSDM_ICR_CLRSCDF_CH_MASK(y) BIT(24 + (y)) | ||
194 | #define DFSDM_ICR_CLRSCDF_CH(v, y) \ | ||
195 | (((v) << (24 + (y))) & DFSDM_ICR_CLRSCDF_MASK(y)) | ||
196 | |||
197 | /* FCR: Filter control register */ | ||
198 | #define DFSDM_FCR_IOSR_MASK GENMASK(7, 0) | ||
199 | #define DFSDM_FCR_IOSR(v) FIELD_PREP(DFSDM_FCR_IOSR_MASK, v) | ||
200 | #define DFSDM_FCR_FOSR_MASK GENMASK(25, 16) | ||
201 | #define DFSDM_FCR_FOSR(v) FIELD_PREP(DFSDM_FCR_FOSR_MASK, v) | ||
202 | #define DFSDM_FCR_FORD_MASK GENMASK(31, 29) | ||
203 | #define DFSDM_FCR_FORD(v) FIELD_PREP(DFSDM_FCR_FORD_MASK, v) | ||
204 | |||
205 | /* RDATAR: Filter data register for regular channel */ | ||
206 | #define DFSDM_DATAR_CH_MASK GENMASK(2, 0) | ||
207 | #define DFSDM_DATAR_DATA_OFFSET 8 | ||
208 | #define DFSDM_DATAR_DATA_MASK GENMASK(31, DFSDM_DATAR_DATA_OFFSET) | ||
209 | |||
210 | /* AWLTR: Filter analog watchdog low threshold register */ | ||
211 | #define DFSDM_AWLTR_BKAWL_MASK GENMASK(3, 0) | ||
212 | #define DFSDM_AWLTR_BKAWL(v) FIELD_PREP(DFSDM_AWLTR_BKAWL_MASK, v) | ||
213 | #define DFSDM_AWLTR_AWLT_MASK GENMASK(31, 8) | ||
214 | #define DFSDM_AWLTR_AWLT(v) FIELD_PREP(DFSDM_AWLTR_AWLT_MASK, v) | ||
215 | |||
216 | /* AWHTR: Filter analog watchdog low threshold register */ | ||
217 | #define DFSDM_AWHTR_BKAWH_MASK GENMASK(3, 0) | ||
218 | #define DFSDM_AWHTR_BKAWH(v) FIELD_PREP(DFSDM_AWHTR_BKAWH_MASK, v) | ||
219 | #define DFSDM_AWHTR_AWHT_MASK GENMASK(31, 8) | ||
220 | #define DFSDM_AWHTR_AWHT(v) FIELD_PREP(DFSDM_AWHTR_AWHT_MASK, v) | ||
221 | |||
222 | /* AWSR: Filter watchdog status register */ | ||
223 | #define DFSDM_AWSR_AWLTF_MASK GENMASK(7, 0) | ||
224 | #define DFSDM_AWSR_AWLTF(v) FIELD_PREP(DFSDM_AWSR_AWLTF_MASK, v) | ||
225 | #define DFSDM_AWSR_AWHTF_MASK GENMASK(15, 8) | ||
226 | #define DFSDM_AWSR_AWHTF(v) FIELD_PREP(DFSDM_AWSR_AWHTF_MASK, v) | ||
227 | |||
228 | /* AWCFR: Filter watchdog status register */ | ||
229 | #define DFSDM_AWCFR_AWLTF_MASK GENMASK(7, 0) | ||
230 | #define DFSDM_AWCFR_AWLTF(v) FIELD_PREP(DFSDM_AWCFR_AWLTF_MASK, v) | ||
231 | #define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8) | ||
232 | #define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v) | ||
233 | |||
234 | /* DFSDM filter order */ | ||
235 | enum stm32_dfsdm_sinc_order { | ||
236 | DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ | ||
237 | DFSDM_SINC1_ORDER, /* Sinc 1 filter type */ | ||
238 | DFSDM_SINC2_ORDER, /* Sinc 2 filter type */ | ||
239 | DFSDM_SINC3_ORDER, /* Sinc 3 filter type */ | ||
240 | DFSDM_SINC4_ORDER, /* Sinc 4 filter type (N.A. for watchdog) */ | ||
241 | DFSDM_SINC5_ORDER, /* Sinc 5 filter type (N.A. for watchdog) */ | ||
242 | DFSDM_NB_SINC_ORDER, | ||
243 | }; | ||
244 | |||
245 | /** | ||
246 | * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter | ||
247 | * @iosr: integrator oversampling | ||
248 | * @fosr: filter oversampling | ||
249 | * @ford: filter order | ||
250 | * @res: output sample resolution | ||
251 | * @sync_mode: filter synchronized with filter 0 | ||
252 | * @fast: filter fast mode | ||
253 | */ | ||
254 | struct stm32_dfsdm_filter { | ||
255 | unsigned int iosr; | ||
256 | unsigned int fosr; | ||
257 | enum stm32_dfsdm_sinc_order ford; | ||
258 | u64 res; | ||
259 | unsigned int sync_mode; | ||
260 | unsigned int fast; | ||
261 | }; | ||
262 | |||
263 | /** | ||
264 | * struct stm32_dfsdm_channel - structure relative to stm32 FDSDM channel | ||
265 | * @id: id of the channel | ||
266 | * @type: interface type linked to stm32_dfsdm_chan_type | ||
267 | * @src: interface type linked to stm32_dfsdm_chan_src | ||
268 | * @alt_si: alternative serial input interface | ||
269 | */ | ||
270 | struct stm32_dfsdm_channel { | ||
271 | unsigned int id; | ||
272 | unsigned int type; | ||
273 | unsigned int src; | ||
274 | unsigned int alt_si; | ||
275 | }; | ||
276 | |||
277 | /** | ||
278 | * struct stm32_dfsdm - stm32 FDSDM driver common data (for all instances) | ||
279 | * @base: control registers base cpu addr | ||
280 | * @phys_base: DFSDM IP register physical address | ||
281 | * @regmap: regmap for register read/write | ||
282 | * @fl_list: filter resources list | ||
283 | * @num_fls: number of filter resources available | ||
284 | * @ch_list: channel resources list | ||
285 | * @num_chs: number of channel resources available | ||
286 | * @spi_master_freq: SPI clock out frequency | ||
287 | */ | ||
288 | struct stm32_dfsdm { | ||
289 | void __iomem *base; | ||
290 | phys_addr_t phys_base; | ||
291 | struct regmap *regmap; | ||
292 | struct stm32_dfsdm_filter *fl_list; | ||
293 | unsigned int num_fls; | ||
294 | struct stm32_dfsdm_channel *ch_list; | ||
295 | unsigned int num_chs; | ||
296 | unsigned int spi_master_freq; | ||
297 | }; | ||
298 | |||
299 | /* DFSDM channel serial spi clock source */ | ||
300 | enum stm32_dfsdm_spi_clk_src { | ||
301 | DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL, | ||
302 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL, | ||
303 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING, | ||
304 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING | ||
305 | }; | ||
306 | |||
307 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm); | ||
308 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm); | ||
309 | |||
310 | #endif | ||
diff --git a/drivers/iio/buffer/Kconfig b/drivers/iio/buffer/Kconfig index 4ffd3db7817f..338774cba19b 100644 --- a/drivers/iio/buffer/Kconfig +++ b/drivers/iio/buffer/Kconfig | |||
@@ -29,6 +29,16 @@ config IIO_BUFFER_DMAENGINE | |||
29 | 29 | ||
30 | Should be selected by drivers that want to use this functionality. | 30 | Should be selected by drivers that want to use this functionality. |
31 | 31 | ||
32 | config IIO_BUFFER_HW_CONSUMER | ||
33 | tristate "Industrial I/O HW buffering" | ||
34 | help | ||
35 | Provides a way to bonding when an IIO device has a direct connection | ||
36 | to another device in hardware. In this case buffers for data transfers | ||
37 | are handled by hardware. | ||
38 | |||
39 | Should be selected by drivers that want to use the generic Hw consumer | ||
40 | interface. | ||
41 | |||
32 | config IIO_KFIFO_BUF | 42 | config IIO_KFIFO_BUF |
33 | tristate "Industrial I/O buffering based on kfifo" | 43 | tristate "Industrial I/O buffering based on kfifo" |
34 | help | 44 | help |
diff --git a/drivers/iio/buffer/Makefile b/drivers/iio/buffer/Makefile index 95f9f41c58b7..1403eb2f9409 100644 --- a/drivers/iio/buffer/Makefile +++ b/drivers/iio/buffer/Makefile | |||
@@ -7,5 +7,6 @@ | |||
7 | obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o | 7 | obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o |
8 | obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o | 8 | obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o |
9 | obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o | 9 | obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o |
10 | obj-$(CONFIG_IIO_BUFFER_HW_CONSUMER) += industrialio-hw-consumer.o | ||
10 | obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o | 11 | obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o |
11 | obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o | 12 | obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o |
diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index 4847534700e7..ea63c838eeae 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c | |||
@@ -104,6 +104,17 @@ error_free_cb_buff: | |||
104 | } | 104 | } |
105 | EXPORT_SYMBOL_GPL(iio_channel_get_all_cb); | 105 | EXPORT_SYMBOL_GPL(iio_channel_get_all_cb); |
106 | 106 | ||
107 | int iio_channel_cb_set_buffer_watermark(struct iio_cb_buffer *cb_buff, | ||
108 | size_t watermark) | ||
109 | { | ||
110 | if (!watermark) | ||
111 | return -EINVAL; | ||
112 | cb_buff->buffer.watermark = watermark; | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(iio_channel_cb_set_buffer_watermark); | ||
117 | |||
107 | int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff) | 118 | int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff) |
108 | { | 119 | { |
109 | return iio_update_buffers(cb_buff->indio_dev, &cb_buff->buffer, | 120 | return iio_update_buffers(cb_buff->indio_dev, &cb_buff->buffer, |
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c new file mode 100644 index 000000000000..95165697d8ae --- /dev/null +++ b/drivers/iio/buffer/industrialio-hw-consumer.c | |||
@@ -0,0 +1,247 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright 2017 Analog Devices Inc. | ||
4 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
5 | */ | ||
6 | |||
7 | #include <linux/err.h> | ||
8 | #include <linux/export.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/module.h> | ||
11 | |||
12 | #include <linux/iio/iio.h> | ||
13 | #include <linux/iio/consumer.h> | ||
14 | #include <linux/iio/hw-consumer.h> | ||
15 | #include <linux/iio/buffer_impl.h> | ||
16 | |||
17 | /** | ||
18 | * struct iio_hw_consumer - IIO hw consumer block | ||
19 | * @buffers: hardware buffers list head. | ||
20 | * @channels: IIO provider channels. | ||
21 | */ | ||
22 | struct iio_hw_consumer { | ||
23 | struct list_head buffers; | ||
24 | struct iio_channel *channels; | ||
25 | }; | ||
26 | |||
27 | struct hw_consumer_buffer { | ||
28 | struct list_head head; | ||
29 | struct iio_dev *indio_dev; | ||
30 | struct iio_buffer buffer; | ||
31 | long scan_mask[]; | ||
32 | }; | ||
33 | |||
34 | static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer( | ||
35 | struct iio_buffer *buffer) | ||
36 | { | ||
37 | return container_of(buffer, struct hw_consumer_buffer, buffer); | ||
38 | } | ||
39 | |||
40 | static void iio_hw_buf_release(struct iio_buffer *buffer) | ||
41 | { | ||
42 | struct hw_consumer_buffer *hw_buf = | ||
43 | iio_buffer_to_hw_consumer_buffer(buffer); | ||
44 | kfree(hw_buf); | ||
45 | } | ||
46 | |||
47 | static const struct iio_buffer_access_funcs iio_hw_buf_access = { | ||
48 | .release = &iio_hw_buf_release, | ||
49 | .modes = INDIO_BUFFER_HARDWARE, | ||
50 | }; | ||
51 | |||
52 | static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( | ||
53 | struct iio_hw_consumer *hwc, struct iio_dev *indio_dev) | ||
54 | { | ||
55 | size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long); | ||
56 | struct hw_consumer_buffer *buf; | ||
57 | |||
58 | list_for_each_entry(buf, &hwc->buffers, head) { | ||
59 | if (buf->indio_dev == indio_dev) | ||
60 | return buf; | ||
61 | } | ||
62 | |||
63 | buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL); | ||
64 | if (!buf) | ||
65 | return NULL; | ||
66 | |||
67 | buf->buffer.access = &iio_hw_buf_access; | ||
68 | buf->indio_dev = indio_dev; | ||
69 | buf->buffer.scan_mask = buf->scan_mask; | ||
70 | |||
71 | iio_buffer_init(&buf->buffer); | ||
72 | list_add_tail(&buf->head, &hwc->buffers); | ||
73 | |||
74 | return buf; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * iio_hw_consumer_alloc() - Allocate IIO hardware consumer | ||
79 | * @dev: Pointer to consumer device. | ||
80 | * | ||
81 | * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure. | ||
82 | */ | ||
83 | struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev) | ||
84 | { | ||
85 | struct hw_consumer_buffer *buf; | ||
86 | struct iio_hw_consumer *hwc; | ||
87 | struct iio_channel *chan; | ||
88 | int ret; | ||
89 | |||
90 | hwc = kzalloc(sizeof(*hwc), GFP_KERNEL); | ||
91 | if (!hwc) | ||
92 | return ERR_PTR(-ENOMEM); | ||
93 | |||
94 | INIT_LIST_HEAD(&hwc->buffers); | ||
95 | |||
96 | hwc->channels = iio_channel_get_all(dev); | ||
97 | if (IS_ERR(hwc->channels)) { | ||
98 | ret = PTR_ERR(hwc->channels); | ||
99 | goto err_free_hwc; | ||
100 | } | ||
101 | |||
102 | chan = &hwc->channels[0]; | ||
103 | while (chan->indio_dev) { | ||
104 | buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev); | ||
105 | if (!buf) { | ||
106 | ret = -ENOMEM; | ||
107 | goto err_put_buffers; | ||
108 | } | ||
109 | set_bit(chan->channel->scan_index, buf->buffer.scan_mask); | ||
110 | chan++; | ||
111 | } | ||
112 | |||
113 | return hwc; | ||
114 | |||
115 | err_put_buffers: | ||
116 | list_for_each_entry(buf, &hwc->buffers, head) | ||
117 | iio_buffer_put(&buf->buffer); | ||
118 | iio_channel_release_all(hwc->channels); | ||
119 | err_free_hwc: | ||
120 | kfree(hwc); | ||
121 | return ERR_PTR(ret); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc); | ||
124 | |||
125 | /** | ||
126 | * iio_hw_consumer_free() - Free IIO hardware consumer | ||
127 | * @hwc: hw consumer to free. | ||
128 | */ | ||
129 | void iio_hw_consumer_free(struct iio_hw_consumer *hwc) | ||
130 | { | ||
131 | struct hw_consumer_buffer *buf, *n; | ||
132 | |||
133 | iio_channel_release_all(hwc->channels); | ||
134 | list_for_each_entry_safe(buf, n, &hwc->buffers, head) | ||
135 | iio_buffer_put(&buf->buffer); | ||
136 | kfree(hwc); | ||
137 | } | ||
138 | EXPORT_SYMBOL_GPL(iio_hw_consumer_free); | ||
139 | |||
140 | static void devm_iio_hw_consumer_release(struct device *dev, void *res) | ||
141 | { | ||
142 | iio_hw_consumer_free(*(struct iio_hw_consumer **)res); | ||
143 | } | ||
144 | |||
145 | static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) | ||
146 | { | ||
147 | struct iio_hw_consumer **r = res; | ||
148 | |||
149 | if (!r || !*r) { | ||
150 | WARN_ON(!r || !*r); | ||
151 | return 0; | ||
152 | } | ||
153 | return *r == data; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc() | ||
158 | * @dev: Pointer to consumer device. | ||
159 | * | ||
160 | * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function | ||
161 | * is automatically freed on driver detach. | ||
162 | * | ||
163 | * If an iio_hw_consumer allocated with this function needs to be freed | ||
164 | * separately, devm_iio_hw_consumer_free() must be used. | ||
165 | * | ||
166 | * returns pointer to allocated iio_hw_consumer on success, NULL on failure. | ||
167 | */ | ||
168 | struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) | ||
169 | { | ||
170 | struct iio_hw_consumer **ptr, *iio_hwc; | ||
171 | |||
172 | ptr = devres_alloc(devm_iio_hw_consumer_release, sizeof(*ptr), | ||
173 | GFP_KERNEL); | ||
174 | if (!ptr) | ||
175 | return NULL; | ||
176 | |||
177 | iio_hwc = iio_hw_consumer_alloc(dev); | ||
178 | if (IS_ERR(iio_hwc)) { | ||
179 | devres_free(ptr); | ||
180 | } else { | ||
181 | *ptr = iio_hwc; | ||
182 | devres_add(dev, ptr); | ||
183 | } | ||
184 | |||
185 | return iio_hwc; | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc); | ||
188 | |||
189 | /** | ||
190 | * devm_iio_hw_consumer_free - Resource-managed iio_hw_consumer_free() | ||
191 | * @dev: Pointer to consumer device. | ||
192 | * @hwc: iio_hw_consumer to free. | ||
193 | * | ||
194 | * Free iio_hw_consumer allocated with devm_iio_hw_consumer_alloc(). | ||
195 | */ | ||
196 | void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc) | ||
197 | { | ||
198 | int rc; | ||
199 | |||
200 | rc = devres_release(dev, devm_iio_hw_consumer_release, | ||
201 | devm_iio_hw_consumer_match, hwc); | ||
202 | WARN_ON(rc); | ||
203 | } | ||
204 | EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_free); | ||
205 | |||
206 | /** | ||
207 | * iio_hw_consumer_enable() - Enable IIO hardware consumer | ||
208 | * @hwc: iio_hw_consumer to enable. | ||
209 | * | ||
210 | * Returns 0 on success. | ||
211 | */ | ||
212 | int iio_hw_consumer_enable(struct iio_hw_consumer *hwc) | ||
213 | { | ||
214 | struct hw_consumer_buffer *buf; | ||
215 | int ret; | ||
216 | |||
217 | list_for_each_entry(buf, &hwc->buffers, head) { | ||
218 | ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL); | ||
219 | if (ret) | ||
220 | goto err_disable_buffers; | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | |||
225 | err_disable_buffers: | ||
226 | list_for_each_entry_continue_reverse(buf, &hwc->buffers, head) | ||
227 | iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); | ||
228 | return ret; | ||
229 | } | ||
230 | EXPORT_SYMBOL_GPL(iio_hw_consumer_enable); | ||
231 | |||
232 | /** | ||
233 | * iio_hw_consumer_disable() - Disable IIO hardware consumer | ||
234 | * @hwc: iio_hw_consumer to disable. | ||
235 | */ | ||
236 | void iio_hw_consumer_disable(struct iio_hw_consumer *hwc) | ||
237 | { | ||
238 | struct hw_consumer_buffer *buf; | ||
239 | |||
240 | list_for_each_entry(buf, &hwc->buffers, head) | ||
241 | iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); | ||
242 | } | ||
243 | EXPORT_SYMBOL_GPL(iio_hw_consumer_disable); | ||
244 | |||
245 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
246 | MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework"); | ||
247 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 069defcc6d9b..ec98790e2a28 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c | |||
@@ -664,9 +664,8 @@ err_unlock: | |||
664 | } | 664 | } |
665 | EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); | 665 | EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); |
666 | 666 | ||
667 | static int iio_read_channel_attribute(struct iio_channel *chan, | 667 | int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, |
668 | int *val, int *val2, | 668 | enum iio_chan_info_enum attribute) |
669 | enum iio_chan_info_enum attribute) | ||
670 | { | 669 | { |
671 | int ret; | 670 | int ret; |
672 | 671 | ||
@@ -682,6 +681,7 @@ err_unlock: | |||
682 | 681 | ||
683 | return ret; | 682 | return ret; |
684 | } | 683 | } |
684 | EXPORT_SYMBOL_GPL(iio_read_channel_attribute); | ||
685 | 685 | ||
686 | int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) | 686 | int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) |
687 | { | 687 | { |
@@ -850,7 +850,8 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2, | |||
850 | chan->channel, val, val2, info); | 850 | chan->channel, val, val2, info); |
851 | } | 851 | } |
852 | 852 | ||
853 | int iio_write_channel_raw(struct iio_channel *chan, int val) | 853 | int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, |
854 | enum iio_chan_info_enum attribute) | ||
854 | { | 855 | { |
855 | int ret; | 856 | int ret; |
856 | 857 | ||
@@ -860,12 +861,18 @@ int iio_write_channel_raw(struct iio_channel *chan, int val) | |||
860 | goto err_unlock; | 861 | goto err_unlock; |
861 | } | 862 | } |
862 | 863 | ||
863 | ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW); | 864 | ret = iio_channel_write(chan, val, val2, attribute); |
864 | err_unlock: | 865 | err_unlock: |
865 | mutex_unlock(&chan->indio_dev->info_exist_lock); | 866 | mutex_unlock(&chan->indio_dev->info_exist_lock); |
866 | 867 | ||
867 | return ret; | 868 | return ret; |
868 | } | 869 | } |
870 | EXPORT_SYMBOL_GPL(iio_write_channel_attribute); | ||
871 | |||
872 | int iio_write_channel_raw(struct iio_channel *chan, int val) | ||
873 | { | ||
874 | return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW); | ||
875 | } | ||
869 | EXPORT_SYMBOL_GPL(iio_write_channel_raw); | 876 | EXPORT_SYMBOL_GPL(iio_write_channel_raw); |
870 | 877 | ||
871 | unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) | 878 | unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) |
diff --git a/include/linux/iio/adc/stm32-dfsdm-adc.h b/include/linux/iio/adc/stm32-dfsdm-adc.h new file mode 100644 index 000000000000..e7dc7a542a4e --- /dev/null +++ b/include/linux/iio/adc/stm32-dfsdm-adc.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * This file discribe the STM32 DFSDM IIO driver API for audio part | ||
4 | * | ||
5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
6 | * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com>. | ||
7 | */ | ||
8 | |||
9 | #ifndef STM32_DFSDM_ADC_H | ||
10 | #define STM32_DFSDM_ADC_H | ||
11 | |||
12 | int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev, | ||
13 | int (*cb)(const void *data, size_t size, | ||
14 | void *private), | ||
15 | void *private); | ||
16 | int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev); | ||
17 | |||
18 | #endif | ||
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 5e347a9805fd..9887f4f8e2a8 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h | |||
@@ -134,6 +134,17 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, | |||
134 | void *private), | 134 | void *private), |
135 | void *private); | 135 | void *private); |
136 | /** | 136 | /** |
137 | * iio_channel_cb_set_buffer_watermark() - set the buffer watermark. | ||
138 | * @cb_buffer: The callback buffer from whom we want the channel | ||
139 | * information. | ||
140 | * @watermark: buffer watermark in bytes. | ||
141 | * | ||
142 | * This function allows to configure the buffer watermark. | ||
143 | */ | ||
144 | int iio_channel_cb_set_buffer_watermark(struct iio_cb_buffer *cb_buffer, | ||
145 | size_t watermark); | ||
146 | |||
147 | /** | ||
137 | * iio_channel_release_all_cb() - release and unregister the callback. | 148 | * iio_channel_release_all_cb() - release and unregister the callback. |
138 | * @cb_buffer: The callback buffer that was allocated. | 149 | * @cb_buffer: The callback buffer that was allocated. |
139 | */ | 150 | */ |
@@ -216,6 +227,32 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val); | |||
216 | int iio_read_channel_processed(struct iio_channel *chan, int *val); | 227 | int iio_read_channel_processed(struct iio_channel *chan, int *val); |
217 | 228 | ||
218 | /** | 229 | /** |
230 | * iio_write_channel_attribute() - Write values to the device attribute. | ||
231 | * @chan: The channel being queried. | ||
232 | * @val: Value being written. | ||
233 | * @val2: Value being written.val2 use depends on attribute type. | ||
234 | * @attribute: info attribute to be read. | ||
235 | * | ||
236 | * Returns an error code or 0. | ||
237 | */ | ||
238 | int iio_write_channel_attribute(struct iio_channel *chan, int val, | ||
239 | int val2, enum iio_chan_info_enum attribute); | ||
240 | |||
241 | /** | ||
242 | * iio_read_channel_attribute() - Read values from the device attribute. | ||
243 | * @chan: The channel being queried. | ||
244 | * @val: Value being written. | ||
245 | * @val2: Value being written.Val2 use depends on attribute type. | ||
246 | * @attribute: info attribute to be written. | ||
247 | * | ||
248 | * Returns an error code if failed. Else returns a description of what is in val | ||
249 | * and val2, such as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val | ||
250 | * + val2/1e6 | ||
251 | */ | ||
252 | int iio_read_channel_attribute(struct iio_channel *chan, int *val, | ||
253 | int *val2, enum iio_chan_info_enum attribute); | ||
254 | |||
255 | /** | ||
219 | * iio_write_channel_raw() - write to a given channel | 256 | * iio_write_channel_raw() - write to a given channel |
220 | * @chan: The channel being queried. | 257 | * @chan: The channel being queried. |
221 | * @val: Value being written. | 258 | * @val: Value being written. |
diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h new file mode 100644 index 000000000000..44d48bb1d39f --- /dev/null +++ b/include/linux/iio/hw-consumer.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Industrial I/O in kernel hardware consumer interface | ||
4 | * | ||
5 | * Copyright 2017 Analog Devices Inc. | ||
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
7 | */ | ||
8 | |||
9 | #ifndef LINUX_IIO_HW_CONSUMER_H | ||
10 | #define LINUX_IIO_HW_CONSUMER_H | ||
11 | |||
12 | struct iio_hw_consumer; | ||
13 | |||
14 | struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev); | ||
15 | void iio_hw_consumer_free(struct iio_hw_consumer *hwc); | ||
16 | struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev); | ||
17 | void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc); | ||
18 | int iio_hw_consumer_enable(struct iio_hw_consumer *hwc); | ||
19 | void iio_hw_consumer_disable(struct iio_hw_consumer *hwc); | ||
20 | |||
21 | #endif | ||
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 20b61347ea58..f12a61be1ede 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h | |||
@@ -20,34 +20,6 @@ | |||
20 | * Currently assumes nano seconds. | 20 | * Currently assumes nano seconds. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | enum iio_chan_info_enum { | ||
24 | IIO_CHAN_INFO_RAW = 0, | ||
25 | IIO_CHAN_INFO_PROCESSED, | ||
26 | IIO_CHAN_INFO_SCALE, | ||
27 | IIO_CHAN_INFO_OFFSET, | ||
28 | IIO_CHAN_INFO_CALIBSCALE, | ||
29 | IIO_CHAN_INFO_CALIBBIAS, | ||
30 | IIO_CHAN_INFO_PEAK, | ||
31 | IIO_CHAN_INFO_PEAK_SCALE, | ||
32 | IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, | ||
33 | IIO_CHAN_INFO_AVERAGE_RAW, | ||
34 | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, | ||
35 | IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY, | ||
36 | IIO_CHAN_INFO_SAMP_FREQ, | ||
37 | IIO_CHAN_INFO_FREQUENCY, | ||
38 | IIO_CHAN_INFO_PHASE, | ||
39 | IIO_CHAN_INFO_HARDWAREGAIN, | ||
40 | IIO_CHAN_INFO_HYSTERESIS, | ||
41 | IIO_CHAN_INFO_INT_TIME, | ||
42 | IIO_CHAN_INFO_ENABLE, | ||
43 | IIO_CHAN_INFO_CALIBHEIGHT, | ||
44 | IIO_CHAN_INFO_CALIBWEIGHT, | ||
45 | IIO_CHAN_INFO_DEBOUNCE_COUNT, | ||
46 | IIO_CHAN_INFO_DEBOUNCE_TIME, | ||
47 | IIO_CHAN_INFO_CALIBEMISSIVITY, | ||
48 | IIO_CHAN_INFO_OVERSAMPLING_RATIO, | ||
49 | }; | ||
50 | |||
51 | enum iio_shared_by { | 23 | enum iio_shared_by { |
52 | IIO_SEPARATE, | 24 | IIO_SEPARATE, |
53 | IIO_SHARED_BY_TYPE, | 25 | IIO_SHARED_BY_TYPE, |
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 2aa7b6384d64..6eb3d683ef62 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h | |||
@@ -34,4 +34,32 @@ enum iio_available_type { | |||
34 | IIO_AVAIL_RANGE, | 34 | IIO_AVAIL_RANGE, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | enum iio_chan_info_enum { | ||
38 | IIO_CHAN_INFO_RAW = 0, | ||
39 | IIO_CHAN_INFO_PROCESSED, | ||
40 | IIO_CHAN_INFO_SCALE, | ||
41 | IIO_CHAN_INFO_OFFSET, | ||
42 | IIO_CHAN_INFO_CALIBSCALE, | ||
43 | IIO_CHAN_INFO_CALIBBIAS, | ||
44 | IIO_CHAN_INFO_PEAK, | ||
45 | IIO_CHAN_INFO_PEAK_SCALE, | ||
46 | IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, | ||
47 | IIO_CHAN_INFO_AVERAGE_RAW, | ||
48 | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, | ||
49 | IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY, | ||
50 | IIO_CHAN_INFO_SAMP_FREQ, | ||
51 | IIO_CHAN_INFO_FREQUENCY, | ||
52 | IIO_CHAN_INFO_PHASE, | ||
53 | IIO_CHAN_INFO_HARDWAREGAIN, | ||
54 | IIO_CHAN_INFO_HYSTERESIS, | ||
55 | IIO_CHAN_INFO_INT_TIME, | ||
56 | IIO_CHAN_INFO_ENABLE, | ||
57 | IIO_CHAN_INFO_CALIBHEIGHT, | ||
58 | IIO_CHAN_INFO_CALIBWEIGHT, | ||
59 | IIO_CHAN_INFO_DEBOUNCE_COUNT, | ||
60 | IIO_CHAN_INFO_DEBOUNCE_TIME, | ||
61 | IIO_CHAN_INFO_CALIBEMISSIVITY, | ||
62 | IIO_CHAN_INFO_OVERSAMPLING_RATIO, | ||
63 | }; | ||
64 | |||
37 | #endif /* _IIO_TYPES_H_ */ | 65 | #endif /* _IIO_TYPES_H_ */ |