Pull char/misc and other driver subsystem updates from Greg KH: "Here is the big set of char/misc and a number of other driver subsystem updates for 6.9-rc1. Included in here are: - IIO driver updates, loads of new ones and evolution of existing ones - coresight driver updates - const cleanups for many driver subsystems - speakup driver additions - platform remove callback void cleanups - mei driver updates - mhi driver updates - cdx driver updates for MSI interrupt handling - nvmem driver updates - other smaller driver updates and cleanups, full details in the shortlog All of these have been in linux-next for a long time with no reported issue, other than a build warning for the speakup driver" The build warning hits clang and is a gcc (and C23) extension, and is fixed up in the merge. Link: https://lore.kernel.org/all/20240321134831.GA2762840@dev-arch.thelio-3990X/ * tag 'char-misc-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (279 commits) binder: remove redundant variable page_addr uio_dmem_genirq: UIO_MEM_DMA_COHERENT conversion uio_pruss: UIO_MEM_DMA_COHERENT conversion cnic,bnx2,bnx2x: use UIO_MEM_DMA_COHERENT uio: introduce UIO_MEM_DMA_COHERENT type cdx: add MSI support for CDX bus pps: use cflags-y instead of EXTRA_CFLAGS speakup: Add /dev/synthu device speakup: Fix 8bit characters from direct synth parport: sunbpp: Convert to platform remove callback returning void parport: amiga: Convert to platform remove callback returning void char: xillybus: Convert to platform remove callback returning void vmw_balloon: change maintainership MAINTAINERS: change the maintainer for hpilo driver char: xilinx_hwicap: Fix NULL vs IS_ERR() bug hpet: remove hpets::hp_clocksource platform: goldfish: move the separate 'default' propery for CONFIG_GOLDFISH char: xilinx_hwicap: drop casting to void in dev_set_drvdata greybus: move is_gb_* functions out of greybus.h greybus: Remove usage of the deprecated ida_simple_xx() API ...
Unified · Split
| @@ -439,6 +439,8 @@ Mukesh Ojha <quic_mojha@quicinc.com> <mojha@codeaurora.org> · 438 unmodified lines | |||
| 439 | Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org> | 439 | Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org> |
| 440 | Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org> | 440 | Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org> |
| 441 | Mythri P K <mythripk@ti.com> | 441 | Mythri P K <mythripk@ti.com> |
| 442 | Nadav Amit <nadav.amit@gmail.com> <namit@vmware.com> | ||
| 443 | Nadav Amit <nadav.amit@gmail.com> <namit@cs.technion.ac.il> | ||
| 442 | Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com> | 444 | Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com> |
| 443 | Naoya Horiguchi <naoya.horiguchi@nec.com> <n-horiguchi@ah.jp.nec.com> | 445 | Naoya Horiguchi <naoya.horiguchi@nec.com> <n-horiguchi@ah.jp.nec.com> |
| 444 | Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com> | 446 | Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com> |
| @@ -170,3 +170,90 @@ Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_t · 169 unmodified lines | |||
| 170 | Description: | 170 | Description: |
| 171 | (RW) Set/Get the MSR(mux select register) for the DSB subunit | 171 | (RW) Set/Get the MSR(mux select register) for the DSB subunit |
| 172 | TPDM. | 172 | TPDM. |
| 173 | |||
| 174 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_mode | ||
| 175 | Date: January 2024 | ||
| 176 | KernelVersion 6.9 | ||
| 177 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 178 | Description: (Write) Set the data collection mode of CMB tpdm. Continuous | ||
| 179 | change creates CMB data set elements on every CMBCLK edge. | ||
| 180 | Trace-on-change creates CMB data set elements only when a new | ||
| 181 | data set element differs in value from the previous element | ||
| 182 | in a CMB data set. | ||
| 183 | |||
| 184 | Accepts only one of the 2 values - 0 or 1. | ||
| 185 | 0 : Continuous CMB collection mode. | ||
| 186 | 1 : Trace-on-change CMB collection mode. | ||
| 187 | |||
| 188 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpr[0:1] | ||
| 189 | Date: January 2024 | ||
| 190 | KernelVersion 6.9 | ||
| 191 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 192 | Description: | ||
| 193 | (RW) Set/Get the value of the trigger pattern for the CMB | ||
| 194 | subunit TPDM. | ||
| 195 | |||
| 196 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpmr[0:1] | ||
| 197 | Date: January 2024 | ||
| 198 | KernelVersion 6.9 | ||
| 199 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 200 | Description: | ||
| 201 | (RW) Set/Get the mask of the trigger pattern for the CMB | ||
| 202 | subunit TPDM. | ||
| 203 | |||
| 204 | What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:1] | ||
| 205 | Date: January 2024 | ||
| 206 | KernelVersion 6.9 | ||
| 207 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 208 | Description: | ||
| 209 | (RW) Set/Get the value of the pattern for the CMB subunit TPDM. | ||
| 210 | |||
| 211 | What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:1] | ||
| 212 | Date: January 2024 | ||
| 213 | KernelVersion 6.9 | ||
| 214 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 215 | Description: | ||
| 216 | (RW) Set/Get the mask of the pattern for the CMB subunit TPDM. | ||
| 217 | |||
| 218 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_patt/enable_ts | ||
| 219 | Date: January 2024 | ||
| 220 | KernelVersion 6.9 | ||
| 221 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 222 | Description: | ||
| 223 | (Write) Set the pattern timestamp of CMB tpdm. Read | ||
| 224 | the pattern timestamp of CMB tpdm. | ||
| 225 | |||
| 226 | Accepts only one of the 2 values - 0 or 1. | ||
| 227 | 0 : Disable CMB pattern timestamp. | ||
| 228 | 1 : Enable CMB pattern timestamp. | ||
| 229 | |||
| 230 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_ts | ||
| 231 | Date: January 2024 | ||
| 232 | KernelVersion 6.9 | ||
| 233 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 234 | Description: | ||
| 235 | (RW) Set/Get the trigger timestamp of the CMB for tpdm. | ||
| 236 | |||
| 237 | Accepts only one of the 2 values - 0 or 1. | ||
| 238 | 0 : Set the CMB trigger type to false | ||
| 239 | 1 : Set the CMB trigger type to true | ||
| 240 | |||
| 241 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_ts_all | ||
| 242 | Date: January 2024 | ||
| 243 | KernelVersion 6.9 | ||
| 244 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 245 | Description: | ||
| 246 | (RW) Read or write the status of timestamp upon all interface. | ||
| 247 | Only value 0 and 1 can be written to this node. Set this node to 1 to requeset | ||
| 248 | timestamp to all trace packet. | ||
| 249 | Accepts only one of the 2 values - 0 or 1. | ||
| 250 | 0 : Disable the timestamp of all trace packets. | ||
| 251 | 1 : Enable the timestamp of all trace packets. | ||
| 252 | |||
| 253 | What: /sys/bus/coresight/devices/<tpdm-name>/cmb_msr/msr[0:31] | ||
| 254 | Date: January 2024 | ||
| 255 | KernelVersion 6.9 | ||
| 256 | Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||
| 257 | Description: | ||
| 258 | (RW) Set/Get the MSR(mux select register) for the CMB subunit | ||
| 259 | TPDM. | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/in_shunt_resistorY | ||
| 2 | KernelVersion: 6.7 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | The value of the shunt resistor may be known only at runtime | ||
| 6 | and set by a client application. This attribute allows to | ||
| 7 | set its value in micro-ohms. X is the IIO index of the device. | ||
| 8 | Y is the channel number. The value is used to calculate | ||
| 9 | current, power and accumulated energy. | ||
| @@ -44,14 +44,21 @@ properties: · 43 unmodified lines | |||
| 44 | minItems: 1 | 44 | minItems: 1 |
| 45 | maxItems: 2 | 45 | maxItems: 2 |
| 46 | 46 | ||
| 47 | qcom,dsb-element-size: | 47 | qcom,dsb-element-bits: |
| 48 | description: | 48 | description: |
| 49 | Specifies the DSB(Discrete Single Bit) element size supported by | 49 | Specifies the DSB(Discrete Single Bit) element size supported by |
| 50 | the monitor. The associated aggregator will read this size before it | 50 | the monitor. The associated aggregator will read this size before it |
| 51 | is enabled. DSB element size currently only supports 32-bit and 64-bit. | 51 | is enabled. DSB element size currently only supports 32-bit and 64-bit. |
| 52 | $ref: /schemas/types.yaml#/definitions/uint8 | ||
| 53 | enum: [32, 64] | 52 | enum: [32, 64] |
| 54 | 53 | ||
| 54 | qcom,cmb-element-bits: | ||
| 55 | description: | ||
| 56 | Specifies the CMB(Continuous Multi-Bit) element size supported by | ||
| 57 | the monitor. The associated aggregator will read this size before it | ||
| 58 | is enabled. CMB element size currently only supports 8-bit, 32-bit | ||
| 59 | and 64-bit. | ||
| 60 | enum: [8, 32, 64] | ||
| 61 | |||
| 55 | qcom,dsb-msrs-num: | 62 | qcom,dsb-msrs-num: |
| 56 | description: | 63 | description: |
| 57 | Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) | 64 | Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) |
| @@ -61,6 +68,15 @@ properties: · 3 unmodified lines | |||
| 61 | minimum: 0 | 68 | minimum: 0 |
| 62 | maximum: 32 | 69 | maximum: 32 |
| 63 | 70 | ||
| 71 | qcom,cmb-msrs-num: | ||
| 72 | description: | ||
| 73 | Specifies the number of CMB MSR(mux select register) registers supported | ||
| 74 | by the monitor. If this property is not configured or set to 0, it means | ||
| 75 | this TPDM doesn't support CMB MSR. | ||
| 76 | $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 77 | minimum: 0 | ||
| 78 | maximum: 32 | ||
| 79 | |||
| 64 | clocks: | 80 | clocks: |
| 65 | maxItems: 1 | 81 | maxItems: 1 |
| 66 | 82 | ||
| @@ -94,7 +110,7 @@ examples: · 27 unmodified lines | |||
| 94 | compatible = "qcom,coresight-tpdm", "arm,primecell"; | 110 | compatible = "qcom,coresight-tpdm", "arm,primecell"; |
| 95 | reg = <0x0684c000 0x1000>; | 111 | reg = <0x0684c000 0x1000>; |
| 96 | 112 | ||
| 97 | qcom,dsb-element-size = /bits/ 8 <32>; | 113 | qcom,dsb-element-bits = <32>; |
| 98 | qcom,dsb-msrs-num = <16>; | 114 | qcom,dsb-msrs-num = <16>; |
| 99 | 115 | ||
| 100 | clocks = <&aoss_qmp>; | 116 | clocks = <&aoss_qmp>; |
| @@ -110,4 +126,22 @@ examples: · 9 unmodified lines | |||
| 110 | }; | 126 | }; |
| 111 | }; | 127 | }; |
| 112 | 128 | ||
| 129 | tpdm@6c29000 { | ||
| 130 | compatible = "qcom,coresight-tpdm", "arm,primecell"; | ||
| 131 | reg = <0x06c29000 0x1000>; | ||
| 132 | |||
| 133 | qcom,cmb-element-bits = <64>; | ||
| 134 | qcom,cmb-msrs-num = <32>; | ||
| 135 | |||
| 136 | clocks = <&aoss_qmp>; | ||
| 137 | clock-names = "apb_pclk"; | ||
| 138 | |||
| 139 | out-ports { | ||
| 140 | port { | ||
| 141 | tpdm_ipcc_out_funnel_center: endpoint { | ||
| 142 | remote-endpoint = <&funnel_center_in_tpdm_ipcc>; | ||
| 143 | }; | ||
| 144 | }; | ||
| 145 | }; | ||
| 146 | }; | ||
| 113 | ... | 147 | ... |
| @@ -22,7 +22,6 @@ properties: · 21 unmodified lines | |||
| 22 | maxItems: 1 | 22 | maxItems: 1 |
| 23 | 23 | ||
| 24 | label: | 24 | label: |
| 25 | $ref: /schemas/types.yaml#/definitions/string | ||
| 26 | description: Unique name to identify which channel this is. | 25 | description: Unique name to identify which channel this is. |
| 27 | 26 | ||
| 28 | bipolar: | 27 | bipolar: |
| @@ -44,6 +44,9 @@ properties: · 43 unmodified lines | |||
| 44 | Pin that controls the powerdown mode of the device. | 44 | Pin that controls the powerdown mode of the device. |
| 45 | maxItems: 1 | 45 | maxItems: 1 |
| 46 | 46 | ||
| 47 | io-backends: | ||
| 48 | maxItems: 1 | ||
| 49 | |||
| 47 | reset-gpios: | 50 | reset-gpios: |
| 48 | description: | 51 | description: |
| 49 | Reset pin for the device. | 52 | Reset pin for the device. |
| @@ -68,6 +71,7 @@ examples: · 18 unmodified lines | |||
| 68 | reg = <0>; | 71 | reg = <0>; |
| 69 | clocks = <&adc_clk>; | 72 | clocks = <&adc_clk>; |
| 70 | clock-names = "adc-clk"; | 73 | clock-names = "adc-clk"; |
| 74 | io-backends = <&iio_backend>; | ||
| 71 | }; | 75 | }; |
| 72 | }; | 76 | }; |
| 73 | ... | 77 | ... |
| @@ -39,12 +39,15 @@ properties: · 38 unmodified lines | |||
| 39 | $ref: /schemas/types.yaml#/definitions/phandle | 39 | $ref: /schemas/types.yaml#/definitions/phandle |
| 40 | description: | 40 | description: |
| 41 | A reference to a the actual ADC to which this FPGA ADC interfaces to. | 41 | A reference to a the actual ADC to which this FPGA ADC interfaces to. |
| 42 | deprecated: true | ||
| 43 | |||
| 44 | '#io-backend-cells': | ||
| 45 | const: 0 | ||
| 42 | 46 | ||
| 43 | required: | 47 | required: |
| 44 | - compatible | 48 | - compatible |
| 45 | - dmas | 49 | - dmas |
| 46 | - reg | 50 | - reg |
| 47 | - adi,adc-dev | ||
| 48 | 51 | ||
| 49 | additionalProperties: false | 52 | additionalProperties: false |
| 50 | 53 | ||
| @@ -55,7 +58,6 @@ examples: · 4 unmodified lines | |||
| 55 | reg = <0x44a00000 0x10000>; | 58 | reg = <0x44a00000 0x10000>; |
| 56 | dmas = <&rx_dma 0>; | 59 | dmas = <&rx_dma 0>; |
| 57 | dma-names = "rx"; | 60 | dma-names = "rx"; |
| 58 | 61 | #io-backend-cells = <0>; | |
| 59 | adi,adc-dev = <&spi_adc>; | ||
| 60 | }; | 62 | }; |
| 61 | ... | 63 | ... |
| @@ -0,0 +1,120 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/adc/microchip,pac1934.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Microchip PAC1934 Power Monitors with Accumulator | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Marius Cristea <marius.cristea@microchip.com> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | This device is part of the Microchip family of Power Monitors with | ||
| 14 | Accumulator. | ||
| 15 | The datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here: | ||
| 16 | https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf | ||
| 17 | |||
| 18 | properties: | ||
| 19 | compatible: | ||
| 20 | enum: | ||
| 21 | - microchip,pac1931 | ||
| 22 | - microchip,pac1932 | ||
| 23 | - microchip,pac1933 | ||
| 24 | - microchip,pac1934 | ||
| 25 | |||
| 26 | reg: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | "#address-cells": | ||
| 30 | const: 1 | ||
| 31 | |||
| 32 | "#size-cells": | ||
| 33 | const: 0 | ||
| 34 | |||
| 35 | interrupts: | ||
| 36 | maxItems: 1 | ||
| 37 | |||
| 38 | slow-io-gpios: | ||
| 39 | description: | ||
| 40 | A GPIO used to trigger a change is sampling rate (lowering the chip power | ||
| 41 | consumption). If configured in SLOW mode, if this pin is forced high, | ||
| 42 | sampling rate is forced to eight samples/second. When it is forced low, | ||
| 43 | the sampling rate is 1024 samples/second unless a different sample rate | ||
| 44 | has been programmed. | ||
| 45 | |||
| 46 | patternProperties: | ||
| 47 | "^channel@[1-4]+$": | ||
| 48 | type: object | ||
| 49 | $ref: adc.yaml | ||
| 50 | description: | ||
| 51 | Represents the external channels which are connected to the ADC. | ||
| 52 | |||
| 53 | properties: | ||
| 54 | reg: | ||
| 55 | items: | ||
| 56 | minimum: 1 | ||
| 57 | maximum: 4 | ||
| 58 | |||
| 59 | shunt-resistor-micro-ohms: | ||
| 60 | description: | ||
| 61 | Value in micro Ohms of the shunt resistor connected between | ||
| 62 | the SENSE+ and SENSE- inputs, across which the current is measured. | ||
| 63 | Value is needed to compute the scaling of the measured current. | ||
| 64 | |||
| 65 | required: | ||
| 66 | - reg | ||
| 67 | - shunt-resistor-micro-ohms | ||
| 68 | |||
| 69 | unevaluatedProperties: false | ||
| 70 | |||
| 71 | required: | ||
| 72 | - compatible | ||
| 73 | - reg | ||
| 74 | - "#address-cells" | ||
| 75 | - "#size-cells" | ||
| 76 | |||
| 77 | additionalProperties: false | ||
| 78 | |||
| 79 | examples: | ||
| 80 | - | | ||
| 81 | i2c { | ||
| 82 | #address-cells = <1>; | ||
| 83 | #size-cells = <0>; | ||
| 84 | |||
| 85 | power-monitor@10 { | ||
| 86 | compatible = "microchip,pac1934"; | ||
| 87 | reg = <0x10>; | ||
| 88 | |||
| 89 | #address-cells = <1>; | ||
| 90 | #size-cells = <0>; | ||
| 91 | |||
| 92 | channel@1 { | ||
| 93 | reg = <0x1>; | ||
| 94 | shunt-resistor-micro-ohms = <24900000>; | ||
| 95 | label = "CPU"; | ||
| 96 | }; | ||
| 97 | |||
| 98 | channel@2 { | ||
| 99 | reg = <0x2>; | ||
| 100 | shunt-resistor-micro-ohms = <49900000>; | ||
| 101 | label = "GPU"; | ||
| 102 | }; | ||
| 103 | |||
| 104 | channel@3 { | ||
| 105 | reg = <0x3>; | ||
| 106 | shunt-resistor-micro-ohms = <75000000>; | ||
| 107 | label = "MEM"; | ||
| 108 | bipolar; | ||
| 109 | }; | ||
| 110 | |||
| 111 | channel@4 { | ||
| 112 | reg = <0x4>; | ||
| 113 | shunt-resistor-micro-ohms = <100000000>; | ||
| 114 | label = "NET"; | ||
| 115 | bipolar; | ||
| 116 | }; | ||
| 117 | }; | ||
| 118 | }; | ||
| 119 | |||
| 120 | ... | ||
| @@ -31,7 +31,6 @@ properties: · 30 unmodified lines | |||
| 31 | - description: normal conversion, include EOC (End of Conversion), | 31 | - description: normal conversion, include EOC (End of Conversion), |
| 32 | ECH (End of Chain), JEOC (End of Injected Conversion) and | 32 | ECH (End of Chain), JEOC (End of Injected Conversion) and |
| 33 | JECH (End of injected Chain). | 33 | JECH (End of injected Chain). |
| 34 | - description: Self-testing Interrupts. | ||
| 35 | 34 | ||
| 36 | clocks: | 35 | clocks: |
| 37 | maxItems: 1 | 36 | maxItems: 1 |
| @@ -70,8 +69,7 @@ examples: · 32 unmodified lines | |||
| 70 | reg = <0x44530000 0x10000>; | 69 | reg = <0x44530000 0x10000>; |
| 71 | interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, | 70 | interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, |
| 72 | <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>, | 71 | <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>, |
| 73 | <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>, | 72 | <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; |
| 74 | <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; | ||
| 75 | clocks = <&clk IMX93_CLK_ADC1_GATE>; | 73 | clocks = <&clk IMX93_CLK_ADC1_GATE>; |
| 76 | clock-names = "ipg"; | 74 | clock-names = "ipg"; |
| 77 | vref-supply = <®_vref_1v8>; | 75 | vref-supply = <®_vref_1v8>; |
| @@ -75,7 +75,6 @@ patternProperties: · 74 unmodified lines | |||
| 75 | in the PMIC-specific files in include/dt-bindings/iio/. | 75 | in the PMIC-specific files in include/dt-bindings/iio/. |
| 76 | 76 | ||
| 77 | label: | 77 | label: |
| 78 | $ref: /schemas/types.yaml#/definitions/string | ||
| 79 | description: | | 78 | description: | |
| 80 | ADC input of the platform as seen in the schematics. | 79 | ADC input of the platform as seen in the schematics. |
| 81 | For thermistor inputs connected to generic AMUX or GPIO inputs | 80 | For thermistor inputs connected to generic AMUX or GPIO inputs |
| @@ -25,7 +25,14 @@ description: | · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | properties: | 26 | properties: |
| 27 | compatible: | 27 | compatible: |
| 28 | const: richtek,rtq6056 | 28 | oneOf: |
| 29 | - enum: | ||
| 30 | - richtek,rtq6056 | ||
| 31 | - richtek,rtq6059 | ||
| 32 | - items: | ||
| 33 | - enum: | ||
| 34 | - richtek,rtq6053 | ||
| 35 | - const: richtek,rtq6056 | ||
| 29 | 36 | ||
| 30 | reg: | 37 | reg: |
| 31 | maxItems: 1 | 38 | maxItems: 1 |
| @@ -0,0 +1,80 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/adc/ti,ads1298.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Texas Instruments' ads1298 medical ADC chips | ||
| 8 | |||
| 9 | description: | | ||
| 10 | Datasheet at: https://www.ti.com/product/ADS1298 | ||
| 11 | Bindings for this chip aren't complete. | ||
| 12 | |||
| 13 | maintainers: | ||
| 14 | - Mike Looijmans <mike.looijmans@topic.nl> | ||
| 15 | |||
| 16 | properties: | ||
| 17 | compatible: | ||
| 18 | enum: | ||
| 19 | - ti,ads1298 | ||
| 20 | |||
| 21 | reg: | ||
| 22 | maxItems: 1 | ||
| 23 | |||
| 24 | spi-cpha: true | ||
| 25 | |||
| 26 | reset-gpios: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | avdd-supply: | ||
| 30 | description: | ||
| 31 | Analog power supply, voltage between AVDD and AVSS. When providing a | ||
| 32 | symmetric +/- 2.5V, the regulator should report 5V. | ||
| 33 | |||
| 34 | vref-supply: | ||
| 35 | description: | ||
| 36 | Optional reference voltage. If omitted, internal reference is used, | ||
| 37 | which is 2.4V when analog supply is below 4.4V, 4V otherwise. | ||
| 38 | |||
| 39 | clocks: | ||
| 40 | description: Optional 2.048 MHz external source clock on CLK pin | ||
| 41 | maxItems: 1 | ||
| 42 | |||
| 43 | interrupts: | ||
| 44 | description: Interrupt on DRDY pin, triggers on falling edge | ||
| 45 | maxItems: 1 | ||
| 46 | |||
| 47 | label: true | ||
| 48 | |||
| 49 | required: | ||
| 50 | - compatible | ||
| 51 | - reg | ||
| 52 | - avdd-supply | ||
| 53 | - interrupts | ||
| 54 | |||
| 55 | allOf: | ||
| 56 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
| 57 | |||
| 58 | unevaluatedProperties: false | ||
| 59 | |||
| 60 | examples: | ||
| 61 | - | | ||
| 62 | #include <dt-bindings/gpio/gpio.h> | ||
| 63 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 64 | spi { | ||
| 65 | #address-cells = <1>; | ||
| 66 | #size-cells = <0>; | ||
| 67 | |||
| 68 | adc@1 { | ||
| 69 | reg = <1>; | ||
| 70 | compatible = "ti,ads1298"; | ||
| 71 | label = "ads1298-1-ecg"; | ||
| 72 | avdd-supply = <®_iso_5v_a>; | ||
| 73 | clocks = <&clk_ads1298>; | ||
| 74 | interrupt-parent = <&gpio0>; | ||
| 75 | interrupts = <78 IRQ_TYPE_EDGE_FALLING>; | ||
| 76 | spi-max-frequency = <20000000>; | ||
| 77 | spi-cpha; | ||
| 78 | }; | ||
| 79 | }; | ||
| 80 | ... | ||
| @@ -39,6 +39,17 @@ properties: · 38 unmodified lines | |||
| 39 | description: | | 39 | description: | |
| 40 | Channel node of a voltage io-channel. | 40 | Channel node of a voltage io-channel. |
| 41 | 41 | ||
| 42 | '#io-channel-cells': | ||
| 43 | description: | ||
| 44 | In addition to consuming the measurement services of a voltage | ||
| 45 | output channel, the voltage divider can act as a provider of | ||
| 46 | measurement services to other devices. This is particularly | ||
| 47 | useful in scenarios wherein an ADC has an analog frontend, | ||
| 48 | such as a voltage divider, and then consuming its raw value | ||
| 49 | isn't interesting. In this case, the voltage before the divider | ||
| 50 | is desired. | ||
| 51 | const: 1 | ||
| 52 | |||
| 42 | output-ohms: | 53 | output-ohms: |
| 43 | description: | 54 | description: |
| 44 | Resistance Rout over which the output voltage is measured. See full-ohms. | 55 | Resistance Rout over which the output voltage is measured. See full-ohms. |
| @@ -21,6 +21,8 @@ description: | · 20 unmodified lines | |||
| 21 | HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz | 21 | HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz |
| 22 | https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf | 22 | https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf |
| 23 | 23 | ||
| 24 | LTC6373 is a 3-Bit precision instrumentation amplifier with fully differential outputs | ||
| 25 | https://www.analog.com/media/en/technical-documentation/data-sheets/ltc6373.pdf | ||
| 24 | 26 | ||
| 25 | properties: | 27 | properties: |
| 26 | compatible: | 28 | compatible: |
| @@ -28,16 +30,55 @@ properties: · 1 unmodified line | |||
| 28 | - adi,adrf5740 | 30 | - adi,adrf5740 |
| 29 | - adi,hmc425a | 31 | - adi,hmc425a |
| 30 | - adi,hmc540s | 32 | - adi,hmc540s |
| 33 | - adi,ltc6373 | ||
| 31 | 34 | ||
| 32 | vcc-supply: true | 35 | vcc-supply: true |
| 33 | 36 | ||
| 34 | ctrl-gpios: | 37 | ctrl-gpios: |
| 35 | description: | 38 | description: |
| 36 | Must contain an array of 6 GPIO specifiers, referring to the GPIO pins | 39 | Must contain an array of GPIO specifiers, referring to the GPIO pins |
| 37 | connected to the control pins V1-V6. | 40 | connected to the control pins. |
| 38 | minItems: 6 | 41 | ADRF5740 - 4 GPIO connected to D2-D5 |
| 42 | HMC540S - 4 GPIO connected to V1-V4 | ||
| 43 | HMC425A - 6 GPIO connected to V1-V6 | ||
| 44 | LTC6373 - 3 GPIO connected to A0-A2 | ||
| 45 | minItems: 1 | ||
| 39 | maxItems: 6 | 46 | maxItems: 6 |
| 40 | 47 | ||
| 48 | allOf: | ||
| 49 | - if: | ||
| 50 | properties: | ||
| 51 | compatible: | ||
| 52 | contains: | ||
| 53 | const: adi,hmc425a | ||
| 54 | then: | ||
| 55 | properties: | ||
| 56 | ctrl-gpios: | ||
| 57 | minItems: 6 | ||
| 58 | maxItems: 6 | ||
| 59 | - if: | ||
| 60 | properties: | ||
| 61 | compatible: | ||
| 62 | contains: | ||
| 63 | anyOf: | ||
| 64 | - const: adi,adrf5740 | ||
| 65 | - const: adi,hmc540s | ||
| 66 | then: | ||
| 67 | properties: | ||
| 68 | ctrl-gpios: | ||
| 69 | minItems: 4 | ||
| 70 | maxItems: 4 | ||
| 71 | - if: | ||
| 72 | properties: | ||
| 73 | compatible: | ||
| 74 | contains: | ||
| 75 | const: adi,ltc6373 | ||
| 76 | then: | ||
| 77 | properties: | ||
| 78 | ctrl-gpios: | ||
| 79 | minItems: 3 | ||
| 80 | maxItems: 3 | ||
| 81 | |||
| 41 | required: | 82 | required: |
| 42 | - compatible | 83 | - compatible |
| 43 | - ctrl-gpios | 84 | - ctrl-gpios |
| @@ -0,0 +1,127 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | # Copyright 2024 Analog Devices Inc. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/iio/frequency/adi,admfm2000.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: ADMFM2000 Dual Microwave Down Converter | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Kim Seer Paller <kimseer.paller@analog.com> | ||
| 12 | |||
| 13 | description: | ||
| 14 | Dual microwave down converter module with input RF and LO frequency ranges | ||
| 15 | from 0.5 to 32 GHz and an output IF frequency range from 0.1 to 8 GHz. | ||
| 16 | It consists of a LNA, mixer, IF filter, DSA, and IF amplifier for each down | ||
| 17 | conversion path. | ||
| 18 | |||
| 19 | properties: | ||
| 20 | compatible: | ||
| 21 | enum: | ||
| 22 | - adi,admfm2000 | ||
| 23 | |||
| 24 | '#address-cells': | ||
| 25 | const: 1 | ||
| 26 | |||
| 27 | '#size-cells': | ||
| 28 | const: 0 | ||
| 29 | |||
| 30 | patternProperties: | ||
| 31 | "^channel@[0-1]$": | ||
| 32 | type: object | ||
| 33 | description: Represents a channel of the device. | ||
| 34 | |||
| 35 | additionalProperties: false | ||
| 36 | |||
| 37 | properties: | ||
| 38 | reg: | ||
| 39 | description: | ||
| 40 | The channel number. | ||
| 41 | minimum: 0 | ||
| 42 | maximum: 1 | ||
| 43 | |||
| 44 | adi,mixer-mode: | ||
| 45 | description: | ||
| 46 | Enable mixer mode for the channel. It downconverts RF between 5 GHz | ||
| 47 | and 32 GHz to IF between 0.5 GHz and 8 GHz. If not present, the channel | ||
| 48 | is in direct IF mode which bypasses the mixer and downconverts RF | ||
| 49 | between 2 GHz and 8 GHz to IF between 0.5 GHz and 8 GHz. | ||
| 50 | type: boolean | ||
| 51 | |||
| 52 | switch-gpios: | ||
| 53 | description: | | ||
| 54 | GPIOs to select the RF path for the channel. The same state of CTRL-A | ||
| 55 | and CTRL-B GPIOs is not permitted. | ||
| 56 | CTRL-A CTRL-B CH1 Status CH2 Status | ||
| 57 | 1 0 Direct IF mode Mixer mode | ||
| 58 | 0 1 Mixer mode Direct IF mode | ||
| 59 | |||
| 60 | items: | ||
| 61 | - description: CTRL-A GPIO | ||
| 62 | - description: CTRL-B GPIO | ||
| 63 | |||
| 64 | attenuation-gpios: | ||
| 65 | description: | | ||
| 66 | Choice of attenuation: | ||
| 67 | DSA-V4 DSA-V3 DSA-V2 DSA-V1 DSA-V0 | ||
| 68 | 1 1 1 1 1 0 dB | ||
| 69 | 1 1 1 1 0 -1 dB | ||
| 70 | 1 1 1 0 1 -2 dB | ||
| 71 | 1 1 0 1 1 -4 dB | ||
| 72 | 1 0 1 1 1 -8 dB | ||
| 73 | 0 1 1 1 1 -16 dB | ||
| 74 | 0 0 0 0 0 -31 dB | ||
| 75 | |||
| 76 | items: | ||
| 77 | - description: DSA-V0 GPIO | ||
| 78 | - description: DSA-V1 GPIO | ||
| 79 | - description: DSA-V2 GPIO | ||
| 80 | - description: DSA-V3 GPIO | ||
| 81 | - description: DSA-V4 GPIO | ||
| 82 | |||
| 83 | required: | ||
| 84 | - reg | ||
| 85 | - switch-gpios | ||
| 86 | - attenuation-gpios | ||
| 87 | |||
| 88 | required: | ||
| 89 | - compatible | ||
| 90 | |||
| 91 | additionalProperties: false | ||
| 92 | |||
| 93 | examples: | ||
| 94 | - | | ||
| 95 | #include <dt-bindings/gpio/gpio.h> | ||
| 96 | converter { | ||
| 97 | compatible = "adi,admfm2000"; | ||
| 98 | |||
| 99 | #address-cells = <1>; | ||
| 100 | #size-cells = <0>; | ||
| 101 | |||
| 102 | channel@0 { | ||
| 103 | reg = <0>; | ||
| 104 | switch-gpios = <&gpio 1 GPIO_ACTIVE_LOW>, | ||
| 105 | <&gpio 2 GPIO_ACTIVE_HIGH>; | ||
| 106 | |||
| 107 | attenuation-gpios = <&gpio 17 GPIO_ACTIVE_LOW>, | ||
| 108 | <&gpio 22 GPIO_ACTIVE_LOW>, | ||
| 109 | <&gpio 23 GPIO_ACTIVE_LOW>, | ||
| 110 | <&gpio 24 GPIO_ACTIVE_LOW>, | ||
| 111 | <&gpio 25 GPIO_ACTIVE_LOW>; | ||
| 112 | }; | ||
| 113 | |||
| 114 | channel@1 { | ||
| 115 | reg = <1>; | ||
| 116 | adi,mixer-mode; | ||
| 117 | switch-gpios = <&gpio 3 GPIO_ACTIVE_LOW>, | ||
| 118 | <&gpio 4 GPIO_ACTIVE_HIGH>; | ||
| 119 | |||
| 120 | attenuation-gpios = <&gpio 0 GPIO_ACTIVE_LOW>, | ||
| 121 | <&gpio 5 GPIO_ACTIVE_LOW>, | ||
| 122 | <&gpio 6 GPIO_ACTIVE_LOW>, | ||
| 123 | <&gpio 16 GPIO_ACTIVE_LOW>, | ||
| 124 | <&gpio 26 GPIO_ACTIVE_LOW>; | ||
| 125 | }; | ||
| 126 | }; | ||
| 127 | ... | ||
| @@ -22,6 +22,9 @@ properties: · 21 unmodified lines | |||
| 22 | vdd-supply: true | 22 | vdd-supply: true |
| 23 | vddio-supply: true | 23 | vddio-supply: true |
| 24 | 24 | ||
| 25 | spi-max-frequency: | ||
| 26 | maximum: 10000000 | ||
| 27 | |||
| 25 | interrupts: | 28 | interrupts: |
| 26 | minItems: 1 | 29 | minItems: 1 |
| 27 | maxItems: 2 | 30 | maxItems: 2 |
| @@ -33,7 +36,10 @@ required: · 5 unmodified lines | |||
| 33 | - compatible | 36 | - compatible |
| 34 | - reg | 37 | - reg |
| 35 | 38 | ||
| 36 | additionalProperties: false | 39 | allOf: |
| 40 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
| 41 | |||
| 42 | unevaluatedProperties: false | ||
| 37 | 43 | ||
| 38 | examples: | 44 | examples: |
| 39 | - | | 45 | - | |
| @@ -27,6 +27,9 @@ properties: · 26 unmodified lines | |||
| 27 | reg: | 27 | reg: |
| 28 | maxItems: 1 | 28 | maxItems: 1 |
| 29 | 29 | ||
| 30 | interrupts: | ||
| 31 | maxItems: 1 | ||
| 32 | |||
| 30 | required: | 33 | required: |
| 31 | - compatible | 34 | - compatible |
| 32 | - reg | 35 | - reg |
| @@ -43,6 +43,7 @@ additionalProperties: false · 42 unmodified lines | |||
| 43 | 43 | ||
| 44 | examples: | 44 | examples: |
| 45 | - | | 45 | - | |
| 46 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 46 | i2c { | 47 | i2c { |
| 47 | #address-cells = <1>; | 48 | #address-cells = <1>; |
| 48 | #size-cells = <0>; | 49 | #size-cells = <0>; |
| @@ -51,5 +52,7 @@ examples: · 2 unmodified lines | |||
| 51 | compatible = "ti,hdc3021", "ti,hdc3020"; | 52 | compatible = "ti,hdc3021", "ti,hdc3020"; |
| 52 | reg = <0x47>; | 53 | reg = <0x47>; |
| 53 | vdd-supply = <&vcc_3v3>; | 54 | vdd-supply = <&vcc_3v3>; |
| 55 | interrupt-parent = <&gpio3>; | ||
| 56 | interrupts = <23 IRQ_TYPE_EDGE_RISING>; | ||
| 54 | }; | 57 | }; |
| 55 | }; | 58 | }; |
| @@ -35,7 +35,9 @@ properties: · 34 unmodified lines | |||
| 35 | - st,lsm6dsv | 35 | - st,lsm6dsv |
| 36 | - st,lsm6dso16is | 36 | - st,lsm6dso16is |
| 37 | - items: | 37 | - items: |
| 38 | - const: st,asm330lhhx | 38 | - enum: |
| 39 | - st,asm330lhhx | ||
| 40 | - st,asm330lhhxg1 | ||
| 39 | - const: st,lsm6dsr | 41 | - const: st,lsm6dsr |
| 40 | - items: | 42 | - items: |
| 41 | - const: st,lsm6dstx | 43 | - const: st,lsm6dstx |
| @@ -4,19 +4,22 @@ · 3 unmodified lines | |||
| 4 | $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml# | 4 | $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml# |
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | ||
| 7 | title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor | 7 | title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 UV Sensor |
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Christian Eggers <ceggers@arri.de> | 10 | - Christian Eggers <ceggers@arri.de> |
| 11 | 11 | ||
| 12 | description: | | 12 | description: | |
| 13 | XYZ True Color Sensor with I2C Interface | 13 | AMS AS73211 XYZ True Color Sensor with I2C Interface |
| 14 | https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df | 14 | https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df |
| 15 | AMS AS7331 UVA, UVB and UVC Sensor with I2C Interface | ||
| 16 | https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf | ||
| 15 | 17 | ||
| 16 | properties: | 18 | properties: |
| 17 | compatible: | 19 | compatible: |
| 18 | enum: | 20 | enum: |
| 19 | - ams,as73211 | 21 | - ams,as73211 |
| 22 | - ams,as7331 | ||
| 20 | 23 | ||
| 21 | reg: | 24 | reg: |
| 22 | description: | 25 | description: |
| @@ -21,6 +21,7 @@ properties: · 20 unmodified lines | |||
| 21 | required: | 21 | required: |
| 22 | - compatible | 22 | - compatible |
| 23 | - reg | 23 | - reg |
| 24 | - vdd-supply | ||
| 24 | 25 | ||
| 25 | additionalProperties: false | 26 | additionalProperties: false |
| 26 | 27 | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/magnetometer/voltafield,af8133j.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Voltafield AF8133J magnetometer sensor | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Ondřej Jirman <megi@xff.cz> | ||
| 11 | |||
| 12 | properties: | ||
| 13 | compatible: | ||
| 14 | const: voltafield,af8133j | ||
| 15 | |||
| 16 | reg: | ||
| 17 | maxItems: 1 | ||
| 18 | |||
| 19 | reset-gpios: | ||
| 20 | description: | ||
| 21 | A signal for active low reset input of the sensor. (optional; if not | ||
| 22 | used, software reset over I2C will be used instead) | ||
| 23 | |||
| 24 | avdd-supply: | ||
| 25 | description: | ||
| 26 | A regulator that provides AVDD power (Working power, usually 3.3V) to | ||
| 27 | the sensor. | ||
| 28 | |||
| 29 | dvdd-supply: | ||
| 30 | description: | ||
| 31 | A regulator that provides DVDD power (Digital IO power, 1.8V - AVDD) | ||
| 32 | to the sensor. | ||
| 33 | |||
| 34 | mount-matrix: | ||
| 35 | description: An optional 3x3 mounting rotation matrix. | ||
| 36 | |||
| 37 | required: | ||
| 38 | - compatible | ||
| 39 | - reg | ||
| 40 | - avdd-supply | ||
| 41 | - dvdd-supply | ||
| 42 | |||
| 43 | additionalProperties: false | ||
| 44 | |||
| 45 | examples: | ||
| 46 | - | | ||
| 47 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 48 | #include <dt-bindings/gpio/gpio.h> | ||
| 49 | i2c { | ||
| 50 | #address-cells = <1>; | ||
| 51 | #size-cells = <0>; | ||
| 52 | |||
| 53 | magnetometer@1c { | ||
| 54 | compatible = "voltafield,af8133j"; | ||
| 55 | reg = <0x1c>; | ||
| 56 | avdd-supply = <®_dldo1>; | ||
| 57 | dvdd-supply = <®_dldo1>; | ||
| 58 | reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>; | ||
| 59 | }; | ||
| 60 | }; | ||
| @@ -99,6 +99,9 @@ required: · 98 unmodified lines | |||
| 99 | - honeywell,transfer-function | 99 | - honeywell,transfer-function |
| 100 | - honeywell,pressure-triplet | 100 | - honeywell,pressure-triplet |
| 101 | 101 | ||
| 102 | allOf: | ||
| 103 | - $ref: /schemas/spi/spi-peripheral-props.yaml | ||
| 104 | |||
| 102 | additionalProperties: false | 105 | additionalProperties: false |
| 103 | 106 | ||
| 104 | dependentSchemas: | 107 | dependentSchemas: |
| @@ -8,25 +8,28 @@ title: Honeywell mprls0025pa pressure sensor · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Andreas Klinger <ak@it-klinger.de> | 10 | - Andreas Klinger <ak@it-klinger.de> |
| 11 | - Petre Rodan <petre.rodan@subdimension.ro> | ||
| 11 | 12 | ||
| 12 | description: | | 13 | description: | |
| 13 | Honeywell pressure sensor of model mprls0025pa. | 14 | Honeywell pressure sensor of model mprls0025pa. |
| 14 | 15 | ||
| 15 | This sensor has an I2C and SPI interface. Only the I2C interface is | 16 | This sensor has an I2C and SPI interface. |
| 16 | implemented. | ||
| 17 | 17 | ||
| 18 | There are many models with different pressure ranges available. The vendor | 18 | There are many models with different pressure ranges available. The vendor |
| 19 | calls them "mpr series". All of them have the identical programming model and | 19 | calls them "mpr series". All of them have the identical programming model and |
| 20 | differ in the pressure range, unit and transfer function. | 20 | differ in the pressure range, unit and transfer function. |
| 21 | 21 | ||
| 22 | To support different models one need to specify the pressure range as well as | 22 | To support different models one need to specify its pressure triplet as well |
| 23 | the transfer function. Pressure range needs to be converted from its unit to | 23 | as the transfer function. |
| 24 | pascal. | 24 | |
| 25 | For custom silicon chips not covered by the Honeywell MPR series datasheet, | ||
| 26 | the pressure values can be specified manually via honeywell,pmin-pascal and | ||
| 27 | honeywell,pmax-pascal. | ||
| 28 | The minimal range value stands for the minimum pressure and the maximum value | ||
| 29 | also for the maximum pressure with linear relation inside the range. | ||
| 25 | 30 | ||
| 26 | The transfer function defines the ranges of numerical values delivered by the | 31 | The transfer function defines the ranges of numerical values delivered by the |
| 27 | sensor. The minimal range value stands for the minimum pressure and the | 32 | sensor. |
| 28 | maximum value also for the maximum pressure with linear relation inside the | ||
| 29 | range. | ||
| 30 | 33 | ||
| 31 | Specifications about the devices can be found at: | 34 | Specifications about the devices can be found at: |
| 32 | https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ | 35 | https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ |
| @@ -42,6 +45,10 @@ properties: · 9 unmodified lines | |||
| 42 | maxItems: 1 | 45 | maxItems: 1 |
| 43 | 46 | ||
| 44 | interrupts: | 47 | interrupts: |
| 48 | description: | ||
| 49 | Optional interrupt for indicating End-of-conversion. | ||
| 50 | If not present, the driver loops for a while until the received status | ||
| 51 | byte indicates correct measurement. | ||
| 45 | maxItems: 1 | 52 | maxItems: 1 |
| 46 | 53 | ||
| 47 | reset-gpios: | 54 | reset-gpios: |
| @@ -50,14 +57,6 @@ properties: · 2 unmodified lines | |||
| 50 | If not present the device is not reset during the probe. | 57 | If not present the device is not reset during the probe. |
| 51 | maxItems: 1 | 58 | maxItems: 1 |
| 52 | 59 | ||
| 53 | honeywell,pmin-pascal: | ||
| 54 | description: | ||
| 55 | Minimum pressure value the sensor can measure in pascal. | ||
| 56 | |||
| 57 | honeywell,pmax-pascal: | ||
| 58 | description: | ||
| 59 | Maximum pressure value the sensor can measure in pascal. | ||
| 60 | |||
| 61 | honeywell,transfer-function: | 60 | honeywell,transfer-function: |
| 62 | description: | | 61 | description: | |
| 63 | Transfer function which defines the range of valid values delivered by the | 62 | Transfer function which defines the range of valid values delivered by the |
| @@ -65,19 +64,57 @@ properties: · 1 unmodified line | |||
| 65 | 1 - A, 10% to 90% of 2^24 (1677722 .. 15099494) | 64 | 1 - A, 10% to 90% of 2^24 (1677722 .. 15099494) |
| 66 | 2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874) | 65 | 2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874) |
| 67 | 3 - C, 20% to 80% of 2^24 (3355443 .. 13421773) | 66 | 3 - C, 20% to 80% of 2^24 (3355443 .. 13421773) |
| 67 | enum: [1, 2, 3] | ||
| 68 | $ref: /schemas/types.yaml#/definitions/uint32 | 68 | $ref: /schemas/types.yaml#/definitions/uint32 |
| 69 | 69 | ||
| 70 | honeywell,pressure-triplet: | ||
| 71 | description: | | ||
| 72 | Case-sensitive five character string that defines pressure range, unit | ||
| 73 | and type as part of the device nomenclature. In the unlikely case of a | ||
| 74 | custom chip, unset and provide pmin-pascal and pmax-pascal instead. | ||
| 75 | enum: [0001BA, 01.6BA, 02.5BA, 0060MG, 0100MG, 0160MG, 0250MG, 0400MG, | ||
| 76 | 0600MG, 0001BG, 01.6BG, 02.5BG, 0100KA, 0160KA, 0250KA, 0006KG, | ||
| 77 | 0010KG, 0016KG, 0025KG, 0040KG, 0060KG, 0100KG, 0160KG, 0250KG, | ||
| 78 | 0015PA, 0025PA, 0030PA, 0001PG, 0005PG, 0015PG, 0030PG, 0300YG] | ||
| 79 | $ref: /schemas/types.yaml#/definitions/string | ||
| 80 | |||
| 81 | honeywell,pmin-pascal: | ||
| 82 | description: | ||
| 83 | Minimum pressure value the sensor can measure in pascal. | ||
| 84 | |||
| 85 | honeywell,pmax-pascal: | ||
| 86 | description: | ||
| 87 | Maximum pressure value the sensor can measure in pascal. | ||
| 88 | |||
| 89 | spi-max-frequency: | ||
| 90 | maximum: 800000 | ||
| 91 | |||
| 70 | vdd-supply: | 92 | vdd-supply: |
| 71 | description: provide VDD power to the sensor. | 93 | description: provide VDD power to the sensor. |
| 72 | 94 | ||
| 73 | required: | 95 | required: |
| 74 | - compatible | 96 | - compatible |
| 75 | - reg | 97 | - reg |
| 76 | - honeywell,pmin-pascal | ||
| 77 | - honeywell,pmax-pascal | ||
| 78 | - honeywell,transfer-function | 98 | - honeywell,transfer-function |
| 79 | - vdd-supply | 99 | - vdd-supply |
| 80 | 100 | ||
| 101 | oneOf: | ||
| 102 | - required: | ||
| 103 | - honeywell,pressure-triplet | ||
| 104 | - required: | ||
| 105 | - honeywell,pmin-pascal | ||
| 106 | - honeywell,pmax-pascal | ||
| 107 | |||
| 108 | allOf: | ||
| 109 | - $ref: /schemas/spi/spi-peripheral-props.yaml | ||
| 110 | - if: | ||
| 111 | required: | ||
| 112 | - honeywell,pressure-triplet | ||
| 113 | then: | ||
| 114 | properties: | ||
| 115 | honeywell,pmin-pascal: false | ||
| 116 | honeywell,pmax-pascal: false | ||
| 117 | |||
| 81 | additionalProperties: false | 118 | additionalProperties: false |
| 82 | 119 | ||
| 83 | examples: | 120 | examples: |
| @@ -93,10 +130,29 @@ examples: · 9 unmodified lines | |||
| 93 | reg = <0x18>; | 130 | reg = <0x18>; |
| 94 | reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; | 131 | reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; |
| 95 | interrupt-parent = <&gpio3>; | 132 | interrupt-parent = <&gpio3>; |
| 96 | interrupts = <21 IRQ_TYPE_EDGE_FALLING>; | 133 | interrupts = <21 IRQ_TYPE_EDGE_RISING>; |
| 97 | honeywell,pmin-pascal = <0>; | 134 | |
| 98 | honeywell,pmax-pascal = <172369>; | 135 | honeywell,pressure-triplet = "0025PA"; |
| 136 | honeywell,transfer-function = <1>; | ||
| 137 | vdd-supply = <&vcc_3v3>; | ||
| 138 | }; | ||
| 139 | }; | ||
| 140 | - | | ||
| 141 | spi { | ||
| 142 | #address-cells = <1>; | ||
| 143 | #size-cells = <0>; | ||
| 144 | |||
| 145 | pressure@0 { | ||
| 146 | compatible = "honeywell,mprls0025pa"; | ||
| 147 | reg = <0>; | ||
| 148 | spi-max-frequency = <800000>; | ||
| 149 | reset-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; | ||
| 150 | interrupt-parent = <&gpio0>; | ||
| 151 | interrupts = <30 IRQ_TYPE_EDGE_RISING>; | ||
| 152 | |||
| 153 | honeywell,pressure-triplet = "0015PA"; | ||
| 99 | honeywell,transfer-function = <1>; | 154 | honeywell,transfer-function = <1>; |
| 100 | vdd-supply = <&vcc_3v3>; | 155 | vdd-supply = <&vcc_3v3>; |
| 101 | }; | 156 | }; |
| 102 | }; | 157 | }; |
| 158 | ... | ||
| @@ -24,9 +24,16 @@ properties: · 23 unmodified lines | |||
| 24 | reg: | 24 | reg: |
| 25 | maxItems: 1 | 25 | maxItems: 1 |
| 26 | 26 | ||
| 27 | vcc-supply: | ||
| 28 | description: provide VCC power to the sensor. | ||
| 29 | |||
| 30 | label: | ||
| 31 | description: Unique name to identify which device this is. | ||
| 32 | |||
| 27 | required: | 33 | required: |
| 28 | - compatible | 34 | - compatible |
| 29 | - reg | 35 | - reg |
| 36 | - vcc-supply | ||
| 30 | 37 | ||
| 31 | additionalProperties: false | 38 | additionalProperties: false |
| 32 | 39 | ||
| @@ -39,5 +46,6 @@ examples: · 6 unmodified lines | |||
| 39 | tmp117@48 { | 46 | tmp117@48 { |
| 40 | compatible = "ti,tmp117"; | 47 | compatible = "ti,tmp117"; |
| 41 | reg = <0x48>; | 48 | reg = <0x48>; |
| 49 | vcc-supply = <&pmic_reg_3v3>; | ||
| 42 | }; | 50 | }; |
| 43 | }; | 51 | }; |
| @@ -23,6 +23,9 @@ properties: · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | compatible: | 24 | compatible: |
| 25 | enum: | 25 | enum: |
| 26 | - qcom,msm8909-bimc | ||
| 27 | - qcom,msm8909-pcnoc | ||
| 28 | - qcom,msm8909-snoc | ||
| 26 | - qcom,msm8916-bimc | 29 | - qcom,msm8916-bimc |
| 27 | - qcom,msm8916-pcnoc | 30 | - qcom,msm8916-pcnoc |
| 28 | - qcom,msm8916-snoc | 31 | - qcom,msm8916-snoc |
| @@ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Georgi Djakov <georgi.djakov@linaro.org> | 10 | - Georgi Djakov <georgi.djakov@linaro.org> |
| 11 | - Odelu Kukatla <okukatla@codeaurora.org> | 11 | - Odelu Kukatla <quic_okukatla@quicinc.com> |
| 12 | 12 | ||
| 13 | description: | | 13 | description: | |
| 14 | RPMh interconnect providers support system bandwidth requirements through | 14 | RPMh interconnect providers support system bandwidth requirements through |
| @@ -0,0 +1,84 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/interconnect/qcom,sm7150-rpmh.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm RPMh Network-On-Chip Interconnect on SM7150 | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Danila Tikhonov <danila@jiaxyga.com> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | RPMh interconnect providers support system bandwidth requirements through | ||
| 14 | RPMh hardware accelerators known as Bus Clock Manager (BCM). | ||
| 15 | |||
| 16 | See also:: include/dt-bindings/interconnect/qcom,sm7150-rpmh.h | ||
| 17 | |||
| 18 | allOf: | ||
| 19 | - $ref: qcom,rpmh-common.yaml# | ||
| 20 | |||
| 21 | properties: | ||
| 22 | compatible: | ||
| 23 | enum: | ||
| 24 | - qcom,sm7150-aggre1-noc | ||
| 25 | - qcom,sm7150-aggre2-noc | ||
| 26 | - qcom,sm7150-compute-noc | ||
| 27 | - qcom,sm7150-config-noc | ||
| 28 | - qcom,sm7150-dc-noc | ||
| 29 | - qcom,sm7150-gem-noc | ||
| 30 | - qcom,sm7150-mc-virt | ||
| 31 | - qcom,sm7150-mmss-noc | ||
| 32 | - qcom,sm7150-system-noc | ||
| 33 | |||
| 34 | reg: | ||
| 35 | maxItems: 1 | ||
| 36 | |||
| 37 | # Child node's properties | ||
| 38 | patternProperties: | ||
| 39 | '^interconnect-[0-9]+$': | ||
| 40 | type: object | ||
| 41 | description: | ||
| 42 | The interconnect providers do not have a separate QoS register space, | ||
| 43 | but share parent's space. | ||
| 44 | |||
| 45 | allOf: | ||
| 46 | - $ref: qcom,rpmh-common.yaml# | ||
| 47 | |||
| 48 | properties: | ||
| 49 | compatible: | ||
| 50 | enum: | ||
| 51 | - qcom,sm7150-camnoc-virt | ||
| 52 | |||
| 53 | required: | ||
| 54 | - compatible | ||
| 55 | |||
| 56 | unevaluatedProperties: false | ||
| 57 | |||
| 58 | required: | ||
| 59 | - compatible | ||
| 60 | - reg | ||
| 61 | |||
| 62 | unevaluatedProperties: false | ||
| 63 | |||
| 64 | examples: | ||
| 65 | - | | ||
| 66 | mc_virt: interconnect@1380000 { | ||
| 67 | compatible = "qcom,sm7150-mc-virt"; | ||
| 68 | reg = <0x01380000 0x40000>; | ||
| 69 | #interconnect-cells = <2>; | ||
| 70 | qcom,bcm-voters = <&apps_bcm_voter>; | ||
| 71 | }; | ||
| 72 | |||
| 73 | system_noc: interconnect@1620000 { | ||
| 74 | compatible = "qcom,sm7150-system-noc"; | ||
| 75 | reg = <0x01620000 0x40000>; | ||
| 76 | #interconnect-cells = <2>; | ||
| 77 | qcom,bcm-voters = <&apps_bcm_voter>; | ||
| 78 | |||
| 79 | camnoc_virt: interconnect-0 { | ||
| 80 | compatible = "qcom,sm7150-camnoc-virt"; | ||
| 81 | #interconnect-cells = <2>; | ||
| 82 | qcom,bcm-voters = <&apps_bcm_voter>; | ||
| 83 | }; | ||
| 84 | }; | ||
| @@ -36,20 +36,18 @@ properties: · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | allOf: | 37 | allOf: |
| 38 | - if: | 38 | - if: |
| 39 | properties: | ||
| 40 | compatible: | ||
| 41 | contains: | ||
| 42 | const: mac-base | ||
| 39 | required: [ compatible ] | 43 | required: [ compatible ] |
| 40 | then: | 44 | then: |
| 41 | if: | 45 | properties: |
| 42 | properties: | 46 | "#nvmem-cell-cells": |
| 43 | compatible: | 47 | description: The first argument is a MAC address offset. |
| 44 | contains: | 48 | const: 1 |
| 45 | const: mac-base | 49 | required: |
| 46 | then: | 50 | - "#nvmem-cell-cells" |
| 47 | properties: | ||
| 48 | "#nvmem-cell-cells": | ||
| 49 | description: The first argument is a MAC address offset. | ||
| 50 | const: 1 | ||
| 51 | required: | ||
| 52 | - "#nvmem-cell-cells" | ||
| 53 | 51 | ||
| 54 | required: | 52 | required: |
| 55 | - reg | 53 | - reg |
| @@ -0,0 +1,18 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/nvmem/nvmem-provider.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/base.yaml# | ||
| 6 | |||
| 7 | title: NVMEM (Non Volatile Memory) Provider | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | ||
| 11 | |||
| 12 | select: true | ||
| 13 | |||
| 14 | properties: | ||
| 15 | '#nvmem-cell-cells': | ||
| 16 | enum: [0, 1] | ||
| 17 | |||
| 18 | additionalProperties: true | ||
| @@ -1,46 +0,0 @@ | |||
| 1 | -------------------------------------------------------------------------- | ||
| 2 | = Zynq UltraScale+ MPSoC nvmem firmware driver binding = | ||
| 3 | -------------------------------------------------------------------------- | ||
| 4 | The nvmem_firmware node provides access to the hardware related data | ||
| 5 | like soc revision, IDCODE... etc, By using the firmware interface. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | - compatible: should be "xlnx,zynqmp-nvmem-fw" | ||
| 9 | |||
| 10 | = Data cells = | ||
| 11 | Are child nodes of silicon id, bindings of which as described in | ||
| 12 | bindings/nvmem/nvmem.txt | ||
| 13 | |||
| 14 | ------- | ||
| 15 | Example | ||
| 16 | ------- | ||
| 17 | firmware { | ||
| 18 | zynqmp_firmware: zynqmp-firmware { | ||
| 19 | compatible = "xlnx,zynqmp-firmware"; | ||
| 20 | method = "smc"; | ||
| 21 | |||
| 22 | nvmem_firmware { | ||
| 23 | compatible = "xlnx,zynqmp-nvmem-fw"; | ||
| 24 | #address-cells = <1>; | ||
| 25 | #size-cells = <1>; | ||
| 26 | |||
| 27 | /* Data cells */ | ||
| 28 | soc_revision: soc_revision { | ||
| 29 | reg = <0x0 0x4>; | ||
| 30 | }; | ||
| 31 | }; | ||
| 32 | }; | ||
| 33 | }; | ||
| 34 | |||
| 35 | = Data consumers = | ||
| 36 | Are device nodes which consume nvmem data cells. | ||
| 37 | |||
| 38 | For example: | ||
| 39 | pcap { | ||
| 40 | ... | ||
| 41 | |||
| 42 | nvmem-cells = <&soc_revision>; | ||
| 43 | nvmem-cell-names = "soc_revision"; | ||
| 44 | |||
| 45 | ... | ||
| 46 | }; | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/nvmem/xlnx,zynqmp-nvmem.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Zynq UltraScale+ MPSoC Non Volatile Memory interface | ||
| 8 | |||
| 9 | description: | | ||
| 10 | The ZynqMP MPSoC provides access to the hardware related data | ||
| 11 | like SOC revision, IDCODE and specific purpose efuses. | ||
| 12 | |||
| 13 | maintainers: | ||
| 14 | - Kalyani Akula <kalyani.akula@amd.com> | ||
| 15 | - Praveen Teja Kundanala <praveen.teja.kundanala@amd.com> | ||
| 16 | |||
| 17 | allOf: | ||
| 18 | - $ref: nvmem.yaml# | ||
| 19 | |||
| 20 | properties: | ||
| 21 | compatible: | ||
| 22 | const: xlnx,zynqmp-nvmem-fw | ||
| 23 | |||
| 24 | required: | ||
| 25 | - compatible | ||
| 26 | |||
| 27 | unevaluatedProperties: false | ||
| 28 | |||
| 29 | examples: | ||
| 30 | - | | ||
| 31 | nvmem { | ||
| 32 | compatible = "xlnx,zynqmp-nvmem-fw"; | ||
| 33 | nvmem-layout { | ||
| 34 | compatible = "fixed-layout"; | ||
| 35 | #address-cells = <1>; | ||
| 36 | #size-cells = <1>; | ||
| 37 | |||
| 38 | soc_revision: soc-revision@0 { | ||
| 39 | reg = <0x0 0x4>; | ||
| 40 | }; | ||
| 41 | }; | ||
| 42 | }; | ||
| @@ -1573,6 +1573,8 @@ patternProperties: · 1572 unmodified lines | |||
| 1573 | description: VoCore Studio | 1573 | description: VoCore Studio |
| 1574 | "^voipac,.*": | 1574 | "^voipac,.*": |
| 1575 | description: Voipac Technologies s.r.o. | 1575 | description: Voipac Technologies s.r.o. |
| 1576 | "^voltafield,.*": | ||
| 1577 | description: Voltafield Technology Corp. | ||
| 1576 | "^vot,.*": | 1578 | "^vot,.*": |
| 1577 | description: Vision Optical Technology Co., Ltd. | 1579 | description: Vision Optical Technology Co., Ltd. |
| 1578 | "^vscom,.*": | 1580 | "^vscom,.*": |
| @@ -0,0 +1,407 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | ================ | ||
| 4 | ADIS16475 driver | ||
| 5 | ================ | ||
| 6 | |||
| 7 | This driver supports Analog Device's IMUs on SPI bus. | ||
| 8 | |||
| 9 | 1. Supported devices | ||
| 10 | ==================== | ||
| 11 | |||
| 12 | * `ADIS16465 <https://www.analog.com/ADIS16465>`_ | ||
| 13 | * `ADIS16467 <https://www.analog.com/ADIS16467>`_ | ||
| 14 | * `ADIS16470 <https://www.analog.com/ADIS16470>`_ | ||
| 15 | * `ADIS16475 <https://www.analog.com/ADIS16475>`_ | ||
| 16 | * `ADIS16477 <https://www.analog.com/ADIS16477>`_ | ||
| 17 | * `ADIS16500 <https://www.analog.com/ADIS16500>`_ | ||
| 18 | * `ADIS16505 <https://www.analog.com/ADIS16505>`_ | ||
| 19 | * `ADIS16507 <https://www.analog.com/ADIS16507>`_ | ||
| 20 | |||
| 21 | Each supported device is a precision, miniature microelectromechanical system | ||
| 22 | (MEMS) inertial measurement unit (IMU) that includes a triaxial gyroscope and a | ||
| 23 | triaxial accelerometer. Each inertial sensor in the IMU device combines with | ||
| 24 | signal conditioning that optimizes dynamic performance. The factory calibration | ||
| 25 | characterizes each sensor for sensitivity, bias, alignment, linear acceleration | ||
| 26 | (gyroscope bias), and point of percussion (accelerometer location). As a result, | ||
| 27 | each sensor has dynamic compensation formulas that provide accurate sensor | ||
| 28 | measurements over a broad set of conditions. | ||
| 29 | |||
| 30 | 2. Device attributes | ||
| 31 | ==================== | ||
| 32 | |||
| 33 | Accelerometer, gyroscope measurements are always provided. Furthermore, the | ||
| 34 | driver offers the capability to retrieve the delta angle and the delta velocity | ||
| 35 | measurements computed by the device. | ||
| 36 | |||
| 37 | The delta angle measurements represent a calculation of angular displacement | ||
| 38 | between each sample update, while the delta velocity measurements represent a | ||
| 39 | calculation of linear velocity change between each sample update. | ||
| 40 | |||
| 41 | Finally, temperature data are provided which show a coarse measurement of | ||
| 42 | the temperature inside of the IMU device. This data is most useful for | ||
| 43 | monitoring relative changes in the thermal environment. | ||
| 44 | |||
| 45 | The signal chain of each inertial sensor (accelerometers and gyroscopes) | ||
| 46 | includes the application of unique correction formulas, which are derived from | ||
| 47 | extensive characterization of bias, sensitivity, alignment, response to linear | ||
| 48 | acceleration (gyroscopes), and point of percussion (accelerometer location) | ||
| 49 | over a temperature range of −40°C to +85°C, for each ADIS device. These | ||
| 50 | correction formulas are not accessible, but users do have the opportunity to | ||
| 51 | adjust the bias for each sensor individually through the calibbias attribute. | ||
| 52 | |||
| 53 | Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, | ||
| 54 | where X is the IIO index of the device. Under these folders reside a set of | ||
| 55 | device files, depending on the characteristics and features of the hardware | ||
| 56 | device in questions. These files are consistently generalized and documented in | ||
| 57 | the IIO ABI documentation. | ||
| 58 | |||
| 59 | The following tables show the adis16475 related device files, found in the | ||
| 60 | specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. | ||
| 61 | |||
| 62 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 63 | | 3-Axis Accelerometer related device files | Description | | ||
| 64 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 65 | | in_accel_scale | Scale for the accelerometer channels. | | ||
| 66 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 67 | | in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. | | ||
| 68 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 69 | | in_accel_calibbias_x | x-axis acceleration offset correction | | ||
| 70 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 71 | | in_accel_x_raw | Raw X-axis accelerometer channel value. | | ||
| 72 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 73 | | in_accel_calibbias_y | y-axis acceleration offset correction | | ||
| 74 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 75 | | in_accel_y_raw | Raw Y-axis accelerometer channel value. | | ||
| 76 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 77 | | in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. | | ||
| 78 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 79 | | in_accel_z_raw | Raw Z-axis accelerometer channel value. | | ||
| 80 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 81 | | in_deltavelocity_scale | Scale for delta velocity channels. | | ||
| 82 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 83 | | in_deltavelocity_x_raw | Raw X-axis delta velocity channel value. | | ||
| 84 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 85 | | in_deltavelocity_y_raw | Raw Y-axis delta velocity channel value. | | ||
| 86 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 87 | | in_deltavelocity_z_raw | Raw Z-axis delta velocity channel value. | | ||
| 88 | +-------------------------------------------+----------------------------------------------------------+ | ||
| 89 | |||
| 90 | +---------------------------------------+------------------------------------------------------+ | ||
| 91 | | 3-Axis Gyroscope related device files | Description | | ||
| 92 | +---------------------------------------+------------------------------------------------------+ | ||
| 93 | | in_anglvel_scale | Scale for the gyroscope channels. | | ||
| 94 | +---------------------------------------+------------------------------------------------------+ | ||
| 95 | | in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. | | ||
| 96 | +---------------------------------------+------------------------------------------------------+ | ||
| 97 | | in_anglvel_calibbias_x | x-axis gyroscope offset correction | | ||
| 98 | +---------------------------------------+------------------------------------------------------+ | ||
| 99 | | in_anglvel_x_raw | Raw X-axis gyroscope channel value. | | ||
| 100 | +---------------------------------------+------------------------------------------------------+ | ||
| 101 | | in_anglvel_calibbias_y | y-axis gyroscope offset correction | | ||
| 102 | +---------------------------------------+------------------------------------------------------+ | ||
| 103 | | in_anglvel_y_raw | Raw Y-axis gyroscope channel value. | | ||
| 104 | +---------------------------------------+------------------------------------------------------+ | ||
| 105 | | in_anglvel_z_calibbias | Calibration offset for the Z-axis gyroscope channel. | | ||
| 106 | +---------------------------------------+------------------------------------------------------+ | ||
| 107 | | in_anglvel_z_raw | Raw Z-axis gyroscope channel value. | | ||
| 108 | +---------------------------------------+------------------------------------------------------+ | ||
| 109 | | in_deltaangl_scale | Scale for delta angle channels. | | ||
| 110 | +---------------------------------------+------------------------------------------------------+ | ||
| 111 | | in_deltaangl_x_raw | Raw X-axis delta angle channel value. | | ||
| 112 | +---------------------------------------+------------------------------------------------------+ | ||
| 113 | | in_deltaangl_y_raw | Raw Y-axis delta angle channel value. | | ||
| 114 | +---------------------------------------+------------------------------------------------------+ | ||
| 115 | | in_deltaangl_z_raw | Raw Z-axis delta angle channel value. | | ||
| 116 | +---------------------------------------+------------------------------------------------------+ | ||
| 117 | |||
| 118 | +----------------------------------+-------------------------------------------+ | ||
| 119 | | Temperature sensor related files | Description | | ||
| 120 | +----------------------------------+-------------------------------------------+ | ||
| 121 | | in_temp0_raw | Raw temperature channel value. | | ||
| 122 | +----------------------------------+-------------------------------------------+ | ||
| 123 | | in_temp0_scale | Scale for the temperature sensor channel. | | ||
| 124 | +----------------------------------+-------------------------------------------+ | ||
| 125 | |||
| 126 | +-------------------------------+---------------------------------------------------------+ | ||
| 127 | | Miscellaneous device files | Description | | ||
| 128 | +-------------------------------+---------------------------------------------------------+ | ||
| 129 | | name | Name of the IIO device. | | ||
| 130 | +-------------------------------+---------------------------------------------------------+ | ||
| 131 | | sampling_frequency | Currently selected sample rate. | | ||
| 132 | +-------------------------------+---------------------------------------------------------+ | ||
| 133 | | filter_low_pass_3db_frequency | Bandwidth for the accelerometer and gyroscope channels. | | ||
| 134 | +-------------------------------+---------------------------------------------------------+ | ||
| 135 | |||
| 136 | The following table shows the adis16475 related device debug files, found in the | ||
| 137 | specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``. | ||
| 138 | |||
| 139 | +----------------------+-------------------------------------------------------------------------+ | ||
| 140 | | Debugfs device files | Description | | ||
| 141 | +----------------------+-------------------------------------------------------------------------+ | ||
| 142 | | serial_number | The serial number of the chip in hexadecimal format. | | ||
| 143 | +----------------------+-------------------------------------------------------------------------+ | ||
| 144 | | product_id | Chip specific product id (e.g. 16475, 16500, 16505, etc.). | | ||
| 145 | +----------------------+-------------------------------------------------------------------------+ | ||
| 146 | | flash_count | The number of flash writes performed on the device. | | ||
| 147 | +----------------------+-------------------------------------------------------------------------+ | ||
| 148 | | firmware_revision | String containing the firmware revision in the following format ##.##. | | ||
| 149 | +----------------------+-------------------------------------------------------------------------+ | ||
| 150 | | firmware_date | String containing the firmware date in the following format mm-dd-yyyy. | | ||
| 151 | +----------------------+-------------------------------------------------------------------------+ | ||
| 152 | |||
| 153 | Channels processed values | ||
| 154 | ------------------------- | ||
| 155 | |||
| 156 | A channel value can be read from its _raw attribute. The value returned is the | ||
| 157 | raw value as reported by the devices. To get the processed value of the channel, | ||
| 158 | apply the following formula: | ||
| 159 | |||
| 160 | .. code-block:: bash | ||
| 161 | |||
| 162 | processed value = (_raw + _offset) * _scale | ||
| 163 | |||
| 164 | Where _offset and _scale are device attributes. If no _offset attribute is | ||
| 165 | present, simply assume its value is 0. | ||
| 166 | |||
| 167 | The adis16475 driver offers data for 5 types of channels, the table below shows | ||
| 168 | the measurement units for the processed value, which are defined by the IIO | ||
| 169 | framework: | ||
| 170 | |||
| 171 | +-------------------------------------+---------------------------+ | ||
| 172 | | Channel type | Measurement unit | | ||
| 173 | +-------------------------------------+---------------------------+ | ||
| 174 | | Acceleration on X, Y, and Z axis | Meters per Second squared | | ||
| 175 | +-------------------------------------+---------------------------+ | ||
| 176 | | Angular velocity on X, Y and Z axis | Radians per second | | ||
| 177 | +-------------------------------------+---------------------------+ | ||
| 178 | | Delta velocity on X. Y, and Z axis | Meters per Second | | ||
| 179 | +-------------------------------------+---------------------------+ | ||
| 180 | | Delta angle on X, Y, and Z axis | Radians | | ||
| 181 | +-------------------------------------+---------------------------+ | ||
| 182 | | Temperature | Millidegrees Celsius | | ||
| 183 | +-------------------------------------+---------------------------+ | ||
| 184 | |||
| 185 | Usage examples | ||
| 186 | -------------- | ||
| 187 | |||
| 188 | Show device name: | ||
| 189 | |||
| 190 | .. code-block:: bash | ||
| 191 | |||
| 192 | root:/sys/bus/iio/devices/iio:device0> cat name | ||
| 193 | adis16505-2 | ||
| 194 | |||
| 195 | Show accelerometer channels value: | ||
| 196 | |||
| 197 | .. code-block:: bash | ||
| 198 | |||
| 199 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw | ||
| 200 | -275924 | ||
| 201 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw | ||
| 202 | -30142222 | ||
| 203 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw | ||
| 204 | 261265769 | ||
| 205 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale | ||
| 206 | 0.000000037 | ||
| 207 | |||
| 208 | - X-axis acceleration = in_accel_x_raw * in_accel_scale = −0.010209188 m/s^2 | ||
| 209 | - Y-axis acceleration = in_accel_y_raw * in_accel_scale = −1.115262214 m/s^2 | ||
| 210 | - Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.666833453 m/s^2 | ||
| 211 | |||
| 212 | Show gyroscope channels value: | ||
| 213 | |||
| 214 | .. code-block:: bash | ||
| 215 | |||
| 216 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw | ||
| 217 | -3324626 | ||
| 218 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw | ||
| 219 | 1336980 | ||
| 220 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw | ||
| 221 | -602983 | ||
| 222 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale | ||
| 223 | 0.000000006 | ||
| 224 | |||
| 225 | - X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.019947756 rad/s | ||
| 226 | - Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = 0.00802188 rad/s | ||
| 227 | - Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = −0.003617898 rad/s | ||
| 228 | |||
| 229 | Set calibration offset for accelerometer channels: | ||
| 230 | |||
| 231 | .. code-block:: bash | ||
| 232 | |||
| 233 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias | ||
| 234 | 0 | ||
| 235 | |||
| 236 | root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias | ||
| 237 | root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias | ||
| 238 | 5000 | ||
| 239 | |||
| 240 | Set calibration offset for gyroscope channels: | ||
| 241 | |||
| 242 | .. code-block:: bash | ||
| 243 | |||
| 244 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias | ||
| 245 | 0 | ||
| 246 | |||
| 247 | root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias | ||
| 248 | root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias | ||
| 249 | -5000 | ||
| 250 | |||
| 251 | Set sampling frequency: | ||
| 252 | |||
| 253 | .. code-block:: bash | ||
| 254 | |||
| 255 | root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency | ||
| 256 | 2000.000000 | ||
| 257 | |||
| 258 | root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency | ||
| 259 | 1000.000000 | ||
| 260 | |||
| 261 | Set bandwidth for accelerometer and gyroscope: | ||
| 262 | |||
| 263 | .. code-block:: bash | ||
| 264 | |||
| 265 | root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency | ||
| 266 | 720 | ||
| 267 | |||
| 268 | root:/sys/bus/iio/devices/iio:device0> echo 360 > filter_low_pass_3db_frequency | ||
| 269 | root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency | ||
| 270 | 360 | ||
| 271 | |||
| 272 | Show serial number: | ||
| 273 | |||
| 274 | .. code-block:: bash | ||
| 275 | |||
| 276 | root:/sys/kernel/debug/iio/iio:device0> cat serial_number | ||
| 277 | 0x04f9 | ||
| 278 | |||
| 279 | Show product id: | ||
| 280 | |||
| 281 | .. code-block:: bash | ||
| 282 | |||
| 283 | root:/sys/kernel/debug/iio/iio:device0> cat product_id | ||
| 284 | 16505 | ||
| 285 | |||
| 286 | Show flash count: | ||
| 287 | |||
| 288 | .. code-block:: bash | ||
| 289 | |||
| 290 | root:/sys/kernel/debug/iio/iio:device0> cat flash_count | ||
| 291 | 150 | ||
| 292 | |||
| 293 | Show firmware revision: | ||
| 294 | |||
| 295 | .. code-block:: bash | ||
| 296 | |||
| 297 | root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision | ||
| 298 | 1.6 | ||
| 299 | |||
| 300 | Show firmware date: | ||
| 301 | |||
| 302 | .. code-block:: bash | ||
| 303 | |||
| 304 | root:/sys/kernel/debug/iio/iio:device0> cat firmware_date | ||
| 305 | 06-27-2019 | ||
| 306 | |||
| 307 | 3. Device buffers | ||
| 308 | ================= | ||
| 309 | |||
| 310 | This driver supports IIO buffers. | ||
| 311 | |||
| 312 | All devices support retrieving the raw acceleration, gyroscope and temperature | ||
| 313 | measurements using buffers. | ||
| 314 | |||
| 315 | The following device families also support retrieving the delta velocity, delta | ||
| 316 | angle and temperature measurements using buffers: | ||
| 317 | |||
| 318 | - ADIS16477 | ||
| 319 | - ADIS16500 | ||
| 320 | - ADIS16505 | ||
| 321 | - ADIS16507 | ||
| 322 | |||
| 323 | However, when retrieving acceleration or gyroscope data using buffers, delta | ||
| 324 | readings will not be available and vice versa. | ||
| 325 | |||
| 326 | Usage examples | ||
| 327 | -------------- | ||
| 328 | |||
| 329 | Set device trigger in current_trigger, if not already set: | ||
| 330 | |||
| 331 | .. code-block:: bash | ||
| 332 | |||
| 333 | root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger | ||
| 334 | |||
| 335 | root:/sys/bus/iio/devices/iio:device0> echo adis16505-2-dev0 > trigger/current_trigger | ||
| 336 | root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger | ||
| 337 | adis16505-2-dev0 | ||
| 338 | |||
| 339 | Select channels for buffer read: | ||
| 340 | |||
| 341 | .. code-block:: bash | ||
| 342 | |||
| 343 | root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en | ||
| 344 | root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en | ||
| 345 | root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en | ||
| 346 | root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en | ||
| 347 | |||
| 348 | Set the number of samples to be stored in the buffer: | ||
| 349 | |||
| 350 | .. code-block:: bash | ||
| 351 | |||
| 352 | root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length | ||
| 353 | |||
| 354 | Enable buffer readings: | ||
| 355 | |||
| 356 | .. code-block:: bash | ||
| 357 | |||
| 358 | root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable | ||
| 359 | |||
| 360 | Obtain buffered data: | ||
| 361 | |||
| 362 | .. code-block:: bash | ||
| 363 | |||
| 364 | root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0 | ||
| 365 | ... | ||
| 366 | 00001680 01 1f 00 00 ff ff fe ef 00 00 47 bf 00 03 35 55 |..........G...5U| | ||
| 367 | 00001690 01 1f 00 00 ff ff ff d9 00 00 46 f1 00 03 35 35 |..........F...55| | ||
| 368 | 000016a0 01 1f 00 00 ff ff fe fc 00 00 46 cb 00 03 35 7b |..........F...5{| | ||
| 369 | 000016b0 01 1f 00 00 ff ff fe 41 00 00 47 0d 00 03 35 8b |.......A..G...5.| | ||
| 370 | 000016c0 01 1f 00 00 ff ff fe 37 00 00 46 b4 00 03 35 90 |.......7..F...5.| | ||
| 371 | 000016d0 01 1d 00 00 ff ff fe 5a 00 00 45 d7 00 03 36 08 |.......Z..E...6.| | ||
| 372 | 000016e0 01 1b 00 00 ff ff fe fb 00 00 45 e7 00 03 36 60 |..........E...6`| | ||
| 373 | 000016f0 01 1a 00 00 ff ff ff 17 00 00 46 bc 00 03 36 de |..........F...6.| | ||
| 374 | 00001700 01 1a 00 00 ff ff fe 59 00 00 46 d7 00 03 37 b8 |.......Y..F...7.| | ||
| 375 | 00001710 01 1a 00 00 ff ff fe ae 00 00 46 95 00 03 37 ba |..........F...7.| | ||
| 376 | 00001720 01 1a 00 00 ff ff fe c5 00 00 46 63 00 03 37 9f |..........Fc..7.| | ||
| 377 | 00001730 01 1a 00 00 ff ff fe 55 00 00 46 89 00 03 37 c1 |.......U..F...7.| | ||
| 378 | 00001740 01 1a 00 00 ff ff fe 31 00 00 46 aa 00 03 37 f7 |.......1..F...7.| | ||
| 379 | ... | ||
| 380 | |||
| 381 | See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered | ||
| 382 | data is structured. | ||
| 383 | |||
| 384 | 4. IIO Interfacing Tools | ||
| 385 | ======================== | ||
| 386 | |||
| 387 | Linux Kernel Tools | ||
| 388 | ------------------ | ||
| 389 | |||
| 390 | Linux Kernel provides some userspace tools that can be used to retrieve data | ||
| 391 | from IIO sysfs: | ||
| 392 | |||
| 393 | * lsiio: example application that provides a list of IIO devices and triggers | ||
| 394 | * iio_event_monitor: example application that reads events from an IIO device | ||
| 395 | and prints them | ||
| 396 | * iio_generic_buffer: example application that reads data from buffer | ||
| 397 | * iio_utils: set of APIs, typically used to access sysfs files. | ||
| 398 | |||
| 399 | LibIIO | ||
| 400 | ------ | ||
| 401 | |||
| 402 | LibIIO is a C/C++ library that provides generic access to IIO devices. The | ||
| 403 | library abstracts the low-level details of the hardware, and provides a simple | ||
| 404 | yet complete programming interface that can be used for advanced projects. | ||
| 405 | |||
| 406 | For more information about LibIIO, please see: | ||
| 407 | https://github.com/analogdevicesinc/libiio | ||
| @@ -0,0 +1,152 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | ============================= | ||
| 4 | Industrial IIO device buffers | ||
| 5 | ============================= | ||
| 6 | |||
| 7 | 1. Overview | ||
| 8 | =========== | ||
| 9 | |||
| 10 | The Industrial I/O core offers a way for continuous data capture based on a | ||
| 11 | trigger source. Multiple data channels can be read at once from | ||
| 12 | ``/dev/iio:deviceX`` character device node, thus reducing the CPU load. | ||
| 13 | |||
| 14 | Devices with buffer support feature an additional sub-directory in the | ||
| 15 | ``/sys/bus/iio/devices/iio:deviceX/`` directory hierarchy, called bufferY, where | ||
| 16 | Y defaults to 0, for devices with a single buffer. | ||
| 17 | |||
| 18 | 2. Buffer attributes | ||
| 19 | ==================== | ||
| 20 | |||
| 21 | An IIO buffer has an associated attributes directory under | ||
| 22 | ``/sys/bus/iio/iio:deviceX/bufferY/``. The attributes are described below. | ||
| 23 | |||
| 24 | ``length`` | ||
| 25 | ---------- | ||
| 26 | |||
| 27 | Read / Write attribute which states the total number of data samples (capacity) | ||
| 28 | that can be stored by the buffer. | ||
| 29 | |||
| 30 | ``enable`` | ||
| 31 | ---------- | ||
| 32 | |||
| 33 | Read / Write attribute which starts / stops the buffer capture. This file should | ||
| 34 | be written last, after length and selection of scan elements. Writing a non-zero | ||
| 35 | value may result in an error, such as EINVAL, if, for example, an unsupported | ||
| 36 | combination of channels is given. | ||
| 37 | |||
| 38 | ``watermark`` | ||
| 39 | ------------- | ||
| 40 | |||
| 41 | Read / Write positive integer attribute specifying the maximum number of scan | ||
| 42 | elements to wait for. | ||
| 43 | |||
| 44 | Poll will block until the watermark is reached. | ||
| 45 | |||
| 46 | Blocking read will wait until the minimum between the requested read amount or | ||
| 47 | the low watermark is available. | ||
| 48 | |||
| 49 | Non-blocking read will retrieve the available samples from the buffer even if | ||
| 50 | there are less samples than the watermark level. This allows the application to | ||
| 51 | block on poll with a timeout and read the available samples after the timeout | ||
| 52 | expires and thus have a maximum delay guarantee. | ||
| 53 | |||
| 54 | Data available | ||
| 55 | -------------- | ||
| 56 | |||
| 57 | Read-only attribute indicating the bytes of data available in the buffer. In the | ||
| 58 | case of an output buffer, this indicates the amount of empty space available to | ||
| 59 | write data to. In the case of an input buffer, this indicates the amount of data | ||
| 60 | available for reading. | ||
| 61 | |||
| 62 | Scan elements | ||
| 63 | ------------- | ||
| 64 | |||
| 65 | The meta information associated with a channel data placed in a buffer is called | ||
| 66 | a scan element. The scan elements attributes are presented below. | ||
| 67 | |||
| 68 | **_en** | ||
| 69 | |||
| 70 | Read / Write attribute used for enabling a channel. If and only if its value | ||
| 71 | is non-zero, then a triggered capture will contain data samples for this | ||
| 72 | channel. | ||
| 73 | |||
| 74 | **_index** | ||
| 75 | |||
| 76 | Read-only unsigned integer attribute specifying the position of the channel in | ||
| 77 | the buffer. Note these are not dependent on what is enabled and may not be | ||
| 78 | contiguous. Thus for userspace to establish the full layout these must be used | ||
| 79 | in conjunction with all _en attributes to establish which channels are present, | ||
| 80 | and the relevant _type attributes to establish the data storage format. | ||
| 81 | |||
| 82 | **_type** | ||
| 83 | |||
| 84 | Read-only attribute containing the description of the scan element data storage | ||
| 85 | within the buffer and hence the form in which it is read from userspace. Format | ||
| 86 | is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift], where: | ||
| 87 | |||
| 88 | - **be** or **le** specifies big or little-endian. | ||
| 89 | - **s** or **u** specifies if signed (2's complement) or unsigned. | ||
| 90 | - **bits** is the number of valid data bits. | ||
| 91 | - **storagebits** is the number of bits (after padding) that it occupies in the | ||
| 92 | buffer. | ||
| 93 | - **repeat** specifies the number of bits/storagebits repetitions. When the | ||
| 94 | repeat element is 0 or 1, then the repeat value is omitted. | ||
| 95 | - **shift** if specified, is the shift that needs to be applied prior to | ||
| 96 | masking out unused bits. | ||
| 97 | |||
| 98 | For example, a driver for a 3-axis accelerometer with 12-bit resolution where | ||
| 99 | data is stored in two 8-bit registers is as follows:: | ||
| 100 | |||
| 101 | 7 6 5 4 3 2 1 0 | ||
| 102 | +---+---+---+---+---+---+---+---+ | ||
| 103 | |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) | ||
| 104 | +---+---+---+---+---+---+---+---+ | ||
| 105 | |||
| 106 | 7 6 5 4 3 2 1 0 | ||
| 107 | +---+---+---+---+---+---+---+---+ | ||
| 108 | |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) | ||
| 109 | +---+---+---+---+---+---+---+---+ | ||
| 110 | |||
| 111 | will have the following scan element type for each axis: | ||
| 112 | |||
| 113 | .. code-block:: bash | ||
| 114 | |||
| 115 | $ cat /sys/bus/iio/devices/iio:device0/buffer0/in_accel_y_type | ||
| 116 | le:s12/16>>4 | ||
| 117 | |||
| 118 | A userspace application will interpret data samples read from the buffer as | ||
| 119 | two-byte little-endian signed data, that needs a 4 bits right shift before | ||
| 120 | masking out the 12 valid bits of data. | ||
| 121 | |||
| 122 | It is also worth mentioning that the data in the buffer will be naturally | ||
| 123 | aligned, so the userspace application has to handle the buffers accordingly. | ||
| 124 | |||
| 125 | Take for example, a driver with four channels with the following description: | ||
| 126 | - channel0: index: 0, type: be:u16/16>>0 | ||
| 127 | - channel1: index: 1, type: be:u32/32>>0 | ||
| 128 | - channel2: index: 2, type: be:u32/32>>0 | ||
| 129 | - channel3: index: 3, type: be:u64/64>>0 | ||
| 130 | |||
| 131 | If all channels are enabled, the data will be aligned in the buffer as follows:: | ||
| 132 | |||
| 133 | 0-1 2 3 4-7 8-11 12 13 14 15 16-23 -> buffer byte number | ||
| 134 | +-----+---+---+-----+-----+---+---+---+---+-----+ | ||
| 135 | |CHN_0|PAD|PAD|CHN_1|CHN_2|PAD|PAD|PAD|PAD|CHN_3| -> buffer content | ||
| 136 | +-----+---+---+-----+-----+---+---+---+---+-----+ | ||
| 137 | |||
| 138 | If only channel0 and channel3 are enabled, the data will be aligned in the | ||
| 139 | buffer as follows:: | ||
| 140 | |||
| 141 | 0-1 2 3 4 5 6 7 8-15 -> buffer byte number | ||
| 142 | +-----+---+---+---+---+---+---+-----+ | ||
| 143 | |CHN_0|PAD|PAD|PAD|PAD|PAD|PAD|CHN_3| -> buffer content | ||
| 144 | +-----+---+---+---+---+---+---+-----+ | ||
| 145 | |||
| 146 | Typically the buffered data is found in raw format (unscaled with no offset | ||
| 147 | applied), however there are corner cases in which the buffered data may be found | ||
| 148 | in a processed form. Please note that these corner cases are not addressed by | ||
| 149 | this documentation. | ||
| 150 | |||
| 151 | Please see ``Documentation/ABI/testing/sysfs-bus-iio`` for a complete | ||
| 152 | description of the attributes. | ||
| @@ -8,7 +8,14 @@ Industrial I/O · 7 unmodified lines | |||
| 8 | :maxdepth: 1 | 8 | :maxdepth: 1 |
| 9 | 9 | ||
| 10 | iio_configfs | 10 | iio_configfs |
| 11 | iio_devbuf | ||
| 11 | 12 | ||
| 12 | ep93xx_adc | 13 | Industrial I/O Kernel Drivers |
| 14 | ============================= | ||
| 13 | 15 | ||
| 16 | .. toctree:: | ||
| 17 | :maxdepth: 1 | ||
| 18 | |||
| 19 | adis16475 | ||
| 14 | bno055 | 20 | bno055 |
| 21 | ep93xx_adc | ||
| @@ -579,6 +579,12 @@ F: drivers/iio/accel/adxl372.c · 578 unmodified lines | |||
| 579 | F: drivers/iio/accel/adxl372_i2c.c | 579 | F: drivers/iio/accel/adxl372_i2c.c |
| 580 | F: drivers/iio/accel/adxl372_spi.c | 580 | F: drivers/iio/accel/adxl372_spi.c |
| 581 | 581 | ||
| 582 | AF8133J THREE-AXIS MAGNETOMETER DRIVER | ||
| 583 | M: Ondřej Jirman <megi@xff.cz> | ||
| 584 | S: Maintained | ||
| 585 | F: Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml | ||
| 586 | F: drivers/iio/magnetometer/af8133j.c | ||
| 587 | |||
| 582 | AF9013 MEDIA DRIVER | 588 | AF9013 MEDIA DRIVER |
| 583 | L: linux-media@vger.kernel.org | 589 | L: linux-media@vger.kernel.org |
| 584 | S: Orphan | 590 | S: Orphan |
| @@ -1158,7 +1164,7 @@ L: linux-iio@vger.kernel.org · 573 unmodified lines | |||
| 1158 | S: Supported | 1164 | S: Supported |
| 1159 | W: http://ez.analog.com/community/linux-device-drivers | 1165 | W: http://ez.analog.com/community/linux-device-drivers |
| 1160 | F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* | 1166 | F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* |
| 1161 | F: drivers/iio/adc/drivers/iio/adc/ad7091r* | 1167 | F: drivers/iio/adc/ad7091r* |
| 1162 | 1168 | ||
| 1163 | ANALOG DEVICES INC AD7192 DRIVER | 1169 | ANALOG DEVICES INC AD7192 DRIVER |
| 1164 | M: Alexandru Tachici <alexandru.tachici@analog.com> | 1170 | M: Alexandru Tachici <alexandru.tachici@analog.com> |
| @@ -1281,6 +1287,14 @@ W: https://ez.analog.com/linux-software-drivers · 116 unmodified lines | |||
| 1281 | F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml | 1287 | F: Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml |
| 1282 | F: drivers/hwmon/adm1177.c | 1288 | F: drivers/hwmon/adm1177.c |
| 1283 | 1289 | ||
| 1290 | ANALOG DEVICES INC ADMFM2000 DRIVER | ||
| 1291 | M: Kim Seer Paller <kimseer.paller@analog.com> | ||
| 1292 | L: linux-iio@vger.kernel.org | ||
| 1293 | S: Supported | ||
| 1294 | W: https://ez.analog.com/linux-software-drivers | ||
| 1295 | F: Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml | ||
| 1296 | F: drivers/iio/frequency/admfm2000.c | ||
| 1297 | |||
| 1284 | ANALOG DEVICES INC ADMV1013 DRIVER | 1298 | ANALOG DEVICES INC ADMV1013 DRIVER |
| 1285 | M: Antoniu Miclaus <antoniu.miclaus@analog.com> | 1299 | M: Antoniu Miclaus <antoniu.miclaus@analog.com> |
| 1286 | L: linux-iio@vger.kernel.org | 1300 | L: linux-iio@vger.kernel.org |
| @@ -9509,7 +9523,7 @@ T: git git://linuxtv.org/media_tree.git · 8222 unmodified lines | |||
| 9509 | F: drivers/media/usb/hdpvr/ | 9523 | F: drivers/media/usb/hdpvr/ |
| 9510 | 9524 | ||
| 9511 | HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER | 9525 | HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER |
| 9512 | M: Matt Hsiao <matt.hsiao@hpe.com> | 9526 | M: Keng-Yu Lin <keng-yu.lin@hpe.com> |
| 9513 | S: Supported | 9527 | S: Supported |
| 9514 | F: drivers/misc/hpilo.[ch] | 9528 | F: drivers/misc/hpilo.[ch] |
| 9515 | 9529 | ||
| @@ -9879,10 +9893,11 @@ F: drivers/iio/pressure/hsc030pa* · 363 unmodified lines | |||
| 9879 | 9893 | ||
| 9880 | HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER | 9894 | HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER |
| 9881 | M: Andreas Klinger <ak@it-klinger.de> | 9895 | M: Andreas Klinger <ak@it-klinger.de> |
| 9896 | M: Petre Rodan <petre.rodan@subdimension.ro> | ||
| 9882 | L: linux-iio@vger.kernel.org | 9897 | L: linux-iio@vger.kernel.org |
| 9883 | S: Maintained | 9898 | S: Maintained |
| 9884 | F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml | 9899 | F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml |
| 9885 | F: drivers/iio/pressure/mprls0025pa.c | 9900 | F: drivers/iio/pressure/mprls0025pa* |
| 9886 | 9901 | ||
| 9887 | HP BIOSCFG DRIVER | 9902 | HP BIOSCFG DRIVER |
| 9888 | M: Jorge Lopez <jorge.lopez2@hp.com> | 9903 | M: Jorge Lopez <jorge.lopez2@hp.com> |
| @@ -10475,6 +10490,14 @@ L: linux-media@vger.kernel.org · 586 unmodified lines | |||
| 10475 | S: Maintained | 10490 | S: Maintained |
| 10476 | F: drivers/media/rc/iguanair.c | 10491 | F: drivers/media/rc/iguanair.c |
| 10477 | 10492 | ||
| 10493 | IIO BACKEND FRAMEWORK | ||
| 10494 | M: Nuno Sa <nuno.sa@analog.com> | ||
| 10495 | R: Olivier Moysan <olivier.moysan@foss.st.com> | ||
| 10496 | L: linux-iio@vger.kernel.org | ||
| 10497 | S: Maintained | ||
| 10498 | F: drivers/iio/industrialio-backend.c | ||
| 10499 | F: include/linux/iio/backend.h | ||
| 10500 | |||
| 10478 | IIO DIGITAL POTENTIOMETER DAC | 10501 | IIO DIGITAL POTENTIOMETER DAC |
| 10479 | M: Peter Rosin <peda@axentia.se> | 10502 | M: Peter Rosin <peda@axentia.se> |
| 10480 | L: linux-iio@vger.kernel.org | 10503 | L: linux-iio@vger.kernel.org |
| @@ -10497,6 +10520,7 @@ L: linux-iio@vger.kernel.org · 16 unmodified lines | |||
| 10497 | S: Maintained | 10520 | S: Maintained |
| 10498 | F: drivers/iio/industrialio-gts-helper.c | 10521 | F: drivers/iio/industrialio-gts-helper.c |
| 10499 | F: include/linux/iio/iio-gts-helper.h | 10522 | F: include/linux/iio/iio-gts-helper.h |
| 10523 | F: drivers/iio/test/iio-test-gts.c | ||
| 10500 | 10524 | ||
| 10501 | IIO MULTIPLEXER | 10525 | IIO MULTIPLEXER |
| 10502 | M: Peter Rosin <peda@axentia.se> | 10526 | M: Peter Rosin <peda@axentia.se> |
| @@ -14487,6 +14511,13 @@ F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml · 3984 unmodified lines | |||
| 14487 | F: drivers/nvmem/microchip-otpc.c | 14511 | F: drivers/nvmem/microchip-otpc.c |
| 14488 | F: include/dt-bindings/nvmem/microchip,sama7g5-otpc.h | 14512 | F: include/dt-bindings/nvmem/microchip,sama7g5-otpc.h |
| 14489 | 14513 | ||
| 14514 | MICROCHIP PAC1934 POWER/ENERGY MONITOR DRIVER | ||
| 14515 | M: Marius Cristea <marius.cristea@microchip.com> | ||
| 14516 | L: linux-iio@vger.kernel.org | ||
| 14517 | S: Supported | ||
| 14518 | F: Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml | ||
| 14519 | F: drivers/iio/adc/pac1934.c | ||
| 14520 | |||
| 14490 | MICROCHIP PCI1XXXX GP DRIVER | 14521 | MICROCHIP PCI1XXXX GP DRIVER |
| 14491 | M: Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com> | 14522 | M: Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com> |
| 14492 | M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> | 14523 | M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> |
| @@ -23566,8 +23597,8 @@ F: Documentation/driver-api/vme.rst · 9073 unmodified lines | |||
| 23566 | F: drivers/staging/vme_user/ | 23597 | F: drivers/staging/vme_user/ |
| 23567 | 23598 | ||
| 23568 | VMWARE BALLOON DRIVER | 23599 | VMWARE BALLOON DRIVER |
| 23569 | M: Nadav Amit <namit@vmware.com> | 23600 | M: Jerrin Shaji George <jerrin.shaji-george@broadcom.com> |
| 23570 | R: VMware PV-Drivers Reviewers <pv-drivers@vmware.com> | 23601 | R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com> |
| 23571 | L: linux-kernel@vger.kernel.org | 23602 | L: linux-kernel@vger.kernel.org |
| 23572 | S: Supported | 23603 | S: Supported |
| 23573 | F: drivers/misc/vmw_balloon.c | 23604 | F: drivers/misc/vmw_balloon.c |
| @@ -24344,6 +24375,14 @@ M: Harsha <harsha.harsha@amd.com> · 770 unmodified lines | |||
| 24344 | S: Maintained | 24375 | S: Maintained |
| 24345 | F: drivers/crypto/xilinx/zynqmp-sha.c | 24376 | F: drivers/crypto/xilinx/zynqmp-sha.c |
| 24346 | 24377 | ||
| 24378 | XILINX ZYNQMP NVMEM DRIVER | ||
| 24379 | M: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com> | ||
| 24380 | M: Kalyani Akula <kalyani.akula@amd.com> | ||
| 24381 | R: Michal Simek <michal.simek@amd.com> | ||
| 24382 | S: Maintained | ||
| 24383 | F: Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml | ||
| 24384 | F: drivers/nvmem/zynqmp_nvmem.c | ||
| 24385 | |||
| 24347 | XILLYBUS DRIVER | 24386 | XILLYBUS DRIVER |
| 24348 | M: Eli Billauer <eli.billauer@gmail.com> | 24387 | M: Eli Billauer <eli.billauer@gmail.com> |
| 24349 | L: linux-kernel@vger.kernel.org | 24388 | L: linux-kernel@vger.kernel.org |
| @@ -472,10 +472,6 @@ config X86_MPPARSE · 471 unmodified lines | |||
| 472 | For old smp systems that do not have proper acpi support. Newer systems | 472 | For old smp systems that do not have proper acpi support. Newer systems |
| 473 | (esp with 64bit cpus) with acpi support, MADT and DSDT will override it | 473 | (esp with 64bit cpus) with acpi support, MADT and DSDT will override it |
| 474 | 474 | ||
| 475 | config GOLDFISH | ||
| 476 | def_bool y | ||
| 477 | depends on X86_GOLDFISH | ||
| 478 | |||
| 479 | config X86_CPU_RESCTRL | 475 | config X86_CPU_RESCTRL |
| 480 | bool "x86 CPU resource control support" | 476 | bool "x86 CPU resource control support" |
| 481 | depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) | 477 | depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) |
| @@ -7,9 +7,10 @@ · 6 unmodified lines | |||
| 7 | #include "speakup.h" | 7 | #include "speakup.h" |
| 8 | #include "spk_priv.h" | 8 | #include "spk_priv.h" |
| 9 | 9 | ||
| 10 | static int misc_registered; | 10 | static int synth_registered, synthu_registered; |
| 11 | static int dev_opened; | 11 | static int dev_opened; |
| 12 | 12 | ||
| 13 | /* Latin1 version */ | ||
| 13 | static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, | 14 | static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, |
| 14 | size_t nbytes, loff_t *ppos) | 15 | size_t nbytes, loff_t *ppos) |
| 15 | { | 16 | { |
| @@ -34,6 +35,98 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, · 18 unmodified lines | |||
| 34 | return (ssize_t)nbytes; | 35 | return (ssize_t)nbytes; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | /* UTF-8 version */ | ||
| 39 | static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer, | ||
| 40 | size_t nbytes, loff_t *ppos) | ||
| 41 | { | ||
| 42 | size_t count = nbytes, want; | ||
| 43 | const char __user *ptr = buffer; | ||
| 44 | size_t bytes; | ||
| 45 | unsigned long flags; | ||
| 46 | unsigned char buf[256]; | ||
| 47 | u16 ubuf[256]; | ||
| 48 | size_t in, in2, out; | ||
| 49 | |||
| 50 | if (!synth) | ||
| 51 | return -ENODEV; | ||
| 52 | |||
| 53 | want = 1; | ||
| 54 | while (count >= want) { | ||
| 55 | /* Copy some UTF-8 piece from userland */ | ||
| 56 | bytes = min(count, sizeof(buf)); | ||
| 57 | if (copy_from_user(buf, ptr, bytes)) | ||
| 58 | return -EFAULT; | ||
| 59 | |||
| 60 | /* Convert to u16 */ | ||
| 61 | for (in = 0, out = 0; in < bytes; in++) { | ||
| 62 | unsigned char c = buf[in]; | ||
| 63 | int nbytes = 8 - fls(c ^ 0xff); | ||
| 64 | u32 value; | ||
| 65 | |||
| 66 | switch (nbytes) { | ||
| 67 | case 8: /* 0xff */ | ||
| 68 | case 7: /* 0xfe */ | ||
| 69 | case 1: /* 0x80 */ | ||
| 70 | /* Invalid, drop */ | ||
| 71 | goto drop; | ||
| 72 | |||
| 73 | case 0: | ||
| 74 | /* ASCII, copy */ | ||
| 75 | ubuf[out++] = c; | ||
| 76 | continue; | ||
| 77 | |||
| 78 | default: | ||
| 79 | /* 2..6-byte UTF-8 */ | ||
| 80 | |||
| 81 | if (bytes - in < nbytes) { | ||
| 82 | /* We don't have it all yet, stop here | ||
| 83 | * and wait for the rest | ||
| 84 | */ | ||
| 85 | bytes = in; | ||
| 86 | want = nbytes; | ||
| 87 | continue; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* First byte */ | ||
| 91 | value = c & ((1u << (7 - nbytes)) - 1); | ||
| 92 | |||
| 93 | /* Other bytes */ | ||
| 94 | for (in2 = 2; in2 <= nbytes; in2++) { | ||
| 95 | c = buf[in + 1]; | ||
| 96 | if ((c & 0xc0) != 0x80) { | ||
| 97 | /* Invalid, drop the head */ | ||
| 98 | want = 1; | ||
| 99 | goto drop; | ||
| 100 | } | ||
| 101 | value = (value << 6) | (c & 0x3f); | ||
| 102 | in++; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (value < 0x10000) | ||
| 106 | ubuf[out++] = value; | ||
| 107 | want = 1; | ||
| 108 | break; | ||
| 109 | } | ||
| 110 | drop: | ||
| 111 | /* empty statement */; | ||
| 112 | } | ||
| 113 | |||
| 114 | count -= bytes; | ||
| 115 | ptr += bytes; | ||
| 116 | |||
| 117 | /* And speak this up */ | ||
| 118 | if (out) { | ||
| 119 | spin_lock_irqsave(&speakup_info.spinlock, flags); | ||
| 120 | for (in = 0; in < out; in++) | ||
| 121 | synth_buffer_add(ubuf[in]); | ||
| 122 | synth_start(); | ||
| 123 | spin_unlock_irqrestore(&speakup_info.spinlock, flags); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | return (ssize_t)(nbytes - count); | ||
| 128 | } | ||
| 129 | |||
| 37 | static ssize_t speakup_file_read(struct file *fp, char __user *buf, | 130 | static ssize_t speakup_file_read(struct file *fp, char __user *buf, |
| 38 | size_t nbytes, loff_t *ppos) | 131 | size_t nbytes, loff_t *ppos) |
| 39 | { | 132 | { |
| @@ -62,31 +155,57 @@ static const struct file_operations synth_fops = { · 22 unmodified lines | |||
| 62 | .release = speakup_file_release, | 155 | .release = speakup_file_release, |
| 63 | }; | 156 | }; |
| 64 | 157 | ||
| 158 | static const struct file_operations synthu_fops = { | ||
| 159 | .read = speakup_file_read, | ||
| 160 | .write = speakup_file_writeu, | ||
| 161 | .open = speakup_file_open, | ||
| 162 | .release = speakup_file_release, | ||
| 163 | }; | ||
| 164 | |||
| 65 | static struct miscdevice synth_device = { | 165 | static struct miscdevice synth_device = { |
| 66 | .minor = MISC_DYNAMIC_MINOR, | 166 | .minor = MISC_DYNAMIC_MINOR, |
| 67 | .name = "synth", | 167 | .name = "synth", |
| 68 | .fops = &synth_fops, | 168 | .fops = &synth_fops, |
| 69 | }; | 169 | }; |
| 70 | 170 | ||
| 171 | static struct miscdevice synthu_device = { | ||
| 172 | .minor = MISC_DYNAMIC_MINOR, | ||
| 173 | .name = "synthu", | ||
| 174 | .fops = &synthu_fops, | ||
| 175 | }; | ||
| 176 | |||
| 71 | void speakup_register_devsynth(void) | 177 | void speakup_register_devsynth(void) |
| 72 | { | 178 | { |
| 73 | if (misc_registered != 0) | 179 | if (!synth_registered) { |
| 74 | return; | 180 | if (misc_register(&synth_device)) { |
| 75 | /* zero it so if register fails, deregister will not ref invalid ptrs */ | 181 | pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); |
| 76 | if (misc_register(&synth_device)) { | 182 | } else { |
| 77 | pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); | 183 | pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", |
| 78 | } else { | 184 | MISC_MAJOR, synth_device.minor); |
| 79 | pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", | 185 | synth_registered = 1; |
| 80 | MISC_MAJOR, synth_device.minor); | 186 | } |
| 81 | misc_registered = 1; | 187 | } |
| 188 | if (!synthu_registered) { | ||
| 189 | if (misc_register(&synthu_device)) { | ||
| 190 | pr_warn("Couldn't initialize miscdevice /dev/synthu.\n"); | ||
| 191 | } else { | ||
| 192 | pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n", | ||
| 193 | MISC_MAJOR, synthu_device.minor); | ||
| 194 | synthu_registered = 1; | ||
| 195 | } | ||
| 82 | } | 196 | } |
| 83 | } | 197 | } |
| 84 | 198 | ||
| 85 | void speakup_unregister_devsynth(void) | 199 | void speakup_unregister_devsynth(void) |
| 86 | { | 200 | { |
| 87 | if (!misc_registered) | 201 | if (synth_registered) { |
| 88 | return; | 202 | pr_info("speakup: unregistering synth device /dev/synth\n"); |
| 89 | pr_info("speakup: unregistering synth device /dev/synth\n"); | 203 | misc_deregister(&synth_device); |
| 90 | misc_deregister(&synth_device); | 204 | synth_registered = 0; |
| 91 | misc_registered = 0; | 205 | } |
| 206 | if (synthu_registered) { | ||
| 207 | pr_info("speakup: unregistering synth device /dev/synthu\n"); | ||
| 208 | misc_deregister(&synthu_device); | ||
| 209 | synthu_registered = 0; | ||
| 210 | } | ||
| 92 | } | 211 | } |
| @@ -208,8 +208,10 @@ void spk_do_flush(void) · 207 unmodified lines | |||
| 208 | wake_up_process(speakup_task); | 208 | wake_up_process(speakup_task); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | void synth_write(const char *buf, size_t count) | 211 | void synth_write(const char *_buf, size_t count) |
| 212 | { | 212 | { |
| 213 | const unsigned char *buf = (const unsigned char *) _buf; | ||
| 214 | |||
| 213 | while (count--) | 215 | while (count--) |
| 214 | synth_buffer_add(*buf++); | 216 | synth_buffer_add(*buf++); |
| 215 | synth_start(); | 217 | synth_start(); |
| @@ -925,7 +925,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) · 924 unmodified lines | |||
| 925 | int i; | 925 | int i; |
| 926 | 926 | ||
| 927 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | 927 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { |
| 928 | unsigned long page_addr; | ||
| 929 | bool on_lru; | 928 | bool on_lru; |
| 930 | 929 | ||
| 931 | if (!alloc->pages[i].page_ptr) | 930 | if (!alloc->pages[i].page_ptr) |
| @@ -933,7 +932,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) · 1 unmodified line | |||
| 933 | 932 | ||
| 934 | on_lru = list_lru_del_obj(&binder_freelist, | 933 | on_lru = list_lru_del_obj(&binder_freelist, |
| 935 | &alloc->pages[i].lru); | 934 | &alloc->pages[i].lru); |
| 936 | page_addr = alloc->buffer + i * PAGE_SIZE; | ||
| 937 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | 935 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, |
| 938 | "%s: %d: page %d %s\n", | 936 | "%s: %d: page %d %s\n", |
| 939 | __func__, alloc->pid, i, | 937 | __func__, alloc->pid, i, |
| @@ -297,30 +297,30 @@ struct mhi_ring_element { · 296 unmodified lines | |||
| 297 | __le32 dword[2]; | 297 | __le32 dword[2]; |
| 298 | }; | 298 | }; |
| 299 | 299 | ||
| 300 | #define MHI_STATE_LIST \ | ||
| 301 | mhi_state(RESET, "RESET") \ | ||
| 302 | mhi_state(READY, "READY") \ | ||
| 303 | mhi_state(M0, "M0") \ | ||
| 304 | mhi_state(M1, "M1") \ | ||
| 305 | mhi_state(M2, "M2") \ | ||
| 306 | mhi_state(M3, "M3") \ | ||
| 307 | mhi_state(M3_FAST, "M3_FAST") \ | ||
| 308 | mhi_state(BHI, "BHI") \ | ||
| 309 | mhi_state_end(SYS_ERR, "SYS ERROR") | ||
| 310 | |||
| 311 | #undef mhi_state | ||
| 312 | #undef mhi_state_end | ||
| 313 | |||
| 314 | #define mhi_state(a, b) case MHI_STATE_##a: return b; | ||
| 315 | #define mhi_state_end(a, b) case MHI_STATE_##a: return b; | ||
| 316 | |||
| 300 | static inline const char *mhi_state_str(enum mhi_state state) | 317 | static inline const char *mhi_state_str(enum mhi_state state) |
| 301 | { | 318 | { |
| 302 | switch (state) { | 319 | switch (state) { |
| 303 | case MHI_STATE_RESET: | 320 | MHI_STATE_LIST |
| 304 | return "RESET"; | ||
| 305 | case MHI_STATE_READY: | ||
| 306 | return "READY"; | ||
| 307 | case MHI_STATE_M0: | ||
| 308 | return "M0"; | ||
| 309 | case MHI_STATE_M1: | ||
| 310 | return "M1"; | ||
| 311 | case MHI_STATE_M2: | ||
| 312 | return "M2"; | ||
| 313 | case MHI_STATE_M3: | ||
| 314 | return "M3"; | ||
| 315 | case MHI_STATE_M3_FAST: | ||
| 316 | return "M3 FAST"; | ||
| 317 | case MHI_STATE_BHI: | ||
| 318 | return "BHI"; | ||
| 319 | case MHI_STATE_SYS_ERR: | ||
| 320 | return "SYS ERROR"; | ||
| 321 | default: | 321 | default: |
| 322 | return "Unknown state"; | 322 | return "Unknown state"; |
| 323 | } | 323 | } |
| 324 | }; | 324 | } |
| 325 | 325 | ||
| 326 | #endif /* _MHI_COMMON_H */ | 326 | #endif /* _MHI_COMMON_H */ |
| @@ -1149,8 +1149,9 @@ int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl) · 1148 unmodified lines | |||
| 1149 | mhi_ep_mmio_mask_interrupts(mhi_cntrl); | 1149 | mhi_ep_mmio_mask_interrupts(mhi_cntrl); |
| 1150 | mhi_ep_mmio_init(mhi_cntrl); | 1150 | mhi_ep_mmio_init(mhi_cntrl); |
| 1151 | 1151 | ||
| 1152 | mhi_cntrl->mhi_event = kzalloc(mhi_cntrl->event_rings * (sizeof(*mhi_cntrl->mhi_event)), | 1152 | mhi_cntrl->mhi_event = kcalloc(mhi_cntrl->event_rings, |
| 1153 | GFP_KERNEL); | 1153 | sizeof(*mhi_cntrl->mhi_event), |
| 1154 | GFP_KERNEL); | ||
| 1154 | if (!mhi_cntrl->mhi_event) | 1155 | if (!mhi_cntrl->mhi_event) |
| 1155 | return -ENOMEM; | 1156 | return -ENOMEM; |
| 1156 | 1157 | ||
| @@ -1496,7 +1497,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, · 339 unmodified lines | |||
| 1496 | mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", | 1497 | mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", |
| 1497 | sizeof(struct mhi_ep_ring_item), 0, | 1498 | sizeof(struct mhi_ep_ring_item), 0, |
| 1498 | 0, NULL); | 1499 | 0, NULL); |
| 1499 | if (!mhi_cntrl->ev_ring_el_cache) { | 1500 | if (!mhi_cntrl->ring_item_cache) { |
| 1500 | ret = -ENOMEM; | 1501 | ret = -ENOMEM; |
| 1501 | goto err_destroy_tre_buf_cache; | 1502 | goto err_destroy_tre_buf_cache; |
| 1502 | } | 1503 | } |
| @@ -395,7 +395,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) · 394 unmodified lines | |||
| 395 | void *buf; | 395 | void *buf; |
| 396 | dma_addr_t dma_addr; | 396 | dma_addr_t dma_addr; |
| 397 | size_t size, fw_sz; | 397 | size_t size, fw_sz; |
| 398 | int i, ret; | 398 | int ret; |
| 399 | 399 | ||
| 400 | if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { | 400 | if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { |
| 401 | dev_err(dev, "Device MHI is not in valid state\n"); | 401 | dev_err(dev, "Device MHI is not in valid state\n"); |
| @@ -408,15 +408,6 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) · 6 unmodified lines | |||
| 408 | if (ret) | 408 | if (ret) |
| 409 | dev_err(dev, "Could not capture serial number via BHI\n"); | 409 | dev_err(dev, "Could not capture serial number via BHI\n"); |
| 410 | 410 | ||
| 411 | for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) { | ||
| 412 | ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), | ||
| 413 | &mhi_cntrl->oem_pk_hash[i]); | ||
| 414 | if (ret) { | ||
| 415 | dev_err(dev, "Could not capture OEM PK HASH via BHI\n"); | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | /* wait for ready on pass through or any other execution environment */ | 411 | /* wait for ready on pass through or any other execution environment */ |
| 421 | if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee)) | 412 | if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee)) |
| 422 | goto fw_load_ready_state; | 413 | goto fw_load_ready_state; |
| @@ -20,50 +20,49 @@ · 19 unmodified lines | |||
| 20 | #include <linux/wait.h> | 20 | #include <linux/wait.h> |
| 21 | #include "internal.h" | 21 | #include "internal.h" |
| 22 | 22 | ||
| 23 | #define CREATE_TRACE_POINTS | ||
| 24 | #include "trace.h" | ||
| 25 | |||
| 23 | static DEFINE_IDA(mhi_controller_ida); | 26 | static DEFINE_IDA(mhi_controller_ida); |
| 24 | 27 | ||
| 28 | #undef mhi_ee | ||
| 29 | #undef mhi_ee_end | ||
| 30 | |||
| 31 | #define mhi_ee(a, b) [MHI_EE_##a] = b, | ||
| 32 | #define mhi_ee_end(a, b) [MHI_EE_##a] = b, | ||
| 33 | |||
| 25 | const char * const mhi_ee_str[MHI_EE_MAX] = { | 34 | const char * const mhi_ee_str[MHI_EE_MAX] = { |
| 26 | [MHI_EE_PBL] = "PRIMARY BOOTLOADER", | 35 | MHI_EE_LIST |
| 27 | [MHI_EE_SBL] = "SECONDARY BOOTLOADER", | ||
| 28 | [MHI_EE_AMSS] = "MISSION MODE", | ||
| 29 | [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE", | ||
| 30 | [MHI_EE_WFW] = "WLAN FIRMWARE", | ||
| 31 | [MHI_EE_PTHRU] = "PASS THROUGH", | ||
| 32 | [MHI_EE_EDL] = "EMERGENCY DOWNLOAD", | ||
| 33 | [MHI_EE_FP] = "FLASH PROGRAMMER", | ||
| 34 | [MHI_EE_DISABLE_TRANSITION] = "DISABLE", | ||
| 35 | [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", | ||
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | #undef dev_st_trans | ||
| 39 | #undef dev_st_trans_end | ||
| 40 | |||
| 41 | #define dev_st_trans(a, b) [DEV_ST_TRANSITION_##a] = b, | ||
| 42 | #define dev_st_trans_end(a, b) [DEV_ST_TRANSITION_##a] = b, | ||
| 43 | |||
| 38 | const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { | 44 | const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { |
| 39 | [DEV_ST_TRANSITION_PBL] = "PBL", | 45 | DEV_ST_TRANSITION_LIST |
| 40 | [DEV_ST_TRANSITION_READY] = "READY", | ||
| 41 | [DEV_ST_TRANSITION_SBL] = "SBL", | ||
| 42 | [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", | ||
| 43 | [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER", | ||
| 44 | [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR", | ||
| 45 | [DEV_ST_TRANSITION_DISABLE] = "DISABLE", | ||
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | #undef ch_state_type | ||
| 49 | #undef ch_state_type_end | ||
| 50 | |||
| 51 | #define ch_state_type(a, b) [MHI_CH_STATE_TYPE_##a] = b, | ||
| 52 | #define ch_state_type_end(a, b) [MHI_CH_STATE_TYPE_##a] = b, | ||
| 53 | |||
| 48 | const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { | 54 | const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { |
| 49 | [MHI_CH_STATE_TYPE_RESET] = "RESET", | 55 | MHI_CH_STATE_TYPE_LIST |
| 50 | [MHI_CH_STATE_TYPE_STOP] = "STOP", | ||
| 51 | [MHI_CH_STATE_TYPE_START] = "START", | ||
| 52 | }; | 56 | }; |
| 53 | 57 | ||
| 58 | #undef mhi_pm_state | ||
| 59 | #undef mhi_pm_state_end | ||
| 60 | |||
| 61 | #define mhi_pm_state(a, b) [MHI_PM_STATE_##a] = b, | ||
| 62 | #define mhi_pm_state_end(a, b) [MHI_PM_STATE_##a] = b, | ||
| 63 | |||
| 54 | static const char * const mhi_pm_state_str[] = { | 64 | static const char * const mhi_pm_state_str[] = { |
| 55 | [MHI_PM_STATE_DISABLE] = "DISABLE", | 65 | MHI_PM_STATE_LIST |
| 56 | [MHI_PM_STATE_POR] = "POWER ON RESET", | ||
| 57 | [MHI_PM_STATE_M0] = "M0", | ||
| 58 | [MHI_PM_STATE_M2] = "M2", | ||
| 59 | [MHI_PM_STATE_M3_ENTER] = "M?->M3", | ||
| 60 | [MHI_PM_STATE_M3] = "M3", | ||
| 61 | [MHI_PM_STATE_M3_EXIT] = "M3->M0", | ||
| 62 | [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", | ||
| 63 | [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", | ||
| 64 | [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", | ||
| 65 | [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", | ||
| 66 | [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", | ||
| 67 | }; | 66 | }; |
| 68 | 67 | ||
| 69 | const char *to_mhi_pm_state_str(u32 state) | 68 | const char *to_mhi_pm_state_str(u32 state) |
| @@ -97,11 +96,19 @@ static ssize_t oem_pk_hash_show(struct device *dev, · 27 unmodified lines | |||
| 97 | { | 96 | { |
| 98 | struct mhi_device *mhi_dev = to_mhi_device(dev); | 97 | struct mhi_device *mhi_dev = to_mhi_device(dev); |
| 99 | struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; | 98 | struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; |
| 100 | int i, cnt = 0; | 99 | u32 hash_segment[MHI_MAX_OEM_PK_HASH_SEGMENTS]; |
| 100 | int i, cnt = 0, ret; | ||
| 101 | 101 | ||
| 102 | for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) | 102 | for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) { |
| 103 | cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", | 103 | ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), &hash_segment[i]); |
| 104 | i, mhi_cntrl->oem_pk_hash[i]); | 104 | if (ret) { |
| 105 | dev_err(dev, "Could not capture OEM PK HASH\n"); | ||
| 106 | return ret; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) | ||
| 111 | cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", i, hash_segment[i]); | ||
| 105 | 112 | ||
| 106 | return cnt; | 113 | return cnt; |
| 107 | } | 114 | } |
| @@ -907,7 +914,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, · 799 unmodified lines | |||
| 907 | struct mhi_chan *mhi_chan; | 914 | struct mhi_chan *mhi_chan; |
| 908 | struct mhi_cmd *mhi_cmd; | 915 | struct mhi_cmd *mhi_cmd; |
| 909 | struct mhi_device *mhi_dev; | 916 | struct mhi_device *mhi_dev; |
| 910 | u32 soc_info; | ||
| 911 | int ret, i; | 917 | int ret, i; |
| 912 | 918 | ||
| 913 | if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || | 919 | if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || |
| @@ -982,17 +988,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, · 68 unmodified lines | |||
| 982 | mhi_cntrl->unmap_single = mhi_unmap_single_no_bb; | 988 | mhi_cntrl->unmap_single = mhi_unmap_single_no_bb; |
| 983 | } | 989 | } |
| 984 | 990 | ||
| 985 | /* Read the MHI device info */ | ||
| 986 | ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, | ||
| 987 | SOC_HW_VERSION_OFFS, &soc_info); | ||
| 988 | if (ret) | ||
| 989 | goto err_destroy_wq; | ||
| 990 | |||
| 991 | mhi_cntrl->family_number = FIELD_GET(SOC_HW_VERSION_FAM_NUM_BMSK, soc_info); | ||
| 992 | mhi_cntrl->device_number = FIELD_GET(SOC_HW_VERSION_DEV_NUM_BMSK, soc_info); | ||
| 993 | mhi_cntrl->major_version = FIELD_GET(SOC_HW_VERSION_MAJOR_VER_BMSK, soc_info); | ||
| 994 | mhi_cntrl->minor_version = FIELD_GET(SOC_HW_VERSION_MINOR_VER_BMSK, soc_info); | ||
| 995 | |||
| 996 | mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL); | 991 | mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL); |
| 997 | if (mhi_cntrl->index < 0) { | 992 | if (mhi_cntrl->index < 0) { |
| 998 | ret = mhi_cntrl->index; | 993 | ret = mhi_cntrl->index; |
| @@ -15,12 +15,6 @@ extern struct bus_type mhi_bus_type; · 14 unmodified lines | |||
| 15 | #define MHI_SOC_RESET_REQ_OFFSET 0xb0 | 15 | #define MHI_SOC_RESET_REQ_OFFSET 0xb0 |
| 16 | #define MHI_SOC_RESET_REQ BIT(0) | 16 | #define MHI_SOC_RESET_REQ BIT(0) |
| 17 | 17 | ||
| 18 | #define SOC_HW_VERSION_OFFS 0x224 | ||
| 19 | #define SOC_HW_VERSION_FAM_NUM_BMSK GENMASK(31, 28) | ||
| 20 | #define SOC_HW_VERSION_DEV_NUM_BMSK GENMASK(27, 16) | ||
| 21 | #define SOC_HW_VERSION_MAJOR_VER_BMSK GENMASK(15, 8) | ||
| 22 | #define SOC_HW_VERSION_MINOR_VER_BMSK GENMASK(7, 0) | ||
| 23 | |||
| 24 | struct mhi_ctxt { | 18 | struct mhi_ctxt { |
| 25 | struct mhi_event_ctxt *er_ctxt; | 19 | struct mhi_event_ctxt *er_ctxt; |
| 26 | struct mhi_chan_ctxt *chan_ctxt; | 20 | struct mhi_chan_ctxt *chan_ctxt; |
| @@ -42,6 +36,11 @@ enum mhi_ch_state_type { · 15 unmodified lines | |||
| 42 | MHI_CH_STATE_TYPE_MAX, | 36 | MHI_CH_STATE_TYPE_MAX, |
| 43 | }; | 37 | }; |
| 44 | 38 | ||
| 39 | #define MHI_CH_STATE_TYPE_LIST \ | ||
| 40 | ch_state_type(RESET, "RESET") \ | ||
| 41 | ch_state_type(STOP, "STOP") \ | ||
| 42 | ch_state_type_end(START, "START") | ||
| 43 | |||
| 45 | extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; | 44 | extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; |
| 46 | #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ | 45 | #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ |
| 47 | "INVALID_STATE" : \ | 46 | "INVALID_STATE" : \ |
| @@ -50,6 +49,18 @@ extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; · 2 unmodified lines | |||
| 50 | #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ | 49 | #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ |
| 51 | mode != MHI_DB_BRST_ENABLE) | 50 | mode != MHI_DB_BRST_ENABLE) |
| 52 | 51 | ||
| 52 | #define MHI_EE_LIST \ | ||
| 53 | mhi_ee(PBL, "PRIMARY BOOTLOADER") \ | ||
| 54 | mhi_ee(SBL, "SECONDARY BOOTLOADER") \ | ||
| 55 | mhi_ee(AMSS, "MISSION MODE") \ | ||
| 56 | mhi_ee(RDDM, "RAMDUMP DOWNLOAD MODE")\ | ||
| 57 | mhi_ee(WFW, "WLAN FIRMWARE") \ | ||
| 58 | mhi_ee(PTHRU, "PASS THROUGH") \ | ||
| 59 | mhi_ee(EDL, "EMERGENCY DOWNLOAD") \ | ||
| 60 | mhi_ee(FP, "FLASH PROGRAMMER") \ | ||
| 61 | mhi_ee(DISABLE_TRANSITION, "DISABLE") \ | ||
| 62 | mhi_ee_end(NOT_SUPPORTED, "NOT SUPPORTED") | ||
| 63 | |||
| 53 | extern const char * const mhi_ee_str[MHI_EE_MAX]; | 64 | extern const char * const mhi_ee_str[MHI_EE_MAX]; |
| 54 | #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ | 65 | #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ |
| 55 | "INVALID_EE" : mhi_ee_str[ee]) | 66 | "INVALID_EE" : mhi_ee_str[ee]) |
| @@ -72,6 +83,15 @@ enum dev_st_transition { · 16 unmodified lines | |||
| 72 | DEV_ST_TRANSITION_MAX, | 83 | DEV_ST_TRANSITION_MAX, |
| 73 | }; | 84 | }; |
| 74 | 85 | ||
| 86 | #define DEV_ST_TRANSITION_LIST \ | ||
| 87 | dev_st_trans(PBL, "PBL") \ | ||
| 88 | dev_st_trans(READY, "READY") \ | ||
| 89 | dev_st_trans(SBL, "SBL") \ | ||
| 90 | dev_st_trans(MISSION_MODE, "MISSION MODE") \ | ||
| 91 | dev_st_trans(FP, "FLASH PROGRAMMER") \ | ||
| 92 | dev_st_trans(SYS_ERR, "SYS ERROR") \ | ||
| 93 | dev_st_trans_end(DISABLE, "DISABLE") | ||
| 94 | |||
| 75 | extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX]; | 95 | extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX]; |
| 76 | #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \ | 96 | #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \ |
| 77 | "INVALID_STATE" : dev_state_tran_str[state]) | 97 | "INVALID_STATE" : dev_state_tran_str[state]) |
| @@ -88,11 +108,27 @@ enum mhi_pm_state { · 10 unmodified lines | |||
| 88 | MHI_PM_STATE_FW_DL_ERR, | 108 | MHI_PM_STATE_FW_DL_ERR, |
| 89 | MHI_PM_STATE_SYS_ERR_DETECT, | 109 | MHI_PM_STATE_SYS_ERR_DETECT, |
| 90 | MHI_PM_STATE_SYS_ERR_PROCESS, | 110 | MHI_PM_STATE_SYS_ERR_PROCESS, |
| 111 | MHI_PM_STATE_SYS_ERR_FAIL, | ||
| 91 | MHI_PM_STATE_SHUTDOWN_PROCESS, | 112 | MHI_PM_STATE_SHUTDOWN_PROCESS, |
| 92 | MHI_PM_STATE_LD_ERR_FATAL_DETECT, | 113 | MHI_PM_STATE_LD_ERR_FATAL_DETECT, |
| 93 | MHI_PM_STATE_MAX | 114 | MHI_PM_STATE_MAX |
| 94 | }; | 115 | }; |
| 95 | 116 | ||
| 117 | #define MHI_PM_STATE_LIST \ | ||
| 118 | mhi_pm_state(DISABLE, "DISABLE") \ | ||
| 119 | mhi_pm_state(POR, "POWER ON RESET") \ | ||
| 120 | mhi_pm_state(M0, "M0") \ | ||
| 121 | mhi_pm_state(M2, "M2") \ | ||
| 122 | mhi_pm_state(M3_ENTER, "M?->M3") \ | ||
| 123 | mhi_pm_state(M3, "M3") \ | ||
| 124 | mhi_pm_state(M3_EXIT, "M3->M0") \ | ||
| 125 | mhi_pm_state(FW_DL_ERR, "Firmware Download Error") \ | ||
| 126 | mhi_pm_state(SYS_ERR_DETECT, "SYS ERROR Detect") \ | ||
| 127 | mhi_pm_state(SYS_ERR_PROCESS, "SYS ERROR Process") \ | ||
| 128 | mhi_pm_state(SYS_ERR_FAIL, "SYS ERROR Failure") \ | ||
| 129 | mhi_pm_state(SHUTDOWN_PROCESS, "SHUTDOWN Process") \ | ||
| 130 | mhi_pm_state_end(LD_ERR_FATAL_DETECT, "Linkdown or Error Fatal Detect") | ||
| 131 | |||
| 96 | #define MHI_PM_DISABLE BIT(0) | 132 | #define MHI_PM_DISABLE BIT(0) |
| 97 | #define MHI_PM_POR BIT(1) | 133 | #define MHI_PM_POR BIT(1) |
| 98 | #define MHI_PM_M0 BIT(2) | 134 | #define MHI_PM_M0 BIT(2) |
| @@ -104,14 +140,16 @@ enum mhi_pm_state { · 5 unmodified lines | |||
| 104 | #define MHI_PM_FW_DL_ERR BIT(7) | 140 | #define MHI_PM_FW_DL_ERR BIT(7) |
| 105 | #define MHI_PM_SYS_ERR_DETECT BIT(8) | 141 | #define MHI_PM_SYS_ERR_DETECT BIT(8) |
| 106 | #define MHI_PM_SYS_ERR_PROCESS BIT(9) | 142 | #define MHI_PM_SYS_ERR_PROCESS BIT(9) |
| 107 | #define MHI_PM_SHUTDOWN_PROCESS BIT(10) | 143 | #define MHI_PM_SYS_ERR_FAIL BIT(10) |
| 144 | #define MHI_PM_SHUTDOWN_PROCESS BIT(11) | ||
| 108 | /* link not accessible */ | 145 | /* link not accessible */ |
| 109 | #define MHI_PM_LD_ERR_FATAL_DETECT BIT(11) | 146 | #define MHI_PM_LD_ERR_FATAL_DETECT BIT(12) |
| 110 | 147 | ||
| 111 | #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ | 148 | #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ |
| 112 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ | 149 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ |
| 113 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ | 150 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ |
| 114 | MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) | 151 | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | \ |
| 152 | MHI_PM_FW_DL_ERR))) | ||
| 115 | #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) | 153 | #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) |
| 116 | #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT) | 154 | #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT) |
| 117 | #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access) | 155 | #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access) |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include "internal.h" | 17 | #include "internal.h" |
| 18 | #include "trace.h" | ||
| 18 | 19 | ||
| 19 | int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, | 20 | int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, |
| 20 | void __iomem *base, u32 offset, u32 *out) | 21 | void __iomem *base, u32 offset, u32 *out) |
| @@ -493,11 +494,8 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) · 472 unmodified lines | |||
| 493 | 494 | ||
| 494 | state = mhi_get_mhi_state(mhi_cntrl); | 495 | state = mhi_get_mhi_state(mhi_cntrl); |
| 495 | ee = mhi_get_exec_env(mhi_cntrl); | 496 | ee = mhi_get_exec_env(mhi_cntrl); |
| 496 | dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n", | ||
| 497 | TO_MHI_EXEC_STR(mhi_cntrl->ee), | ||
| 498 | mhi_state_str(mhi_cntrl->dev_state), | ||
| 499 | TO_MHI_EXEC_STR(ee), mhi_state_str(state)); | ||
| 500 | 497 | ||
| 498 | trace_mhi_intvec_states(mhi_cntrl, ee, state); | ||
| 501 | if (state == MHI_STATE_SYS_ERR) { | 499 | if (state == MHI_STATE_SYS_ERR) { |
| 502 | dev_dbg(dev, "System error detected\n"); | 500 | dev_dbg(dev, "System error detected\n"); |
| 503 | pm_state = mhi_tryset_pm_state(mhi_cntrl, | 501 | pm_state = mhi_tryset_pm_state(mhi_cntrl, |
| @@ -838,6 +836,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, · 334 unmodified lines | |||
| 838 | while (dev_rp != local_rp) { | 836 | while (dev_rp != local_rp) { |
| 839 | enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | 837 | enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); |
| 840 | 838 | ||
| 839 | trace_mhi_ctrl_event(mhi_cntrl, local_rp); | ||
| 840 | |||
| 841 | switch (type) { | 841 | switch (type) { |
| 842 | case MHI_PKT_TYPE_BW_REQ_EVENT: | 842 | case MHI_PKT_TYPE_BW_REQ_EVENT: |
| 843 | { | 843 | { |
| @@ -1003,6 +1003,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, · 159 unmodified lines | |||
| 1003 | while (dev_rp != local_rp && event_quota > 0) { | 1003 | while (dev_rp != local_rp && event_quota > 0) { |
| 1004 | enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | 1004 | enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); |
| 1005 | 1005 | ||
| 1006 | trace_mhi_data_event(mhi_cntrl, local_rp); | ||
| 1007 | |||
| 1006 | chan = MHI_TRE_GET_EV_CHID(local_rp); | 1008 | chan = MHI_TRE_GET_EV_CHID(local_rp); |
| 1007 | 1009 | ||
| 1008 | WARN_ON(chan >= mhi_cntrl->max_chan); | 1010 | WARN_ON(chan >= mhi_cntrl->max_chan); |
| @@ -1243,6 +1245,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, · 234 unmodified lines | |||
| 1243 | mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len); | 1245 | mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len); |
| 1244 | mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain); | 1246 | mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain); |
| 1245 | 1247 | ||
| 1248 | trace_mhi_gen_tre(mhi_cntrl, mhi_chan, mhi_tre); | ||
| 1246 | /* increment WP */ | 1249 | /* increment WP */ |
| 1247 | mhi_add_ring_element(mhi_cntrl, tre_ring); | 1250 | mhi_add_ring_element(mhi_cntrl, tre_ring); |
| 1248 | mhi_add_ring_element(mhi_cntrl, buf_ring); | 1251 | mhi_add_ring_element(mhi_cntrl, buf_ring); |
| @@ -1337,9 +1340,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, · 88 unmodified lines | |||
| 1337 | enum mhi_cmd_type cmd = MHI_CMD_NOP; | 1340 | enum mhi_cmd_type cmd = MHI_CMD_NOP; |
| 1338 | int ret; | 1341 | int ret; |
| 1339 | 1342 | ||
| 1340 | dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan, | 1343 | trace_mhi_channel_command_start(mhi_cntrl, mhi_chan, to_state, TPS("Updating")); |
| 1341 | TO_CH_STATE_TYPE_STR(to_state)); | ||
| 1342 | |||
| 1343 | switch (to_state) { | 1344 | switch (to_state) { |
| 1344 | case MHI_CH_STATE_TYPE_RESET: | 1345 | case MHI_CH_STATE_TYPE_RESET: |
| 1345 | write_lock_irq(&mhi_chan->lock); | 1346 | write_lock_irq(&mhi_chan->lock); |
| @@ -1406,9 +1407,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, · 60 unmodified lines | |||
| 1406 | write_unlock_irq(&mhi_chan->lock); | 1407 | write_unlock_irq(&mhi_chan->lock); |
| 1407 | } | 1408 | } |
| 1408 | 1409 | ||
| 1409 | dev_dbg(dev, "%d: Channel state change to %s successful\n", | 1410 | trace_mhi_channel_command_end(mhi_cntrl, mhi_chan, to_state, TPS("Updated")); |
| 1410 | mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); | ||
| 1411 | |||
| 1412 | exit_channel_update: | 1411 | exit_channel_update: |
| 1413 | mhi_cntrl->runtime_put(mhi_cntrl); | 1412 | mhi_cntrl->runtime_put(mhi_cntrl); |
| 1414 | mhi_device_put(mhi_cntrl->mhi_dev); | 1413 | mhi_device_put(mhi_cntrl->mhi_dev); |
| @@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = { · 537 unmodified lines | |||
| 538 | MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) | 538 | MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) |
| 539 | }; | 539 | }; |
| 540 | 540 | ||
| 541 | static struct mhi_controller_config modem_telit_fn980_hw_v1_config = { | 541 | static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = { |
| 542 | .max_channels = 128, | 542 | .max_channels = 128, |
| 543 | .timeout_ms = 20000, | 543 | .timeout_ms = 20000, |
| 544 | .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), | 544 | .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
| 17 | #include "internal.h" | 17 | #include "internal.h" |
| 18 | #include "trace.h" | ||
| 18 | 19 | ||
| 19 | /* | 20 | /* |
| 20 | * Not all MHI state transitions are synchronous. Transitions like Linkdown, | 21 | * Not all MHI state transitions are synchronous. Transitions like Linkdown, |
| @@ -36,7 +37,10 @@ · 15 unmodified lines | |||
| 36 | * M0 <--> M0 | 37 | * M0 <--> M0 |
| 37 | * M0 -> FW_DL_ERR | 38 | * M0 -> FW_DL_ERR |
| 38 | * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 | 39 | * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 |
| 39 | * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR | 40 | * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS |
| 41 | * SYS_ERR_PROCESS -> SYS_ERR_FAIL | ||
| 42 | * SYS_ERR_FAIL -> SYS_ERR_DETECT | ||
| 43 | * SYS_ERR_PROCESS --> POR | ||
| 40 | * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT | 44 | * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT |
| 41 | * SHUTDOWN_PROCESS -> DISABLE | 45 | * SHUTDOWN_PROCESS -> DISABLE |
| 42 | * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT | 46 | * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT |
| @@ -93,7 +97,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = { · 50 unmodified lines | |||
| 93 | }, | 97 | }, |
| 94 | { | 98 | { |
| 95 | MHI_PM_SYS_ERR_PROCESS, | 99 | MHI_PM_SYS_ERR_PROCESS, |
| 96 | MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS | | 100 | MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | |
| 101 | MHI_PM_LD_ERR_FATAL_DETECT | ||
| 102 | }, | ||
| 103 | { | ||
| 104 | MHI_PM_SYS_ERR_FAIL, | ||
| 105 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | | ||
| 97 | MHI_PM_LD_ERR_FATAL_DETECT | 106 | MHI_PM_LD_ERR_FATAL_DETECT |
| 98 | }, | 107 | }, |
| 99 | /* L2 States */ | 108 | /* L2 States */ |
| @@ -123,6 +132,7 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn · 23 unmodified lines | |||
| 123 | if (unlikely(!(dev_state_transitions[index].to_states & state))) | 132 | if (unlikely(!(dev_state_transitions[index].to_states & state))) |
| 124 | return cur_state; | 133 | return cur_state; |
| 125 | 134 | ||
| 135 | trace_mhi_tryset_pm_state(mhi_cntrl, state); | ||
| 126 | mhi_cntrl->pm_state = state; | 136 | mhi_cntrl->pm_state = state; |
| 127 | return mhi_cntrl->pm_state; | 137 | return mhi_cntrl->pm_state; |
| 128 | } | 138 | } |
| @@ -629,7 +639,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) · 500 unmodified lines | |||
| 629 | !in_reset, timeout); | 639 | !in_reset, timeout); |
| 630 | if (!ret || in_reset) { | 640 | if (!ret || in_reset) { |
| 631 | dev_err(dev, "Device failed to exit MHI Reset state\n"); | 641 | dev_err(dev, "Device failed to exit MHI Reset state\n"); |
| 632 | goto exit_sys_error_transition; | 642 | write_lock_irq(&mhi_cntrl->pm_lock); |
| 643 | cur_state = mhi_tryset_pm_state(mhi_cntrl, | ||
| 644 | MHI_PM_SYS_ERR_FAIL); | ||
| 645 | write_unlock_irq(&mhi_cntrl->pm_lock); | ||
| 646 | /* Shutdown may have occurred, otherwise cleanup now */ | ||
| 647 | if (cur_state != MHI_PM_SYS_ERR_FAIL) | ||
| 648 | goto exit_sys_error_transition; | ||
| 633 | } | 649 | } |
| 634 | 650 | ||
| 635 | /* | 651 | /* |
| @@ -758,7 +774,6 @@ void mhi_pm_st_worker(struct work_struct *work) · 122 unmodified lines | |||
| 758 | struct mhi_controller *mhi_cntrl = container_of(work, | 774 | struct mhi_controller *mhi_cntrl = container_of(work, |
| 759 | struct mhi_controller, | 775 | struct mhi_controller, |
| 760 | st_worker); | 776 | st_worker); |
| 761 | struct device *dev = &mhi_cntrl->mhi_dev->dev; | ||
| 762 | 777 | ||
| 763 | spin_lock_irq(&mhi_cntrl->transition_lock); | 778 | spin_lock_irq(&mhi_cntrl->transition_lock); |
| 764 | list_splice_tail_init(&mhi_cntrl->transition_list, &head); | 779 | list_splice_tail_init(&mhi_cntrl->transition_list, &head); |
| @@ -766,8 +781,8 @@ void mhi_pm_st_worker(struct work_struct *work) · 1 unmodified line | |||
| 766 | 781 | ||
| 767 | list_for_each_entry_safe(itr, tmp, &head, node) { | 782 | list_for_each_entry_safe(itr, tmp, &head, node) { |
| 768 | list_del(&itr->node); | 783 | list_del(&itr->node); |
| 769 | dev_dbg(dev, "Handling state transition: %s\n", | 784 | |
| 770 | TO_DEV_STATE_TRANS_STR(itr->state)); | 785 | trace_mhi_pm_st_transition(mhi_cntrl, itr->state); |
| 771 | 786 | ||
| 772 | switch (itr->state) { | 787 | switch (itr->state) { |
| 773 | case DEV_ST_TRANSITION_PBL: | 788 | case DEV_ST_TRANSITION_PBL: |
| @@ -0,0 +1,282 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #undef TRACE_SYSTEM | ||
| 7 | #define TRACE_SYSTEM mhi_host | ||
| 8 | |||
| 9 | #if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 10 | #define _TRACE_EVENT_MHI_HOST_H | ||
| 11 | |||
| 12 | #include <linux/tracepoint.h> | ||
| 13 | #include <linux/trace_seq.h> | ||
| 14 | #include "../common.h" | ||
| 15 | #include "internal.h" | ||
| 16 | |||
| 17 | #undef mhi_state | ||
| 18 | #undef mhi_state_end | ||
| 19 | |||
| 20 | #define mhi_state(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a); | ||
| 21 | #define mhi_state_end(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a); | ||
| 22 | |||
| 23 | MHI_STATE_LIST | ||
| 24 | |||
| 25 | #undef mhi_state | ||
| 26 | #undef mhi_state_end | ||
| 27 | |||
| 28 | #define mhi_state(a, b) { MHI_STATE_##a, b }, | ||
| 29 | #define mhi_state_end(a, b) { MHI_STATE_##a, b } | ||
| 30 | |||
| 31 | #undef mhi_pm_state | ||
| 32 | #undef mhi_pm_state_end | ||
| 33 | |||
| 34 | #define mhi_pm_state(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); | ||
| 35 | #define mhi_pm_state_end(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); | ||
| 36 | |||
| 37 | MHI_PM_STATE_LIST | ||
| 38 | |||
| 39 | #undef mhi_pm_state | ||
| 40 | #undef mhi_pm_state_end | ||
| 41 | |||
| 42 | #define mhi_pm_state(a, b) { MHI_PM_STATE_##a, b }, | ||
| 43 | #define mhi_pm_state_end(a, b) { MHI_PM_STATE_##a, b } | ||
| 44 | |||
| 45 | #undef mhi_ee | ||
| 46 | #undef mhi_ee_end | ||
| 47 | |||
| 48 | #define mhi_ee(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a); | ||
| 49 | #define mhi_ee_end(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a); | ||
| 50 | |||
| 51 | MHI_EE_LIST | ||
| 52 | |||
| 53 | #undef mhi_ee | ||
| 54 | #undef mhi_ee_end | ||
| 55 | |||
| 56 | #define mhi_ee(a, b) { MHI_EE_##a, b }, | ||
| 57 | #define mhi_ee_end(a, b) { MHI_EE_##a, b } | ||
| 58 | |||
| 59 | #undef ch_state_type | ||
| 60 | #undef ch_state_type_end | ||
| 61 | |||
| 62 | #define ch_state_type(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); | ||
| 63 | #define ch_state_type_end(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); | ||
| 64 | |||
| 65 | MHI_CH_STATE_TYPE_LIST | ||
| 66 | |||
| 67 | #undef ch_state_type | ||
| 68 | #undef ch_state_type_end | ||
| 69 | |||
| 70 | #define ch_state_type(a, b) { MHI_CH_STATE_TYPE_##a, b }, | ||
| 71 | #define ch_state_type_end(a, b) { MHI_CH_STATE_TYPE_##a, b } | ||
| 72 | |||
| 73 | #undef dev_st_trans | ||
| 74 | #undef dev_st_trans_end | ||
| 75 | |||
| 76 | #define dev_st_trans(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); | ||
| 77 | #define dev_st_trans_end(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); | ||
| 78 | |||
| 79 | DEV_ST_TRANSITION_LIST | ||
| 80 | |||
| 81 | #undef dev_st_trans | ||
| 82 | #undef dev_st_trans_end | ||
| 83 | |||
| 84 | #define dev_st_trans(a, b) { DEV_ST_TRANSITION_##a, b }, | ||
| 85 | #define dev_st_trans_end(a, b) { DEV_ST_TRANSITION_##a, b } | ||
| 86 | |||
| 87 | #define TPS(x) tracepoint_string(x) | ||
| 88 | |||
| 89 | TRACE_EVENT(mhi_gen_tre, | ||
| 90 | |||
| 91 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, | ||
| 92 | struct mhi_ring_element *mhi_tre), | ||
| 93 | |||
| 94 | TP_ARGS(mhi_cntrl, mhi_chan, mhi_tre), | ||
| 95 | |||
| 96 | TP_STRUCT__entry( | ||
| 97 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 98 | __field(int, ch_num) | ||
| 99 | __field(void *, wp) | ||
| 100 | __field(__le64, tre_ptr) | ||
| 101 | __field(__le32, dword0) | ||
| 102 | __field(__le32, dword1) | ||
| 103 | ), | ||
| 104 | |||
| 105 | TP_fast_assign( | ||
| 106 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 107 | __entry->ch_num = mhi_chan->chan; | ||
| 108 | __entry->wp = mhi_tre; | ||
| 109 | __entry->tre_ptr = mhi_tre->ptr; | ||
| 110 | __entry->dword0 = mhi_tre->dword[0]; | ||
| 111 | __entry->dword1 = mhi_tre->dword[1]; | ||
| 112 | ), | ||
| 113 | |||
| 114 | TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n", | ||
| 115 | __get_str(name), __entry->ch_num, __entry->wp, __entry->tre_ptr, | ||
| 116 | __entry->dword0, __entry->dword1) | ||
| 117 | ); | ||
| 118 | |||
| 119 | TRACE_EVENT(mhi_intvec_states, | ||
| 120 | |||
| 121 | TP_PROTO(struct mhi_controller *mhi_cntrl, int dev_ee, int dev_state), | ||
| 122 | |||
| 123 | TP_ARGS(mhi_cntrl, dev_ee, dev_state), | ||
| 124 | |||
| 125 | TP_STRUCT__entry( | ||
| 126 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 127 | __field(int, local_ee) | ||
| 128 | __field(int, state) | ||
| 129 | __field(int, dev_ee) | ||
| 130 | __field(int, dev_state) | ||
| 131 | ), | ||
| 132 | |||
| 133 | TP_fast_assign( | ||
| 134 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 135 | __entry->local_ee = mhi_cntrl->ee; | ||
| 136 | __entry->state = mhi_cntrl->dev_state; | ||
| 137 | __entry->dev_ee = dev_ee; | ||
| 138 | __entry->dev_state = dev_state; | ||
| 139 | ), | ||
| 140 | |||
| 141 | TP_printk("%s: Local EE: %s State: %s Device EE: %s Dev State: %s\n", | ||
| 142 | __get_str(name), | ||
| 143 | __print_symbolic(__entry->local_ee, MHI_EE_LIST), | ||
| 144 | __print_symbolic(__entry->state, MHI_STATE_LIST), | ||
| 145 | __print_symbolic(__entry->dev_ee, MHI_EE_LIST), | ||
| 146 | __print_symbolic(__entry->dev_state, MHI_STATE_LIST)) | ||
| 147 | ); | ||
| 148 | |||
| 149 | TRACE_EVENT(mhi_tryset_pm_state, | ||
| 150 | |||
| 151 | TP_PROTO(struct mhi_controller *mhi_cntrl, int pm_state), | ||
| 152 | |||
| 153 | TP_ARGS(mhi_cntrl, pm_state), | ||
| 154 | |||
| 155 | TP_STRUCT__entry( | ||
| 156 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 157 | __field(int, pm_state) | ||
| 158 | ), | ||
| 159 | |||
| 160 | TP_fast_assign( | ||
| 161 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 162 | if (pm_state) | ||
| 163 | pm_state = __fls(pm_state); | ||
| 164 | __entry->pm_state = pm_state; | ||
| 165 | ), | ||
| 166 | |||
| 167 | TP_printk("%s: PM state: %s\n", __get_str(name), | ||
| 168 | __print_symbolic(__entry->pm_state, MHI_PM_STATE_LIST)) | ||
| 169 | ); | ||
| 170 | |||
| 171 | DECLARE_EVENT_CLASS(mhi_process_event_ring, | ||
| 172 | |||
| 173 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||
| 174 | |||
| 175 | TP_ARGS(mhi_cntrl, rp), | ||
| 176 | |||
| 177 | TP_STRUCT__entry( | ||
| 178 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 179 | __field(__le32, dword0) | ||
| 180 | __field(__le32, dword1) | ||
| 181 | __field(int, state) | ||
| 182 | __field(__le64, ptr) | ||
| 183 | __field(void *, rp) | ||
| 184 | ), | ||
| 185 | |||
| 186 | TP_fast_assign( | ||
| 187 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 188 | __entry->rp = rp; | ||
| 189 | __entry->ptr = rp->ptr; | ||
| 190 | __entry->dword0 = rp->dword[0]; | ||
| 191 | __entry->dword1 = rp->dword[1]; | ||
| 192 | __entry->state = MHI_TRE_GET_EV_STATE(rp); | ||
| 193 | ), | ||
| 194 | |||
| 195 | TP_printk("%s: TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x State: %s\n", | ||
| 196 | __get_str(name), __entry->rp, __entry->ptr, __entry->dword0, | ||
| 197 | __entry->dword1, __print_symbolic(__entry->state, MHI_STATE_LIST)) | ||
| 198 | ); | ||
| 199 | |||
| 200 | DEFINE_EVENT(mhi_process_event_ring, mhi_data_event, | ||
| 201 | |||
| 202 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||
| 203 | |||
| 204 | TP_ARGS(mhi_cntrl, rp) | ||
| 205 | ); | ||
| 206 | |||
| 207 | DEFINE_EVENT(mhi_process_event_ring, mhi_ctrl_event, | ||
| 208 | |||
| 209 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||
| 210 | |||
| 211 | TP_ARGS(mhi_cntrl, rp) | ||
| 212 | ); | ||
| 213 | |||
| 214 | DECLARE_EVENT_CLASS(mhi_update_channel_state, | ||
| 215 | |||
| 216 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||
| 217 | const char *reason), | ||
| 218 | |||
| 219 | TP_ARGS(mhi_cntrl, mhi_chan, state, reason), | ||
| 220 | |||
| 221 | TP_STRUCT__entry( | ||
| 222 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 223 | __field(int, ch_num) | ||
| 224 | __field(int, state) | ||
| 225 | __field(const char *, reason) | ||
| 226 | ), | ||
| 227 | |||
| 228 | TP_fast_assign( | ||
| 229 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 230 | __entry->ch_num = mhi_chan->chan; | ||
| 231 | __entry->state = state; | ||
| 232 | __entry->reason = reason; | ||
| 233 | ), | ||
| 234 | |||
| 235 | TP_printk("%s: chan%d: %s state to: %s\n", | ||
| 236 | __get_str(name), __entry->ch_num, __entry->reason, | ||
| 237 | __print_symbolic(__entry->state, MHI_CH_STATE_TYPE_LIST)) | ||
| 238 | ); | ||
| 239 | |||
| 240 | DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_start, | ||
| 241 | |||
| 242 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||
| 243 | const char *reason), | ||
| 244 | |||
| 245 | TP_ARGS(mhi_cntrl, mhi_chan, state, reason) | ||
| 246 | ); | ||
| 247 | |||
| 248 | DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_end, | ||
| 249 | |||
| 250 | TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||
| 251 | const char *reason), | ||
| 252 | |||
| 253 | TP_ARGS(mhi_cntrl, mhi_chan, state, reason) | ||
| 254 | ); | ||
| 255 | |||
| 256 | TRACE_EVENT(mhi_pm_st_transition, | ||
| 257 | |||
| 258 | TP_PROTO(struct mhi_controller *mhi_cntrl, int state), | ||
| 259 | |||
| 260 | TP_ARGS(mhi_cntrl, state), | ||
| 261 | |||
| 262 | TP_STRUCT__entry( | ||
| 263 | __string(name, mhi_cntrl->mhi_dev->name) | ||
| 264 | __field(int, state) | ||
| 265 | ), | ||
| 266 | |||
| 267 | TP_fast_assign( | ||
| 268 | __assign_str(name, mhi_cntrl->mhi_dev->name); | ||
| 269 | __entry->state = state; | ||
| 270 | ), | ||
| 271 | |||
| 272 | TP_printk("%s: Handling state transition: %s\n", __get_str(name), | ||
| 273 | __print_symbolic(__entry->state, DEV_ST_TRANSITION_LIST)) | ||
| 274 | ); | ||
| 275 | |||
| 276 | #endif | ||
| 277 | #undef TRACE_INCLUDE_PATH | ||
| 278 | #define TRACE_INCLUDE_PATH ../../drivers/bus/mhi/host | ||
| 279 | #undef TRACE_INCLUDE_FILE | ||
| 280 | #define TRACE_INCLUDE_FILE trace | ||
| 281 | |||
| 282 | #include <trace/define_trace.h> | ||
| @@ -8,3 +8,7 @@ · 7 unmodified lines | |||
| 8 | ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS | 8 | ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS |
| 9 | 9 | ||
| 10 | obj-$(CONFIG_CDX_BUS) += cdx.o controller/ | 10 | obj-$(CONFIG_CDX_BUS) += cdx.o controller/ |
| 11 | |||
| 12 | ifdef CONFIG_GENERIC_MSI_IRQ | ||
| 13 | obj-$(CONFIG_CDX_BUS) += cdx_msi.o | ||
| 14 | endif | ||
| @@ -56,6 +56,7 @@ · 55 unmodified lines | |||
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | #include <linux/init.h> | 58 | #include <linux/init.h> |
| 59 | #include <linux/irqdomain.h> | ||
| 59 | #include <linux/kernel.h> | 60 | #include <linux/kernel.h> |
| 60 | #include <linux/of.h> | 61 | #include <linux/of.h> |
| 61 | #include <linux/of_device.h> | 62 | #include <linux/of_device.h> |
| @@ -302,8 +303,19 @@ static int cdx_probe(struct device *dev) · 240 unmodified lines | |||
| 302 | { | 303 | { |
| 303 | struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); | 304 | struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); |
| 304 | struct cdx_device *cdx_dev = to_cdx_device(dev); | 305 | struct cdx_device *cdx_dev = to_cdx_device(dev); |
| 306 | struct cdx_controller *cdx = cdx_dev->cdx; | ||
| 305 | int error; | 307 | int error; |
| 306 | 308 | ||
| 309 | /* | ||
| 310 | * Setup MSI device data so that generic MSI alloc/free can | ||
| 311 | * be used by the device driver. | ||
| 312 | */ | ||
| 313 | if (cdx->msi_domain) { | ||
| 314 | error = msi_setup_device_data(&cdx_dev->dev); | ||
| 315 | if (error) | ||
| 316 | return error; | ||
| 317 | } | ||
| 318 | |||
| 307 | error = cdx_drv->probe(cdx_dev); | 319 | error = cdx_drv->probe(cdx_dev); |
| 308 | if (error) { | 320 | if (error) { |
| 309 | dev_err_probe(dev, error, "%s failed\n", __func__); | 321 | dev_err_probe(dev, error, "%s failed\n", __func__); |
| @@ -787,6 +799,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) · 477 unmodified lines | |||
| 787 | 799 | ||
| 788 | /* Populate CDX dev params */ | 800 | /* Populate CDX dev params */ |
| 789 | cdx_dev->req_id = dev_params->req_id; | 801 | cdx_dev->req_id = dev_params->req_id; |
| 802 | cdx_dev->msi_dev_id = dev_params->msi_dev_id; | ||
| 790 | cdx_dev->vendor = dev_params->vendor; | 803 | cdx_dev->vendor = dev_params->vendor; |
| 791 | cdx_dev->device = dev_params->device; | 804 | cdx_dev->device = dev_params->device; |
| 792 | cdx_dev->subsystem_vendor = dev_params->subsys_vendor; | 805 | cdx_dev->subsystem_vendor = dev_params->subsys_vendor; |
| @@ -804,12 +817,19 @@ int cdx_device_add(struct cdx_dev_params *dev_params) · 11 unmodified lines | |||
| 804 | cdx_dev->dev.bus = &cdx_bus_type; | 817 | cdx_dev->dev.bus = &cdx_bus_type; |
| 805 | cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; | 818 | cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; |
| 806 | cdx_dev->dev.release = cdx_device_release; | 819 | cdx_dev->dev.release = cdx_device_release; |
| 820 | cdx_dev->msi_write_pending = false; | ||
| 821 | mutex_init(&cdx_dev->irqchip_lock); | ||
| 807 | 822 | ||
| 808 | /* Set Name */ | 823 | /* Set Name */ |
| 809 | dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", | 824 | dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", |
| 810 | ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), | 825 | ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), |
| 811 | cdx_dev->dev_num); | 826 | cdx_dev->dev_num); |
| 812 | 827 | ||
| 828 | if (cdx->msi_domain) { | ||
| 829 | cdx_dev->num_msi = dev_params->num_msi; | ||
| 830 | dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain); | ||
| 831 | } | ||
| 832 | |||
| 813 | ret = device_add(&cdx_dev->dev); | 833 | ret = device_add(&cdx_dev->dev); |
| 814 | if (ret) { | 834 | if (ret) { |
| 815 | dev_err(&cdx_dev->dev, | 835 | dev_err(&cdx_dev->dev, |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | |||
| 25 | * @req_id: Requestor ID associated with CDX device | 25 | * @req_id: Requestor ID associated with CDX device |
| 26 | * @class: Class of the CDX Device | 26 | * @class: Class of the CDX Device |
| 27 | * @revision: Revision of the CDX device | 27 | * @revision: Revision of the CDX device |
| 28 | * @msi_dev_id: MSI device ID associated with CDX device | ||
| 29 | * @num_msi: Number of MSI's supported by the device | ||
| 28 | */ | 30 | */ |
| 29 | struct cdx_dev_params { | 31 | struct cdx_dev_params { |
| 30 | struct cdx_controller *cdx; | 32 | struct cdx_controller *cdx; |
| @@ -40,6 +42,8 @@ struct cdx_dev_params { · 9 unmodified lines | |||
| 40 | u32 req_id; | 42 | u32 req_id; |
| 41 | u32 class; | 43 | u32 class; |
| 42 | u8 revision; | 44 | u8 revision; |
| 45 | u32 msi_dev_id; | ||
| 46 | u32 num_msi; | ||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | /** | 49 | /** |
| @@ -79,4 +83,12 @@ int cdx_device_add(struct cdx_dev_params *dev_params); · 33 unmodified lines | |||
| 79 | */ | 83 | */ |
| 80 | struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); | 84 | struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); |
| 81 | 85 | ||
| 86 | /** | ||
| 87 | * cdx_msi_domain_init - Init the CDX bus MSI domain. | ||
| 88 | * @dev: Device of the CDX bus controller | ||
| 89 | * | ||
| 90 | * Return: CDX MSI domain, NULL on failure | ||
| 91 | */ | ||
| 92 | struct irq_domain *cdx_msi_domain_init(struct device *dev); | ||
| 93 | |||
| 82 | #endif /* _CDX_H_ */ | 94 | #endif /* _CDX_H_ */ |
| @@ -0,0 +1,192 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * AMD CDX bus driver MSI support | ||
| 4 | * | ||
| 5 | * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/of.h> | ||
| 9 | #include <linux/of_device.h> | ||
| 10 | #include <linux/of_address.h> | ||
| 11 | #include <linux/of_irq.h> | ||
| 12 | #include <linux/irq.h> | ||
| 13 | #include <linux/irqdomain.h> | ||
| 14 | #include <linux/msi.h> | ||
| 15 | #include <linux/cdx/cdx_bus.h> | ||
| 16 | |||
| 17 | #include "cdx.h" | ||
| 18 | |||
| 19 | static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg) | ||
| 20 | { | ||
| 21 | struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||
| 22 | struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||
| 23 | |||
| 24 | /* We would not operate on msg here rather we wait for irq_bus_sync_unlock() | ||
| 25 | * to be called from preemptible task context. | ||
| 26 | */ | ||
| 27 | msi_desc->msg = *msg; | ||
| 28 | cdx_dev->msi_write_pending = true; | ||
| 29 | } | ||
| 30 | |||
| 31 | static void cdx_msi_write_irq_lock(struct irq_data *irq_data) | ||
| 32 | { | ||
| 33 | struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||
| 34 | struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||
| 35 | |||
| 36 | mutex_lock(&cdx_dev->irqchip_lock); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void cdx_msi_write_irq_unlock(struct irq_data *irq_data) | ||
| 40 | { | ||
| 41 | struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||
| 42 | struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||
| 43 | struct cdx_controller *cdx = cdx_dev->cdx; | ||
| 44 | struct cdx_device_config dev_config; | ||
| 45 | |||
| 46 | if (!cdx_dev->msi_write_pending) { | ||
| 47 | mutex_unlock(&cdx_dev->irqchip_lock); | ||
| 48 | return; | ||
| 49 | } | ||
| 50 | |||
| 51 | cdx_dev->msi_write_pending = false; | ||
| 52 | mutex_unlock(&cdx_dev->irqchip_lock); | ||
| 53 | |||
| 54 | dev_config.msi.msi_index = msi_desc->msi_index; | ||
| 55 | dev_config.msi.data = msi_desc->msg.data; | ||
| 56 | dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo; | ||
| 57 | |||
| 58 | /* | ||
| 59 | * dev_configure() is a controller callback which can interact with | ||
| 60 | * Firmware or other entities, and can sleep, so invoke this function | ||
| 61 | * outside of the mutex held region. | ||
| 62 | */ | ||
| 63 | dev_config.type = CDX_DEV_MSI_CONF; | ||
| 64 | if (cdx->ops->dev_configure) | ||
| 65 | cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); | ||
| 66 | } | ||
| 67 | |||
| 68 | int cdx_enable_msi(struct cdx_device *cdx_dev) | ||
| 69 | { | ||
| 70 | struct cdx_controller *cdx = cdx_dev->cdx; | ||
| 71 | struct cdx_device_config dev_config; | ||
| 72 | |||
| 73 | dev_config.type = CDX_DEV_MSI_ENABLE; | ||
| 74 | dev_config.msi_enable = true; | ||
| 75 | if (cdx->ops->dev_configure) { | ||
| 76 | return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, | ||
| 77 | &dev_config); | ||
| 78 | } | ||
| 79 | |||
| 80 | return -EOPNOTSUPP; | ||
| 81 | } | ||
| 82 | EXPORT_SYMBOL_GPL(cdx_enable_msi); | ||
| 83 | |||
| 84 | void cdx_disable_msi(struct cdx_device *cdx_dev) | ||
| 85 | { | ||
| 86 | struct cdx_controller *cdx = cdx_dev->cdx; | ||
| 87 | struct cdx_device_config dev_config; | ||
| 88 | |||
| 89 | dev_config.type = CDX_DEV_MSI_ENABLE; | ||
| 90 | dev_config.msi_enable = false; | ||
| 91 | if (cdx->ops->dev_configure) | ||
| 92 | cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(cdx_disable_msi); | ||
| 95 | |||
| 96 | static struct irq_chip cdx_msi_irq_chip = { | ||
| 97 | .name = "CDX-MSI", | ||
| 98 | .irq_mask = irq_chip_mask_parent, | ||
| 99 | .irq_unmask = irq_chip_unmask_parent, | ||
| 100 | .irq_eoi = irq_chip_eoi_parent, | ||
| 101 | .irq_set_affinity = msi_domain_set_affinity, | ||
| 102 | .irq_write_msi_msg = cdx_msi_write_msg, | ||
| 103 | .irq_bus_lock = cdx_msi_write_irq_lock, | ||
| 104 | .irq_bus_sync_unlock = cdx_msi_write_irq_unlock | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* Convert an msi_desc to a unique identifier within the domain. */ | ||
| 108 | static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev, | ||
| 109 | struct msi_desc *desc) | ||
| 110 | { | ||
| 111 | return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) | ||
| 115 | { | ||
| 116 | arg->desc = desc; | ||
| 117 | arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc); | ||
| 118 | } | ||
| 119 | |||
| 120 | static int cdx_msi_prepare(struct irq_domain *msi_domain, | ||
| 121 | struct device *dev, | ||
| 122 | int nvec, msi_alloc_info_t *info) | ||
| 123 | { | ||
| 124 | struct cdx_device *cdx_dev = to_cdx_device(dev); | ||
| 125 | struct device *parent = cdx_dev->cdx->dev; | ||
| 126 | struct msi_domain_info *msi_info; | ||
| 127 | u32 dev_id; | ||
| 128 | int ret; | ||
| 129 | |||
| 130 | /* Retrieve device ID from requestor ID using parent device */ | ||
| 131 | ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask", | ||
| 132 | NULL, &dev_id); | ||
| 133 | if (ret) { | ||
| 134 | dev_err(dev, "of_map_id failed for MSI: %d\n", ret); | ||
| 135 | return ret; | ||
| 136 | } | ||
| 137 | |||
| 138 | #ifdef GENERIC_MSI_DOMAIN_OPS | ||
| 139 | /* Set the device Id to be passed to the GIC-ITS */ | ||
| 140 | info->scratchpad[0].ul = dev_id; | ||
| 141 | #endif | ||
| 142 | |||
| 143 | msi_info = msi_get_domain_info(msi_domain->parent); | ||
| 144 | |||
| 145 | return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); | ||
| 146 | } | ||
| 147 | |||
| 148 | static struct msi_domain_ops cdx_msi_ops = { | ||
| 149 | .msi_prepare = cdx_msi_prepare, | ||
| 150 | .set_desc = cdx_msi_set_desc | ||
| 151 | }; | ||
| 152 | |||
| 153 | static struct msi_domain_info cdx_msi_domain_info = { | ||
| 154 | .ops = &cdx_msi_ops, | ||
| 155 | .chip = &cdx_msi_irq_chip, | ||
| 156 | .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | | ||
| 157 | MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct irq_domain *cdx_msi_domain_init(struct device *dev) | ||
| 161 | { | ||
| 162 | struct device_node *np = dev->of_node; | ||
| 163 | struct fwnode_handle *fwnode_handle; | ||
| 164 | struct irq_domain *cdx_msi_domain; | ||
| 165 | struct device_node *parent_node; | ||
| 166 | struct irq_domain *parent; | ||
| 167 | |||
| 168 | fwnode_handle = of_node_to_fwnode(np); | ||
| 169 | |||
| 170 | parent_node = of_parse_phandle(np, "msi-map", 1); | ||
| 171 | if (!parent_node) { | ||
| 172 | dev_err(dev, "msi-map not present on cdx controller\n"); | ||
| 173 | return NULL; | ||
| 174 | } | ||
| 175 | |||
| 176 | parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS); | ||
| 177 | if (!parent || !msi_get_domain_info(parent)) { | ||
| 178 | dev_err(dev, "unable to locate ITS domain\n"); | ||
| 179 | return NULL; | ||
| 180 | } | ||
| 181 | |||
| 182 | cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent); | ||
| 183 | if (!cdx_msi_domain) { | ||
| 184 | dev_err(dev, "unable to create CDX-MSI domain\n"); | ||
| 185 | return NULL; | ||
| 186 | } | ||
| 187 | |||
| 188 | dev_dbg(dev, "CDX-MSI domain created\n"); | ||
| 189 | |||
| 190 | return cdx_msi_domain; | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER); | ||
| @@ -9,6 +9,7 @@ if CDX_BUS · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | config CDX_CONTROLLER | 10 | config CDX_CONTROLLER |
| 11 | tristate "CDX bus controller" | 11 | tristate "CDX bus controller" |
| 12 | select GENERIC_MSI_IRQ | ||
| 12 | select REMOTEPROC | 13 | select REMOTEPROC |
| 13 | select RPMSG | 14 | select RPMSG |
| 14 | help | 15 | help |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <linux/cdx/cdx_bus.h> | 11 | #include <linux/cdx/cdx_bus.h> |
| 12 | #include <linux/irqdomain.h> | ||
| 12 | 13 | ||
| 13 | #include "cdx_controller.h" | 14 | #include "cdx_controller.h" |
| 14 | #include "../cdx.h" | 15 | #include "../cdx.h" |
| @@ -60,9 +61,19 @@ static int cdx_configure_device(struct cdx_controller *cdx, · 45 unmodified lines | |||
| 60 | u8 bus_num, u8 dev_num, | 61 | u8 bus_num, u8 dev_num, |
| 61 | struct cdx_device_config *dev_config) | 62 | struct cdx_device_config *dev_config) |
| 62 | { | 63 | { |
| 64 | u16 msi_index; | ||
| 63 | int ret = 0; | 65 | int ret = 0; |
| 66 | u32 data; | ||
| 67 | u64 addr; | ||
| 64 | 68 | ||
| 65 | switch (dev_config->type) { | 69 | switch (dev_config->type) { |
| 70 | case CDX_DEV_MSI_CONF: | ||
| 71 | msi_index = dev_config->msi.msi_index; | ||
| 72 | data = dev_config->msi.data; | ||
| 73 | addr = dev_config->msi.addr; | ||
| 74 | |||
| 75 | ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data); | ||
| 76 | break; | ||
| 66 | case CDX_DEV_RESET_CONF: | 77 | case CDX_DEV_RESET_CONF: |
| 67 | ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); | 78 | ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); |
| 68 | break; | 79 | break; |
| @@ -70,6 +81,9 @@ static int cdx_configure_device(struct cdx_controller *cdx, · 1 unmodified line | |||
| 70 | ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, | 81 | ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, |
| 71 | dev_config->bus_master_enable); | 82 | dev_config->bus_master_enable); |
| 72 | break; | 83 | break; |
| 84 | case CDX_DEV_MSI_ENABLE: | ||
| 85 | ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable); | ||
| 86 | break; | ||
| 73 | default: | 87 | default: |
| 74 | ret = -EINVAL; | 88 | ret = -EINVAL; |
| 75 | } | 89 | } |
| @@ -178,6 +192,14 @@ static int xlnx_cdx_probe(struct platform_device *pdev) · 102 unmodified lines | |||
| 178 | cdx->priv = cdx_mcdi; | 192 | cdx->priv = cdx_mcdi; |
| 179 | cdx->ops = &cdx_ops; | 193 | cdx->ops = &cdx_ops; |
| 180 | 194 | ||
| 195 | /* Create MSI domain */ | ||
| 196 | cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); | ||
| 197 | if (!cdx->msi_domain) { | ||
| 198 | dev_err(&pdev->dev, "cdx_msi_domain_init() failed"); | ||
| 199 | ret = -ENODEV; | ||
| 200 | goto cdx_msi_fail; | ||
| 201 | } | ||
| 202 | |||
| 181 | ret = cdx_setup_rpmsg(pdev); | 203 | ret = cdx_setup_rpmsg(pdev); |
| 182 | if (ret) { | 204 | if (ret) { |
| 183 | if (ret != -EPROBE_DEFER) | 205 | if (ret != -EPROBE_DEFER) |
| @@ -189,6 +211,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 189 | return 0; | 211 | return 0; |
| 190 | 212 | ||
| 191 | cdx_rpmsg_fail: | 213 | cdx_rpmsg_fail: |
| 214 | irq_domain_remove(cdx->msi_domain); | ||
| 215 | cdx_msi_fail: | ||
| 192 | kfree(cdx); | 216 | kfree(cdx); |
| 193 | cdx_alloc_fail: | 217 | cdx_alloc_fail: |
| 194 | cdx_mcdi_finish(cdx_mcdi); | 218 | cdx_mcdi_finish(cdx_mcdi); |
| @@ -205,6 +229,7 @@ static int xlnx_cdx_remove(struct platform_device *pdev) · 10 unmodified lines | |||
| 205 | 229 | ||
| 206 | cdx_destroy_rpmsg(pdev); | 230 | cdx_destroy_rpmsg(pdev); |
| 207 | 231 | ||
| 232 | irq_domain_remove(cdx->msi_domain); | ||
| 208 | kfree(cdx); | 233 | kfree(cdx); |
| 209 | 234 | ||
| 210 | cdx_mcdi_finish(cdx_mcdi); | 235 | cdx_mcdi_finish(cdx_mcdi); |
| @@ -455,6 +455,12 @@ · 454 unmodified lines | |||
| 455 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 | 455 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 |
| 456 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 | 456 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 |
| 457 | 457 | ||
| 458 | /* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2 msgresponse */ | ||
| 459 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN 92 | ||
| 460 | /* Requester ID used by device for GIC ITS DeviceID */ | ||
| 461 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST 88 | ||
| 462 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_LEN 4 | ||
| 463 | |||
| 458 | /***********************************/ | 464 | /***********************************/ |
| 459 | /* | 465 | /* |
| 460 | * MC_CMD_CDX_BUS_DOWN | 466 | * MC_CMD_CDX_BUS_DOWN |
| @@ -616,6 +622,64 @@ · 155 unmodified lines | |||
| 616 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN 2 | 622 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN 2 |
| 617 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1 | 623 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1 |
| 618 | 624 | ||
| 625 | /***********************************/ | ||
| 626 | /* | ||
| 627 | * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG | ||
| 628 | * Populates the MSI message to be used by the hardware to raise the specified | ||
| 629 | * interrupt vector. Versal-net implementation specific limitations are that | ||
| 630 | * only 4 CDX devices with MSI interrupt capability are supported and all | ||
| 631 | * vectors within a device must use the same write address. The command will | ||
| 632 | * return EINVAL if any of these limitations is violated. | ||
| 633 | */ | ||
| 634 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG 0x9 | ||
| 635 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET 0x9 | ||
| 636 | #undef MC_CMD_0x9_PRIVILEGE_CTG | ||
| 637 | |||
| 638 | #define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN | ||
| 639 | |||
| 640 | /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */ | ||
| 641 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN 28 | ||
| 642 | /* Device bus number, in range 0 to BUS_COUNT-1 */ | ||
| 643 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST 0 | ||
| 644 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN 4 | ||
| 645 | /* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ | ||
| 646 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST 4 | ||
| 647 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN 4 | ||
| 648 | /* | ||
| 649 | * Device-relative MSI vector number. Must be < MSI_COUNT reported for the | ||
| 650 | * device. | ||
| 651 | */ | ||
| 652 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST 8 | ||
| 653 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN 4 | ||
| 654 | /* Reserved (alignment) */ | ||
| 655 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST 12 | ||
| 656 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN 4 | ||
| 657 | /* | ||
| 658 | * MSI address to be used by the hardware. Typically, on ARM systems this | ||
| 659 | * address is translated by the IOMMU (if enabled) and it is the responsibility | ||
| 660 | * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA | ||
| 661 | * here. | ||
| 662 | */ | ||
| 663 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST 16 | ||
| 664 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN 8 | ||
| 665 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST 16 | ||
| 666 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN 4 | ||
| 667 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN 128 | ||
| 668 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH 32 | ||
| 669 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST 20 | ||
| 670 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN 4 | ||
| 671 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN 160 | ||
| 672 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH 32 | ||
| 673 | /* | ||
| 674 | * MSI data to be used by the hardware. On versal-net, only the lower 16-bits | ||
| 675 | * are used, the remaining bits are ignored and should be set to zero. | ||
| 676 | */ | ||
| 677 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST 24 | ||
| 678 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN 4 | ||
| 679 | |||
| 680 | /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */ | ||
| 681 | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN 0 | ||
| 682 | |||
| 619 | /***********************************/ | 683 | /***********************************/ |
| 620 | /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ | 684 | /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ |
| 621 | #define MC_CMD_V2_EXTN 0x7f | 685 | #define MC_CMD_V2_EXTN 0x7f |
| @@ -49,7 +49,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, · 48 unmodified lines | |||
| 49 | u8 bus_num, u8 dev_num, | 49 | u8 bus_num, u8 dev_num, |
| 50 | struct cdx_dev_params *dev_params) | 50 | struct cdx_dev_params *dev_params) |
| 51 | { | 51 | { |
| 52 | MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); | 52 | MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN); |
| 53 | MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); | 53 | MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); |
| 54 | struct resource *res = &dev_params->res[0]; | 54 | struct resource *res = &dev_params->res[0]; |
| 55 | size_t outlen; | 55 | size_t outlen; |
| @@ -64,7 +64,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, · 8 unmodified lines | |||
| 64 | if (ret) | 64 | if (ret) |
| 65 | return ret; | 65 | return ret; |
| 66 | 66 | ||
| 67 | if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) | 67 | if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN) |
| 68 | return -EIO; | 68 | return -EIO; |
| 69 | 69 | ||
| 70 | dev_params->bus_num = bus_num; | 70 | dev_params->bus_num = bus_num; |
| @@ -73,6 +73,9 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, · 2 unmodified lines | |||
| 73 | req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); | 73 | req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); |
| 74 | dev_params->req_id = req_id; | 74 | dev_params->req_id = req_id; |
| 75 | 75 | ||
| 76 | dev_params->msi_dev_id = MCDI_DWORD(outbuf, | ||
| 77 | CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); | ||
| 78 | |||
| 76 | dev_params->res_count = 0; | 79 | dev_params->res_count = 0; |
| 77 | if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { | 80 | if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { |
| 78 | res[dev_params->res_count].start = | 81 | res[dev_params->res_count].start = |
| @@ -127,6 +130,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, · 48 unmodified lines | |||
| 127 | dev_params->class = MCDI_DWORD(outbuf, | 130 | dev_params->class = MCDI_DWORD(outbuf, |
| 128 | CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; | 131 | CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; |
| 129 | dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); | 132 | dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); |
| 133 | dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); | ||
| 130 | 134 | ||
| 131 | return 0; | 135 | return 0; |
| 132 | } | 136 | } |
| @@ -155,6 +159,24 @@ int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) · 22 unmodified lines | |||
| 155 | return ret; | 159 | return ret; |
| 156 | } | 160 | } |
| 157 | 161 | ||
| 162 | int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, | ||
| 163 | u32 msi_vector, u64 msi_address, u32 msi_data) | ||
| 164 | { | ||
| 165 | MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); | ||
| 166 | int ret; | ||
| 167 | |||
| 168 | MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); | ||
| 169 | MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); | ||
| 170 | MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); | ||
| 171 | MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); | ||
| 172 | MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); | ||
| 173 | |||
| 174 | ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf), | ||
| 175 | NULL, 0, NULL); | ||
| 176 | |||
| 177 | return ret; | ||
| 178 | } | ||
| 179 | |||
| 158 | int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) | 180 | int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) |
| 159 | { | 181 | { |
| 160 | MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); | 182 | MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); |
| @@ -226,3 +248,10 @@ int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, · 65 unmodified lines | |||
| 226 | return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, | 248 | return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, |
| 227 | MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); | 249 | MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); |
| 228 | } | 250 | } |
| 251 | |||
| 252 | int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||
| 253 | u8 dev_num, bool enable) | ||
| 254 | { | ||
| 255 | return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, | ||
| 256 | MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); | ||
| 257 | } | ||
| @@ -65,6 +65,26 @@ int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num); · 64 unmodified lines | |||
| 65 | */ | 65 | */ |
| 66 | int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); | 66 | int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); |
| 67 | 67 | ||
| 68 | /** | ||
| 69 | * cdx_mcdi_write_msi - Write MSI configuration for CDX device | ||
| 70 | * @cdx: pointer to MCDI interface. | ||
| 71 | * @bus_num: Bus number. | ||
| 72 | * @dev_num: Device number. | ||
| 73 | * @msi_vector: Device-relative MSI vector number. | ||
| 74 | * Must be < MSI_COUNT reported for the device. | ||
| 75 | * @msi_address: MSI address to be used by the hardware. Typically, on ARM | ||
| 76 | * systems this address is translated by the IOMMU (if enabled) and | ||
| 77 | * it is the responsibility of the entity managing the IOMMU (APU kernel) | ||
| 78 | * to supply the correct IOVA here. | ||
| 79 | * @msi_data: MSI data to be used by the hardware. On versal-net, only the | ||
| 80 | * lower 16-bits are used, the remaining bits are ignored and should be | ||
| 81 | * set to zero. | ||
| 82 | * | ||
| 83 | * Return: 0 on success, <0 on failure | ||
| 84 | */ | ||
| 85 | int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, | ||
| 86 | u32 msi_vector, u64 msi_address, u32 msi_data); | ||
| 87 | |||
| 68 | /** | 88 | /** |
| 69 | * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num | 89 | * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num |
| 70 | * @cdx: pointer to MCDI interface. | 90 | * @cdx: pointer to MCDI interface. |
| @@ -89,4 +109,17 @@ int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, · 18 unmodified lines | |||
| 89 | int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, | 109 | int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, |
| 90 | u8 dev_num, bool enable); | 110 | u8 dev_num, bool enable); |
| 91 | 111 | ||
| 112 | /** | ||
| 113 | * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented | ||
| 114 | * by bus_num:dev_num | ||
| 115 | * @cdx: pointer to MCDI interface. | ||
| 116 | * @bus_num: Bus number. | ||
| 117 | * @dev_num: Device number. | ||
| 118 | * @enable: Enable msi's if set, disable otherwise. | ||
| 119 | * | ||
| 120 | * Return: 0 on success, <0 on failure | ||
| 121 | */ | ||
| 122 | int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||
| 123 | u8 dev_num, bool enable); | ||
| 124 | |||
| 92 | #endif /* CDX_MCDI_FUNCTIONS_H */ | 125 | #endif /* CDX_MCDI_FUNCTIONS_H */ |
| @@ -87,7 +87,6 @@ struct hpets { · 86 unmodified lines | |||
| 87 | struct hpets *hp_next; | 87 | struct hpets *hp_next; |
| 88 | struct hpet __iomem *hp_hpet; | 88 | struct hpet __iomem *hp_hpet; |
| 89 | unsigned long hp_hpet_phys; | 89 | unsigned long hp_hpet_phys; |
| 90 | struct clocksource *hp_clocksource; | ||
| 91 | unsigned long long hp_tick_freq; | 90 | unsigned long long hp_tick_freq; |
| 92 | unsigned long hp_delta; | 91 | unsigned long hp_delta; |
| 93 | unsigned int hp_ntimer; | 92 | unsigned int hp_ntimer; |
| @@ -636,11 +636,11 @@ static int hwicap_setup(struct platform_device *pdev, int id, · 635 unmodified lines | |||
| 636 | retval = -ENOMEM; | 636 | retval = -ENOMEM; |
| 637 | goto failed; | 637 | goto failed; |
| 638 | } | 638 | } |
| 639 | dev_set_drvdata(dev, (void *)drvdata); | 639 | dev_set_drvdata(dev, drvdata); |
| 640 | 640 | ||
| 641 | drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); | 641 | drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); |
| 642 | if (!drvdata->base_address) { | 642 | if (IS_ERR(drvdata->base_address)) { |
| 643 | retval = -ENODEV; | 643 | retval = PTR_ERR(drvdata->base_address); |
| 644 | goto failed; | 644 | goto failed; |
| 645 | } | 645 | } |
| 646 | 646 | ||
| @@ -64,19 +64,17 @@ static int xilly_drv_probe(struct platform_device *op) · 63 unmodified lines | |||
| 64 | return xillybus_endpoint_discovery(endpoint); | 64 | return xillybus_endpoint_discovery(endpoint); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static int xilly_drv_remove(struct platform_device *op) | 67 | static void xilly_drv_remove(struct platform_device *op) |
| 68 | { | 68 | { |
| 69 | struct device *dev = &op->dev; | 69 | struct device *dev = &op->dev; |
| 70 | struct xilly_endpoint *endpoint = dev_get_drvdata(dev); | 70 | struct xilly_endpoint *endpoint = dev_get_drvdata(dev); |
| 71 | 71 | ||
| 72 | xillybus_endpoint_remove(endpoint); | 72 | xillybus_endpoint_remove(endpoint); |
| 73 | |||
| 74 | return 0; | ||
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | static struct platform_driver xillybus_platform_driver = { | 75 | static struct platform_driver xillybus_platform_driver = { |
| 78 | .probe = xilly_drv_probe, | 76 | .probe = xilly_drv_probe, |
| 79 | .remove = xilly_drv_remove, | 77 | .remove_new = xilly_drv_remove, |
| 80 | .driver = { | 78 | .driver = { |
| 81 | .name = xillyname, | 79 | .name = xillyname, |
| 82 | .of_match_table = xillybus_of_match, | 80 | .of_match_table = xillybus_of_match, |
| @@ -177,7 +177,6 @@ static int das08_ai_insn_read(struct comedi_device *dev, · 176 unmodified lines | |||
| 177 | int ret; | 177 | int ret; |
| 178 | 178 | ||
| 179 | chan = CR_CHAN(insn->chanspec); | 179 | chan = CR_CHAN(insn->chanspec); |
| 180 | range = CR_RANGE(insn->chanspec); | ||
| 181 | 180 | ||
| 182 | /* clear crap */ | 181 | /* clear crap */ |
| 183 | inb(dev->iobase + DAS08_AI_LSB_REG); | 182 | inb(dev->iobase + DAS08_AI_LSB_REG); |
| @@ -123,7 +123,7 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv) · 122 unmodified lines | |||
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | 125 | ||
| 126 | struct bus_type dio_bus_type = { | 126 | const struct bus_type dio_bus_type = { |
| 127 | .name = "dio", | 127 | .name = "dio", |
| 128 | .match = dio_bus_match, | 128 | .match = dio_bus_match, |
| 129 | .probe = dio_device_probe, | 129 | .probe = dio_device_probe, |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | |||
| 3 | * Xilinx Zynq MPSoC Firmware layer | 3 | * Xilinx Zynq MPSoC Firmware layer |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2014-2022 Xilinx, Inc. | 5 | * Copyright (C) 2014-2022 Xilinx, Inc. |
| 6 | * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc. | ||
| 6 | * | 7 | * |
| 7 | * Michal Simek <michal.simek@amd.com> | 8 | * Michal Simek <michal.simek@amd.com> |
| 8 | * Davorin Mista <davorin.mista@aggios.com> | 9 | * Davorin Mista <davorin.mista@aggios.com> |
| @@ -1384,6 +1385,30 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out) · 1375 unmodified lines | |||
| 1384 | } | 1385 | } |
| 1385 | EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); | 1386 | EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); |
| 1386 | 1387 | ||
| 1388 | /** | ||
| 1389 | * zynqmp_pm_efuse_access - Provides access to efuse memory. | ||
| 1390 | * @address: Address of the efuse params structure | ||
| 1391 | * @out: Returned output value | ||
| 1392 | * | ||
| 1393 | * Return: Returns status, either success or error code. | ||
| 1394 | */ | ||
| 1395 | int zynqmp_pm_efuse_access(const u64 address, u32 *out) | ||
| 1396 | { | ||
| 1397 | u32 ret_payload[PAYLOAD_ARG_CNT]; | ||
| 1398 | int ret; | ||
| 1399 | |||
| 1400 | if (!out) | ||
| 1401 | return -EINVAL; | ||
| 1402 | |||
| 1403 | ret = zynqmp_pm_invoke_fn(PM_EFUSE_ACCESS, ret_payload, 2, | ||
| 1404 | upper_32_bits(address), | ||
| 1405 | lower_32_bits(address)); | ||
| 1406 | *out = ret_payload[1]; | ||
| 1407 | |||
| 1408 | return ret; | ||
| 1409 | } | ||
| 1410 | EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access); | ||
| 1411 | |||
| 1387 | /** | 1412 | /** |
| 1388 | * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash | 1413 | * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash |
| 1389 | * @address: Address of the data/ Address of output buffer where | 1414 | * @address: Address of the data/ Address of output buffer where |
| @@ -327,7 +327,7 @@ static struct attribute *dfl_dev_attrs[] = { · 326 unmodified lines | |||
| 327 | }; | 327 | }; |
| 328 | ATTRIBUTE_GROUPS(dfl_dev); | 328 | ATTRIBUTE_GROUPS(dfl_dev); |
| 329 | 329 | ||
| 330 | static struct bus_type dfl_bus_type = { | 330 | static const struct bus_type dfl_bus_type = { |
| 331 | .name = "dfl", | 331 | .name = "dfl", |
| 332 | .match = dfl_bus_match, | 332 | .match = dfl_bus_match, |
| 333 | .probe = dfl_bus_probe, | 333 | .probe = dfl_bus_probe, |
| @@ -30,7 +30,7 @@ int fpga_bridge_enable(struct fpga_bridge *bridge) · 29 unmodified lines | |||
| 30 | { | 30 | { |
| 31 | dev_dbg(&bridge->dev, "enable\n"); | 31 | dev_dbg(&bridge->dev, "enable\n"); |
| 32 | 32 | ||
| 33 | if (bridge->br_ops && bridge->br_ops->enable_set) | 33 | if (bridge->br_ops->enable_set) |
| 34 | return bridge->br_ops->enable_set(bridge, 1); | 34 | return bridge->br_ops->enable_set(bridge, 1); |
| 35 | 35 | ||
| 36 | return 0; | 36 | return 0; |
| @@ -48,7 +48,7 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) · 11 unmodified lines | |||
| 48 | { | 48 | { |
| 49 | dev_dbg(&bridge->dev, "disable\n"); | 49 | dev_dbg(&bridge->dev, "disable\n"); |
| 50 | 50 | ||
| 51 | if (bridge->br_ops && bridge->br_ops->enable_set) | 51 | if (bridge->br_ops->enable_set) |
| 52 | return bridge->br_ops->enable_set(bridge, 0); | 52 | return bridge->br_ops->enable_set(bridge, 0); |
| 53 | 53 | ||
| 54 | return 0; | 54 | return 0; |
| @@ -296,7 +296,7 @@ static ssize_t state_show(struct device *dev, · 241 unmodified lines | |||
| 296 | struct fpga_bridge *bridge = to_fpga_bridge(dev); | 296 | struct fpga_bridge *bridge = to_fpga_bridge(dev); |
| 297 | int state = 1; | 297 | int state = 1; |
| 298 | 298 | ||
| 299 | if (bridge->br_ops && bridge->br_ops->enable_show) { | 299 | if (bridge->br_ops->enable_show) { |
| 300 | state = bridge->br_ops->enable_show(bridge); | 300 | state = bridge->br_ops->enable_show(bridge); |
| 301 | if (state < 0) | 301 | if (state < 0) |
| 302 | return state; | 302 | return state; |
| @@ -401,7 +401,7 @@ void fpga_bridge_unregister(struct fpga_bridge *bridge) · 98 unmodified lines | |||
| 401 | * If the low level driver provides a method for putting bridge into | 401 | * If the low level driver provides a method for putting bridge into |
| 402 | * a desired state upon unregister, do it. | 402 | * a desired state upon unregister, do it. |
| 403 | */ | 403 | */ |
| 404 | if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove) | 404 | if (bridge->br_ops->fpga_bridge_remove) |
| 405 | bridge->br_ops->fpga_bridge_remove(bridge); | 405 | bridge->br_ops->fpga_bridge_remove(bridge); |
| 406 | 406 | ||
| 407 | device_unregister(&bridge->dev); | 407 | device_unregister(&bridge->dev); |
| @@ -166,7 +166,7 @@ static const struct dev_pm_ops gb_bundle_pm_ops = { · 165 unmodified lines | |||
| 166 | SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle) | 166 | SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle) |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | struct device_type greybus_bundle_type = { | 169 | const struct device_type greybus_bundle_type = { |
| 170 | .name = "greybus_bundle", | 170 | .name = "greybus_bundle", |
| 171 | .release = gb_bundle_release, | 171 | .release = gb_bundle_release, |
| 172 | .pm = &gb_bundle_pm_ops, | 172 | .pm = &gb_bundle_pm_ops, |
| @@ -436,7 +436,7 @@ static void gb_control_release(struct device *dev) · 435 unmodified lines | |||
| 436 | kfree(control); | 436 | kfree(control); |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | struct device_type greybus_control_type = { | 439 | const struct device_type greybus_control_type = { |
| 440 | .name = "greybus_control", | 440 | .name = "greybus_control", |
| 441 | .release = gb_control_release, | 441 | .release = gb_control_release, |
| 442 | }; | 442 | }; |
| @@ -27,6 +27,36 @@ int greybus_disabled(void) · 26 unmodified lines | |||
| 27 | } | 27 | } |
| 28 | EXPORT_SYMBOL_GPL(greybus_disabled); | 28 | EXPORT_SYMBOL_GPL(greybus_disabled); |
| 29 | 29 | ||
| 30 | static int is_gb_host_device(const struct device *dev) | ||
| 31 | { | ||
| 32 | return dev->type == &greybus_hd_type; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int is_gb_module(const struct device *dev) | ||
| 36 | { | ||
| 37 | return dev->type == &greybus_module_type; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int is_gb_interface(const struct device *dev) | ||
| 41 | { | ||
| 42 | return dev->type == &greybus_interface_type; | ||
| 43 | } | ||
| 44 | |||
| 45 | static int is_gb_control(const struct device *dev) | ||
| 46 | { | ||
| 47 | return dev->type == &greybus_control_type; | ||
| 48 | } | ||
| 49 | |||
| 50 | static int is_gb_bundle(const struct device *dev) | ||
| 51 | { | ||
| 52 | return dev->type == &greybus_bundle_type; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int is_gb_svc(const struct device *dev) | ||
| 56 | { | ||
| 57 | return dev->type == &greybus_svc_type; | ||
| 58 | } | ||
| 59 | |||
| 30 | static bool greybus_match_one_id(struct gb_bundle *bundle, | 60 | static bool greybus_match_one_id(struct gb_bundle *bundle, |
| 31 | const struct greybus_bundle_id *id) | 61 | const struct greybus_bundle_id *id) |
| 32 | { | 62 | { |
| @@ -155,7 +185,7 @@ static void greybus_shutdown(struct device *dev) · 122 unmodified lines | |||
| 155 | } | 185 | } |
| 156 | } | 186 | } |
| 157 | 187 | ||
| 158 | struct bus_type greybus_bus_type = { | 188 | const struct bus_type greybus_bus_type = { |
| 159 | .name = "greybus", | 189 | .name = "greybus", |
| 160 | .match = greybus_match_device, | 190 | .match = greybus_match_device, |
| 161 | .uevent = greybus_uevent, | 191 | .uevent = greybus_uevent, |
| @@ -513,16 +513,16 @@ static int es2_cport_allocate(struct gb_host_device *hd, int cport_id, · 512 unmodified lines | |||
| 513 | 513 | ||
| 514 | if (cport_id < 0) { | 514 | if (cport_id < 0) { |
| 515 | ida_start = 0; | 515 | ida_start = 0; |
| 516 | ida_end = hd->num_cports; | 516 | ida_end = hd->num_cports - 1; |
| 517 | } else if (cport_id < hd->num_cports) { | 517 | } else if (cport_id < hd->num_cports) { |
| 518 | ida_start = cport_id; | 518 | ida_start = cport_id; |
| 519 | ida_end = cport_id + 1; | 519 | ida_end = cport_id; |
| 520 | } else { | 520 | } else { |
| 521 | dev_err(&hd->dev, "cport %d not available\n", cport_id); | 521 | dev_err(&hd->dev, "cport %d not available\n", cport_id); |
| 522 | return -EINVAL; | 522 | return -EINVAL; |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); | 525 | return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL); |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) | 528 | static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) |
| @@ -535,7 +535,7 @@ static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) · 6 unmodified lines | |||
| 535 | return; | 535 | return; |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | ida_simple_remove(&hd->cport_id_map, cport_id); | 538 | ida_free(&hd->cport_id_map, cport_id); |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | static int cport_enable(struct gb_host_device *hd, u16 cport_id, | 541 | static int cport_enable(struct gb_host_device *hd, u16 cport_id, |
| @@ -50,7 +50,7 @@ int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id) · 49 unmodified lines | |||
| 50 | struct ida *id_map = &hd->cport_id_map; | 50 | struct ida *id_map = &hd->cport_id_map; |
| 51 | int ret; | 51 | int ret; |
| 52 | 52 | ||
| 53 | ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL); | 53 | ret = ida_alloc_range(id_map, cport_id, cport_id, GFP_KERNEL); |
| 54 | if (ret < 0) { | 54 | if (ret < 0) { |
| 55 | dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id); | 55 | dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id); |
| 56 | return ret; | 56 | return ret; |
| @@ -64,7 +64,7 @@ void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id) · 7 unmodified lines | |||
| 64 | { | 64 | { |
| 65 | struct ida *id_map = &hd->cport_id_map; | 65 | struct ida *id_map = &hd->cport_id_map; |
| 66 | 66 | ||
| 67 | ida_simple_remove(id_map, cport_id); | 67 | ida_free(id_map, cport_id); |
| 68 | } | 68 | } |
| 69 | EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved); | 69 | EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved); |
| 70 | 70 | ||
| @@ -80,16 +80,16 @@ int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id, · 9 unmodified lines | |||
| 80 | 80 | ||
| 81 | if (cport_id < 0) { | 81 | if (cport_id < 0) { |
| 82 | ida_start = 0; | 82 | ida_start = 0; |
| 83 | ida_end = hd->num_cports; | 83 | ida_end = hd->num_cports - 1; |
| 84 | } else if (cport_id < hd->num_cports) { | 84 | } else if (cport_id < hd->num_cports) { |
| 85 | ida_start = cport_id; | 85 | ida_start = cport_id; |
| 86 | ida_end = cport_id + 1; | 86 | ida_end = cport_id; |
| 87 | } else { | 87 | } else { |
| 88 | dev_err(&hd->dev, "cport %d not available\n", cport_id); | 88 | dev_err(&hd->dev, "cport %d not available\n", cport_id); |
| 89 | return -EINVAL; | 89 | return -EINVAL; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); | 92 | return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /* Locking: Caller guarantees serialisation */ | 95 | /* Locking: Caller guarantees serialisation */ |
| @@ -100,7 +100,7 @@ void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id) · 4 unmodified lines | |||
| 100 | return; | 100 | return; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | ida_simple_remove(&hd->cport_id_map, cport_id); | 103 | ida_free(&hd->cport_id_map, cport_id); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void gb_hd_release(struct device *dev) | 106 | static void gb_hd_release(struct device *dev) |
| @@ -111,12 +111,12 @@ static void gb_hd_release(struct device *dev) · 4 unmodified lines | |||
| 111 | 111 | ||
| 112 | if (hd->svc) | 112 | if (hd->svc) |
| 113 | gb_svc_put(hd->svc); | 113 | gb_svc_put(hd->svc); |
| 114 | ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id); | 114 | ida_free(&gb_hd_bus_id_map, hd->bus_id); |
| 115 | ida_destroy(&hd->cport_id_map); | 115 | ida_destroy(&hd->cport_id_map); |
| 116 | kfree(hd); | 116 | kfree(hd); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | struct device_type greybus_hd_type = { | 119 | const struct device_type greybus_hd_type = { |
| 120 | .name = "greybus_host_device", | 120 | .name = "greybus_host_device", |
| 121 | .release = gb_hd_release, | 121 | .release = gb_hd_release, |
| 122 | }; | 122 | }; |
| @@ -162,7 +162,7 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, · 39 unmodified lines | |||
| 162 | if (!hd) | 162 | if (!hd) |
| 163 | return ERR_PTR(-ENOMEM); | 163 | return ERR_PTR(-ENOMEM); |
| 164 | 164 | ||
| 165 | ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL); | 165 | ret = ida_alloc_min(&gb_hd_bus_id_map, 1, GFP_KERNEL); |
| 166 | if (ret < 0) { | 166 | if (ret < 0) { |
| 167 | kfree(hd); | 167 | kfree(hd); |
| 168 | return ERR_PTR(ret); | 168 | return ERR_PTR(ret); |
| @@ -131,9 +131,8 @@ static int gb_interface_route_create(struct gb_interface *intf) · 130 unmodified lines | |||
| 131 | int ret; | 131 | int ret; |
| 132 | 132 | ||
| 133 | /* Allocate an interface device id. */ | 133 | /* Allocate an interface device id. */ |
| 134 | ret = ida_simple_get(&svc->device_id_map, | 134 | ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN, |
| 135 | GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1, | 135 | GB_SVC_DEVICE_ID_MAX, GFP_KERNEL); |
| 136 | GFP_KERNEL); | ||
| 137 | if (ret < 0) { | 136 | if (ret < 0) { |
| 138 | dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); | 137 | dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); |
| 139 | return ret; | 138 | return ret; |
| @@ -165,7 +164,7 @@ err_svc_id_free: · 25 unmodified lines | |||
| 165 | * XXX anymore. | 164 | * XXX anymore. |
| 166 | */ | 165 | */ |
| 167 | err_ida_remove: | 166 | err_ida_remove: |
| 168 | ida_simple_remove(&svc->device_id_map, device_id); | 167 | ida_free(&svc->device_id_map, device_id); |
| 169 | 168 | ||
| 170 | return ret; | 169 | return ret; |
| 171 | } | 170 | } |
| @@ -178,7 +177,7 @@ static void gb_interface_route_destroy(struct gb_interface *intf) · 6 unmodified lines | |||
| 178 | return; | 177 | return; |
| 179 | 178 | ||
| 180 | gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id); | 179 | gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id); |
| 181 | ida_simple_remove(&svc->device_id_map, intf->device_id); | 180 | ida_free(&svc->device_id_map, intf->device_id); |
| 182 | intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; | 181 | intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; |
| 183 | } | 182 | } |
| 184 | 183 | ||
| @@ -765,7 +764,7 @@ static const struct dev_pm_ops gb_interface_pm_ops = { · 580 unmodified lines | |||
| 765 | gb_interface_runtime_idle) | 764 | gb_interface_runtime_idle) |
| 766 | }; | 765 | }; |
| 767 | 766 | ||
| 768 | struct device_type greybus_interface_type = { | 767 | const struct device_type greybus_interface_type = { |
| 769 | .name = "greybus_interface", | 768 | .name = "greybus_interface", |
| 770 | .release = gb_interface_release, | 769 | .release = gb_interface_release, |
| 771 | .pm = &gb_interface_pm_ops, | 770 | .pm = &gb_interface_pm_ops, |
| @@ -81,7 +81,7 @@ static void gb_module_release(struct device *dev) · 80 unmodified lines | |||
| 81 | kfree(module); | 81 | kfree(module); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | struct device_type greybus_module_type = { | 84 | const struct device_type greybus_module_type = { |
| 85 | .name = "greybus_module", | 85 | .name = "greybus_module", |
| 86 | .release = gb_module_release, | 86 | .release = gb_module_release, |
| 87 | }; | 87 | }; |
| @@ -1305,7 +1305,7 @@ static void gb_svc_release(struct device *dev) · 1304 unmodified lines | |||
| 1305 | kfree(svc); | 1305 | kfree(svc); |
| 1306 | } | 1306 | } |
| 1307 | 1307 | ||
| 1308 | struct device_type greybus_svc_type = { | 1308 | const struct device_type greybus_svc_type = { |
| 1309 | .name = "greybus_svc", | 1309 | .name = "greybus_svc", |
| 1310 | .release = gb_svc_release, | 1310 | .release = gb_svc_release, |
| 1311 | }; | 1311 | }; |
| @@ -2,6 +2,26 @@ · 1 unmodified line | |||
| 2 | # | 2 | # |
| 3 | # Makefile for CoreSight drivers. | 3 | # Makefile for CoreSight drivers. |
| 4 | # | 4 | # |
| 5 | |||
| 6 | # Current W=1 warnings | ||
| 7 | subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter | ||
| 8 | subdir-ccflags-y += -Wmissing-declarations | ||
| 9 | subdir-ccflags-y += -Wmissing-format-attribute | ||
| 10 | subdir-ccflags-y += -Wmissing-prototypes | ||
| 11 | subdir-ccflags-y += -Wold-style-definition | ||
| 12 | subdir-ccflags-y += -Wmissing-include-dirs | ||
| 13 | subdir-ccflags-y += -Wno-sign-compare | ||
| 14 | condflags := \ | ||
| 15 | $(call cc-option, -Wrestrict) \ | ||
| 16 | $(call cc-option, -Wunused-but-set-variable) \ | ||
| 17 | $(call cc-option, -Wunused-const-variable) \ | ||
| 18 | $(call cc-option, -Wpacked-not-aligned) \ | ||
| 19 | $(call cc-option, -Wformat-overflow) \ | ||
| 20 | $(call cc-option, -Wformat-truncation) \ | ||
| 21 | $(call cc-option, -Wstringop-overflow) \ | ||
| 22 | $(call cc-option, -Wstringop-truncation) | ||
| 23 | subdir-ccflags-y += $(condflags) | ||
| 24 | |||
| 5 | obj-$(CONFIG_CORESIGHT) += coresight.o | 25 | obj-$(CONFIG_CORESIGHT) += coresight.o |
| 6 | coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ | 26 | coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ |
| 7 | coresight-sysfs.o coresight-syscfg.o coresight-config.o \ | 27 | coresight-sysfs.o coresight-syscfg.o coresight-config.o \ |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | /* ETMv4 includes and features */ | 9 | /* ETMv4 includes and features */ |
| 10 | #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) | 10 | #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) |
| 11 | #include "coresight-etm4x-cfg.h" | 11 | #include "coresight-etm4x-cfg.h" |
| 12 | #include "coresight-cfg-preload.h" | ||
| 12 | 13 | ||
| 13 | /* preload configurations and features */ | 14 | /* preload configurations and features */ |
| 14 | 15 | ||
| @@ -9,7 +9,6 @@ · 8 unmodified lines | |||
| 9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/io.h> | 11 | #include <linux/io.h> |
| 12 | #include <linux/idr.h> | ||
| 13 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 14 | #include <linux/export.h> | 13 | #include <linux/export.h> |
| 15 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| @@ -25,15 +24,12 @@ · 9 unmodified lines | |||
| 25 | #include "coresight-priv.h" | 24 | #include "coresight-priv.h" |
| 26 | #include "coresight-syscfg.h" | 25 | #include "coresight-syscfg.h" |
| 27 | 26 | ||
| 28 | static DEFINE_MUTEX(coresight_mutex); | ||
| 29 | static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); | ||
| 30 | |||
| 31 | /* | 27 | /* |
| 32 | * Use IDR to map the hash of the source's device name | 28 | * Mutex used to lock all sysfs enable and disable actions and loading and |
| 33 | * to the pointer of path for the source. The idr is for | 29 | * unloading devices by the Coresight core. |
| 34 | * the sources which aren't associated with CPU. | ||
| 35 | */ | 30 | */ |
| 36 | static DEFINE_IDR(path_idr); | 31 | DEFINE_MUTEX(coresight_mutex); |
| 32 | static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); | ||
| 37 | 33 | ||
| 38 | /** | 34 | /** |
| 39 | * struct coresight_node - elements of a path, from source to sink | 35 | * struct coresight_node - elements of a path, from source to sink |
| @@ -45,12 +41,6 @@ struct coresight_node { · 5 unmodified lines | |||
| 45 | struct list_head link; | 41 | struct list_head link; |
| 46 | }; | 42 | }; |
| 47 | 43 | ||
| 48 | /* | ||
| 49 | * When operating Coresight drivers from the sysFS interface, only a single | ||
| 50 | * path can exist from a tracer (associated to a CPU) to a sink. | ||
| 51 | */ | ||
| 52 | static DEFINE_PER_CPU(struct list_head *, tracer_path); | ||
| 53 | |||
| 54 | /* | 44 | /* |
| 55 | * When losing synchronisation a new barrier packet needs to be inserted at the | 45 | * When losing synchronisation a new barrier packet needs to be inserted at the |
| 56 | * beginning of the data collected in a buffer. That way the decoder knows that | 46 | * beginning of the data collected in a buffer. That way the decoder knows that |
| @@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt); · 4 unmodified lines | |||
| 61 | 51 | ||
| 62 | static const struct cti_assoc_op *cti_assoc_ops; | 52 | static const struct cti_assoc_op *cti_assoc_ops; |
| 63 | 53 | ||
| 64 | ssize_t coresight_simple_show_pair(struct device *_dev, | ||
| 65 | struct device_attribute *attr, char *buf) | ||
| 66 | { | ||
| 67 | struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||
| 68 | struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); | ||
| 69 | u64 val; | ||
| 70 | |||
| 71 | pm_runtime_get_sync(_dev->parent); | ||
| 72 | val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); | ||
| 73 | pm_runtime_put_sync(_dev->parent); | ||
| 74 | return sysfs_emit(buf, "0x%llx\n", val); | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL_GPL(coresight_simple_show_pair); | ||
| 77 | |||
| 78 | ssize_t coresight_simple_show32(struct device *_dev, | ||
| 79 | struct device_attribute *attr, char *buf) | ||
| 80 | { | ||
| 81 | struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||
| 82 | struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); | ||
| 83 | u64 val; | ||
| 84 | |||
| 85 | pm_runtime_get_sync(_dev->parent); | ||
| 86 | val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); | ||
| 87 | pm_runtime_put_sync(_dev->parent); | ||
| 88 | return sysfs_emit(buf, "0x%llx\n", val); | ||
| 89 | } | ||
| 90 | EXPORT_SYMBOL_GPL(coresight_simple_show32); | ||
| 91 | |||
| 92 | void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) | 54 | void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) |
| 93 | { | 55 | { |
| 94 | cti_assoc_ops = cti_op; | 56 | cti_assoc_ops = cti_op; |
| @@ -279,42 +241,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper); · 184 unmodified lines | |||
| 279 | static int coresight_enable_sink(struct coresight_device *csdev, | 241 | static int coresight_enable_sink(struct coresight_device *csdev, |
| 280 | enum cs_mode mode, void *data) | 242 | enum cs_mode mode, void *data) |
| 281 | { | 243 | { |
| 282 | int ret; | 244 | return sink_ops(csdev)->enable(csdev, mode, data); |
| 283 | |||
| 284 | /* | ||
| 285 | * We need to make sure the "new" session is compatible with the | ||
| 286 | * existing "mode" of operation. | ||
| 287 | */ | ||
| 288 | if (!sink_ops(csdev)->enable) | ||
| 289 | return -EINVAL; | ||
| 290 | |||
| 291 | ret = sink_ops(csdev)->enable(csdev, mode, data); | ||
| 292 | if (ret) | ||
| 293 | return ret; | ||
| 294 | |||
| 295 | csdev->enable = true; | ||
| 296 | |||
| 297 | return 0; | ||
| 298 | } | 245 | } |
| 299 | 246 | ||
| 300 | static void coresight_disable_sink(struct coresight_device *csdev) | 247 | static void coresight_disable_sink(struct coresight_device *csdev) |
| 301 | { | 248 | { |
| 302 | int ret; | 249 | sink_ops(csdev)->disable(csdev); |
| 303 | |||
| 304 | if (!sink_ops(csdev)->disable) | ||
| 305 | return; | ||
| 306 | |||
| 307 | ret = sink_ops(csdev)->disable(csdev); | ||
| 308 | if (ret) | ||
| 309 | return; | ||
| 310 | csdev->enable = false; | ||
| 311 | } | 250 | } |
| 312 | 251 | ||
| 313 | static int coresight_enable_link(struct coresight_device *csdev, | 252 | static int coresight_enable_link(struct coresight_device *csdev, |
| 314 | struct coresight_device *parent, | 253 | struct coresight_device *parent, |
| 315 | struct coresight_device *child) | 254 | struct coresight_device *child) |
| 316 | { | 255 | { |
| 317 | int ret = 0; | ||
| 318 | int link_subtype; | 256 | int link_subtype; |
| 319 | struct coresight_connection *inconn, *outconn; | 257 | struct coresight_connection *inconn, *outconn; |
| 320 | 258 | ||
| @@ -330,21 +268,13 @@ static int coresight_enable_link(struct coresight_device *csdev, · 9 unmodified lines | |||
| 330 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) | 268 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) |
| 331 | return PTR_ERR(outconn); | 269 | return PTR_ERR(outconn); |
| 332 | 270 | ||
| 333 | if (link_ops(csdev)->enable) { | 271 | return link_ops(csdev)->enable(csdev, inconn, outconn); |
| 334 | ret = link_ops(csdev)->enable(csdev, inconn, outconn); | ||
| 335 | if (!ret) | ||
| 336 | csdev->enable = true; | ||
| 337 | } | ||
| 338 | |||
| 339 | return ret; | ||
| 340 | } | 272 | } |
| 341 | 273 | ||
| 342 | static void coresight_disable_link(struct coresight_device *csdev, | 274 | static void coresight_disable_link(struct coresight_device *csdev, |
| 343 | struct coresight_device *parent, | 275 | struct coresight_device *parent, |
| 344 | struct coresight_device *child) | 276 | struct coresight_device *child) |
| 345 | { | 277 | { |
| 346 | int i; | ||
| 347 | int link_subtype; | ||
| 348 | struct coresight_connection *inconn, *outconn; | 278 | struct coresight_connection *inconn, *outconn; |
| 349 | 279 | ||
| 350 | if (!parent || !child) | 280 | if (!parent || !child) |
| @@ -352,49 +282,9 @@ static void coresight_disable_link(struct coresight_device *csdev, · 1 unmodified line | |||
| 352 | 282 | ||
| 353 | inconn = coresight_find_out_connection(parent, csdev); | 283 | inconn = coresight_find_out_connection(parent, csdev); |
| 354 | outconn = coresight_find_out_connection(csdev, child); | 284 | outconn = coresight_find_out_connection(csdev, child); |
| 355 | link_subtype = csdev->subtype.link_subtype; | ||
| 356 | 285 | ||
| 357 | if (link_ops(csdev)->disable) { | 286 | link_ops(csdev)->disable(csdev, inconn, outconn); |
| 358 | link_ops(csdev)->disable(csdev, inconn, outconn); | ||
| 359 | } | ||
| 360 | |||
| 361 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { | ||
| 362 | for (i = 0; i < csdev->pdata->nr_inconns; i++) | ||
| 363 | if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) != | ||
| 364 | 0) | ||
| 365 | return; | ||
| 366 | } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { | ||
| 367 | for (i = 0; i < csdev->pdata->nr_outconns; i++) | ||
| 368 | if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) != | ||
| 369 | 0) | ||
| 370 | return; | ||
| 371 | } else { | ||
| 372 | if (atomic_read(&csdev->refcnt) != 0) | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | |||
| 376 | csdev->enable = false; | ||
| 377 | } | ||
| 378 | |||
| 379 | int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, | ||
| 380 | void *data) | ||
| 381 | { | ||
| 382 | int ret; | ||
| 383 | |||
| 384 | if (!csdev->enable) { | ||
| 385 | if (source_ops(csdev)->enable) { | ||
| 386 | ret = source_ops(csdev)->enable(csdev, data, mode); | ||
| 387 | if (ret) | ||
| 388 | return ret; | ||
| 389 | } | ||
| 390 | csdev->enable = true; | ||
| 391 | } | ||
| 392 | |||
| 393 | atomic_inc(&csdev->refcnt); | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | 287 | } |
| 397 | EXPORT_SYMBOL_GPL(coresight_enable_source); | ||
| 398 | 288 | ||
| 399 | static bool coresight_is_helper(struct coresight_device *csdev) | 289 | static bool coresight_is_helper(struct coresight_device *csdev) |
| 400 | { | 290 | { |
| @@ -404,29 +294,12 @@ static bool coresight_is_helper(struct coresight_device *csdev) · 3 unmodified lines | |||
| 404 | static int coresight_enable_helper(struct coresight_device *csdev, | 294 | static int coresight_enable_helper(struct coresight_device *csdev, |
| 405 | enum cs_mode mode, void *data) | 295 | enum cs_mode mode, void *data) |
| 406 | { | 296 | { |
| 407 | int ret; | 297 | return helper_ops(csdev)->enable(csdev, mode, data); |
| 408 | |||
| 409 | if (!helper_ops(csdev)->enable) | ||
| 410 | return 0; | ||
| 411 | ret = helper_ops(csdev)->enable(csdev, mode, data); | ||
| 412 | if (ret) | ||
| 413 | return ret; | ||
| 414 | |||
| 415 | csdev->enable = true; | ||
| 416 | return 0; | ||
| 417 | } | 298 | } |
| 418 | 299 | ||
| 419 | static void coresight_disable_helper(struct coresight_device *csdev) | 300 | static void coresight_disable_helper(struct coresight_device *csdev) |
| 420 | { | 301 | { |
| 421 | int ret; | 302 | helper_ops(csdev)->disable(csdev, NULL); |
| 422 | |||
| 423 | if (!helper_ops(csdev)->disable) | ||
| 424 | return; | ||
| 425 | |||
| 426 | ret = helper_ops(csdev)->disable(csdev, NULL); | ||
| 427 | if (ret) | ||
| 428 | return; | ||
| 429 | csdev->enable = false; | ||
| 430 | } | 303 | } |
| 431 | 304 | ||
| 432 | static void coresight_disable_helpers(struct coresight_device *csdev) | 305 | static void coresight_disable_helpers(struct coresight_device *csdev) |
| @@ -441,25 +314,20 @@ static void coresight_disable_helpers(struct coresight_device *csdev) · 8 unmodified lines | |||
| 441 | } | 314 | } |
| 442 | } | 315 | } |
| 443 | 316 | ||
| 444 | /** | 317 | /* |
| 445 | * coresight_disable_source - Drop the reference count by 1 and disable | 318 | * Helper function to call source_ops(csdev)->disable and also disable the |
| 446 | * the device if there are no users left. | 319 | * helpers. |
| 447 | * | ||
| 448 | * @csdev: The coresight device to disable | ||
| 449 | * @data: Opaque data to pass on to the disable function of the source device. | ||
| 450 | * For example in perf mode this is a pointer to the struct perf_event. | ||
| 451 | * | 320 | * |
| 452 | * Returns true if the device has been disabled. | 321 | * There is an imbalance between coresight_enable_path() and |
| 322 | * coresight_disable_path(). Enabling also enables the source's helpers as part | ||
| 323 | * of the path, but disabling always skips the first item in the path (which is | ||
| 324 | * the source), so sources and their helpers don't get disabled as part of that | ||
| 325 | * function and we need the extra step here. | ||
| 453 | */ | 326 | */ |
| 454 | bool coresight_disable_source(struct coresight_device *csdev, void *data) | 327 | void coresight_disable_source(struct coresight_device *csdev, void *data) |
| 455 | { | 328 | { |
| 456 | if (atomic_dec_return(&csdev->refcnt) == 0) { | 329 | source_ops(csdev)->disable(csdev, data); |
| 457 | if (source_ops(csdev)->disable) | 330 | coresight_disable_helpers(csdev); |
| 458 | source_ops(csdev)->disable(csdev, data); | ||
| 459 | coresight_disable_helpers(csdev); | ||
| 460 | csdev->enable = false; | ||
| 461 | } | ||
| 462 | return !csdev->enable; | ||
| 463 | } | 331 | } |
| 464 | EXPORT_SYMBOL_GPL(coresight_disable_source); | 332 | EXPORT_SYMBOL_GPL(coresight_disable_source); |
| 465 | 333 | ||
| @@ -484,7 +352,7 @@ static void coresight_disable_path_from(struct list_head *path, · 18 unmodified lines | |||
| 484 | /* | 352 | /* |
| 485 | * ETF devices are tricky... They can be a link or a sink, | 353 | * ETF devices are tricky... They can be a link or a sink, |
| 486 | * depending on how they are configured. If an ETF has been | 354 | * depending on how they are configured. If an ETF has been |
| 487 | * "activated" it will be configured as a sink, otherwise | 355 | * selected as a sink it will be configured as a sink, otherwise |
| 488 | * go ahead with the link configuration. | 356 | * go ahead with the link configuration. |
| 489 | */ | 357 | */ |
| 490 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) | 358 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) |
| @@ -562,7 +430,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, · 71 unmodified lines | |||
| 562 | /* | 430 | /* |
| 563 | * ETF devices are tricky... They can be a link or a sink, | 431 | * ETF devices are tricky... They can be a link or a sink, |
| 564 | * depending on how they are configured. If an ETF has been | 432 | * depending on how they are configured. If an ETF has been |
| 565 | * "activated" it will be configured as a sink, otherwise | 433 | * selected as a sink it will be configured as a sink, otherwise |
| 566 | * go ahead with the link configuration. | 434 | * go ahead with the link configuration. |
| 567 | */ | 435 | */ |
| 568 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) | 436 | if (type == CORESIGHT_DEV_TYPE_LINKSINK) |
| @@ -619,48 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path) · 50 unmodified lines | |||
| 619 | return csdev; | 487 | return csdev; |
| 620 | } | 488 | } |
| 621 | 489 | ||
| 622 | static struct coresight_device * | ||
| 623 | coresight_find_enabled_sink(struct coresight_device *csdev) | ||
| 624 | { | ||
| 625 | int i; | ||
| 626 | struct coresight_device *sink = NULL; | ||
| 627 | |||
| 628 | if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || | ||
| 629 | csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && | ||
| 630 | csdev->activated) | ||
| 631 | return csdev; | ||
| 632 | |||
| 633 | /* | ||
| 634 | * Recursively explore each port found on this element. | ||
| 635 | */ | ||
| 636 | for (i = 0; i < csdev->pdata->nr_outconns; i++) { | ||
| 637 | struct coresight_device *child_dev; | ||
| 638 | |||
| 639 | child_dev = csdev->pdata->out_conns[i]->dest_dev; | ||
| 640 | if (child_dev) | ||
| 641 | sink = coresight_find_enabled_sink(child_dev); | ||
| 642 | if (sink) | ||
| 643 | return sink; | ||
| 644 | } | ||
| 645 | |||
| 646 | return NULL; | ||
| 647 | } | ||
| 648 | |||
| 649 | /** | ||
| 650 | * coresight_get_enabled_sink - returns the first enabled sink using | ||
| 651 | * connection based search starting from the source reference | ||
| 652 | * | ||
| 653 | * @source: Coresight source device reference | ||
| 654 | */ | ||
| 655 | struct coresight_device * | ||
| 656 | coresight_get_enabled_sink(struct coresight_device *source) | ||
| 657 | { | ||
| 658 | if (!source) | ||
| 659 | return NULL; | ||
| 660 | |||
| 661 | return coresight_find_enabled_sink(source); | ||
| 662 | } | ||
| 663 | |||
| 664 | static int coresight_sink_by_id(struct device *dev, const void *data) | 490 | static int coresight_sink_by_id(struct device *dev, const void *data) |
| 665 | { | 491 | { |
| 666 | struct coresight_device *csdev = to_coresight_device(dev); | 492 | struct coresight_device *csdev = to_coresight_device(dev); |
| @@ -794,11 +620,10 @@ static void coresight_drop_device(struct coresight_device *csdev) · 127 unmodified lines | |||
| 794 | * @sink: The final sink we want in this path. | 620 | * @sink: The final sink we want in this path. |
| 795 | * @path: The list to add devices to. | 621 | * @path: The list to add devices to. |
| 796 | * | 622 | * |
| 797 | * The tree of Coresight device is traversed until an activated sink is | 623 | * The tree of Coresight device is traversed until @sink is found. |
| 798 | * found. From there the sink is added to the list along with all the | 624 | * From there the sink is added to the list along with all the devices that led |
| 799 | * devices that led to that point - the end result is a list from source | 625 | * to that point - the end result is a list from source to sink. In that list |
| 800 | * to sink. In that list the source is the first device and the sink the | 626 | * the source is the first device and the sink the last one. |
| 801 | * last one. | ||
| 802 | */ | 627 | */ |
| 803 | static int _coresight_build_path(struct coresight_device *csdev, | 628 | static int _coresight_build_path(struct coresight_device *csdev, |
| 804 | struct coresight_device *sink, | 629 | struct coresight_device *sink, |
| @@ -808,7 +633,7 @@ static int _coresight_build_path(struct coresight_device *csdev, · 3 unmodified lines | |||
| 808 | bool found = false; | 633 | bool found = false; |
| 809 | struct coresight_node *node; | 634 | struct coresight_node *node; |
| 810 | 635 | ||
| 811 | /* An activated sink has been found. Enqueue the element */ | 636 | /* The sink has been found. Enqueue the element */ |
| 812 | if (csdev == sink) | 637 | if (csdev == sink) |
| 813 | goto out; | 638 | goto out; |
| 814 | 639 | ||
| @@ -1072,269 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev) · 257 unmodified lines | |||
| 1072 | } | 897 | } |
| 1073 | } | 898 | } |
| 1074 | 899 | ||
| 1075 | /** coresight_validate_source - make sure a source has the right credentials | ||
| 1076 | * @csdev: the device structure for a source. | ||
| 1077 | * @function: the function this was called from. | ||
| 1078 | * | ||
| 1079 | * Assumes the coresight_mutex is held. | ||
| 1080 | */ | ||
| 1081 | static int coresight_validate_source(struct coresight_device *csdev, | ||
| 1082 | const char *function) | ||
| 1083 | { | ||
| 1084 | u32 type, subtype; | ||
| 1085 | |||
| 1086 | type = csdev->type; | ||
| 1087 | subtype = csdev->subtype.source_subtype; | ||
| 1088 | |||
| 1089 | if (type != CORESIGHT_DEV_TYPE_SOURCE) { | ||
| 1090 | dev_err(&csdev->dev, "wrong device type in %s\n", function); | ||
| 1091 | return -EINVAL; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && | ||
| 1095 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && | ||
| 1096 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && | ||
| 1097 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { | ||
| 1098 | dev_err(&csdev->dev, "wrong device subtype in %s\n", function); | ||
| 1099 | return -EINVAL; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | int coresight_enable(struct coresight_device *csdev) | ||
| 1106 | { | ||
| 1107 | int cpu, ret = 0; | ||
| 1108 | struct coresight_device *sink; | ||
| 1109 | struct list_head *path; | ||
| 1110 | enum coresight_dev_subtype_source subtype; | ||
| 1111 | u32 hash; | ||
| 1112 | |||
| 1113 | subtype = csdev->subtype.source_subtype; | ||
| 1114 | |||
| 1115 | mutex_lock(&coresight_mutex); | ||
| 1116 | |||
| 1117 | ret = coresight_validate_source(csdev, __func__); | ||
| 1118 | if (ret) | ||
| 1119 | goto out; | ||
| 1120 | |||
| 1121 | if (csdev->enable) { | ||
| 1122 | /* | ||
| 1123 | * There could be multiple applications driving the software | ||
| 1124 | * source. So keep the refcount for each such user when the | ||
| 1125 | * source is already enabled. | ||
| 1126 | */ | ||
| 1127 | if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) | ||
| 1128 | atomic_inc(&csdev->refcnt); | ||
| 1129 | goto out; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | sink = coresight_get_enabled_sink(csdev); | ||
| 1133 | if (!sink) { | ||
| 1134 | ret = -EINVAL; | ||
| 1135 | goto out; | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | path = coresight_build_path(csdev, sink); | ||
| 1139 | if (IS_ERR(path)) { | ||
| 1140 | pr_err("building path(s) failed\n"); | ||
| 1141 | ret = PTR_ERR(path); | ||
| 1142 | goto out; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); | ||
| 1146 | if (ret) | ||
| 1147 | goto err_path; | ||
| 1148 | |||
| 1149 | ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL); | ||
| 1150 | if (ret) | ||
| 1151 | goto err_source; | ||
| 1152 | |||
| 1153 | switch (subtype) { | ||
| 1154 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||
| 1155 | /* | ||
| 1156 | * When working from sysFS it is important to keep track | ||
| 1157 | * of the paths that were created so that they can be | ||
| 1158 | * undone in 'coresight_disable()'. Since there can only | ||
| 1159 | * be a single session per tracer (when working from sysFS) | ||
| 1160 | * a per-cpu variable will do just fine. | ||
| 1161 | */ | ||
| 1162 | cpu = source_ops(csdev)->cpu_id(csdev); | ||
| 1163 | per_cpu(tracer_path, cpu) = path; | ||
| 1164 | break; | ||
| 1165 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||
| 1166 | case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||
| 1167 | case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||
| 1168 | /* | ||
| 1169 | * Use the hash of source's device name as ID | ||
| 1170 | * and map the ID to the pointer of the path. | ||
| 1171 | */ | ||
| 1172 | hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||
| 1173 | ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); | ||
| 1174 | if (ret) | ||
| 1175 | goto err_source; | ||
| 1176 | break; | ||
| 1177 | default: | ||
| 1178 | /* We can't be here */ | ||
| 1179 | break; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | out: | ||
| 1183 | mutex_unlock(&coresight_mutex); | ||
| 1184 | return ret; | ||
| 1185 | |||
| 1186 | err_source: | ||
| 1187 | coresight_disable_path(path); | ||
| 1188 | |||
| 1189 | err_path: | ||
| 1190 | coresight_release_path(path); | ||
| 1191 | goto out; | ||
| 1192 | } | ||
| 1193 | EXPORT_SYMBOL_GPL(coresight_enable); | ||
| 1194 | |||
| 1195 | void coresight_disable(struct coresight_device *csdev) | ||
| 1196 | { | ||
| 1197 | int cpu, ret; | ||
| 1198 | struct list_head *path = NULL; | ||
| 1199 | u32 hash; | ||
| 1200 | |||
| 1201 | mutex_lock(&coresight_mutex); | ||
| 1202 | |||
| 1203 | ret = coresight_validate_source(csdev, __func__); | ||
| 1204 | if (ret) | ||
| 1205 | goto out; | ||
| 1206 | |||
| 1207 | if (!csdev->enable || !coresight_disable_source(csdev, NULL)) | ||
| 1208 | goto out; | ||
| 1209 | |||
| 1210 | switch (csdev->subtype.source_subtype) { | ||
| 1211 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||
| 1212 | cpu = source_ops(csdev)->cpu_id(csdev); | ||
| 1213 | path = per_cpu(tracer_path, cpu); | ||
| 1214 | per_cpu(tracer_path, cpu) = NULL; | ||
| 1215 | break; | ||
| 1216 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||
| 1217 | case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||
| 1218 | case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||
| 1219 | hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||
| 1220 | /* Find the path by the hash. */ | ||
| 1221 | path = idr_find(&path_idr, hash); | ||
| 1222 | if (path == NULL) { | ||
| 1223 | pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); | ||
| 1224 | goto out; | ||
| 1225 | } | ||
| 1226 | idr_remove(&path_idr, hash); | ||
| 1227 | break; | ||
| 1228 | default: | ||
| 1229 | /* We can't be here */ | ||
| 1230 | break; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | coresight_disable_path(path); | ||
| 1234 | coresight_release_path(path); | ||
| 1235 | |||
| 1236 | out: | ||
| 1237 | mutex_unlock(&coresight_mutex); | ||
| 1238 | } | ||
| 1239 | EXPORT_SYMBOL_GPL(coresight_disable); | ||
| 1240 | |||
| 1241 | static ssize_t enable_sink_show(struct device *dev, | ||
| 1242 | struct device_attribute *attr, char *buf) | ||
| 1243 | { | ||
| 1244 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 1245 | |||
| 1246 | return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated); | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static ssize_t enable_sink_store(struct device *dev, | ||
| 1250 | struct device_attribute *attr, | ||
| 1251 | const char *buf, size_t size) | ||
| 1252 | { | ||
| 1253 | int ret; | ||
| 1254 | unsigned long val; | ||
| 1255 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 1256 | |||
| 1257 | ret = kstrtoul(buf, 10, &val); | ||
| 1258 | if (ret) | ||
| 1259 | return ret; | ||
| 1260 | |||
| 1261 | if (val) | ||
| 1262 | csdev->activated = true; | ||
| 1263 | else | ||
| 1264 | csdev->activated = false; | ||
| 1265 | |||
| 1266 | return size; | ||
| 1267 | |||
| 1268 | } | ||
| 1269 | static DEVICE_ATTR_RW(enable_sink); | ||
| 1270 | |||
| 1271 | static ssize_t enable_source_show(struct device *dev, | ||
| 1272 | struct device_attribute *attr, char *buf) | ||
| 1273 | { | ||
| 1274 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 1275 | |||
| 1276 | return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static ssize_t enable_source_store(struct device *dev, | ||
| 1280 | struct device_attribute *attr, | ||
| 1281 | const char *buf, size_t size) | ||
| 1282 | { | ||
| 1283 | int ret = 0; | ||
| 1284 | unsigned long val; | ||
| 1285 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 1286 | |||
| 1287 | ret = kstrtoul(buf, 10, &val); | ||
| 1288 | if (ret) | ||
| 1289 | return ret; | ||
| 1290 | |||
| 1291 | if (val) { | ||
| 1292 | ret = coresight_enable(csdev); | ||
| 1293 | if (ret) | ||
| 1294 | return ret; | ||
| 1295 | } else { | ||
| 1296 | coresight_disable(csdev); | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | return size; | ||
| 1300 | } | ||
| 1301 | static DEVICE_ATTR_RW(enable_source); | ||
| 1302 | |||
| 1303 | static struct attribute *coresight_sink_attrs[] = { | ||
| 1304 | &dev_attr_enable_sink.attr, | ||
| 1305 | NULL, | ||
| 1306 | }; | ||
| 1307 | ATTRIBUTE_GROUPS(coresight_sink); | ||
| 1308 | |||
| 1309 | static struct attribute *coresight_source_attrs[] = { | ||
| 1310 | &dev_attr_enable_source.attr, | ||
| 1311 | NULL, | ||
| 1312 | }; | ||
| 1313 | ATTRIBUTE_GROUPS(coresight_source); | ||
| 1314 | |||
| 1315 | static struct device_type coresight_dev_type[] = { | ||
| 1316 | { | ||
| 1317 | .name = "sink", | ||
| 1318 | .groups = coresight_sink_groups, | ||
| 1319 | }, | ||
| 1320 | { | ||
| 1321 | .name = "link", | ||
| 1322 | }, | ||
| 1323 | { | ||
| 1324 | .name = "linksink", | ||
| 1325 | .groups = coresight_sink_groups, | ||
| 1326 | }, | ||
| 1327 | { | ||
| 1328 | .name = "source", | ||
| 1329 | .groups = coresight_source_groups, | ||
| 1330 | }, | ||
| 1331 | { | ||
| 1332 | .name = "helper", | ||
| 1333 | } | ||
| 1334 | }; | ||
| 1335 | /* Ensure the enum matches the names and groups */ | ||
| 1336 | static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); | ||
| 1337 | |||
| 1338 | static void coresight_device_release(struct device *dev) | 900 | static void coresight_device_release(struct device *dev) |
| 1339 | { | 901 | { |
| 1340 | struct coresight_device *csdev = to_coresight_device(dev); | 902 | struct coresight_device *csdev = to_coresight_device(dev); |
| @@ -1799,7 +1361,7 @@ done: · 458 unmodified lines | |||
| 1799 | } | 1361 | } |
| 1800 | EXPORT_SYMBOL_GPL(coresight_alloc_device_name); | 1362 | EXPORT_SYMBOL_GPL(coresight_alloc_device_name); |
| 1801 | 1363 | ||
| 1802 | struct bus_type coresight_bustype = { | 1364 | const struct bus_type coresight_bustype = { |
| 1803 | .name = "coresight", | 1365 | .name = "coresight", |
| 1804 | }; | 1366 | }; |
| 1805 | 1367 | ||
| @@ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = { · 973 unmodified lines | |||
| 974 | CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ | 974 | CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ |
| 975 | CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ | 975 | CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ |
| 976 | CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ | 976 | CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ |
| 977 | { 0, 0}, | 977 | { 0, 0, NULL }, |
| 978 | }; | 978 | }; |
| 979 | 979 | ||
| 980 | MODULE_DEVICE_TABLE(amba, cti_ids); | 980 | MODULE_DEVICE_TABLE(amba, cti_ids); |
| @@ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb"); · 75 unmodified lines | |||
| 76 | * @pid: Process ID of the process being monitored by the session | 76 | * @pid: Process ID of the process being monitored by the session |
| 77 | * that is using this component. | 77 | * that is using this component. |
| 78 | * @buf: area of memory where ETB buffer content gets sent. | 78 | * @buf: area of memory where ETB buffer content gets sent. |
| 79 | * @mode: this ETB is being used. | ||
| 80 | * @buffer_depth: size of @buf. | 79 | * @buffer_depth: size of @buf. |
| 81 | * @trigger_cntr: amount of words to store after a trigger. | 80 | * @trigger_cntr: amount of words to store after a trigger. |
| 82 | */ | 81 | */ |
| @@ -89,7 +88,6 @@ struct etb_drvdata { · 6 unmodified lines | |||
| 89 | local_t reading; | 88 | local_t reading; |
| 90 | pid_t pid; | 89 | pid_t pid; |
| 91 | u8 *buf; | 90 | u8 *buf; |
| 92 | u32 mode; | ||
| 93 | u32 buffer_depth; | 91 | u32 buffer_depth; |
| 94 | u32 trigger_cntr; | 92 | u32 trigger_cntr; |
| 95 | }; | 93 | }; |
| @@ -150,20 +148,20 @@ static int etb_enable_sysfs(struct coresight_device *csdev) · 54 unmodified lines | |||
| 150 | spin_lock_irqsave(&drvdata->spinlock, flags); | 148 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 151 | 149 | ||
| 152 | /* Don't messup with perf sessions. */ | 150 | /* Don't messup with perf sessions. */ |
| 153 | if (drvdata->mode == CS_MODE_PERF) { | 151 | if (coresight_get_mode(csdev) == CS_MODE_PERF) { |
| 154 | ret = -EBUSY; | 152 | ret = -EBUSY; |
| 155 | goto out; | 153 | goto out; |
| 156 | } | 154 | } |
| 157 | 155 | ||
| 158 | if (drvdata->mode == CS_MODE_DISABLED) { | 156 | if (coresight_get_mode(csdev) == CS_MODE_DISABLED) { |
| 159 | ret = etb_enable_hw(drvdata); | 157 | ret = etb_enable_hw(drvdata); |
| 160 | if (ret) | 158 | if (ret) |
| 161 | goto out; | 159 | goto out; |
| 162 | 160 | ||
| 163 | drvdata->mode = CS_MODE_SYSFS; | 161 | coresight_set_mode(csdev, CS_MODE_SYSFS); |
| 164 | } | 162 | } |
| 165 | 163 | ||
| 166 | atomic_inc(&csdev->refcnt); | 164 | csdev->refcnt++; |
| 167 | out: | 165 | out: |
| 168 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 166 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 169 | return ret; | 167 | return ret; |
| @@ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) · 11 unmodified lines | |||
| 181 | spin_lock_irqsave(&drvdata->spinlock, flags); | 179 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 182 | 180 | ||
| 183 | /* No need to continue if the component is already in used by sysFS. */ | 181 | /* No need to continue if the component is already in used by sysFS. */ |
| 184 | if (drvdata->mode == CS_MODE_SYSFS) { | 182 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { |
| 185 | ret = -EBUSY; | 183 | ret = -EBUSY; |
| 186 | goto out; | 184 | goto out; |
| 187 | } | 185 | } |
| @@ -199,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) · 11 unmodified lines | |||
| 199 | * use for this session. | 197 | * use for this session. |
| 200 | */ | 198 | */ |
| 201 | if (drvdata->pid == pid) { | 199 | if (drvdata->pid == pid) { |
| 202 | atomic_inc(&csdev->refcnt); | 200 | csdev->refcnt++; |
| 203 | goto out; | 201 | goto out; |
| 204 | } | 202 | } |
| 205 | 203 | ||
| @@ -216,8 +214,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) · 10 unmodified lines | |||
| 216 | if (!ret) { | 214 | if (!ret) { |
| 217 | /* Associate with monitored process. */ | 215 | /* Associate with monitored process. */ |
| 218 | drvdata->pid = pid; | 216 | drvdata->pid = pid; |
| 219 | drvdata->mode = CS_MODE_PERF; | 217 | coresight_set_mode(drvdata->csdev, CS_MODE_PERF); |
| 220 | atomic_inc(&csdev->refcnt); | 218 | csdev->refcnt++; |
| 221 | } | 219 | } |
| 222 | 220 | ||
| 223 | out: | 221 | out: |
| @@ -356,17 +354,18 @@ static int etb_disable(struct coresight_device *csdev) · 132 unmodified lines | |||
| 356 | 354 | ||
| 357 | spin_lock_irqsave(&drvdata->spinlock, flags); | 355 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 358 | 356 | ||
| 359 | if (atomic_dec_return(&csdev->refcnt)) { | 357 | csdev->refcnt--; |
| 358 | if (csdev->refcnt) { | ||
| 360 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 359 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 361 | return -EBUSY; | 360 | return -EBUSY; |
| 362 | } | 361 | } |
| 363 | 362 | ||
| 364 | /* Complain if we (somehow) got out of sync */ | 363 | /* Complain if we (somehow) got out of sync */ |
| 365 | WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 364 | WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); |
| 366 | etb_disable_hw(drvdata); | 365 | etb_disable_hw(drvdata); |
| 367 | /* Dissociate from monitored process. */ | 366 | /* Dissociate from monitored process. */ |
| 368 | drvdata->pid = -1; | 367 | drvdata->pid = -1; |
| 369 | drvdata->mode = CS_MODE_DISABLED; | 368 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 370 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 369 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 371 | 370 | ||
| 372 | dev_dbg(&csdev->dev, "ETB disabled\n"); | 371 | dev_dbg(&csdev->dev, "ETB disabled\n"); |
| @@ -447,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, · 74 unmodified lines | |||
| 447 | spin_lock_irqsave(&drvdata->spinlock, flags); | 446 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 448 | 447 | ||
| 449 | /* Don't do anything if another tracer is using this sink */ | 448 | /* Don't do anything if another tracer is using this sink */ |
| 450 | if (atomic_read(&csdev->refcnt) != 1) | 449 | if (csdev->refcnt != 1) |
| 451 | goto out; | 450 | goto out; |
| 452 | 451 | ||
| 453 | __etb_disable_hw(drvdata); | 452 | __etb_disable_hw(drvdata); |
| @@ -589,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata) · 135 unmodified lines | |||
| 589 | unsigned long flags; | 588 | unsigned long flags; |
| 590 | 589 | ||
| 591 | spin_lock_irqsave(&drvdata->spinlock, flags); | 590 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 592 | if (drvdata->mode == CS_MODE_SYSFS) { | 591 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { |
| 593 | __etb_disable_hw(drvdata); | 592 | __etb_disable_hw(drvdata); |
| 594 | etb_dump_hw(drvdata); | 593 | etb_dump_hw(drvdata); |
| 595 | __etb_enable_hw(drvdata); | 594 | __etb_enable_hw(drvdata); |
| @@ -837,7 +836,7 @@ static const struct amba_id etb_ids[] = { · 241 unmodified lines | |||
| 837 | .id = 0x000bb907, | 836 | .id = 0x000bb907, |
| 838 | .mask = 0x000fffff, | 837 | .mask = 0x000fffff, |
| 839 | }, | 838 | }, |
| 840 | { 0, 0}, | 839 | { 0, 0, NULL }, |
| 841 | }; | 840 | }; |
| 842 | 841 | ||
| 843 | MODULE_DEVICE_TABLE(amba, etb_ids); | 842 | MODULE_DEVICE_TABLE(amba, etb_ids); |
| @@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode) · 588 unmodified lines | |||
| 589 | return; | 589 | return; |
| 590 | 590 | ||
| 591 | /* stop tracer */ | 591 | /* stop tracer */ |
| 592 | source_ops(csdev)->disable(csdev, event); | 592 | coresight_disable_source(csdev, event); |
| 593 | 593 | ||
| 594 | /* tell the core */ | 594 | /* tell the core */ |
| 595 | event->hw.state = PERF_HES_STOPPED; | 595 | event->hw.state = PERF_HES_STOPPED; |
| @@ -215,7 +215,6 @@ struct etm_config { · 214 unmodified lines | |||
| 215 | * @port_size: port size as reported by ETMCR bit 4-6 and 21. | 215 | * @port_size: port size as reported by ETMCR bit 4-6 and 21. |
| 216 | * @arch: ETM/PTM version number. | 216 | * @arch: ETM/PTM version number. |
| 217 | * @use_cpu14: true if management registers need to be accessed via CP14. | 217 | * @use_cpu14: true if management registers need to be accessed via CP14. |
| 218 | * @mode: this tracer's mode, i.e sysFS, Perf or disabled. | ||
| 219 | * @sticky_enable: true if ETM base configuration has been done. | 218 | * @sticky_enable: true if ETM base configuration has been done. |
| 220 | * @boot_enable:true if we should start tracing at boot time. | 219 | * @boot_enable:true if we should start tracing at boot time. |
| 221 | * @os_unlock: true if access to management registers is allowed. | 220 | * @os_unlock: true if access to management registers is allowed. |
| @@ -238,7 +237,6 @@ struct etm_drvdata { · 16 unmodified lines | |||
| 238 | int port_size; | 237 | int port_size; |
| 239 | u8 arch; | 238 | u8 arch; |
| 240 | bool use_cp14; | 239 | bool use_cp14; |
| 241 | local_t mode; | ||
| 242 | bool sticky_enable; | 240 | bool sticky_enable; |
| 243 | bool boot_enable; | 241 | bool boot_enable; |
| 244 | bool os_unlock; | 242 | bool os_unlock; |
| @@ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) · 114 unmodified lines | |||
| 115 | * | 115 | * |
| 116 | * Basically the same as @coresight_timeout except for the register access | 116 | * Basically the same as @coresight_timeout except for the register access |
| 117 | * method where we have to account for CP14 configurations. | 117 | * method where we have to account for CP14 configurations. |
| 118 | 118 | * | |
| 119 | * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if | 119 | * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if |
| 120 | * TIMEOUT_US has elapsed, which ever happens first. | 120 | * TIMEOUT_US has elapsed, which ever happens first. |
| 121 | */ | 121 | */ |
| @@ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, · 434 unmodified lines | |||
| 556 | enum cs_mode mode) | 556 | enum cs_mode mode) |
| 557 | { | 557 | { |
| 558 | int ret; | 558 | int ret; |
| 559 | u32 val; | ||
| 560 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 559 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 561 | 560 | ||
| 562 | val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | 561 | if (!coresight_take_mode(csdev, mode)) { |
| 563 | 562 | /* Someone is already using the tracer */ | |
| 564 | /* Someone is already using the tracer */ | ||
| 565 | if (val) | ||
| 566 | return -EBUSY; | 563 | return -EBUSY; |
| 564 | } | ||
| 567 | 565 | ||
| 568 | switch (mode) { | 566 | switch (mode) { |
| 569 | case CS_MODE_SYSFS: | 567 | case CS_MODE_SYSFS: |
| @@ -578,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, · 8 unmodified lines | |||
| 578 | 576 | ||
| 579 | /* The tracer didn't start */ | 577 | /* The tracer didn't start */ |
| 580 | if (ret) | 578 | if (ret) |
| 581 | local_set(&drvdata->mode, CS_MODE_DISABLED); | 579 | coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); |
| 582 | 580 | ||
| 583 | return ret; | 581 | return ret; |
| 584 | } | 582 | } |
| @@ -672,14 +670,13 @@ static void etm_disable(struct coresight_device *csdev, · 87 unmodified lines | |||
| 672 | struct perf_event *event) | 670 | struct perf_event *event) |
| 673 | { | 671 | { |
| 674 | enum cs_mode mode; | 672 | enum cs_mode mode; |
| 675 | struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
| 676 | 673 | ||
| 677 | /* | 674 | /* |
| 678 | * For as long as the tracer isn't disabled another entity can't | 675 | * For as long as the tracer isn't disabled another entity can't |
| 679 | * change its status. As such we can read the status here without | 676 | * change its status. As such we can read the status here without |
| 680 | * fearing it will change under us. | 677 | * fearing it will change under us. |
| 681 | */ | 678 | */ |
| 682 | mode = local_read(&drvdata->mode); | 679 | mode = coresight_get_mode(csdev); |
| 683 | 680 | ||
| 684 | switch (mode) { | 681 | switch (mode) { |
| 685 | case CS_MODE_DISABLED: | 682 | case CS_MODE_DISABLED: |
| @@ -696,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev, · 10 unmodified lines | |||
| 696 | } | 693 | } |
| 697 | 694 | ||
| 698 | if (mode) | 695 | if (mode) |
| 699 | local_set(&drvdata->mode, CS_MODE_DISABLED); | 696 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 700 | } | 697 | } |
| 701 | 698 | ||
| 702 | static const struct coresight_ops_source etm_source_ops = { | 699 | static const struct coresight_ops_source etm_source_ops = { |
| @@ -715,7 +712,7 @@ static int etm_online_cpu(unsigned int cpu) · 12 unmodified lines | |||
| 715 | return 0; | 712 | return 0; |
| 716 | 713 | ||
| 717 | if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | 714 | if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) |
| 718 | coresight_enable(etmdrvdata[cpu]->csdev); | 715 | coresight_enable_sysfs(etmdrvdata[cpu]->csdev); |
| 719 | return 0; | 716 | return 0; |
| 720 | } | 717 | } |
| 721 | 718 | ||
| @@ -730,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu) · 8 unmodified lines | |||
| 730 | etmdrvdata[cpu]->os_unlock = true; | 727 | etmdrvdata[cpu]->os_unlock = true; |
| 731 | } | 728 | } |
| 732 | 729 | ||
| 733 | if (local_read(&etmdrvdata[cpu]->mode)) | 730 | if (coresight_get_mode(etmdrvdata[cpu]->csdev)) |
| 734 | etm_enable_hw(etmdrvdata[cpu]); | 731 | etm_enable_hw(etmdrvdata[cpu]); |
| 735 | spin_unlock(&etmdrvdata[cpu]->spinlock); | 732 | spin_unlock(&etmdrvdata[cpu]->spinlock); |
| 736 | return 0; | 733 | return 0; |
| @@ -742,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu) · 5 unmodified lines | |||
| 742 | return 0; | 739 | return 0; |
| 743 | 740 | ||
| 744 | spin_lock(&etmdrvdata[cpu]->spinlock); | 741 | spin_lock(&etmdrvdata[cpu]->spinlock); |
| 745 | if (local_read(&etmdrvdata[cpu]->mode)) | 742 | if (coresight_get_mode(etmdrvdata[cpu]->csdev)) |
| 746 | etm_disable_hw(etmdrvdata[cpu]); | 743 | etm_disable_hw(etmdrvdata[cpu]); |
| 747 | spin_unlock(&etmdrvdata[cpu]->spinlock); | 744 | spin_unlock(&etmdrvdata[cpu]->spinlock); |
| 748 | return 0; | 745 | return 0; |
| @@ -925,7 +922,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) · 176 unmodified lines | |||
| 925 | dev_info(&drvdata->csdev->dev, | 922 | dev_info(&drvdata->csdev->dev, |
| 926 | "%s initialized\n", (char *)coresight_get_uci_data(id)); | 923 | "%s initialized\n", (char *)coresight_get_uci_data(id)); |
| 927 | if (boot_enable) { | 924 | if (boot_enable) { |
| 928 | coresight_enable(drvdata->csdev); | 925 | coresight_enable_sysfs(drvdata->csdev); |
| 929 | drvdata->boot_enable = true; | 926 | drvdata->boot_enable = true; |
| 930 | } | 927 | } |
| 931 | 928 | ||
| @@ -1003,7 +1000,7 @@ static const struct amba_id etm_ids[] = { · 71 unmodified lines | |||
| 1003 | CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), | 1000 | CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), |
| 1004 | /* PTM 1.1 Qualcomm */ | 1001 | /* PTM 1.1 Qualcomm */ |
| 1005 | CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), | 1002 | CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), |
| 1006 | { 0, 0}, | 1003 | { 0, 0, NULL}, |
| 1007 | }; | 1004 | }; |
| 1008 | 1005 | ||
| 1009 | MODULE_DEVICE_TABLE(amba, etm_ids); | 1006 | MODULE_DEVICE_TABLE(amba, etm_ids); |
| @@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev, · 721 unmodified lines | |||
| 722 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 722 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 723 | struct etm_config *config = &drvdata->config; | 723 | struct etm_config *config = &drvdata->config; |
| 724 | 724 | ||
| 725 | if (!local_read(&drvdata->mode)) { | 725 | if (!coresight_get_mode(drvdata->csdev)) { |
| 726 | spin_lock(&drvdata->spinlock); | 726 | spin_lock(&drvdata->spinlock); |
| 727 | for (i = 0; i < drvdata->nr_cntr; i++) | 727 | for (i = 0; i < drvdata->nr_cntr; i++) |
| 728 | ret += sprintf(buf, "counter %d: %x\n", | 728 | ret += sprintf(buf, "counter %d: %x\n", |
| @@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev, · 212 unmodified lines | |||
| 941 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 941 | struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 942 | struct etm_config *config = &drvdata->config; | 942 | struct etm_config *config = &drvdata->config; |
| 943 | 943 | ||
| 944 | if (!local_read(&drvdata->mode)) { | 944 | if (!coresight_get_mode(drvdata->csdev)) { |
| 945 | val = config->seq_curr_state; | 945 | val = config->seq_curr_state; |
| 946 | goto out; | 946 | goto out; |
| 947 | } | 947 | } |
| @@ -840,14 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, · 839 unmodified lines | |||
| 840 | enum cs_mode mode) | 840 | enum cs_mode mode) |
| 841 | { | 841 | { |
| 842 | int ret; | 842 | int ret; |
| 843 | u32 val; | ||
| 844 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
| 845 | |||
| 846 | val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | ||
| 847 | 843 | ||
| 848 | /* Someone is already using the tracer */ | 844 | if (!coresight_take_mode(csdev, mode)) { |
| 849 | if (val) | 845 | /* Someone is already using the tracer */ |
| 850 | return -EBUSY; | 846 | return -EBUSY; |
| 847 | } | ||
| 851 | 848 | ||
| 852 | switch (mode) { | 849 | switch (mode) { |
| 853 | case CS_MODE_SYSFS: | 850 | case CS_MODE_SYSFS: |
| @@ -862,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, · 8 unmodified lines | |||
| 862 | 859 | ||
| 863 | /* The tracer didn't start */ | 860 | /* The tracer didn't start */ |
| 864 | if (ret) | 861 | if (ret) |
| 865 | local_set(&drvdata->mode, CS_MODE_DISABLED); | 862 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 866 | 863 | ||
| 867 | return ret; | 864 | return ret; |
| 868 | } | 865 | } |
| @@ -1004,14 +1001,13 @@ static void etm4_disable(struct coresight_device *csdev, · 135 unmodified lines | |||
| 1004 | struct perf_event *event) | 1001 | struct perf_event *event) |
| 1005 | { | 1002 | { |
| 1006 | enum cs_mode mode; | 1003 | enum cs_mode mode; |
| 1007 | struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
| 1008 | 1004 | ||
| 1009 | /* | 1005 | /* |
| 1010 | * For as long as the tracer isn't disabled another entity can't | 1006 | * For as long as the tracer isn't disabled another entity can't |
| 1011 | * change its status. As such we can read the status here without | 1007 | * change its status. As such we can read the status here without |
| 1012 | * fearing it will change under us. | 1008 | * fearing it will change under us. |
| 1013 | */ | 1009 | */ |
| 1014 | mode = local_read(&drvdata->mode); | 1010 | mode = coresight_get_mode(csdev); |
| 1015 | 1011 | ||
| 1016 | switch (mode) { | 1012 | switch (mode) { |
| 1017 | case CS_MODE_DISABLED: | 1013 | case CS_MODE_DISABLED: |
| @@ -1025,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev, · 7 unmodified lines | |||
| 1025 | } | 1021 | } |
| 1026 | 1022 | ||
| 1027 | if (mode) | 1023 | if (mode) |
| 1028 | local_set(&drvdata->mode, CS_MODE_DISABLED); | 1024 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 1029 | } | 1025 | } |
| 1030 | 1026 | ||
| 1031 | static const struct coresight_ops_source etm4_source_ops = { | 1027 | static const struct coresight_ops_source etm4_source_ops = { |
| @@ -1200,6 +1196,7 @@ static void etm4_init_arch_data(void *info) · 168 unmodified lines | |||
| 1200 | struct etm4_init_arg *init_arg = info; | 1196 | struct etm4_init_arg *init_arg = info; |
| 1201 | struct etmv4_drvdata *drvdata; | 1197 | struct etmv4_drvdata *drvdata; |
| 1202 | struct csdev_access *csa; | 1198 | struct csdev_access *csa; |
| 1199 | struct device *dev = init_arg->dev; | ||
| 1203 | int i; | 1200 | int i; |
| 1204 | 1201 | ||
| 1205 | drvdata = dev_get_drvdata(init_arg->dev); | 1202 | drvdata = dev_get_drvdata(init_arg->dev); |
| @@ -1213,6 +1210,10 @@ static void etm4_init_arch_data(void *info) · 7 unmodified lines | |||
| 1213 | if (!etm4_init_csdev_access(drvdata, csa)) | 1210 | if (!etm4_init_csdev_access(drvdata, csa)) |
| 1214 | return; | 1211 | return; |
| 1215 | 1212 | ||
| 1213 | if (!csa->io_mem || | ||
| 1214 | fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) | ||
| 1215 | drvdata->skip_power_up = true; | ||
| 1216 | |||
| 1216 | /* Detect the support for OS Lock before we actually use it */ | 1217 | /* Detect the support for OS Lock before we actually use it */ |
| 1217 | etm_detect_os_lock(drvdata, csa); | 1218 | etm_detect_os_lock(drvdata, csa); |
| 1218 | 1219 | ||
| @@ -1650,7 +1651,7 @@ static int etm4_online_cpu(unsigned int cpu) · 431 unmodified lines | |||
| 1650 | return etm4_probe_cpu(cpu); | 1651 | return etm4_probe_cpu(cpu); |
| 1651 | 1652 | ||
| 1652 | if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | 1653 | if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) |
| 1653 | coresight_enable(etmdrvdata[cpu]->csdev); | 1654 | coresight_enable_sysfs(etmdrvdata[cpu]->csdev); |
| 1654 | return 0; | 1655 | return 0; |
| 1655 | } | 1656 | } |
| 1656 | 1657 | ||
| @@ -1663,7 +1664,7 @@ static int etm4_starting_cpu(unsigned int cpu) · 6 unmodified lines | |||
| 1663 | if (!etmdrvdata[cpu]->os_unlock) | 1664 | if (!etmdrvdata[cpu]->os_unlock) |
| 1664 | etm4_os_unlock(etmdrvdata[cpu]); | 1665 | etm4_os_unlock(etmdrvdata[cpu]); |
| 1665 | 1666 | ||
| 1666 | if (local_read(&etmdrvdata[cpu]->mode)) | 1667 | if (coresight_get_mode(etmdrvdata[cpu]->csdev)) |
| 1667 | etm4_enable_hw(etmdrvdata[cpu]); | 1668 | etm4_enable_hw(etmdrvdata[cpu]); |
| 1668 | spin_unlock(&etmdrvdata[cpu]->spinlock); | 1669 | spin_unlock(&etmdrvdata[cpu]->spinlock); |
| 1669 | return 0; | 1670 | return 0; |
| @@ -1675,7 +1676,7 @@ static int etm4_dying_cpu(unsigned int cpu) · 5 unmodified lines | |||
| 1675 | return 0; | 1676 | return 0; |
| 1676 | 1677 | ||
| 1677 | spin_lock(&etmdrvdata[cpu]->spinlock); | 1678 | spin_lock(&etmdrvdata[cpu]->spinlock); |
| 1678 | if (local_read(&etmdrvdata[cpu]->mode)) | 1679 | if (coresight_get_mode(etmdrvdata[cpu]->csdev)) |
| 1679 | etm4_disable_hw(etmdrvdata[cpu]); | 1680 | etm4_disable_hw(etmdrvdata[cpu]); |
| 1680 | spin_unlock(&etmdrvdata[cpu]->spinlock); | 1681 | spin_unlock(&etmdrvdata[cpu]->spinlock); |
| 1681 | return 0; | 1682 | return 0; |
| @@ -1833,7 +1834,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata) · 151 unmodified lines | |||
| 1833 | * Save and restore the ETM Trace registers only if | 1834 | * Save and restore the ETM Trace registers only if |
| 1834 | * the ETM is active. | 1835 | * the ETM is active. |
| 1835 | */ | 1836 | */ |
| 1836 | if (local_read(&drvdata->mode) && drvdata->save_state) | 1837 | if (coresight_get_mode(drvdata->csdev) && drvdata->save_state) |
| 1837 | ret = __etm4_cpu_save(drvdata); | 1838 | ret = __etm4_cpu_save(drvdata); |
| 1838 | return ret; | 1839 | return ret; |
| 1839 | } | 1840 | } |
| @@ -2040,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) · 200 unmodified lines | |||
| 2040 | if (!drvdata->arch) | 2041 | if (!drvdata->arch) |
| 2041 | return -EINVAL; | 2042 | return -EINVAL; |
| 2042 | 2043 | ||
| 2043 | /* TRCPDCR is not accessible with system instructions. */ | ||
| 2044 | if (!desc.access.io_mem || | ||
| 2045 | fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) | ||
| 2046 | drvdata->skip_power_up = true; | ||
| 2047 | |||
| 2048 | major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); | 2044 | major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); |
| 2049 | minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); | 2045 | minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); |
| 2050 | 2046 | ||
| @@ -2098,7 +2094,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) · 47 unmodified lines | |||
| 2098 | drvdata->cpu, type_name, major, minor); | 2094 | drvdata->cpu, type_name, major, minor); |
| 2099 | 2095 | ||
| 2100 | if (boot_enable) { | 2096 | if (boot_enable) { |
| 2101 | coresight_enable(drvdata->csdev); | 2097 | coresight_enable_sysfs(drvdata->csdev); |
| 2102 | drvdata->boot_enable = true; | 2098 | drvdata->boot_enable = true; |
| 2103 | } | 2099 | } |
| 2104 | 2100 | ||
| @@ -2390,7 +2386,7 @@ static const struct of_device_id etm4_sysreg_match[] = { · 285 unmodified lines | |||
| 2390 | 2386 | ||
| 2391 | #ifdef CONFIG_ACPI | 2387 | #ifdef CONFIG_ACPI |
| 2392 | static const struct acpi_device_id etm4x_acpi_ids[] = { | 2388 | static const struct acpi_device_id etm4x_acpi_ids[] = { |
| 2393 | {"ARMHC500", 0}, /* ARM CoreSight ETM4x */ | 2389 | {"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */ |
| 2394 | {} | 2390 | {} |
| 2395 | }; | 2391 | }; |
| 2396 | MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); | 2392 | MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); |
| @@ -1016,7 +1016,6 @@ struct etmv4_drvdata { · 1015 unmodified lines | |||
| 1016 | void __iomem *base; | 1016 | void __iomem *base; |
| 1017 | struct coresight_device *csdev; | 1017 | struct coresight_device *csdev; |
| 1018 | spinlock_t spinlock; | 1018 | spinlock_t spinlock; |
| 1019 | local_t mode; | ||
| 1020 | int cpu; | 1019 | int cpu; |
| 1021 | u8 arch; | 1020 | u8 arch; |
| 1022 | u8 nr_pe; | 1021 | u8 nr_pe; |
| @@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match); · 349 unmodified lines | |||
| 350 | 350 | ||
| 351 | #ifdef CONFIG_ACPI | 351 | #ifdef CONFIG_ACPI |
| 352 | static const struct acpi_device_id static_funnel_ids[] = { | 352 | static const struct acpi_device_id static_funnel_ids[] = { |
| 353 | {"ARMHC9FE", 0}, | 353 | {"ARMHC9FE", 0, 0, 0}, |
| 354 | {}, | 354 | {}, |
| 355 | }; | 355 | }; |
| 356 | 356 | ||
| @@ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = { · 34 unmodified lines | |||
| 391 | .id = 0x000bb9eb, | 391 | .id = 0x000bb9eb, |
| 392 | .mask = 0x000fffff, | 392 | .mask = 0x000fffff, |
| 393 | }, | 393 | }, |
| 394 | { 0, 0}, | 394 | { 0, 0, NULL }, |
| 395 | }; | 395 | }; |
| 396 | 396 | ||
| 397 | MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); | 397 | MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); |
| @@ -12,6 +12,9 @@ · 11 unmodified lines | |||
| 12 | #include <linux/coresight.h> | 12 | #include <linux/coresight.h> |
| 13 | #include <linux/pm_runtime.h> | 13 | #include <linux/pm_runtime.h> |
| 14 | 14 | ||
| 15 | extern struct mutex coresight_mutex; | ||
| 16 | extern struct device_type coresight_dev_type[]; | ||
| 17 | |||
| 15 | /* | 18 | /* |
| 16 | * Coresight management registers (0xf00-0xfcc) | 19 | * Coresight management registers (0xf00-0xfcc) |
| 17 | * 0xfa0 - 0xfa4: Management registers in PFTv1.0 | 20 | * 0xfa0 - 0xfa4: Management registers in PFTv1.0 |
| @@ -130,8 +133,6 @@ void coresight_disable_path(struct list_head *path); · 112 unmodified lines | |||
| 130 | int coresight_enable_path(struct list_head *path, enum cs_mode mode, | 133 | int coresight_enable_path(struct list_head *path, enum cs_mode mode, |
| 131 | void *sink_data); | 134 | void *sink_data); |
| 132 | struct coresight_device *coresight_get_sink(struct list_head *path); | 135 | struct coresight_device *coresight_get_sink(struct list_head *path); |
| 133 | struct coresight_device * | ||
| 134 | coresight_get_enabled_sink(struct coresight_device *source); | ||
| 135 | struct coresight_device *coresight_get_sink_by_id(u32 id); | 136 | struct coresight_device *coresight_get_sink_by_id(u32 id); |
| 136 | struct coresight_device * | 137 | struct coresight_device * |
| 137 | coresight_find_default_sink(struct coresight_device *csdev); | 138 | coresight_find_default_sink(struct coresight_device *csdev); |
| @@ -231,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev, · 93 unmodified lines | |||
| 231 | 232 | ||
| 232 | void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); | 233 | void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); |
| 233 | struct coresight_device *coresight_get_percpu_sink(int cpu); | 234 | struct coresight_device *coresight_get_percpu_sink(int cpu); |
| 234 | int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, | 235 | void coresight_disable_source(struct coresight_device *csdev, void *data); |
| 235 | void *data); | ||
| 236 | bool coresight_disable_source(struct coresight_device *csdev, void *data); | ||
| 237 | 236 | ||
| 238 | #endif | 237 | #endif |
| @@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match); · 362 unmodified lines | |||
| 363 | 363 | ||
| 364 | #ifdef CONFIG_ACPI | 364 | #ifdef CONFIG_ACPI |
| 365 | static const struct acpi_device_id static_replicator_acpi_ids[] = { | 365 | static const struct acpi_device_id static_replicator_acpi_ids[] = { |
| 366 | {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */ | 366 | {"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */ |
| 367 | {} | 367 | {} |
| 368 | }; | 368 | }; |
| 369 | 369 | ||
| @@ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); · 118 unmodified lines | |||
| 119 | * @spinlock: only one at a time pls. | 119 | * @spinlock: only one at a time pls. |
| 120 | * @chs: the channels accociated to this STM. | 120 | * @chs: the channels accociated to this STM. |
| 121 | * @stm: structure associated to the generic STM interface. | 121 | * @stm: structure associated to the generic STM interface. |
| 122 | * @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled. | ||
| 123 | * @traceid: value of the current ID for this component. | 122 | * @traceid: value of the current ID for this component. |
| 124 | * @write_bytes: Maximus bytes this STM can write at a time. | 123 | * @write_bytes: Maximus bytes this STM can write at a time. |
| 125 | * @stmsper: settings for register STMSPER. | 124 | * @stmsper: settings for register STMSPER. |
| @@ -136,7 +135,6 @@ struct stm_drvdata { · 10 unmodified lines | |||
| 136 | spinlock_t spinlock; | 135 | spinlock_t spinlock; |
| 137 | struct channel_space chs; | 136 | struct channel_space chs; |
| 138 | struct stm_data stm; | 137 | struct stm_data stm; |
| 139 | local_t mode; | ||
| 140 | u8 traceid; | 138 | u8 traceid; |
| 141 | u32 write_bytes; | 139 | u32 write_bytes; |
| 142 | u32 stmsper; | 140 | u32 stmsper; |
| @@ -195,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata) · 52 unmodified lines | |||
| 195 | static int stm_enable(struct coresight_device *csdev, struct perf_event *event, | 193 | static int stm_enable(struct coresight_device *csdev, struct perf_event *event, |
| 196 | enum cs_mode mode) | 194 | enum cs_mode mode) |
| 197 | { | 195 | { |
| 198 | u32 val; | ||
| 199 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 196 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 200 | 197 | ||
| 201 | if (mode != CS_MODE_SYSFS) | 198 | if (mode != CS_MODE_SYSFS) |
| 202 | return -EINVAL; | 199 | return -EINVAL; |
| 203 | 200 | ||
| 204 | val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | 201 | if (!coresight_take_mode(csdev, mode)) { |
| 205 | 202 | /* Someone is already using the tracer */ | |
| 206 | /* Someone is already using the tracer */ | ||
| 207 | if (val) | ||
| 208 | return -EBUSY; | 203 | return -EBUSY; |
| 204 | } | ||
| 209 | 205 | ||
| 210 | pm_runtime_get_sync(csdev->dev.parent); | 206 | pm_runtime_get_sync(csdev->dev.parent); |
| 211 | 207 | ||
| @@ -266,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev, · 54 unmodified lines | |||
| 266 | * change its status. As such we can read the status here without | 262 | * change its status. As such we can read the status here without |
| 267 | * fearing it will change under us. | 263 | * fearing it will change under us. |
| 268 | */ | 264 | */ |
| 269 | if (local_read(&drvdata->mode) == CS_MODE_SYSFS) { | 265 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
| 270 | spin_lock(&drvdata->spinlock); | 266 | spin_lock(&drvdata->spinlock); |
| 271 | stm_disable_hw(drvdata); | 267 | stm_disable_hw(drvdata); |
| 272 | spin_unlock(&drvdata->spinlock); | 268 | spin_unlock(&drvdata->spinlock); |
| @@ -276,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev, · 3 unmodified lines | |||
| 276 | 272 | ||
| 277 | pm_runtime_put(csdev->dev.parent); | 273 | pm_runtime_put(csdev->dev.parent); |
| 278 | 274 | ||
| 279 | local_set(&drvdata->mode, CS_MODE_DISABLED); | 275 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 280 | dev_dbg(&csdev->dev, "STM tracing disabled\n"); | 276 | dev_dbg(&csdev->dev, "STM tracing disabled\n"); |
| 281 | } | 277 | } |
| 282 | } | 278 | } |
| @@ -334,7 +330,7 @@ static int stm_generic_link(struct stm_data *stm_data, · 51 unmodified lines | |||
| 334 | if (!drvdata || !drvdata->csdev) | 330 | if (!drvdata || !drvdata->csdev) |
| 335 | return -EINVAL; | 331 | return -EINVAL; |
| 336 | 332 | ||
| 337 | return coresight_enable(drvdata->csdev); | 333 | return coresight_enable_sysfs(drvdata->csdev); |
| 338 | } | 334 | } |
| 339 | 335 | ||
| 340 | static void stm_generic_unlink(struct stm_data *stm_data, | 336 | static void stm_generic_unlink(struct stm_data *stm_data, |
| @@ -345,7 +341,7 @@ static void stm_generic_unlink(struct stm_data *stm_data, · 4 unmodified lines | |||
| 345 | if (!drvdata || !drvdata->csdev) | 341 | if (!drvdata || !drvdata->csdev) |
| 346 | return; | 342 | return; |
| 347 | 343 | ||
| 348 | coresight_disable(drvdata->csdev); | 344 | coresight_disable_sysfs(drvdata->csdev); |
| 349 | } | 345 | } |
| 350 | 346 | ||
| 351 | static phys_addr_t | 347 | static phys_addr_t |
| @@ -373,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, · 21 unmodified lines | |||
| 373 | { | 369 | { |
| 374 | struct stm_drvdata *drvdata = container_of(stm_data, | 370 | struct stm_drvdata *drvdata = container_of(stm_data, |
| 375 | struct stm_drvdata, stm); | 371 | struct stm_drvdata, stm); |
| 376 | if (!(drvdata && local_read(&drvdata->mode))) | 372 | if (!(drvdata && coresight_get_mode(drvdata->csdev))) |
| 377 | return -EINVAL; | 373 | return -EINVAL; |
| 378 | 374 | ||
| 379 | if (channel >= drvdata->numsp) | 375 | if (channel >= drvdata->numsp) |
| @@ -408,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, · 28 unmodified lines | |||
| 408 | struct stm_drvdata, stm); | 404 | struct stm_drvdata, stm); |
| 409 | unsigned int stm_flags; | 405 | unsigned int stm_flags; |
| 410 | 406 | ||
| 411 | if (!(drvdata && local_read(&drvdata->mode))) | 407 | if (!(drvdata && coresight_get_mode(drvdata->csdev))) |
| 412 | return -EACCES; | 408 | return -EACCES; |
| 413 | 409 | ||
| 414 | if (channel >= drvdata->numsp) | 410 | if (channel >= drvdata->numsp) |
| @@ -515,7 +511,7 @@ static ssize_t port_select_show(struct device *dev, · 100 unmodified lines | |||
| 515 | struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 511 | struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 516 | unsigned long val; | 512 | unsigned long val; |
| 517 | 513 | ||
| 518 | if (!local_read(&drvdata->mode)) { | 514 | if (!coresight_get_mode(drvdata->csdev)) { |
| 519 | val = drvdata->stmspscr; | 515 | val = drvdata->stmspscr; |
| 520 | } else { | 516 | } else { |
| 521 | spin_lock(&drvdata->spinlock); | 517 | spin_lock(&drvdata->spinlock); |
| @@ -541,7 +537,7 @@ static ssize_t port_select_store(struct device *dev, · 19 unmodified lines | |||
| 541 | spin_lock(&drvdata->spinlock); | 537 | spin_lock(&drvdata->spinlock); |
| 542 | drvdata->stmspscr = val; | 538 | drvdata->stmspscr = val; |
| 543 | 539 | ||
| 544 | if (local_read(&drvdata->mode)) { | 540 | if (coresight_get_mode(drvdata->csdev)) { |
| 545 | CS_UNLOCK(drvdata->base); | 541 | CS_UNLOCK(drvdata->base); |
| 546 | /* Process as per ARM's TRM recommendation */ | 542 | /* Process as per ARM's TRM recommendation */ |
| 547 | stmsper = readl_relaxed(drvdata->base + STMSPER); | 543 | stmsper = readl_relaxed(drvdata->base + STMSPER); |
| @@ -562,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev, · 14 unmodified lines | |||
| 562 | struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 558 | struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 563 | unsigned long val; | 559 | unsigned long val; |
| 564 | 560 | ||
| 565 | if (!local_read(&drvdata->mode)) { | 561 | if (!coresight_get_mode(drvdata->csdev)) { |
| 566 | val = drvdata->stmsper; | 562 | val = drvdata->stmsper; |
| 567 | } else { | 563 | } else { |
| 568 | spin_lock(&drvdata->spinlock); | 564 | spin_lock(&drvdata->spinlock); |
| @@ -588,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev, · 19 unmodified lines | |||
| 588 | spin_lock(&drvdata->spinlock); | 584 | spin_lock(&drvdata->spinlock); |
| 589 | drvdata->stmsper = val; | 585 | drvdata->stmsper = val; |
| 590 | 586 | ||
| 591 | if (local_read(&drvdata->mode)) { | 587 | if (coresight_get_mode(drvdata->csdev)) { |
| 592 | CS_UNLOCK(drvdata->base); | 588 | CS_UNLOCK(drvdata->base); |
| 593 | writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); | 589 | writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); |
| 594 | CS_LOCK(drvdata->base); | 590 | CS_LOCK(drvdata->base); |
| @@ -950,7 +946,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = { · 355 unmodified lines | |||
| 950 | static const struct amba_id stm_ids[] = { | 946 | static const struct amba_id stm_ids[] = { |
| 951 | CS_AMBA_ID_DATA(0x000bb962, "STM32"), | 947 | CS_AMBA_ID_DATA(0x000bb962, "STM32"), |
| 952 | CS_AMBA_ID_DATA(0x000bb963, "STM500"), | 948 | CS_AMBA_ID_DATA(0x000bb963, "STM500"), |
| 953 | { 0, 0}, | 949 | { 0, 0, NULL }, |
| 954 | }; | 950 | }; |
| 955 | 951 | ||
| 956 | MODULE_DEVICE_TABLE(amba, stm_ids); | 952 | MODULE_DEVICE_TABLE(amba, stm_ids); |
| @@ -5,10 +5,401 @@ · 4 unmodified lines | |||
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <linux/device.h> | 7 | #include <linux/device.h> |
| 8 | #include <linux/idr.h> | ||
| 8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 9 | 10 | ||
| 10 | #include "coresight-priv.h" | 11 | #include "coresight-priv.h" |
| 11 | 12 | ||
| 13 | /* | ||
| 14 | * Use IDR to map the hash of the source's device name | ||
| 15 | * to the pointer of path for the source. The idr is for | ||
| 16 | * the sources which aren't associated with CPU. | ||
| 17 | */ | ||
| 18 | static DEFINE_IDR(path_idr); | ||
| 19 | |||
| 20 | /* | ||
| 21 | * When operating Coresight drivers from the sysFS interface, only a single | ||
| 22 | * path can exist from a tracer (associated to a CPU) to a sink. | ||
| 23 | */ | ||
| 24 | static DEFINE_PER_CPU(struct list_head *, tracer_path); | ||
| 25 | |||
| 26 | ssize_t coresight_simple_show_pair(struct device *_dev, | ||
| 27 | struct device_attribute *attr, char *buf) | ||
| 28 | { | ||
| 29 | struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||
| 30 | struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); | ||
| 31 | u64 val; | ||
| 32 | |||
| 33 | pm_runtime_get_sync(_dev->parent); | ||
| 34 | val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); | ||
| 35 | pm_runtime_put_sync(_dev->parent); | ||
| 36 | return sysfs_emit(buf, "0x%llx\n", val); | ||
| 37 | } | ||
| 38 | EXPORT_SYMBOL_GPL(coresight_simple_show_pair); | ||
| 39 | |||
| 40 | ssize_t coresight_simple_show32(struct device *_dev, | ||
| 41 | struct device_attribute *attr, char *buf) | ||
| 42 | { | ||
| 43 | struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||
| 44 | struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); | ||
| 45 | u64 val; | ||
| 46 | |||
| 47 | pm_runtime_get_sync(_dev->parent); | ||
| 48 | val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); | ||
| 49 | pm_runtime_put_sync(_dev->parent); | ||
| 50 | return sysfs_emit(buf, "0x%llx\n", val); | ||
| 51 | } | ||
| 52 | EXPORT_SYMBOL_GPL(coresight_simple_show32); | ||
| 53 | |||
| 54 | static int coresight_enable_source_sysfs(struct coresight_device *csdev, | ||
| 55 | enum cs_mode mode, void *data) | ||
| 56 | { | ||
| 57 | int ret; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Comparison with CS_MODE_SYSFS works without taking any device | ||
| 61 | * specific spinlock because the truthyness of that comparison can only | ||
| 62 | * change with coresight_mutex held, which we already have here. | ||
| 63 | */ | ||
| 64 | lockdep_assert_held(&coresight_mutex); | ||
| 65 | if (coresight_get_mode(csdev) != CS_MODE_SYSFS) { | ||
| 66 | ret = source_ops(csdev)->enable(csdev, data, mode); | ||
| 67 | if (ret) | ||
| 68 | return ret; | ||
| 69 | } | ||
| 70 | |||
| 71 | csdev->refcnt++; | ||
| 72 | |||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | /** | ||
| 77 | * coresight_disable_source_sysfs - Drop the reference count by 1 and disable | ||
| 78 | * the device if there are no users left. | ||
| 79 | * | ||
| 80 | * @csdev: The coresight device to disable | ||
| 81 | * @data: Opaque data to pass on to the disable function of the source device. | ||
| 82 | * For example in perf mode this is a pointer to the struct perf_event. | ||
| 83 | * | ||
| 84 | * Returns true if the device has been disabled. | ||
| 85 | */ | ||
| 86 | static bool coresight_disable_source_sysfs(struct coresight_device *csdev, | ||
| 87 | void *data) | ||
| 88 | { | ||
| 89 | lockdep_assert_held(&coresight_mutex); | ||
| 90 | if (coresight_get_mode(csdev) != CS_MODE_SYSFS) | ||
| 91 | return false; | ||
| 92 | |||
| 93 | csdev->refcnt--; | ||
| 94 | if (csdev->refcnt == 0) { | ||
| 95 | coresight_disable_source(csdev, data); | ||
| 96 | return true; | ||
| 97 | } | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * coresight_find_activated_sysfs_sink - returns the first sink activated via | ||
| 103 | * sysfs using connection based search starting from the source reference. | ||
| 104 | * | ||
| 105 | * @csdev: Coresight source device reference | ||
| 106 | */ | ||
| 107 | static struct coresight_device * | ||
| 108 | coresight_find_activated_sysfs_sink(struct coresight_device *csdev) | ||
| 109 | { | ||
| 110 | int i; | ||
| 111 | struct coresight_device *sink = NULL; | ||
| 112 | |||
| 113 | if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || | ||
| 114 | csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && | ||
| 115 | csdev->sysfs_sink_activated) | ||
| 116 | return csdev; | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Recursively explore each port found on this element. | ||
| 120 | */ | ||
| 121 | for (i = 0; i < csdev->pdata->nr_outconns; i++) { | ||
| 122 | struct coresight_device *child_dev; | ||
| 123 | |||
| 124 | child_dev = csdev->pdata->out_conns[i]->dest_dev; | ||
| 125 | if (child_dev) | ||
| 126 | sink = coresight_find_activated_sysfs_sink(child_dev); | ||
| 127 | if (sink) | ||
| 128 | return sink; | ||
| 129 | } | ||
| 130 | |||
| 131 | return NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | /** coresight_validate_source - make sure a source has the right credentials to | ||
| 135 | * be used via sysfs. | ||
| 136 | * @csdev: the device structure for a source. | ||
| 137 | * @function: the function this was called from. | ||
| 138 | * | ||
| 139 | * Assumes the coresight_mutex is held. | ||
| 140 | */ | ||
| 141 | static int coresight_validate_source_sysfs(struct coresight_device *csdev, | ||
| 142 | const char *function) | ||
| 143 | { | ||
| 144 | u32 type, subtype; | ||
| 145 | |||
| 146 | type = csdev->type; | ||
| 147 | subtype = csdev->subtype.source_subtype; | ||
| 148 | |||
| 149 | if (type != CORESIGHT_DEV_TYPE_SOURCE) { | ||
| 150 | dev_err(&csdev->dev, "wrong device type in %s\n", function); | ||
| 151 | return -EINVAL; | ||
| 152 | } | ||
| 153 | |||
| 154 | if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && | ||
| 155 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && | ||
| 156 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && | ||
| 157 | subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { | ||
| 158 | dev_err(&csdev->dev, "wrong device subtype in %s\n", function); | ||
| 159 | return -EINVAL; | ||
| 160 | } | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | int coresight_enable_sysfs(struct coresight_device *csdev) | ||
| 166 | { | ||
| 167 | int cpu, ret = 0; | ||
| 168 | struct coresight_device *sink; | ||
| 169 | struct list_head *path; | ||
| 170 | enum coresight_dev_subtype_source subtype; | ||
| 171 | u32 hash; | ||
| 172 | |||
| 173 | subtype = csdev->subtype.source_subtype; | ||
| 174 | |||
| 175 | mutex_lock(&coresight_mutex); | ||
| 176 | |||
| 177 | ret = coresight_validate_source_sysfs(csdev, __func__); | ||
| 178 | if (ret) | ||
| 179 | goto out; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * mode == SYSFS implies that it's already enabled. Don't look at the | ||
| 183 | * refcount to determine this because we don't claim the source until | ||
| 184 | * coresight_enable_source() so can still race with Perf mode which | ||
| 185 | * doesn't hold coresight_mutex. | ||
| 186 | */ | ||
| 187 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||
| 188 | /* | ||
| 189 | * There could be multiple applications driving the software | ||
| 190 | * source. So keep the refcount for each such user when the | ||
| 191 | * source is already enabled. | ||
| 192 | */ | ||
| 193 | if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) | ||
| 194 | csdev->refcnt++; | ||
| 195 | goto out; | ||
| 196 | } | ||
| 197 | |||
| 198 | sink = coresight_find_activated_sysfs_sink(csdev); | ||
| 199 | if (!sink) { | ||
| 200 | ret = -EINVAL; | ||
| 201 | goto out; | ||
| 202 | } | ||
| 203 | |||
| 204 | path = coresight_build_path(csdev, sink); | ||
| 205 | if (IS_ERR(path)) { | ||
| 206 | pr_err("building path(s) failed\n"); | ||
| 207 | ret = PTR_ERR(path); | ||
| 208 | goto out; | ||
| 209 | } | ||
| 210 | |||
| 211 | ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); | ||
| 212 | if (ret) | ||
| 213 | goto err_path; | ||
| 214 | |||
| 215 | ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL); | ||
| 216 | if (ret) | ||
| 217 | goto err_source; | ||
| 218 | |||
| 219 | switch (subtype) { | ||
| 220 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||
| 221 | /* | ||
| 222 | * When working from sysFS it is important to keep track | ||
| 223 | * of the paths that were created so that they can be | ||
| 224 | * undone in 'coresight_disable()'. Since there can only | ||
| 225 | * be a single session per tracer (when working from sysFS) | ||
| 226 | * a per-cpu variable will do just fine. | ||
| 227 | */ | ||
| 228 | cpu = source_ops(csdev)->cpu_id(csdev); | ||
| 229 | per_cpu(tracer_path, cpu) = path; | ||
| 230 | break; | ||
| 231 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||
| 232 | case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||
| 233 | case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||
| 234 | /* | ||
| 235 | * Use the hash of source's device name as ID | ||
| 236 | * and map the ID to the pointer of the path. | ||
| 237 | */ | ||
| 238 | hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||
| 239 | ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); | ||
| 240 | if (ret) | ||
| 241 | goto err_source; | ||
| 242 | break; | ||
| 243 | default: | ||
| 244 | /* We can't be here */ | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | |||
| 248 | out: | ||
| 249 | mutex_unlock(&coresight_mutex); | ||
| 250 | return ret; | ||
| 251 | |||
| 252 | err_source: | ||
| 253 | coresight_disable_path(path); | ||
| 254 | |||
| 255 | err_path: | ||
| 256 | coresight_release_path(path); | ||
| 257 | goto out; | ||
| 258 | } | ||
| 259 | EXPORT_SYMBOL_GPL(coresight_enable_sysfs); | ||
| 260 | |||
| 261 | void coresight_disable_sysfs(struct coresight_device *csdev) | ||
| 262 | { | ||
| 263 | int cpu, ret; | ||
| 264 | struct list_head *path = NULL; | ||
| 265 | u32 hash; | ||
| 266 | |||
| 267 | mutex_lock(&coresight_mutex); | ||
| 268 | |||
| 269 | ret = coresight_validate_source_sysfs(csdev, __func__); | ||
| 270 | if (ret) | ||
| 271 | goto out; | ||
| 272 | |||
| 273 | if (!coresight_disable_source_sysfs(csdev, NULL)) | ||
| 274 | goto out; | ||
| 275 | |||
| 276 | switch (csdev->subtype.source_subtype) { | ||
| 277 | case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||
| 278 | cpu = source_ops(csdev)->cpu_id(csdev); | ||
| 279 | path = per_cpu(tracer_path, cpu); | ||
| 280 | per_cpu(tracer_path, cpu) = NULL; | ||
| 281 | break; | ||
| 282 | case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||
| 283 | case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||
| 284 | case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||
| 285 | hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||
| 286 | /* Find the path by the hash. */ | ||
| 287 | path = idr_find(&path_idr, hash); | ||
| 288 | if (path == NULL) { | ||
| 289 | pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); | ||
| 290 | goto out; | ||
| 291 | } | ||
| 292 | idr_remove(&path_idr, hash); | ||
| 293 | break; | ||
| 294 | default: | ||
| 295 | /* We can't be here */ | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | |||
| 299 | coresight_disable_path(path); | ||
| 300 | coresight_release_path(path); | ||
| 301 | |||
| 302 | out: | ||
| 303 | mutex_unlock(&coresight_mutex); | ||
| 304 | } | ||
| 305 | EXPORT_SYMBOL_GPL(coresight_disable_sysfs); | ||
| 306 | |||
| 307 | static ssize_t enable_sink_show(struct device *dev, | ||
| 308 | struct device_attribute *attr, char *buf) | ||
| 309 | { | ||
| 310 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 311 | |||
| 312 | return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated); | ||
| 313 | } | ||
| 314 | |||
| 315 | static ssize_t enable_sink_store(struct device *dev, | ||
| 316 | struct device_attribute *attr, | ||
| 317 | const char *buf, size_t size) | ||
| 318 | { | ||
| 319 | int ret; | ||
| 320 | unsigned long val; | ||
| 321 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 322 | |||
| 323 | ret = kstrtoul(buf, 10, &val); | ||
| 324 | if (ret) | ||
| 325 | return ret; | ||
| 326 | |||
| 327 | csdev->sysfs_sink_activated = !!val; | ||
| 328 | |||
| 329 | return size; | ||
| 330 | |||
| 331 | } | ||
| 332 | static DEVICE_ATTR_RW(enable_sink); | ||
| 333 | |||
| 334 | static ssize_t enable_source_show(struct device *dev, | ||
| 335 | struct device_attribute *attr, char *buf) | ||
| 336 | { | ||
| 337 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 338 | |||
| 339 | guard(mutex)(&coresight_mutex); | ||
| 340 | return scnprintf(buf, PAGE_SIZE, "%u\n", | ||
| 341 | coresight_get_mode(csdev) == CS_MODE_SYSFS); | ||
| 342 | } | ||
| 343 | |||
| 344 | static ssize_t enable_source_store(struct device *dev, | ||
| 345 | struct device_attribute *attr, | ||
| 346 | const char *buf, size_t size) | ||
| 347 | { | ||
| 348 | int ret = 0; | ||
| 349 | unsigned long val; | ||
| 350 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 351 | |||
| 352 | ret = kstrtoul(buf, 10, &val); | ||
| 353 | if (ret) | ||
| 354 | return ret; | ||
| 355 | |||
| 356 | if (val) { | ||
| 357 | ret = coresight_enable_sysfs(csdev); | ||
| 358 | if (ret) | ||
| 359 | return ret; | ||
| 360 | } else { | ||
| 361 | coresight_disable_sysfs(csdev); | ||
| 362 | } | ||
| 363 | |||
| 364 | return size; | ||
| 365 | } | ||
| 366 | static DEVICE_ATTR_RW(enable_source); | ||
| 367 | |||
| 368 | static struct attribute *coresight_sink_attrs[] = { | ||
| 369 | &dev_attr_enable_sink.attr, | ||
| 370 | NULL, | ||
| 371 | }; | ||
| 372 | ATTRIBUTE_GROUPS(coresight_sink); | ||
| 373 | |||
| 374 | static struct attribute *coresight_source_attrs[] = { | ||
| 375 | &dev_attr_enable_source.attr, | ||
| 376 | NULL, | ||
| 377 | }; | ||
| 378 | ATTRIBUTE_GROUPS(coresight_source); | ||
| 379 | |||
| 380 | struct device_type coresight_dev_type[] = { | ||
| 381 | [CORESIGHT_DEV_TYPE_SINK] = { | ||
| 382 | .name = "sink", | ||
| 383 | .groups = coresight_sink_groups, | ||
| 384 | }, | ||
| 385 | [CORESIGHT_DEV_TYPE_LINK] = { | ||
| 386 | .name = "link", | ||
| 387 | }, | ||
| 388 | [CORESIGHT_DEV_TYPE_LINKSINK] = { | ||
| 389 | .name = "linksink", | ||
| 390 | .groups = coresight_sink_groups, | ||
| 391 | }, | ||
| 392 | [CORESIGHT_DEV_TYPE_SOURCE] = { | ||
| 393 | .name = "source", | ||
| 394 | .groups = coresight_source_groups, | ||
| 395 | }, | ||
| 396 | [CORESIGHT_DEV_TYPE_HELPER] = { | ||
| 397 | .name = "helper", | ||
| 398 | } | ||
| 399 | }; | ||
| 400 | /* Ensure the enum matches the names and groups */ | ||
| 401 | static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); | ||
| 402 | |||
| 12 | /* | 403 | /* |
| 13 | * Connections group - links attribute. | 404 | * Connections group - links attribute. |
| 14 | * Count of created links between coresight components in the group. | 405 | * Count of created links between coresight components in the group. |
| @@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev) · 557 unmodified lines | |||
| 558 | 558 | ||
| 559 | spin_lock_irqsave(&drvdata->spinlock, flags); | 559 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 560 | 560 | ||
| 561 | if (drvdata->mode == CS_MODE_DISABLED) | 561 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) |
| 562 | goto out; | 562 | goto out; |
| 563 | 563 | ||
| 564 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) | 564 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) |
| @@ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = { · 29 unmodified lines | |||
| 594 | CS_AMBA_ID(0x000bb9e9), | 594 | CS_AMBA_ID(0x000bb9e9), |
| 595 | /* Coresight SoC 600 TMC-ETF */ | 595 | /* Coresight SoC 600 TMC-ETF */ |
| 596 | CS_AMBA_ID(0x000bb9ea), | 596 | CS_AMBA_ID(0x000bb9ea), |
| 597 | { 0, 0}, | 597 | { 0, 0, NULL }, |
| 598 | }; | 598 | }; |
| 599 | 599 | ||
| 600 | MODULE_DEVICE_TABLE(amba, tmc_ids); | 600 | MODULE_DEVICE_TABLE(amba, tmc_ids); |
| @@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata) · 88 unmodified lines | |||
| 89 | * When operating in sysFS mode the content of the buffer needs to be | 89 | * When operating in sysFS mode the content of the buffer needs to be |
| 90 | * read before the TMC is disabled. | 90 | * read before the TMC is disabled. |
| 91 | */ | 91 | */ |
| 92 | if (drvdata->mode == CS_MODE_SYSFS) | 92 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) |
| 93 | tmc_etb_dump_hw(drvdata); | 93 | tmc_etb_dump_hw(drvdata); |
| 94 | tmc_disable_hw(drvdata); | 94 | tmc_disable_hw(drvdata); |
| 95 | 95 | ||
| @@ -205,8 +205,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) · 109 unmodified lines | |||
| 205 | * sink is already enabled no memory is needed and the HW need not be | 205 | * sink is already enabled no memory is needed and the HW need not be |
| 206 | * touched. | 206 | * touched. |
| 207 | */ | 207 | */ |
| 208 | if (drvdata->mode == CS_MODE_SYSFS) { | 208 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
| 209 | atomic_inc(&csdev->refcnt); | 209 | csdev->refcnt++; |
| 210 | goto out; | 210 | goto out; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| @@ -228,8 +228,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) · 15 unmodified lines | |||
| 228 | 228 | ||
| 229 | ret = tmc_etb_enable_hw(drvdata); | 229 | ret = tmc_etb_enable_hw(drvdata); |
| 230 | if (!ret) { | 230 | if (!ret) { |
| 231 | drvdata->mode = CS_MODE_SYSFS; | 231 | coresight_set_mode(csdev, CS_MODE_SYSFS); |
| 232 | atomic_inc(&csdev->refcnt); | 232 | csdev->refcnt++; |
| 233 | } else { | 233 | } else { |
| 234 | /* Free up the buffer if we failed to enable */ | 234 | /* Free up the buffer if we failed to enable */ |
| 235 | used = false; | 235 | used = false; |
| @@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) · 26 unmodified lines | |||
| 262 | * No need to continue if the ETB/ETF is already operated | 262 | * No need to continue if the ETB/ETF is already operated |
| 263 | * from sysFS. | 263 | * from sysFS. |
| 264 | */ | 264 | */ |
| 265 | if (drvdata->mode == CS_MODE_SYSFS) { | 265 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
| 266 | ret = -EBUSY; | 266 | ret = -EBUSY; |
| 267 | break; | 267 | break; |
| 268 | } | 268 | } |
| @@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) · 15 unmodified lines | |||
| 284 | * use for this session. | 284 | * use for this session. |
| 285 | */ | 285 | */ |
| 286 | if (drvdata->pid == pid) { | 286 | if (drvdata->pid == pid) { |
| 287 | atomic_inc(&csdev->refcnt); | 287 | csdev->refcnt++; |
| 288 | break; | 288 | break; |
| 289 | } | 289 | } |
| 290 | 290 | ||
| @@ -292,8 +292,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) · 1 unmodified line | |||
| 292 | if (!ret) { | 292 | if (!ret) { |
| 293 | /* Associate with monitored process. */ | 293 | /* Associate with monitored process. */ |
| 294 | drvdata->pid = pid; | 294 | drvdata->pid = pid; |
| 295 | drvdata->mode = CS_MODE_PERF; | 295 | coresight_set_mode(csdev, CS_MODE_PERF); |
| 296 | atomic_inc(&csdev->refcnt); | 296 | csdev->refcnt++; |
| 297 | } | 297 | } |
| 298 | } while (0); | 298 | } while (0); |
| 299 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 299 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| @@ -338,17 +338,18 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) · 38 unmodified lines | |||
| 338 | return -EBUSY; | 338 | return -EBUSY; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | if (atomic_dec_return(&csdev->refcnt)) { | 341 | csdev->refcnt--; |
| 342 | if (csdev->refcnt) { | ||
| 342 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 343 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 343 | return -EBUSY; | 344 | return -EBUSY; |
| 344 | } | 345 | } |
| 345 | 346 | ||
| 346 | /* Complain if we (somehow) got out of sync */ | 347 | /* Complain if we (somehow) got out of sync */ |
| 347 | WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 348 | WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); |
| 348 | tmc_etb_disable_hw(drvdata); | 349 | tmc_etb_disable_hw(drvdata); |
| 349 | /* Dissociate from monitored process. */ | 350 | /* Dissociate from monitored process. */ |
| 350 | drvdata->pid = -1; | 351 | drvdata->pid = -1; |
| 351 | drvdata->mode = CS_MODE_DISABLED; | 352 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 352 | 353 | ||
| 353 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 354 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 354 | 355 | ||
| @@ -371,15 +372,15 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, · 16 unmodified lines | |||
| 371 | return -EBUSY; | 372 | return -EBUSY; |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | if (atomic_read(&csdev->refcnt) == 0) { | 375 | if (csdev->refcnt == 0) { |
| 375 | ret = tmc_etf_enable_hw(drvdata); | 376 | ret = tmc_etf_enable_hw(drvdata); |
| 376 | if (!ret) { | 377 | if (!ret) { |
| 377 | drvdata->mode = CS_MODE_SYSFS; | 378 | coresight_set_mode(csdev, CS_MODE_SYSFS); |
| 378 | first_enable = true; | 379 | first_enable = true; |
| 379 | } | 380 | } |
| 380 | } | 381 | } |
| 381 | if (!ret) | 382 | if (!ret) |
| 382 | atomic_inc(&csdev->refcnt); | 383 | csdev->refcnt++; |
| 383 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 384 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 384 | 385 | ||
| 385 | if (first_enable) | 386 | if (first_enable) |
| @@ -401,9 +402,10 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, · 15 unmodified lines | |||
| 401 | return; | 402 | return; |
| 402 | } | 403 | } |
| 403 | 404 | ||
| 404 | if (atomic_dec_return(&csdev->refcnt) == 0) { | 405 | csdev->refcnt--; |
| 406 | if (csdev->refcnt == 0) { | ||
| 405 | tmc_etf_disable_hw(drvdata); | 407 | tmc_etf_disable_hw(drvdata); |
| 406 | drvdata->mode = CS_MODE_DISABLED; | 408 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 407 | last_disable = true; | 409 | last_disable = true; |
| 408 | } | 410 | } |
| 409 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 411 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| @@ -483,13 +485,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, · 73 unmodified lines | |||
| 483 | return 0; | 485 | return 0; |
| 484 | 486 | ||
| 485 | /* This shouldn't happen */ | 487 | /* This shouldn't happen */ |
| 486 | if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF)) | 488 | if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF)) |
| 487 | return 0; | 489 | return 0; |
| 488 | 490 | ||
| 489 | spin_lock_irqsave(&drvdata->spinlock, flags); | 491 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 490 | 492 | ||
| 491 | /* Don't do anything if another tracer is using this sink */ | 493 | /* Don't do anything if another tracer is using this sink */ |
| 492 | if (atomic_read(&csdev->refcnt) != 1) | 494 | if (csdev->refcnt != 1) |
| 493 | goto out; | 495 | goto out; |
| 494 | 496 | ||
| 495 | CS_UNLOCK(drvdata->base); | 497 | CS_UNLOCK(drvdata->base); |
| @@ -629,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) · 133 unmodified lines | |||
| 629 | } | 631 | } |
| 630 | 632 | ||
| 631 | /* Don't interfere if operated from Perf */ | 633 | /* Don't interfere if operated from Perf */ |
| 632 | if (drvdata->mode == CS_MODE_PERF) { | 634 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) { |
| 633 | ret = -EINVAL; | 635 | ret = -EINVAL; |
| 634 | goto out; | 636 | goto out; |
| 635 | } | 637 | } |
| @@ -641,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) · 5 unmodified lines | |||
| 641 | } | 643 | } |
| 642 | 644 | ||
| 643 | /* Disable the TMC if need be */ | 645 | /* Disable the TMC if need be */ |
| 644 | if (drvdata->mode == CS_MODE_SYSFS) { | 646 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { |
| 645 | /* There is no point in reading a TMC in HW FIFO mode */ | 647 | /* There is no point in reading a TMC in HW FIFO mode */ |
| 646 | mode = readl_relaxed(drvdata->base + TMC_MODE); | 648 | mode = readl_relaxed(drvdata->base + TMC_MODE); |
| 647 | if (mode != TMC_MODE_CIRCULAR_BUFFER) { | 649 | if (mode != TMC_MODE_CIRCULAR_BUFFER) { |
| @@ -673,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) · 25 unmodified lines | |||
| 673 | spin_lock_irqsave(&drvdata->spinlock, flags); | 675 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 674 | 676 | ||
| 675 | /* Re-enable the TMC if need be */ | 677 | /* Re-enable the TMC if need be */ |
| 676 | if (drvdata->mode == CS_MODE_SYSFS) { | 678 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { |
| 677 | /* There is no point in reading a TMC in HW FIFO mode */ | 679 | /* There is no point in reading a TMC in HW FIFO mode */ |
| 678 | mode = readl_relaxed(drvdata->base + TMC_MODE); | 680 | mode = readl_relaxed(drvdata->base + TMC_MODE); |
| 679 | if (mode != TMC_MODE_CIRCULAR_BUFFER) { | 681 | if (mode != TMC_MODE_CIRCULAR_BUFFER) { |
| @@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) · 1142 unmodified lines | |||
| 1143 | * When operating in sysFS mode the content of the buffer needs to be | 1143 | * When operating in sysFS mode the content of the buffer needs to be |
| 1144 | * read before the TMC is disabled. | 1144 | * read before the TMC is disabled. |
| 1145 | */ | 1145 | */ |
| 1146 | if (drvdata->mode == CS_MODE_SYSFS) | 1146 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) |
| 1147 | tmc_etr_sync_sysfs_buf(drvdata); | 1147 | tmc_etr_sync_sysfs_buf(drvdata); |
| 1148 | 1148 | ||
| 1149 | tmc_disable_hw(drvdata); | 1149 | tmc_disable_hw(drvdata); |
| @@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) · 39 unmodified lines | |||
| 1189 | spin_lock_irqsave(&drvdata->spinlock, flags); | 1189 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 1190 | } | 1190 | } |
| 1191 | 1191 | ||
| 1192 | if (drvdata->reading || drvdata->mode == CS_MODE_PERF) { | 1192 | if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) { |
| 1193 | ret = -EBUSY; | 1193 | ret = -EBUSY; |
| 1194 | goto out; | 1194 | goto out; |
| 1195 | } | 1195 | } |
| @@ -1230,15 +1230,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) · 34 unmodified lines | |||
| 1230 | * sink is already enabled no memory is needed and the HW need not be | 1230 | * sink is already enabled no memory is needed and the HW need not be |
| 1231 | * touched, even if the buffer size has changed. | 1231 | * touched, even if the buffer size has changed. |
| 1232 | */ | 1232 | */ |
| 1233 | if (drvdata->mode == CS_MODE_SYSFS) { | 1233 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
| 1234 | atomic_inc(&csdev->refcnt); | 1234 | csdev->refcnt++; |
| 1235 | goto out; | 1235 | goto out; |
| 1236 | } | 1236 | } |
| 1237 | 1237 | ||
| 1238 | ret = tmc_etr_enable_hw(drvdata, sysfs_buf); | 1238 | ret = tmc_etr_enable_hw(drvdata, sysfs_buf); |
| 1239 | if (!ret) { | 1239 | if (!ret) { |
| 1240 | drvdata->mode = CS_MODE_SYSFS; | 1240 | coresight_set_mode(csdev, CS_MODE_SYSFS); |
| 1241 | atomic_inc(&csdev->refcnt); | 1241 | csdev->refcnt++; |
| 1242 | } | 1242 | } |
| 1243 | 1243 | ||
| 1244 | out: | 1244 | out: |
| @@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, · 319 unmodified lines | |||
| 1564 | spin_lock_irqsave(&drvdata->spinlock, flags); | 1564 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 1565 | 1565 | ||
| 1566 | /* Don't do anything if another tracer is using this sink */ | 1566 | /* Don't do anything if another tracer is using this sink */ |
| 1567 | if (atomic_read(&csdev->refcnt) != 1) { | 1567 | if (csdev->refcnt != 1) { |
| 1568 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 1568 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 1569 | goto out; | 1569 | goto out; |
| 1570 | } | 1570 | } |
| @@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) · 81 unmodified lines | |||
| 1652 | 1652 | ||
| 1653 | spin_lock_irqsave(&drvdata->spinlock, flags); | 1653 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 1654 | /* Don't use this sink if it is already claimed by sysFS */ | 1654 | /* Don't use this sink if it is already claimed by sysFS */ |
| 1655 | if (drvdata->mode == CS_MODE_SYSFS) { | 1655 | if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { |
| 1656 | rc = -EBUSY; | 1656 | rc = -EBUSY; |
| 1657 | goto unlock_out; | 1657 | goto unlock_out; |
| 1658 | } | 1658 | } |
| @@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) · 17 unmodified lines | |||
| 1676 | * use for this session. | 1676 | * use for this session. |
| 1677 | */ | 1677 | */ |
| 1678 | if (drvdata->pid == pid) { | 1678 | if (drvdata->pid == pid) { |
| 1679 | atomic_inc(&csdev->refcnt); | 1679 | csdev->refcnt++; |
| 1680 | goto unlock_out; | 1680 | goto unlock_out; |
| 1681 | } | 1681 | } |
| 1682 | 1682 | ||
| @@ -1684,9 +1684,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) · 1 unmodified line | |||
| 1684 | if (!rc) { | 1684 | if (!rc) { |
| 1685 | /* Associate with monitored process. */ | 1685 | /* Associate with monitored process. */ |
| 1686 | drvdata->pid = pid; | 1686 | drvdata->pid = pid; |
| 1687 | drvdata->mode = CS_MODE_PERF; | 1687 | coresight_set_mode(csdev, CS_MODE_PERF); |
| 1688 | drvdata->perf_buf = etr_perf->etr_buf; | 1688 | drvdata->perf_buf = etr_perf->etr_buf; |
| 1689 | atomic_inc(&csdev->refcnt); | 1689 | csdev->refcnt++; |
| 1690 | } | 1690 | } |
| 1691 | 1691 | ||
| 1692 | unlock_out: | 1692 | unlock_out: |
| @@ -1719,17 +1719,18 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) · 26 unmodified lines | |||
| 1719 | return -EBUSY; | 1719 | return -EBUSY; |
| 1720 | } | 1720 | } |
| 1721 | 1721 | ||
| 1722 | if (atomic_dec_return(&csdev->refcnt)) { | 1722 | csdev->refcnt--; |
| 1723 | if (csdev->refcnt) { | ||
| 1723 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 1724 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 1724 | return -EBUSY; | 1725 | return -EBUSY; |
| 1725 | } | 1726 | } |
| 1726 | 1727 | ||
| 1727 | /* Complain if we (somehow) got out of sync */ | 1728 | /* Complain if we (somehow) got out of sync */ |
| 1728 | WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 1729 | WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); |
| 1729 | tmc_etr_disable_hw(drvdata); | 1730 | tmc_etr_disable_hw(drvdata); |
| 1730 | /* Dissociate from monitored process. */ | 1731 | /* Dissociate from monitored process. */ |
| 1731 | drvdata->pid = -1; | 1732 | drvdata->pid = -1; |
| 1732 | drvdata->mode = CS_MODE_DISABLED; | 1733 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 1733 | /* Reset perf specific data */ | 1734 | /* Reset perf specific data */ |
| 1734 | drvdata->perf_buf = NULL; | 1735 | drvdata->perf_buf = NULL; |
| 1735 | 1736 | ||
| @@ -1777,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) · 41 unmodified lines | |||
| 1777 | } | 1778 | } |
| 1778 | 1779 | ||
| 1779 | /* Disable the TMC if we are trying to read from a running session. */ | 1780 | /* Disable the TMC if we are trying to read from a running session. */ |
| 1780 | if (drvdata->mode == CS_MODE_SYSFS) | 1781 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) |
| 1781 | __tmc_etr_disable_hw(drvdata); | 1782 | __tmc_etr_disable_hw(drvdata); |
| 1782 | 1783 | ||
| 1783 | drvdata->reading = true; | 1784 | drvdata->reading = true; |
| @@ -1799,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) · 15 unmodified lines | |||
| 1799 | spin_lock_irqsave(&drvdata->spinlock, flags); | 1800 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 1800 | 1801 | ||
| 1801 | /* RE-enable the TMC if need be */ | 1802 | /* RE-enable the TMC if need be */ |
| 1802 | if (drvdata->mode == CS_MODE_SYSFS) { | 1803 | if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { |
| 1803 | /* | 1804 | /* |
| 1804 | * The trace run will continue with the same allocated trace | 1805 | * The trace run will continue with the same allocated trace |
| 1805 | * buffer. Since the tracer is still enabled drvdata::buf can't | 1806 | * buffer. Since the tracer is still enabled drvdata::buf can't |
| @@ -178,7 +178,6 @@ struct etr_buf { · 177 unmodified lines | |||
| 178 | * @size: trace buffer size for this TMC (common for all modes). | 178 | * @size: trace buffer size for this TMC (common for all modes). |
| 179 | * @max_burst_size: The maximum burst size that can be initiated by | 179 | * @max_burst_size: The maximum burst size that can be initiated by |
| 180 | * TMC-ETR on AXI bus. | 180 | * TMC-ETR on AXI bus. |
| 181 | * @mode: how this TMC is being used. | ||
| 182 | * @config_type: TMC variant, must be of type @tmc_config_type. | 181 | * @config_type: TMC variant, must be of type @tmc_config_type. |
| 183 | * @memwidth: width of the memory interface databus, in bytes. | 182 | * @memwidth: width of the memory interface databus, in bytes. |
| 184 | * @trigger_cntr: amount of words to store after a trigger. | 183 | * @trigger_cntr: amount of words to store after a trigger. |
| @@ -203,7 +202,6 @@ struct tmc_drvdata { · 18 unmodified lines | |||
| 203 | u32 len; | 202 | u32 len; |
| 204 | u32 size; | 203 | u32 size; |
| 205 | u32 max_burst_size; | 204 | u32 max_burst_size; |
| 206 | u32 mode; | ||
| 207 | enum tmc_config_type config_type; | 205 | enum tmc_config_type config_type; |
| 208 | enum tmc_mem_intf_width memwidth; | 206 | enum tmc_mem_intf_width memwidth; |
| 209 | u32 trigger_cntr; | 207 | u32 trigger_cntr; |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include "coresight-priv.h" | 18 | #include "coresight-priv.h" |
| 19 | #include "coresight-tpda.h" | 19 | #include "coresight-tpda.h" |
| 20 | #include "coresight-trace-id.h" | 20 | #include "coresight-trace-id.h" |
| 21 | #include "coresight-tpdm.h" | ||
| 21 | 22 | ||
| 22 | DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); | 23 | DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); |
| 23 | 24 | ||
| @@ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev) · 4 unmodified lines | |||
| 28 | CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); | 29 | CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 32 | static void tpda_clear_element_size(struct coresight_device *csdev) | ||
| 33 | { | ||
| 34 | struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
| 35 | |||
| 36 | drvdata->dsb_esize = 0; | ||
| 37 | drvdata->cmb_esize = 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val) | ||
| 41 | { | ||
| 42 | /* Clear all relevant fields */ | ||
| 43 | *val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE); | ||
| 44 | |||
| 45 | if (drvdata->dsb_esize == 64) | ||
| 46 | *val |= TPDA_Pn_CR_DSBSIZE; | ||
| 47 | else if (drvdata->dsb_esize == 32) | ||
| 48 | *val &= ~TPDA_Pn_CR_DSBSIZE; | ||
| 49 | |||
| 50 | if (drvdata->cmb_esize == 64) | ||
| 51 | *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2); | ||
| 52 | else if (drvdata->cmb_esize == 32) | ||
| 53 | *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1); | ||
| 54 | else if (drvdata->cmb_esize == 8) | ||
| 55 | *val &= ~TPDA_Pn_CR_CMBSIZE; | ||
| 56 | } | ||
| 57 | |||
| 31 | /* | 58 | /* |
| 32 | * Read the DSB element size from the TPDM device | 59 | * Read the element size from the TPDM device. One TPDM must have at least one of the |
| 60 | * element size property. | ||
| 33 | * Returns | 61 | * Returns |
| 34 | * The dsb element size read from the devicetree if available. | 62 | * 0 - The element size property is read |
| 35 | * 0 - Otherwise, with a warning once. | 63 | * Others - Cannot read the property of the element size |
| 36 | */ | 64 | */ |
| 37 | static int tpdm_read_dsb_element_size(struct coresight_device *csdev) | 65 | static int tpdm_read_element_size(struct tpda_drvdata *drvdata, |
| 66 | struct coresight_device *csdev) | ||
| 38 | { | 67 | { |
| 39 | int rc = 0; | 68 | int rc = -EINVAL; |
| 40 | u8 size = 0; | 69 | struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent); |
| 70 | |||
| 71 | if (tpdm_has_dsb_dataset(tpdm_data)) { | ||
| 72 | rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), | ||
| 73 | "qcom,dsb-element-bits", &drvdata->dsb_esize); | ||
| 74 | } | ||
| 75 | if (tpdm_has_cmb_dataset(tpdm_data)) { | ||
| 76 | rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), | ||
| 77 | "qcom,cmb-element-bits", &drvdata->cmb_esize); | ||
| 78 | } | ||
| 41 | 79 | ||
| 42 | rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent), | ||
| 43 | "qcom,dsb-element-size", &size); | ||
| 44 | if (rc) | 80 | if (rc) |
| 45 | dev_warn_once(&csdev->dev, | 81 | dev_warn_once(&csdev->dev, |
| 46 | "Failed to read TPDM DSB Element size: %d\n", rc); | 82 | "Failed to read TPDM Element size: %d\n", rc); |
| 47 | 83 | ||
| 48 | return size; | 84 | return rc; |
| 49 | } | 85 | } |
| 50 | 86 | ||
| 51 | /* | 87 | /* |
| @@ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev) · 4 unmodified lines | |||
| 56 | * Parameter "inport" is used to pass in the input port number | 92 | * Parameter "inport" is used to pass in the input port number |
| 57 | * of TPDA, and it is set to -1 in the recursize call. | 93 | * of TPDA, and it is set to -1 in the recursize call. |
| 58 | */ | 94 | */ |
| 59 | static int tpda_get_element_size(struct coresight_device *csdev, | 95 | static int tpda_get_element_size(struct tpda_drvdata *drvdata, |
| 96 | struct coresight_device *csdev, | ||
| 60 | int inport) | 97 | int inport) |
| 61 | { | 98 | { |
| 62 | int dsb_size = -ENOENT; | 99 | int rc = 0; |
| 63 | int i, size; | 100 | int i; |
| 64 | struct coresight_device *in; | 101 | struct coresight_device *in; |
| 65 | 102 | ||
| 66 | for (i = 0; i < csdev->pdata->nr_inconns; i++) { | 103 | for (i = 0; i < csdev->pdata->nr_inconns; i++) { |
| @@ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev, · 2 unmodified lines | |||
| 69 | continue; | 106 | continue; |
| 70 | 107 | ||
| 71 | /* Ignore the paths that do not match port */ | 108 | /* Ignore the paths that do not match port */ |
| 72 | if (inport > 0 && | 109 | if (inport >= 0 && |
| 73 | csdev->pdata->in_conns[i]->dest_port != inport) | 110 | csdev->pdata->in_conns[i]->dest_port != inport) |
| 74 | continue; | 111 | continue; |
| 75 | 112 | ||
| 76 | if (coresight_device_is_tpdm(in)) { | 113 | if (coresight_device_is_tpdm(in)) { |
| 77 | size = tpdm_read_dsb_element_size(in); | 114 | if (drvdata->dsb_esize || drvdata->cmb_esize) |
| 115 | return -EEXIST; | ||
| 116 | rc = tpdm_read_element_size(drvdata, in); | ||
| 117 | if (rc) | ||
| 118 | return rc; | ||
| 78 | } else { | 119 | } else { |
| 79 | /* Recurse down the path */ | 120 | /* Recurse down the path */ |
| 80 | size = tpda_get_element_size(in, -1); | 121 | rc = tpda_get_element_size(drvdata, in, -1); |
| 81 | } | 122 | if (rc) |
| 82 | 123 | return rc; | |
| 83 | if (size < 0) | ||
| 84 | return size; | ||
| 85 | |||
| 86 | if (dsb_size < 0) { | ||
| 87 | /* Found a size, save it. */ | ||
| 88 | dsb_size = size; | ||
| 89 | } else { | ||
| 90 | /* Found duplicate TPDMs */ | ||
| 91 | return -EEXIST; | ||
| 92 | } | 124 | } |
| 93 | } | 125 | } |
| 94 | 126 | ||
| 95 | return dsb_size; | 127 | |
| 128 | return rc; | ||
| 96 | } | 129 | } |
| 97 | 130 | ||
| 98 | /* Settings pre enabling port control register */ | 131 | /* Settings pre enabling port control register */ |
| @@ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata) · 10 unmodified lines | |||
| 109 | static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) | 142 | static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) |
| 110 | { | 143 | { |
| 111 | u32 val; | 144 | u32 val; |
| 112 | int size; | 145 | int rc; |
| 113 | 146 | ||
| 114 | val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); | 147 | val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); |
| 115 | /* | 148 | tpda_clear_element_size(drvdata->csdev); |
| 116 | * Configure aggregator port n DSB data set element size | 149 | rc = tpda_get_element_size(drvdata, drvdata->csdev, port); |
| 117 | * Set the bit to 0 if the size is 32 | 150 | if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) { |
| 118 | * Set the bit to 1 if the size is 64 | 151 | tpda_set_element_size(drvdata, &val); |
| 119 | */ | 152 | /* Enable the port */ |
| 120 | size = tpda_get_element_size(drvdata->csdev, port); | 153 | val |= TPDA_Pn_CR_ENA; |
| 121 | switch (size) { | 154 | writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); |
| 122 | case 32: | 155 | } else if (rc == -EEXIST) |
| 123 | val &= ~TPDA_Pn_CR_DSBSIZE; | ||
| 124 | break; | ||
| 125 | case 64: | ||
| 126 | val |= TPDA_Pn_CR_DSBSIZE; | ||
| 127 | break; | ||
| 128 | case 0: | ||
| 129 | return -EEXIST; | ||
| 130 | case -EEXIST: | ||
| 131 | dev_warn_once(&drvdata->csdev->dev, | 156 | dev_warn_once(&drvdata->csdev->dev, |
| 132 | "Detected multiple TPDMs on port %d", -EEXIST); | 157 | "Detected multiple TPDMs on port %d", port); |
| 133 | return -EEXIST; | 158 | else |
| 134 | default: | 159 | dev_warn_once(&drvdata->csdev->dev, |
| 135 | return -EINVAL; | 160 | "Didn't find TPDM element size"); |
| 136 | } | ||
| 137 | |||
| 138 | /* Enable the port */ | ||
| 139 | val |= TPDA_Pn_CR_ENA; | ||
| 140 | writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); | ||
| 141 | 161 | ||
| 142 | return 0; | 162 | return rc; |
| 143 | } | 163 | } |
| 144 | 164 | ||
| 145 | static int __tpda_enable(struct tpda_drvdata *drvdata, int port) | 165 | static int __tpda_enable(struct tpda_drvdata *drvdata, int port) |
| @@ -148,7 +168,12 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) · 2 unmodified lines | |||
| 148 | 168 | ||
| 149 | CS_UNLOCK(drvdata->base); | 169 | CS_UNLOCK(drvdata->base); |
| 150 | 170 | ||
| 151 | if (!drvdata->csdev->enable) | 171 | /* |
| 172 | * Only do pre-port enable for first port that calls enable when the | ||
| 173 | * device's main refcount is still 0 | ||
| 174 | */ | ||
| 175 | lockdep_assert_held(&drvdata->spinlock); | ||
| 176 | if (!drvdata->csdev->refcnt) | ||
| 152 | tpda_enable_pre_port(drvdata); | 177 | tpda_enable_pre_port(drvdata); |
| 153 | 178 | ||
| 154 | ret = tpda_enable_port(drvdata, port); | 179 | ret = tpda_enable_port(drvdata, port); |
| @@ -169,6 +194,7 @@ static int tpda_enable(struct coresight_device *csdev, · 14 unmodified lines | |||
| 169 | ret = __tpda_enable(drvdata, in->dest_port); | 194 | ret = __tpda_enable(drvdata, in->dest_port); |
| 170 | if (!ret) { | 195 | if (!ret) { |
| 171 | atomic_inc(&in->dest_refcnt); | 196 | atomic_inc(&in->dest_refcnt); |
| 197 | csdev->refcnt++; | ||
| 172 | dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); | 198 | dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); |
| 173 | } | 199 | } |
| 174 | } | 200 | } |
| @@ -197,9 +223,10 @@ static void tpda_disable(struct coresight_device *csdev, · 22 unmodified lines | |||
| 197 | struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 223 | struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 198 | 224 | ||
| 199 | spin_lock(&drvdata->spinlock); | 225 | spin_lock(&drvdata->spinlock); |
| 200 | if (atomic_dec_return(&in->dest_refcnt) == 0) | 226 | if (atomic_dec_return(&in->dest_refcnt) == 0) { |
| 201 | __tpda_disable(drvdata, in->dest_port); | 227 | __tpda_disable(drvdata, in->dest_port); |
| 202 | 228 | csdev->refcnt--; | |
| 229 | } | ||
| 203 | spin_unlock(&drvdata->spinlock); | 230 | spin_unlock(&drvdata->spinlock); |
| 204 | 231 | ||
| 205 | dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); | 232 | dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); |
| @@ -300,7 +327,7 @@ static struct amba_id tpda_ids[] = { · 94 unmodified lines | |||
| 300 | .id = 0x000f0f00, | 327 | .id = 0x000f0f00, |
| 301 | .mask = 0x000fff00, | 328 | .mask = 0x000fff00, |
| 302 | }, | 329 | }, |
| 303 | { 0, 0}, | 330 | { 0, 0, NULL }, |
| 304 | }; | 331 | }; |
| 305 | 332 | ||
| 306 | static struct amba_driver tpda_driver = { | 333 | static struct amba_driver tpda_driver = { |
| @@ -10,6 +10,8 @@ · 9 unmodified lines | |||
| 10 | #define TPDA_Pn_CR(n) (0x004 + (n * 4)) | 10 | #define TPDA_Pn_CR(n) (0x004 + (n * 4)) |
| 11 | /* Aggregator port enable bit */ | 11 | /* Aggregator port enable bit */ |
| 12 | #define TPDA_Pn_CR_ENA BIT(0) | 12 | #define TPDA_Pn_CR_ENA BIT(0) |
| 13 | /* Aggregator port CMB data set element size bit */ | ||
| 14 | #define TPDA_Pn_CR_CMBSIZE GENMASK(7, 6) | ||
| 13 | /* Aggregator port DSB data set element size bit */ | 15 | /* Aggregator port DSB data set element size bit */ |
| 14 | #define TPDA_Pn_CR_DSBSIZE BIT(8) | 16 | #define TPDA_Pn_CR_DSBSIZE BIT(8) |
| 15 | 17 | ||
| @@ -25,6 +27,8 @@ · 9 unmodified lines | |||
| 25 | * @csdev: component vitals needed by the framework. | 27 | * @csdev: component vitals needed by the framework. |
| 26 | * @spinlock: lock for the drvdata value. | 28 | * @spinlock: lock for the drvdata value. |
| 27 | * @enable: enable status of the component. | 29 | * @enable: enable status of the component. |
| 30 | * @dsb_esize Record the DSB element size. | ||
| 31 | * @cmb_esize Record the CMB element size. | ||
| 28 | */ | 32 | */ |
| 29 | struct tpda_drvdata { | 33 | struct tpda_drvdata { |
| 30 | void __iomem *base; | 34 | void __iomem *base; |
| @@ -32,6 +36,8 @@ struct tpda_drvdata { · 1 unmodified line | |||
| 32 | struct coresight_device *csdev; | 36 | struct coresight_device *csdev; |
| 33 | spinlock_t spinlock; | 37 | spinlock_t spinlock; |
| 34 | u8 atid; | 38 | u8 atid; |
| 39 | u32 dsb_esize; | ||
| 40 | u32 cmb_esize; | ||
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 37 | #endif /* _CORESIGHT_CORESIGHT_TPDA_H */ | 43 | #endif /* _CORESIGHT_CORESIGHT_TPDA_H */ |
| @@ -66,6 +66,31 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev, · 65 unmodified lines | |||
| 66 | return -EINVAL; | 66 | return -EINVAL; |
| 67 | return sysfs_emit(buf, "0x%x\n", | 67 | return sysfs_emit(buf, "0x%x\n", |
| 68 | drvdata->dsb->msr[tpdm_attr->idx]); | 68 | drvdata->dsb->msr[tpdm_attr->idx]); |
| 69 | case CMB_TRIG_PATT: | ||
| 70 | if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||
| 71 | return -EINVAL; | ||
| 72 | return sysfs_emit(buf, "0x%x\n", | ||
| 73 | drvdata->cmb->trig_patt[tpdm_attr->idx]); | ||
| 74 | case CMB_TRIG_PATT_MASK: | ||
| 75 | if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||
| 76 | return -EINVAL; | ||
| 77 | return sysfs_emit(buf, "0x%x\n", | ||
| 78 | drvdata->cmb->trig_patt_mask[tpdm_attr->idx]); | ||
| 79 | case CMB_PATT: | ||
| 80 | if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||
| 81 | return -EINVAL; | ||
| 82 | return sysfs_emit(buf, "0x%x\n", | ||
| 83 | drvdata->cmb->patt_val[tpdm_attr->idx]); | ||
| 84 | case CMB_PATT_MASK: | ||
| 85 | if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||
| 86 | return -EINVAL; | ||
| 87 | return sysfs_emit(buf, "0x%x\n", | ||
| 88 | drvdata->cmb->patt_mask[tpdm_attr->idx]); | ||
| 89 | case CMB_MSR: | ||
| 90 | if (tpdm_attr->idx >= drvdata->cmb_msr_num) | ||
| 91 | return -EINVAL; | ||
| 92 | return sysfs_emit(buf, "0x%x\n", | ||
| 93 | drvdata->cmb->msr[tpdm_attr->idx]); | ||
| 69 | } | 94 | } |
| 70 | return -EINVAL; | 95 | return -EINVAL; |
| 71 | } | 96 | } |
| @@ -77,67 +102,103 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, · 5 unmodified lines | |||
| 77 | size_t size) | 102 | size_t size) |
| 78 | { | 103 | { |
| 79 | unsigned long val; | 104 | unsigned long val; |
| 80 | ssize_t ret = size; | 105 | ssize_t ret = -EINVAL; |
| 81 | 106 | ||
| 82 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 107 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 83 | struct tpdm_dataset_attribute *tpdm_attr = | 108 | struct tpdm_dataset_attribute *tpdm_attr = |
| 84 | container_of(attr, struct tpdm_dataset_attribute, attr); | 109 | container_of(attr, struct tpdm_dataset_attribute, attr); |
| 85 | 110 | ||
| 86 | if (kstrtoul(buf, 0, &val)) | 111 | if (kstrtoul(buf, 0, &val)) |
| 87 | return -EINVAL; | 112 | return ret; |
| 88 | 113 | ||
| 89 | spin_lock(&drvdata->spinlock); | 114 | guard(spinlock)(&drvdata->spinlock); |
| 90 | switch (tpdm_attr->mem) { | 115 | switch (tpdm_attr->mem) { |
| 91 | case DSB_TRIG_PATT: | 116 | case DSB_TRIG_PATT: |
| 92 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 117 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { |
| 93 | drvdata->dsb->trig_patt[tpdm_attr->idx] = val; | 118 | drvdata->dsb->trig_patt[tpdm_attr->idx] = val; |
| 94 | else | 119 | ret = size; |
| 95 | ret = -EINVAL; | 120 | } |
| 96 | break; | 121 | break; |
| 97 | case DSB_TRIG_PATT_MASK: | 122 | case DSB_TRIG_PATT_MASK: |
| 98 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 123 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { |
| 99 | drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val; | 124 | drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val; |
| 100 | else | 125 | ret = size; |
| 101 | ret = -EINVAL; | 126 | } |
| 102 | break; | 127 | break; |
| 103 | case DSB_PATT: | 128 | case DSB_PATT: |
| 104 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 129 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { |
| 105 | drvdata->dsb->patt_val[tpdm_attr->idx] = val; | 130 | drvdata->dsb->patt_val[tpdm_attr->idx] = val; |
| 106 | else | 131 | ret = size; |
| 107 | ret = -EINVAL; | 132 | } |
| 108 | break; | 133 | break; |
| 109 | case DSB_PATT_MASK: | 134 | case DSB_PATT_MASK: |
| 110 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 135 | if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { |
| 111 | drvdata->dsb->patt_mask[tpdm_attr->idx] = val; | 136 | drvdata->dsb->patt_mask[tpdm_attr->idx] = val; |
| 112 | else | 137 | ret = size; |
| 113 | ret = -EINVAL; | 138 | } |
| 114 | break; | 139 | break; |
| 115 | case DSB_MSR: | 140 | case DSB_MSR: |
| 116 | if (tpdm_attr->idx < drvdata->dsb_msr_num) | 141 | if (tpdm_attr->idx < drvdata->dsb_msr_num) { |
| 117 | drvdata->dsb->msr[tpdm_attr->idx] = val; | 142 | drvdata->dsb->msr[tpdm_attr->idx] = val; |
| 118 | else | 143 | ret = size; |
| 119 | ret = -EINVAL; | 144 | } |
| 145 | break; | ||
| 146 | case CMB_TRIG_PATT: | ||
| 147 | if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||
| 148 | drvdata->cmb->trig_patt[tpdm_attr->idx] = val; | ||
| 149 | ret = size; | ||
| 150 | } | ||
| 151 | break; | ||
| 152 | case CMB_TRIG_PATT_MASK: | ||
| 153 | if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||
| 154 | drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val; | ||
| 155 | ret = size; | ||
| 156 | } | ||
| 157 | break; | ||
| 158 | case CMB_PATT: | ||
| 159 | if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||
| 160 | drvdata->cmb->patt_val[tpdm_attr->idx] = val; | ||
| 161 | ret = size; | ||
| 162 | } | ||
| 163 | break; | ||
| 164 | case CMB_PATT_MASK: | ||
| 165 | if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||
| 166 | drvdata->cmb->patt_mask[tpdm_attr->idx] = val; | ||
| 167 | ret = size; | ||
| 168 | } | ||
| 169 | break; | ||
| 170 | case CMB_MSR: | ||
| 171 | if (tpdm_attr->idx < drvdata->cmb_msr_num) { | ||
| 172 | drvdata->cmb->msr[tpdm_attr->idx] = val; | ||
| 173 | ret = size; | ||
| 174 | } | ||
| 120 | break; | 175 | break; |
| 121 | default: | 176 | default: |
| 122 | ret = -EINVAL; | 177 | break; |
| 123 | } | 178 | } |
| 124 | spin_unlock(&drvdata->spinlock); | ||
| 125 | 179 | ||
| 126 | return ret; | 180 | return ret; |
| 127 | } | 181 | } |
| 128 | 182 | ||
| 129 | static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) | 183 | static umode_t tpdm_dsb_is_visible(struct kobject *kobj, |
| 184 | struct attribute *attr, int n) | ||
| 130 | { | 185 | { |
| 131 | return (drvdata->datasets & TPDM_PIDR0_DS_DSB); | 186 | struct device *dev = kobj_to_dev(kobj); |
| 187 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 188 | |||
| 189 | if (drvdata && tpdm_has_dsb_dataset(drvdata)) | ||
| 190 | return attr->mode; | ||
| 191 | |||
| 192 | return 0; | ||
| 132 | } | 193 | } |
| 133 | 194 | ||
| 134 | static umode_t tpdm_dsb_is_visible(struct kobject *kobj, | 195 | static umode_t tpdm_cmb_is_visible(struct kobject *kobj, |
| 135 | struct attribute *attr, int n) | 196 | struct attribute *attr, int n) |
| 136 | { | 197 | { |
| 137 | struct device *dev = kobj_to_dev(kobj); | 198 | struct device *dev = kobj_to_dev(kobj); |
| 138 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 199 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 139 | 200 | ||
| 140 | if (drvdata && tpdm_has_dsb_dataset(drvdata)) | 201 | if (drvdata && tpdm_has_cmb_dataset(drvdata)) |
| 141 | return attr->mode; | 202 | return attr->mode; |
| 142 | 203 | ||
| 143 | return 0; | 204 | return 0; |
| @@ -159,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, · 15 unmodified lines | |||
| 159 | return 0; | 220 | return 0; |
| 160 | } | 221 | } |
| 161 | 222 | ||
| 223 | static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj, | ||
| 224 | struct attribute *attr, int n) | ||
| 225 | { | ||
| 226 | struct device *dev = kobj_to_dev(kobj); | ||
| 227 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 228 | |||
| 229 | struct device_attribute *dev_attr = | ||
| 230 | container_of(attr, struct device_attribute, attr); | ||
| 231 | struct tpdm_dataset_attribute *tpdm_attr = | ||
| 232 | container_of(dev_attr, struct tpdm_dataset_attribute, attr); | ||
| 233 | |||
| 234 | if (tpdm_attr->idx < drvdata->cmb_msr_num) | ||
| 235 | return attr->mode; | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 162 | static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) | 240 | static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) |
| 163 | { | 241 | { |
| 164 | if (tpdm_has_dsb_dataset(drvdata)) { | 242 | if (tpdm_has_dsb_dataset(drvdata)) { |
| @@ -167,6 +245,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) · 2 unmodified lines | |||
| 167 | drvdata->dsb->trig_ts = true; | 245 | drvdata->dsb->trig_ts = true; |
| 168 | drvdata->dsb->trig_type = false; | 246 | drvdata->dsb->trig_type = false; |
| 169 | } | 247 | } |
| 248 | |||
| 249 | if (drvdata->cmb) | ||
| 250 | memset(drvdata->cmb, 0, sizeof(struct cmb_dataset)); | ||
| 170 | } | 251 | } |
| 171 | 252 | ||
| 172 | static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val) | 253 | static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val) |
| @@ -233,25 +314,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) · 60 unmodified lines | |||
| 233 | { | 314 | { |
| 234 | u32 val, i; | 315 | u32 val, i; |
| 235 | 316 | ||
| 317 | if (!tpdm_has_dsb_dataset(drvdata)) | ||
| 318 | return; | ||
| 319 | |||
| 236 | for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) | 320 | for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) |
| 237 | writel_relaxed(drvdata->dsb->edge_ctrl[i], | 321 | writel_relaxed(drvdata->dsb->edge_ctrl[i], |
| 238 | drvdata->base + TPDM_DSB_EDCR(i)); | 322 | drvdata->base + TPDM_DSB_EDCR(i)); |
| 239 | for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) | 323 | for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) |
| 240 | writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], | 324 | writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], |
| 241 | drvdata->base + TPDM_DSB_EDCMR(i)); | 325 | drvdata->base + TPDM_DSB_EDCMR(i)); |
| 242 | for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { | 326 | for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { |
| 243 | writel_relaxed(drvdata->dsb->patt_val[i], | 327 | writel_relaxed(drvdata->dsb->patt_val[i], |
| 244 | drvdata->base + TPDM_DSB_TPR(i)); | 328 | drvdata->base + TPDM_DSB_TPR(i)); |
| 245 | writel_relaxed(drvdata->dsb->patt_mask[i], | 329 | writel_relaxed(drvdata->dsb->patt_mask[i], |
| 246 | drvdata->base + TPDM_DSB_TPMR(i)); | 330 | drvdata->base + TPDM_DSB_TPMR(i)); |
| 247 | writel_relaxed(drvdata->dsb->trig_patt[i], | 331 | writel_relaxed(drvdata->dsb->trig_patt[i], |
| 248 | drvdata->base + TPDM_DSB_XPR(i)); | 332 | drvdata->base + TPDM_DSB_XPR(i)); |
| 249 | writel_relaxed(drvdata->dsb->trig_patt_mask[i], | 333 | writel_relaxed(drvdata->dsb->trig_patt_mask[i], |
| 250 | drvdata->base + TPDM_DSB_XPMR(i)); | 334 | drvdata->base + TPDM_DSB_XPMR(i)); |
| 251 | } | 335 | } |
| 252 | 336 | ||
| 253 | set_dsb_tier(drvdata); | 337 | set_dsb_tier(drvdata); |
| 254 | |||
| 255 | set_dsb_msr(drvdata); | 338 | set_dsb_msr(drvdata); |
| 256 | 339 | ||
| 257 | val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | 340 | val = readl_relaxed(drvdata->base + TPDM_DSB_CR); |
| @@ -267,6 +350,76 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) · 9 unmodified lines | |||
| 267 | writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | 350 | writel_relaxed(val, drvdata->base + TPDM_DSB_CR); |
| 268 | } | 351 | } |
| 269 | 352 | ||
| 353 | static void set_cmb_tier(struct tpdm_drvdata *drvdata) | ||
| 354 | { | ||
| 355 | u32 val; | ||
| 356 | |||
| 357 | val = readl_relaxed(drvdata->base + TPDM_CMB_TIER); | ||
| 358 | |||
| 359 | /* Clear all relevant fields */ | ||
| 360 | val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL | | ||
| 361 | TPDM_CMB_TIER_XTRIG_TSENAB); | ||
| 362 | |||
| 363 | /* Set pattern timestamp type and enablement */ | ||
| 364 | if (drvdata->cmb->patt_ts) | ||
| 365 | val |= TPDM_CMB_TIER_PATT_TSENAB; | ||
| 366 | |||
| 367 | /* Set trigger timestamp */ | ||
| 368 | if (drvdata->cmb->trig_ts) | ||
| 369 | val |= TPDM_CMB_TIER_XTRIG_TSENAB; | ||
| 370 | |||
| 371 | /* Set all timestamp enablement*/ | ||
| 372 | if (drvdata->cmb->ts_all) | ||
| 373 | val |= TPDM_CMB_TIER_TS_ALL; | ||
| 374 | |||
| 375 | writel_relaxed(val, drvdata->base + TPDM_CMB_TIER); | ||
| 376 | } | ||
| 377 | |||
| 378 | static void set_cmb_msr(struct tpdm_drvdata *drvdata) | ||
| 379 | { | ||
| 380 | int i; | ||
| 381 | |||
| 382 | for (i = 0; i < drvdata->cmb_msr_num; i++) | ||
| 383 | writel_relaxed(drvdata->cmb->msr[i], | ||
| 384 | drvdata->base + TPDM_CMB_MSR(i)); | ||
| 385 | } | ||
| 386 | |||
| 387 | static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) | ||
| 388 | { | ||
| 389 | u32 val, i; | ||
| 390 | |||
| 391 | if (!tpdm_has_cmb_dataset(drvdata)) | ||
| 392 | return; | ||
| 393 | |||
| 394 | /* Configure pattern registers */ | ||
| 395 | for (i = 0; i < TPDM_CMB_MAX_PATT; i++) { | ||
| 396 | writel_relaxed(drvdata->cmb->patt_val[i], | ||
| 397 | drvdata->base + TPDM_CMB_TPR(i)); | ||
| 398 | writel_relaxed(drvdata->cmb->patt_mask[i], | ||
| 399 | drvdata->base + TPDM_CMB_TPMR(i)); | ||
| 400 | writel_relaxed(drvdata->cmb->trig_patt[i], | ||
| 401 | drvdata->base + TPDM_CMB_XPR(i)); | ||
| 402 | writel_relaxed(drvdata->cmb->trig_patt_mask[i], | ||
| 403 | drvdata->base + TPDM_CMB_XPMR(i)); | ||
| 404 | } | ||
| 405 | |||
| 406 | set_cmb_tier(drvdata); | ||
| 407 | set_cmb_msr(drvdata); | ||
| 408 | |||
| 409 | val = readl_relaxed(drvdata->base + TPDM_CMB_CR); | ||
| 410 | /* | ||
| 411 | * Set to 0 for continuous CMB collection mode, | ||
| 412 | * 1 for trace-on-change CMB collection mode. | ||
| 413 | */ | ||
| 414 | if (drvdata->cmb->trace_mode) | ||
| 415 | val |= TPDM_CMB_CR_MODE; | ||
| 416 | else | ||
| 417 | val &= ~TPDM_CMB_CR_MODE; | ||
| 418 | /* Set the enable bit of CMB control register to 1 */ | ||
| 419 | val |= TPDM_CMB_CR_ENA; | ||
| 420 | writel_relaxed(val, drvdata->base + TPDM_CMB_CR); | ||
| 421 | } | ||
| 422 | |||
| 270 | /* | 423 | /* |
| 271 | * TPDM enable operations | 424 | * TPDM enable operations |
| 272 | * The TPDM or Monitor serves as data collection component for various | 425 | * The TPDM or Monitor serves as data collection component for various |
| @@ -279,8 +432,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) · 6 unmodified lines | |||
| 279 | { | 432 | { |
| 280 | CS_UNLOCK(drvdata->base); | 433 | CS_UNLOCK(drvdata->base); |
| 281 | 434 | ||
| 282 | if (tpdm_has_dsb_dataset(drvdata)) | 435 | tpdm_enable_dsb(drvdata); |
| 283 | tpdm_enable_dsb(drvdata); | 436 | tpdm_enable_cmb(drvdata); |
| 284 | 437 | ||
| 285 | CS_LOCK(drvdata->base); | 438 | CS_LOCK(drvdata->base); |
| 286 | } | 439 | } |
| @@ -308,19 +461,35 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata) · 21 unmodified lines | |||
| 308 | { | 461 | { |
| 309 | u32 val; | 462 | u32 val; |
| 310 | 463 | ||
| 464 | if (!tpdm_has_dsb_dataset(drvdata)) | ||
| 465 | return; | ||
| 466 | |||
| 311 | /* Set the enable bit of DSB control register to 0 */ | 467 | /* Set the enable bit of DSB control register to 0 */ |
| 312 | val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | 468 | val = readl_relaxed(drvdata->base + TPDM_DSB_CR); |
| 313 | val &= ~TPDM_DSB_CR_ENA; | 469 | val &= ~TPDM_DSB_CR_ENA; |
| 314 | writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | 470 | writel_relaxed(val, drvdata->base + TPDM_DSB_CR); |
| 315 | } | 471 | } |
| 316 | 472 | ||
| 473 | static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata) | ||
| 474 | { | ||
| 475 | u32 val; | ||
| 476 | |||
| 477 | if (!tpdm_has_cmb_dataset(drvdata)) | ||
| 478 | return; | ||
| 479 | |||
| 480 | val = readl_relaxed(drvdata->base + TPDM_CMB_CR); | ||
| 481 | /* Set the enable bit of CMB control register to 0 */ | ||
| 482 | val &= ~TPDM_CMB_CR_ENA; | ||
| 483 | writel_relaxed(val, drvdata->base + TPDM_CMB_CR); | ||
| 484 | } | ||
| 485 | |||
| 317 | /* TPDM disable operations */ | 486 | /* TPDM disable operations */ |
| 318 | static void __tpdm_disable(struct tpdm_drvdata *drvdata) | 487 | static void __tpdm_disable(struct tpdm_drvdata *drvdata) |
| 319 | { | 488 | { |
| 320 | CS_UNLOCK(drvdata->base); | 489 | CS_UNLOCK(drvdata->base); |
| 321 | 490 | ||
| 322 | if (tpdm_has_dsb_dataset(drvdata)) | 491 | tpdm_disable_dsb(drvdata); |
| 323 | tpdm_disable_dsb(drvdata); | 492 | tpdm_disable_cmb(drvdata); |
| 324 | 493 | ||
| 325 | CS_LOCK(drvdata->base); | 494 | CS_LOCK(drvdata->base); |
| 326 | } | 495 | } |
| @@ -366,6 +535,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata) · 39 unmodified lines | |||
| 366 | if (!drvdata->dsb) | 535 | if (!drvdata->dsb) |
| 367 | return -ENOMEM; | 536 | return -ENOMEM; |
| 368 | } | 537 | } |
| 538 | if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) { | ||
| 539 | drvdata->cmb = devm_kzalloc(drvdata->dev, | ||
| 540 | sizeof(*drvdata->cmb), GFP_KERNEL); | ||
| 541 | if (!drvdata->cmb) | ||
| 542 | return -ENOMEM; | ||
| 543 | } | ||
| 369 | tpdm_reset_datasets(drvdata); | 544 | tpdm_reset_datasets(drvdata); |
| 370 | 545 | ||
| 371 | return 0; | 546 | return 0; |
| @@ -577,9 +752,18 @@ static ssize_t enable_ts_show(struct device *dev, · 205 unmodified lines | |||
| 577 | char *buf) | 752 | char *buf) |
| 578 | { | 753 | { |
| 579 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 754 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 755 | struct tpdm_dataset_attribute *tpdm_attr = | ||
| 756 | container_of(attr, struct tpdm_dataset_attribute, attr); | ||
| 757 | ssize_t size = -EINVAL; | ||
| 580 | 758 | ||
| 581 | return sysfs_emit(buf, "%u\n", | 759 | if (tpdm_attr->mem == DSB_PATT) |
| 582 | (unsigned int)drvdata->dsb->patt_ts); | 760 | size = sysfs_emit(buf, "%u\n", |
| 761 | (unsigned int)drvdata->dsb->patt_ts); | ||
| 762 | else if (tpdm_attr->mem == CMB_PATT) | ||
| 763 | size = sysfs_emit(buf, "%u\n", | ||
| 764 | (unsigned int)drvdata->cmb->patt_ts); | ||
| 765 | |||
| 766 | return size; | ||
| 583 | } | 767 | } |
| 584 | 768 | ||
| 585 | /* | 769 | /* |
| @@ -591,17 +775,23 @@ static ssize_t enable_ts_store(struct device *dev, · 5 unmodified lines | |||
| 591 | size_t size) | 775 | size_t size) |
| 592 | { | 776 | { |
| 593 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 777 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 778 | struct tpdm_dataset_attribute *tpdm_attr = | ||
| 779 | container_of(attr, struct tpdm_dataset_attribute, attr); | ||
| 594 | unsigned long val; | 780 | unsigned long val; |
| 595 | 781 | ||
| 596 | if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | 782 | if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) |
| 597 | return -EINVAL; | 783 | return -EINVAL; |
| 598 | 784 | ||
| 599 | spin_lock(&drvdata->spinlock); | 785 | guard(spinlock)(&drvdata->spinlock); |
| 600 | drvdata->dsb->patt_ts = !!val; | 786 | if (tpdm_attr->mem == DSB_PATT) |
| 601 | spin_unlock(&drvdata->spinlock); | 787 | drvdata->dsb->patt_ts = !!val; |
| 788 | else if (tpdm_attr->mem == CMB_PATT) | ||
| 789 | drvdata->cmb->patt_ts = !!val; | ||
| 790 | else | ||
| 791 | return -EINVAL; | ||
| 792 | |||
| 602 | return size; | 793 | return size; |
| 603 | } | 794 | } |
| 604 | static DEVICE_ATTR_RW(enable_ts); | ||
| 605 | 795 | ||
| 606 | static ssize_t set_type_show(struct device *dev, | 796 | static ssize_t set_type_show(struct device *dev, |
| 607 | struct device_attribute *attr, | 797 | struct device_attribute *attr, |
| @@ -704,6 +894,96 @@ static ssize_t dsb_trig_ts_store(struct device *dev, · 96 unmodified lines | |||
| 704 | } | 894 | } |
| 705 | static DEVICE_ATTR_RW(dsb_trig_ts); | 895 | static DEVICE_ATTR_RW(dsb_trig_ts); |
| 706 | 896 | ||
| 897 | static ssize_t cmb_mode_show(struct device *dev, | ||
| 898 | struct device_attribute *attr, | ||
| 899 | char *buf) | ||
| 900 | { | ||
| 901 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 902 | |||
| 903 | return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode); | ||
| 904 | |||
| 905 | } | ||
| 906 | |||
| 907 | static ssize_t cmb_mode_store(struct device *dev, | ||
| 908 | struct device_attribute *attr, | ||
| 909 | const char *buf, | ||
| 910 | size_t size) | ||
| 911 | { | ||
| 912 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 913 | unsigned long trace_mode; | ||
| 914 | |||
| 915 | if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL)) | ||
| 916 | return -EINVAL; | ||
| 917 | |||
| 918 | spin_lock(&drvdata->spinlock); | ||
| 919 | drvdata->cmb->trace_mode = trace_mode; | ||
| 920 | spin_unlock(&drvdata->spinlock); | ||
| 921 | return size; | ||
| 922 | } | ||
| 923 | static DEVICE_ATTR_RW(cmb_mode); | ||
| 924 | |||
| 925 | static ssize_t cmb_ts_all_show(struct device *dev, | ||
| 926 | struct device_attribute *attr, | ||
| 927 | char *buf) | ||
| 928 | { | ||
| 929 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 930 | |||
| 931 | return sysfs_emit(buf, "%u\n", | ||
| 932 | (unsigned int)drvdata->cmb->ts_all); | ||
| 933 | } | ||
| 934 | |||
| 935 | static ssize_t cmb_ts_all_store(struct device *dev, | ||
| 936 | struct device_attribute *attr, | ||
| 937 | const char *buf, | ||
| 938 | size_t size) | ||
| 939 | { | ||
| 940 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 941 | unsigned long val; | ||
| 942 | |||
| 943 | if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | ||
| 944 | return -EINVAL; | ||
| 945 | |||
| 946 | guard(spinlock)(&drvdata->spinlock); | ||
| 947 | if (val) | ||
| 948 | drvdata->cmb->ts_all = true; | ||
| 949 | else | ||
| 950 | drvdata->cmb->ts_all = false; | ||
| 951 | |||
| 952 | return size; | ||
| 953 | } | ||
| 954 | static DEVICE_ATTR_RW(cmb_ts_all); | ||
| 955 | |||
| 956 | static ssize_t cmb_trig_ts_show(struct device *dev, | ||
| 957 | struct device_attribute *attr, | ||
| 958 | char *buf) | ||
| 959 | { | ||
| 960 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 961 | |||
| 962 | return sysfs_emit(buf, "%u\n", | ||
| 963 | (unsigned int)drvdata->cmb->trig_ts); | ||
| 964 | } | ||
| 965 | |||
| 966 | static ssize_t cmb_trig_ts_store(struct device *dev, | ||
| 967 | struct device_attribute *attr, | ||
| 968 | const char *buf, | ||
| 969 | size_t size) | ||
| 970 | { | ||
| 971 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 972 | unsigned long val; | ||
| 973 | |||
| 974 | if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | ||
| 975 | return -EINVAL; | ||
| 976 | |||
| 977 | guard(spinlock)(&drvdata->spinlock); | ||
| 978 | if (val) | ||
| 979 | drvdata->cmb->trig_ts = true; | ||
| 980 | else | ||
| 981 | drvdata->cmb->trig_ts = false; | ||
| 982 | |||
| 983 | return size; | ||
| 984 | } | ||
| 985 | static DEVICE_ATTR_RW(cmb_trig_ts); | ||
| 986 | |||
| 707 | static struct attribute *tpdm_dsb_edge_attrs[] = { | 987 | static struct attribute *tpdm_dsb_edge_attrs[] = { |
| 708 | &dev_attr_ctrl_idx.attr, | 988 | &dev_attr_ctrl_idx.attr, |
| 709 | &dev_attr_ctrl_val.attr, | 989 | &dev_attr_ctrl_val.attr, |
| @@ -772,7 +1052,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = { · 62 unmodified lines | |||
| 772 | DSB_PATT_MASK_ATTR(5), | 1052 | DSB_PATT_MASK_ATTR(5), |
| 773 | DSB_PATT_MASK_ATTR(6), | 1053 | DSB_PATT_MASK_ATTR(6), |
| 774 | DSB_PATT_MASK_ATTR(7), | 1054 | DSB_PATT_MASK_ATTR(7), |
| 775 | &dev_attr_enable_ts.attr, | 1055 | DSB_PATT_ENABLE_TS, |
| 776 | &dev_attr_set_type.attr, | 1056 | &dev_attr_set_type.attr, |
| 777 | NULL, | 1057 | NULL, |
| 778 | }; | 1058 | }; |
| @@ -813,6 +1093,59 @@ static struct attribute *tpdm_dsb_msr_attrs[] = { · 34 unmodified lines | |||
| 813 | NULL, | 1093 | NULL, |
| 814 | }; | 1094 | }; |
| 815 | 1095 | ||
| 1096 | static struct attribute *tpdm_cmb_trig_patt_attrs[] = { | ||
| 1097 | CMB_TRIG_PATT_ATTR(0), | ||
| 1098 | CMB_TRIG_PATT_ATTR(1), | ||
| 1099 | CMB_TRIG_PATT_MASK_ATTR(0), | ||
| 1100 | CMB_TRIG_PATT_MASK_ATTR(1), | ||
| 1101 | NULL, | ||
| 1102 | }; | ||
| 1103 | |||
| 1104 | static struct attribute *tpdm_cmb_patt_attrs[] = { | ||
| 1105 | CMB_PATT_ATTR(0), | ||
| 1106 | CMB_PATT_ATTR(1), | ||
| 1107 | CMB_PATT_MASK_ATTR(0), | ||
| 1108 | CMB_PATT_MASK_ATTR(1), | ||
| 1109 | CMB_PATT_ENABLE_TS, | ||
| 1110 | NULL, | ||
| 1111 | }; | ||
| 1112 | |||
| 1113 | static struct attribute *tpdm_cmb_msr_attrs[] = { | ||
| 1114 | CMB_MSR_ATTR(0), | ||
| 1115 | CMB_MSR_ATTR(1), | ||
| 1116 | CMB_MSR_ATTR(2), | ||
| 1117 | CMB_MSR_ATTR(3), | ||
| 1118 | CMB_MSR_ATTR(4), | ||
| 1119 | CMB_MSR_ATTR(5), | ||
| 1120 | CMB_MSR_ATTR(6), | ||
| 1121 | CMB_MSR_ATTR(7), | ||
| 1122 | CMB_MSR_ATTR(8), | ||
| 1123 | CMB_MSR_ATTR(9), | ||
| 1124 | CMB_MSR_ATTR(10), | ||
| 1125 | CMB_MSR_ATTR(11), | ||
| 1126 | CMB_MSR_ATTR(12), | ||
| 1127 | CMB_MSR_ATTR(13), | ||
| 1128 | CMB_MSR_ATTR(14), | ||
| 1129 | CMB_MSR_ATTR(15), | ||
| 1130 | CMB_MSR_ATTR(16), | ||
| 1131 | CMB_MSR_ATTR(17), | ||
| 1132 | CMB_MSR_ATTR(18), | ||
| 1133 | CMB_MSR_ATTR(19), | ||
| 1134 | CMB_MSR_ATTR(20), | ||
| 1135 | CMB_MSR_ATTR(21), | ||
| 1136 | CMB_MSR_ATTR(22), | ||
| 1137 | CMB_MSR_ATTR(23), | ||
| 1138 | CMB_MSR_ATTR(24), | ||
| 1139 | CMB_MSR_ATTR(25), | ||
| 1140 | CMB_MSR_ATTR(26), | ||
| 1141 | CMB_MSR_ATTR(27), | ||
| 1142 | CMB_MSR_ATTR(28), | ||
| 1143 | CMB_MSR_ATTR(29), | ||
| 1144 | CMB_MSR_ATTR(30), | ||
| 1145 | CMB_MSR_ATTR(31), | ||
| 1146 | NULL, | ||
| 1147 | }; | ||
| 1148 | |||
| 816 | static struct attribute *tpdm_dsb_attrs[] = { | 1149 | static struct attribute *tpdm_dsb_attrs[] = { |
| 817 | &dev_attr_dsb_mode.attr, | 1150 | &dev_attr_dsb_mode.attr, |
| 818 | &dev_attr_dsb_trig_ts.attr, | 1151 | &dev_attr_dsb_trig_ts.attr, |
| @@ -820,6 +1153,13 @@ static struct attribute *tpdm_dsb_attrs[] = { · 1 unmodified line | |||
| 820 | NULL, | 1153 | NULL, |
| 821 | }; | 1154 | }; |
| 822 | 1155 | ||
| 1156 | static struct attribute *tpdm_cmb_attrs[] = { | ||
| 1157 | &dev_attr_cmb_mode.attr, | ||
| 1158 | &dev_attr_cmb_ts_all.attr, | ||
| 1159 | &dev_attr_cmb_trig_ts.attr, | ||
| 1160 | NULL, | ||
| 1161 | }; | ||
| 1162 | |||
| 823 | static struct attribute_group tpdm_dsb_attr_grp = { | 1163 | static struct attribute_group tpdm_dsb_attr_grp = { |
| 824 | .attrs = tpdm_dsb_attrs, | 1164 | .attrs = tpdm_dsb_attrs, |
| 825 | .is_visible = tpdm_dsb_is_visible, | 1165 | .is_visible = tpdm_dsb_is_visible, |
| @@ -849,6 +1189,29 @@ static struct attribute_group tpdm_dsb_msr_grp = { · 23 unmodified lines | |||
| 849 | .name = "dsb_msr", | 1189 | .name = "dsb_msr", |
| 850 | }; | 1190 | }; |
| 851 | 1191 | ||
| 1192 | static struct attribute_group tpdm_cmb_attr_grp = { | ||
| 1193 | .attrs = tpdm_cmb_attrs, | ||
| 1194 | .is_visible = tpdm_cmb_is_visible, | ||
| 1195 | }; | ||
| 1196 | |||
| 1197 | static struct attribute_group tpdm_cmb_trig_patt_grp = { | ||
| 1198 | .attrs = tpdm_cmb_trig_patt_attrs, | ||
| 1199 | .is_visible = tpdm_cmb_is_visible, | ||
| 1200 | .name = "cmb_trig_patt", | ||
| 1201 | }; | ||
| 1202 | |||
| 1203 | static struct attribute_group tpdm_cmb_patt_grp = { | ||
| 1204 | .attrs = tpdm_cmb_patt_attrs, | ||
| 1205 | .is_visible = tpdm_cmb_is_visible, | ||
| 1206 | .name = "cmb_patt", | ||
| 1207 | }; | ||
| 1208 | |||
| 1209 | static struct attribute_group tpdm_cmb_msr_grp = { | ||
| 1210 | .attrs = tpdm_cmb_msr_attrs, | ||
| 1211 | .is_visible = tpdm_cmb_msr_is_visible, | ||
| 1212 | .name = "cmb_msr", | ||
| 1213 | }; | ||
| 1214 | |||
| 852 | static const struct attribute_group *tpdm_attr_grps[] = { | 1215 | static const struct attribute_group *tpdm_attr_grps[] = { |
| 853 | &tpdm_attr_grp, | 1216 | &tpdm_attr_grp, |
| 854 | &tpdm_dsb_attr_grp, | 1217 | &tpdm_dsb_attr_grp, |
| @@ -856,6 +1219,10 @@ static const struct attribute_group *tpdm_attr_grps[] = { · 1 unmodified line | |||
| 856 | &tpdm_dsb_trig_patt_grp, | 1219 | &tpdm_dsb_trig_patt_grp, |
| 857 | &tpdm_dsb_patt_grp, | 1220 | &tpdm_dsb_patt_grp, |
| 858 | &tpdm_dsb_msr_grp, | 1221 | &tpdm_dsb_msr_grp, |
| 1222 | &tpdm_cmb_attr_grp, | ||
| 1223 | &tpdm_cmb_trig_patt_grp, | ||
| 1224 | &tpdm_cmb_patt_grp, | ||
| 1225 | &tpdm_cmb_msr_grp, | ||
| 859 | NULL, | 1226 | NULL, |
| 860 | }; | 1227 | }; |
| 861 | 1228 | ||
| @@ -894,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) · 32 unmodified lines | |||
| 894 | of_property_read_u32(drvdata->dev->of_node, | 1261 | of_property_read_u32(drvdata->dev->of_node, |
| 895 | "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); | 1262 | "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); |
| 896 | 1263 | ||
| 1264 | if (drvdata && tpdm_has_cmb_dataset(drvdata)) | ||
| 1265 | of_property_read_u32(drvdata->dev->of_node, | ||
| 1266 | "qcom,cmb-msrs-num", &drvdata->cmb_msr_num); | ||
| 1267 | |||
| 897 | /* Set up coresight component description */ | 1268 | /* Set up coresight component description */ |
| 898 | desc.name = coresight_alloc_device_name(&tpdm_devs, dev); | 1269 | desc.name = coresight_alloc_device_name(&tpdm_devs, dev); |
| 899 | if (!desc.name) | 1270 | if (!desc.name) |
| @@ -933,7 +1304,7 @@ static struct amba_id tpdm_ids[] = { · 33 unmodified lines | |||
| 933 | .id = 0x000f0e00, | 1304 | .id = 0x000f0e00, |
| 934 | .mask = 0x000fff00, | 1305 | .mask = 0x000fff00, |
| 935 | }, | 1306 | }, |
| 936 | { 0, 0}, | 1307 | { 0, 0, NULL }, |
| 937 | }; | 1308 | }; |
| 938 | 1309 | ||
| 939 | static struct amba_driver tpdm_driver = { | 1310 | static struct amba_driver tpdm_driver = { |
| @@ -9,6 +9,38 @@ · 8 unmodified lines | |||
| 9 | /* The max number of the datasets that TPDM supports */ | 9 | /* The max number of the datasets that TPDM supports */ |
| 10 | #define TPDM_DATASETS 7 | 10 | #define TPDM_DATASETS 7 |
| 11 | 11 | ||
| 12 | /* CMB Subunit Registers */ | ||
| 13 | #define TPDM_CMB_CR (0xA00) | ||
| 14 | /* CMB subunit timestamp insertion enable register */ | ||
| 15 | #define TPDM_CMB_TIER (0xA04) | ||
| 16 | /* CMB subunit timestamp pattern registers */ | ||
| 17 | #define TPDM_CMB_TPR(n) (0xA08 + (n * 4)) | ||
| 18 | /* CMB subunit timestamp pattern mask registers */ | ||
| 19 | #define TPDM_CMB_TPMR(n) (0xA10 + (n * 4)) | ||
| 20 | /* CMB subunit trigger pattern registers */ | ||
| 21 | #define TPDM_CMB_XPR(n) (0xA18 + (n * 4)) | ||
| 22 | /* CMB subunit trigger pattern mask registers */ | ||
| 23 | #define TPDM_CMB_XPMR(n) (0xA20 + (n * 4)) | ||
| 24 | /* CMB MSR register */ | ||
| 25 | #define TPDM_CMB_MSR(n) (0xA80 + (n * 4)) | ||
| 26 | |||
| 27 | /* Enable bit for CMB subunit */ | ||
| 28 | #define TPDM_CMB_CR_ENA BIT(0) | ||
| 29 | /* Trace collection mode for CMB subunit */ | ||
| 30 | #define TPDM_CMB_CR_MODE BIT(1) | ||
| 31 | /* Timestamp control for pattern match */ | ||
| 32 | #define TPDM_CMB_TIER_PATT_TSENAB BIT(0) | ||
| 33 | /* CMB CTI timestamp request */ | ||
| 34 | #define TPDM_CMB_TIER_XTRIG_TSENAB BIT(1) | ||
| 35 | /* For timestamp fo all trace */ | ||
| 36 | #define TPDM_CMB_TIER_TS_ALL BIT(2) | ||
| 37 | |||
| 38 | /* Patten register number */ | ||
| 39 | #define TPDM_CMB_MAX_PATT 2 | ||
| 40 | |||
| 41 | /* MAX number of DSB MSR */ | ||
| 42 | #define TPDM_CMB_MAX_MSR 32 | ||
| 43 | |||
| 12 | /* DSB Subunit Registers */ | 44 | /* DSB Subunit Registers */ |
| 13 | #define TPDM_DSB_CR (0x780) | 45 | #define TPDM_DSB_CR (0x780) |
| 14 | #define TPDM_DSB_TIER (0x784) | 46 | #define TPDM_DSB_TIER (0x784) |
| @@ -79,10 +111,12 @@ · 64 unmodified lines | |||
| 79 | * | 111 | * |
| 80 | * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0 | 112 | * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0 |
| 81 | * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0 | 113 | * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0 |
| 114 | * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0 | ||
| 82 | */ | 115 | */ |
| 83 | 116 | ||
| 84 | #define TPDM_PIDR0_DS_IMPDEF BIT(0) | 117 | #define TPDM_PIDR0_DS_IMPDEF BIT(0) |
| 85 | #define TPDM_PIDR0_DS_DSB BIT(1) | 118 | #define TPDM_PIDR0_DS_DSB BIT(1) |
| 119 | #define TPDM_PIDR0_DS_CMB BIT(2) | ||
| 86 | 120 | ||
| 87 | #define TPDM_DSB_MAX_LINES 256 | 121 | #define TPDM_DSB_MAX_LINES 256 |
| 88 | /* MAX number of EDCR registers */ | 122 | /* MAX number of EDCR registers */ |
| @@ -113,6 +147,16 @@ · 24 unmodified lines | |||
| 113 | } \ | 147 | } \ |
| 114 | })[0].attr.attr) | 148 | })[0].attr.attr) |
| 115 | 149 | ||
| 150 | #define tpdm_patt_enable_ts(name, mem) \ | ||
| 151 | (&((struct tpdm_dataset_attribute[]) { \ | ||
| 152 | { \ | ||
| 153 | __ATTR(name, 0644, enable_ts_show, \ | ||
| 154 | enable_ts_store), \ | ||
| 155 | mem, \ | ||
| 156 | 0, \ | ||
| 157 | } \ | ||
| 158 | })[0].attr.attr) | ||
| 159 | |||
| 116 | #define DSB_EDGE_CTRL_ATTR(nr) \ | 160 | #define DSB_EDGE_CTRL_ATTR(nr) \ |
| 117 | tpdm_simple_dataset_ro(edcr##nr, \ | 161 | tpdm_simple_dataset_ro(edcr##nr, \ |
| 118 | DSB_EDGE_CTRL, nr) | 162 | DSB_EDGE_CTRL, nr) |
| @@ -137,10 +181,38 @@ · 18 unmodified lines | |||
| 137 | tpdm_simple_dataset_rw(tpmr##nr, \ | 181 | tpdm_simple_dataset_rw(tpmr##nr, \ |
| 138 | DSB_PATT_MASK, nr) | 182 | DSB_PATT_MASK, nr) |
| 139 | 183 | ||
| 184 | #define DSB_PATT_ENABLE_TS \ | ||
| 185 | tpdm_patt_enable_ts(enable_ts, \ | ||
| 186 | DSB_PATT) | ||
| 187 | |||
| 140 | #define DSB_MSR_ATTR(nr) \ | 188 | #define DSB_MSR_ATTR(nr) \ |
| 141 | tpdm_simple_dataset_rw(msr##nr, \ | 189 | tpdm_simple_dataset_rw(msr##nr, \ |
| 142 | DSB_MSR, nr) | 190 | DSB_MSR, nr) |
| 143 | 191 | ||
| 192 | #define CMB_TRIG_PATT_ATTR(nr) \ | ||
| 193 | tpdm_simple_dataset_rw(xpr##nr, \ | ||
| 194 | CMB_TRIG_PATT, nr) | ||
| 195 | |||
| 196 | #define CMB_TRIG_PATT_MASK_ATTR(nr) \ | ||
| 197 | tpdm_simple_dataset_rw(xpmr##nr, \ | ||
| 198 | CMB_TRIG_PATT_MASK, nr) | ||
| 199 | |||
| 200 | #define CMB_PATT_ATTR(nr) \ | ||
| 201 | tpdm_simple_dataset_rw(tpr##nr, \ | ||
| 202 | CMB_PATT, nr) | ||
| 203 | |||
| 204 | #define CMB_PATT_MASK_ATTR(nr) \ | ||
| 205 | tpdm_simple_dataset_rw(tpmr##nr, \ | ||
| 206 | CMB_PATT_MASK, nr) | ||
| 207 | |||
| 208 | #define CMB_PATT_ENABLE_TS \ | ||
| 209 | tpdm_patt_enable_ts(enable_ts, \ | ||
| 210 | CMB_PATT) | ||
| 211 | |||
| 212 | #define CMB_MSR_ATTR(nr) \ | ||
| 213 | tpdm_simple_dataset_rw(msr##nr, \ | ||
| 214 | CMB_MSR, nr) | ||
| 215 | |||
| 144 | /** | 216 | /** |
| 145 | * struct dsb_dataset - specifics associated to dsb dataset | 217 | * struct dsb_dataset - specifics associated to dsb dataset |
| 146 | * @mode: DSB programming mode | 218 | * @mode: DSB programming mode |
| @@ -173,6 +245,30 @@ struct dsb_dataset { · 26 unmodified lines | |||
| 173 | bool trig_type; | 245 | bool trig_type; |
| 174 | }; | 246 | }; |
| 175 | 247 | ||
| 248 | /** | ||
| 249 | * struct cmb_dataset | ||
| 250 | * @trace_mode: Dataset collection mode | ||
| 251 | * @patt_val: Save value for pattern | ||
| 252 | * @patt_mask: Save value for pattern mask | ||
| 253 | * @trig_patt: Save value for trigger pattern | ||
| 254 | * @trig_patt_mask: Save value for trigger pattern mask | ||
| 255 | * @msr Save value for MSR | ||
| 256 | * @patt_ts: Indicates if pattern match for timestamp is enabled. | ||
| 257 | * @trig_ts: Indicates if CTI trigger for timestamp is enabled. | ||
| 258 | * @ts_all: Indicates if timestamp is enabled for all packets. | ||
| 259 | */ | ||
| 260 | struct cmb_dataset { | ||
| 261 | u32 trace_mode; | ||
| 262 | u32 patt_val[TPDM_CMB_MAX_PATT]; | ||
| 263 | u32 patt_mask[TPDM_CMB_MAX_PATT]; | ||
| 264 | u32 trig_patt[TPDM_CMB_MAX_PATT]; | ||
| 265 | u32 trig_patt_mask[TPDM_CMB_MAX_PATT]; | ||
| 266 | u32 msr[TPDM_CMB_MAX_MSR]; | ||
| 267 | bool patt_ts; | ||
| 268 | bool trig_ts; | ||
| 269 | bool ts_all; | ||
| 270 | }; | ||
| 271 | |||
| 176 | /** | 272 | /** |
| 177 | * struct tpdm_drvdata - specifics associated to an TPDM component | 273 | * struct tpdm_drvdata - specifics associated to an TPDM component |
| 178 | * @base: memory mapped base address for this component. | 274 | * @base: memory mapped base address for this component. |
| @@ -182,7 +278,9 @@ struct dsb_dataset { · 3 unmodified lines | |||
| 182 | * @enable: enable status of the component. | 278 | * @enable: enable status of the component. |
| 183 | * @datasets: The datasets types present of the TPDM. | 279 | * @datasets: The datasets types present of the TPDM. |
| 184 | * @dsb Specifics associated to TPDM DSB. | 280 | * @dsb Specifics associated to TPDM DSB. |
| 281 | * @cmb Specifics associated to TPDM CMB. | ||
| 185 | * @dsb_msr_num Number of MSR supported by DSB TPDM | 282 | * @dsb_msr_num Number of MSR supported by DSB TPDM |
| 283 | * @cmb_msr_num Number of MSR supported by CMB TPDM | ||
| 186 | */ | 284 | */ |
| 187 | 285 | ||
| 188 | struct tpdm_drvdata { | 286 | struct tpdm_drvdata { |
| @@ -193,7 +291,9 @@ struct tpdm_drvdata { · 4 unmodified lines | |||
| 193 | bool enable; | 291 | bool enable; |
| 194 | unsigned long datasets; | 292 | unsigned long datasets; |
| 195 | struct dsb_dataset *dsb; | 293 | struct dsb_dataset *dsb; |
| 294 | struct cmb_dataset *cmb; | ||
| 196 | u32 dsb_msr_num; | 295 | u32 dsb_msr_num; |
| 296 | u32 cmb_msr_num; | ||
| 197 | }; | 297 | }; |
| 198 | 298 | ||
| 199 | /* Enumerate members of various datasets */ | 299 | /* Enumerate members of various datasets */ |
| @@ -205,6 +305,11 @@ enum dataset_mem { · 5 unmodified lines | |||
| 205 | DSB_PATT, | 305 | DSB_PATT, |
| 206 | DSB_PATT_MASK, | 306 | DSB_PATT_MASK, |
| 207 | DSB_MSR, | 307 | DSB_MSR, |
| 308 | CMB_TRIG_PATT, | ||
| 309 | CMB_TRIG_PATT_MASK, | ||
| 310 | CMB_PATT, | ||
| 311 | CMB_PATT_MASK, | ||
| 312 | CMB_MSR | ||
| 208 | }; | 313 | }; |
| 209 | 314 | ||
| 210 | /** | 315 | /** |
| @@ -220,4 +325,13 @@ struct tpdm_dataset_attribute { · 9 unmodified lines | |||
| 220 | u32 idx; | 325 | u32 idx; |
| 221 | }; | 326 | }; |
| 222 | 327 | ||
| 328 | static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) | ||
| 329 | { | ||
| 330 | return (drvdata->datasets & TPDM_PIDR0_DS_DSB); | ||
| 331 | } | ||
| 332 | |||
| 333 | static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata) | ||
| 334 | { | ||
| 335 | return (drvdata->datasets & TPDM_PIDR0_DS_CMB); | ||
| 336 | } | ||
| 223 | #endif /* _CORESIGHT_CORESIGHT_TPDM_H */ | 337 | #endif /* _CORESIGHT_CORESIGHT_TPDM_H */ |
| @@ -58,6 +58,7 @@ struct tpiu_drvdata { · 57 unmodified lines | |||
| 58 | void __iomem *base; | 58 | void __iomem *base; |
| 59 | struct clk *atclk; | 59 | struct clk *atclk; |
| 60 | struct coresight_device *csdev; | 60 | struct coresight_device *csdev; |
| 61 | spinlock_t spinlock; | ||
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| 63 | static void tpiu_enable_hw(struct csdev_access *csa) | 64 | static void tpiu_enable_hw(struct csdev_access *csa) |
| @@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa) · 8 unmodified lines | |||
| 72 | static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, | 73 | static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, |
| 73 | void *__unused) | 74 | void *__unused) |
| 74 | { | 75 | { |
| 76 | struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
| 77 | |||
| 78 | guard(spinlock)(&drvdata->spinlock); | ||
| 75 | tpiu_enable_hw(&csdev->access); | 79 | tpiu_enable_hw(&csdev->access); |
| 76 | atomic_inc(&csdev->refcnt); | 80 | csdev->refcnt++; |
| 77 | dev_dbg(&csdev->dev, "TPIU enabled\n"); | 81 | dev_dbg(&csdev->dev, "TPIU enabled\n"); |
| 78 | return 0; | 82 | return 0; |
| 79 | } | 83 | } |
| @@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa) · 16 unmodified lines | |||
| 96 | 100 | ||
| 97 | static int tpiu_disable(struct coresight_device *csdev) | 101 | static int tpiu_disable(struct coresight_device *csdev) |
| 98 | { | 102 | { |
| 99 | if (atomic_dec_return(&csdev->refcnt)) | 103 | struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 104 | |||
| 105 | guard(spinlock)(&drvdata->spinlock); | ||
| 106 | csdev->refcnt--; | ||
| 107 | if (csdev->refcnt) | ||
| 100 | return -EBUSY; | 108 | return -EBUSY; |
| 101 | 109 | ||
| 102 | tpiu_disable_hw(&csdev->access); | 110 | tpiu_disable_hw(&csdev->access); |
| @@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) · 29 unmodified lines | |||
| 132 | if (!drvdata) | 140 | if (!drvdata) |
| 133 | return -ENOMEM; | 141 | return -ENOMEM; |
| 134 | 142 | ||
| 143 | spin_lock_init(&drvdata->spinlock); | ||
| 144 | |||
| 135 | drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ | 145 | drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ |
| 136 | if (!IS_ERR(drvdata->atclk)) { | 146 | if (!IS_ERR(drvdata->atclk)) { |
| 137 | ret = clk_prepare_enable(drvdata->atclk); | 147 | ret = clk_prepare_enable(drvdata->atclk); |
| @@ -218,7 +228,7 @@ static const struct amba_id tpiu_ids[] = { · 80 unmodified lines | |||
| 218 | .id = 0x000bb9e7, | 228 | .id = 0x000bb9e7, |
| 219 | .mask = 0x000fffff, | 229 | .mask = 0x000fffff, |
| 220 | }, | 230 | }, |
| 221 | { 0, 0}, | 231 | { 0, 0, NULL }, |
| 222 | }; | 232 | }; |
| 223 | 233 | ||
| 224 | MODULE_DEVICE_TABLE(amba, tpiu_ids); | 234 | MODULE_DEVICE_TABLE(amba, tpiu_ids); |
| @@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file) · 102 unmodified lines | |||
| 103 | if (drvdata->reading) | 103 | if (drvdata->reading) |
| 104 | return -EBUSY; | 104 | return -EBUSY; |
| 105 | 105 | ||
| 106 | if (atomic_read(&drvdata->csdev->refcnt)) | 106 | if (drvdata->csdev->refcnt) |
| 107 | return -EBUSY; | 107 | return -EBUSY; |
| 108 | 108 | ||
| 109 | smb_update_data_size(drvdata); | 109 | smb_update_data_size(drvdata); |
| @@ -207,11 +207,11 @@ static void smb_enable_sysfs(struct coresight_device *csdev) · 97 unmodified lines | |||
| 207 | { | 207 | { |
| 208 | struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent); | 208 | struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 209 | 209 | ||
| 210 | if (drvdata->mode != CS_MODE_DISABLED) | 210 | if (coresight_get_mode(csdev) != CS_MODE_DISABLED) |
| 211 | return; | 211 | return; |
| 212 | 212 | ||
| 213 | smb_enable_hw(drvdata); | 213 | smb_enable_hw(drvdata); |
| 214 | drvdata->mode = CS_MODE_SYSFS; | 214 | coresight_set_mode(csdev, CS_MODE_SYSFS); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | static int smb_enable_perf(struct coresight_device *csdev, void *data) | 217 | static int smb_enable_perf(struct coresight_device *csdev, void *data) |
| @@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data) · 16 unmodified lines | |||
| 234 | if (drvdata->pid == -1) { | 234 | if (drvdata->pid == -1) { |
| 235 | smb_enable_hw(drvdata); | 235 | smb_enable_hw(drvdata); |
| 236 | drvdata->pid = pid; | 236 | drvdata->pid = pid; |
| 237 | drvdata->mode = CS_MODE_PERF; | 237 | coresight_set_mode(csdev, CS_MODE_PERF); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | return 0; | 240 | return 0; |
| @@ -253,7 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, · 12 unmodified lines | |||
| 253 | return -EBUSY; | 253 | return -EBUSY; |
| 254 | 254 | ||
| 255 | /* Do nothing, the SMB is already enabled as other mode */ | 255 | /* Do nothing, the SMB is already enabled as other mode */ |
| 256 | if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode) | 256 | if (coresight_get_mode(csdev) != CS_MODE_DISABLED && |
| 257 | coresight_get_mode(csdev) != mode) | ||
| 257 | return -EBUSY; | 258 | return -EBUSY; |
| 258 | 259 | ||
| 259 | switch (mode) { | 260 | switch (mode) { |
| @@ -270,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, · 10 unmodified lines | |||
| 270 | if (ret) | 271 | if (ret) |
| 271 | return ret; | 272 | return ret; |
| 272 | 273 | ||
| 273 | atomic_inc(&csdev->refcnt); | 274 | csdev->refcnt++; |
| 274 | dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n"); | 275 | dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n"); |
| 275 | 276 | ||
| 276 | return ret; | 277 | return ret; |
| @@ -285,17 +286,18 @@ static int smb_disable(struct coresight_device *csdev) · 8 unmodified lines | |||
| 285 | if (drvdata->reading) | 286 | if (drvdata->reading) |
| 286 | return -EBUSY; | 287 | return -EBUSY; |
| 287 | 288 | ||
| 288 | if (atomic_dec_return(&csdev->refcnt)) | 289 | csdev->refcnt--; |
| 290 | if (csdev->refcnt) | ||
| 289 | return -EBUSY; | 291 | return -EBUSY; |
| 290 | 292 | ||
| 291 | /* Complain if we (somehow) got out of sync */ | 293 | /* Complain if we (somehow) got out of sync */ |
| 292 | WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 294 | WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); |
| 293 | 295 | ||
| 294 | smb_disable_hw(drvdata); | 296 | smb_disable_hw(drvdata); |
| 295 | 297 | ||
| 296 | /* Dissociate from the target process. */ | 298 | /* Dissociate from the target process. */ |
| 297 | drvdata->pid = -1; | 299 | drvdata->pid = -1; |
| 298 | drvdata->mode = CS_MODE_DISABLED; | 300 | coresight_set_mode(csdev, CS_MODE_DISABLED); |
| 299 | dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n"); | 301 | dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n"); |
| 300 | 302 | ||
| 301 | return 0; | 303 | return 0; |
| @@ -380,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev, · 78 unmodified lines | |||
| 380 | guard(spinlock)(&drvdata->spinlock); | 382 | guard(spinlock)(&drvdata->spinlock); |
| 381 | 383 | ||
| 382 | /* Don't do anything if another tracer is using this sink. */ | 384 | /* Don't do anything if another tracer is using this sink. */ |
| 383 | if (atomic_read(&csdev->refcnt) != 1) | 385 | if (csdev->refcnt != 1) |
| 384 | return 0; | 386 | return 0; |
| 385 | 387 | ||
| 386 | smb_disable_hw(drvdata); | 388 | smb_disable_hw(drvdata); |
| @@ -586,7 +588,7 @@ static void smb_remove(struct platform_device *pdev) · 199 unmodified lines | |||
| 586 | 588 | ||
| 587 | #ifdef CONFIG_ACPI | 589 | #ifdef CONFIG_ACPI |
| 588 | static const struct acpi_device_id ultrasoc_smb_acpi_match[] = { | 590 | static const struct acpi_device_id ultrasoc_smb_acpi_match[] = { |
| 589 | {"HISI03A1", 0}, | 591 | {"HISI03A1", 0, 0, 0}, |
| 590 | {} | 592 | {} |
| 591 | }; | 593 | }; |
| 592 | MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match); | 594 | MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match); |
| @@ -109,7 +109,6 @@ struct smb_data_buffer { · 108 unmodified lines | |||
| 109 | * @reading: Synchronise user space access to SMB buffer. | 109 | * @reading: Synchronise user space access to SMB buffer. |
| 110 | * @pid: Process ID of the process being monitored by the | 110 | * @pid: Process ID of the process being monitored by the |
| 111 | * session that is using this component. | 111 | * session that is using this component. |
| 112 | * @mode: How this SMB is being used, perf mode or sysfs mode. | ||
| 113 | */ | 112 | */ |
| 114 | struct smb_drv_data { | 113 | struct smb_drv_data { |
| 115 | void __iomem *base; | 114 | void __iomem *base; |
| @@ -119,7 +118,6 @@ struct smb_drv_data { · 3 unmodified lines | |||
| 119 | spinlock_t spinlock; | 118 | spinlock_t spinlock; |
| 120 | bool reading; | 119 | bool reading; |
| 121 | pid_t pid; | 120 | pid_t pid; |
| 122 | enum cs_mode mode; | ||
| 123 | }; | 121 | }; |
| 124 | 122 | ||
| 125 | #endif | 123 | #endif |
| @@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) · 997 unmodified lines | |||
| 998 | int ret; | 998 | int ret; |
| 999 | u32 val; | 999 | u32 val; |
| 1000 | 1000 | ||
| 1001 | if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) | ||
| 1002 | return -ENOENT; | ||
| 1003 | |||
| 1001 | if (event->cpu < 0) { | 1004 | if (event->cpu < 0) { |
| 1002 | dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); | 1005 | dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); |
| 1003 | return -EOPNOTSUPP; | 1006 | return -EOPNOTSUPP; |
| @@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) · 2 unmodified lines | |||
| 1006 | if (event->attach_state & PERF_ATTACH_TASK) | 1009 | if (event->attach_state & PERF_ATTACH_TASK) |
| 1007 | return -EOPNOTSUPP; | 1010 | return -EOPNOTSUPP; |
| 1008 | 1011 | ||
| 1009 | if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) | ||
| 1010 | return -ENOENT; | ||
| 1011 | |||
| 1012 | ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config); | 1012 | ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config); |
| 1013 | if (ret < 0) | 1013 | if (ret < 0) |
| 1014 | return ret; | 1014 | return ret; |
| @@ -71,6 +71,15 @@ config IIO_TRIGGERED_EVENT · 70 unmodified lines | |||
| 71 | help | 71 | help |
| 72 | Provides helper functions for setting up triggered events. | 72 | Provides helper functions for setting up triggered events. |
| 73 | 73 | ||
| 74 | config IIO_BACKEND | ||
| 75 | tristate | ||
| 76 | help | ||
| 77 | Framework to handle complex IIO aggregate devices. The typical | ||
| 78 | architecture that can make use of this framework is to have one | ||
| 79 | device as the frontend device which can be "linked" against one or | ||
| 80 | multiple backend devices. The framework then makes it easy to get | ||
| 81 | and control such backend devices. | ||
| 82 | |||
| 74 | source "drivers/iio/accel/Kconfig" | 83 | source "drivers/iio/accel/Kconfig" |
| 75 | source "drivers/iio/adc/Kconfig" | 84 | source "drivers/iio/adc/Kconfig" |
| 76 | source "drivers/iio/addac/Kconfig" | 85 | source "drivers/iio/addac/Kconfig" |
| @@ -13,6 +13,7 @@ obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o · 12 unmodified lines | |||
| 13 | obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o | 13 | obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o |
| 14 | obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o | 14 | obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o |
| 15 | obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o | 15 | obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o |
| 16 | obj-$(CONFIG_IIO_BACKEND) += industrialio-backend.o | ||
| 16 | 17 | ||
| 17 | obj-y += accel/ | 18 | obj-y += accel/ |
| 18 | obj-y += adc/ | 19 | obj-y += adc/ |
| @@ -256,11 +256,11 @@ config BMC150_ACCEL_SPI · 255 unmodified lines | |||
| 256 | 256 | ||
| 257 | config BMI088_ACCEL | 257 | config BMI088_ACCEL |
| 258 | tristate "Bosch BMI088 Accelerometer Driver" | 258 | tristate "Bosch BMI088 Accelerometer Driver" |
| 259 | depends on SPI | ||
| 260 | select IIO_BUFFER | 259 | select IIO_BUFFER |
| 261 | select IIO_TRIGGERED_BUFFER | 260 | select IIO_TRIGGERED_BUFFER |
| 262 | select REGMAP | 261 | select REGMAP |
| 263 | select BMI088_ACCEL_SPI | 262 | select BMI088_ACCEL_SPI if SPI |
| 263 | select BMI088_ACCEL_I2C if I2C | ||
| 264 | help | 264 | help |
| 265 | Say yes here to build support for the following Bosch accelerometers: | 265 | Say yes here to build support for the following Bosch accelerometers: |
| 266 | BMI088, BMI085, BMI090L. Note that all of these are combo module that | 266 | BMI088, BMI085, BMI090L. Note that all of these are combo module that |
| @@ -269,6 +269,10 @@ config BMI088_ACCEL · 2 unmodified lines | |||
| 269 | This driver only implements the accelerometer part, which has its own | 269 | This driver only implements the accelerometer part, which has its own |
| 270 | address and register map. BMG160 provides the gyroscope driver. | 270 | address and register map. BMG160 provides the gyroscope driver. |
| 271 | 271 | ||
| 272 | config BMI088_ACCEL_I2C | ||
| 273 | tristate | ||
| 274 | select REGMAP_I2C | ||
| 275 | |||
| 272 | config BMI088_ACCEL_SPI | 276 | config BMI088_ACCEL_SPI |
| 273 | tristate | 277 | tristate |
| 274 | select REGMAP_SPI | 278 | select REGMAP_SPI |
| @@ -30,6 +30,7 @@ obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o · 29 unmodified lines | |||
| 30 | obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o | 30 | obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o |
| 31 | obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o | 31 | obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o |
| 32 | obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o | 32 | obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o |
| 33 | obj-$(CONFIG_BMI088_ACCEL_I2C) += bmi088-accel-i2c.o | ||
| 33 | obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o | 34 | obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o |
| 34 | obj-$(CONFIG_DA280) += da280.o | 35 | obj-$(CONFIG_DA280) += da280.o |
| 35 | obj-$(CONFIG_DA311) += da311.o | 36 | obj-$(CONFIG_DA311) += da311.o |
| @@ -339,22 +339,17 @@ static int adxl367_set_act_threshold(struct adxl367_state *st, · 338 unmodified lines | |||
| 339 | { | 339 | { |
| 340 | int ret; | 340 | int ret; |
| 341 | 341 | ||
| 342 | mutex_lock(&st->lock); | 342 | guard(mutex)(&st->lock); |
| 343 | 343 | ||
| 344 | ret = adxl367_set_measure_en(st, false); | 344 | ret = adxl367_set_measure_en(st, false); |
| 345 | if (ret) | 345 | if (ret) |
| 346 | goto out; | 346 | return ret; |
| 347 | 347 | ||
| 348 | ret = _adxl367_set_act_threshold(st, act, threshold); | 348 | ret = _adxl367_set_act_threshold(st, act, threshold); |
| 349 | if (ret) | 349 | if (ret) |
| 350 | goto out; | 350 | return ret; |
| 351 | |||
| 352 | ret = adxl367_set_measure_en(st, true); | ||
| 353 | |||
| 354 | out: | ||
| 355 | mutex_unlock(&st->lock); | ||
| 356 | 351 | ||
| 357 | return ret; | 352 | return adxl367_set_measure_en(st, true); |
| 358 | } | 353 | } |
| 359 | 354 | ||
| 360 | static int adxl367_set_act_proc_mode(struct adxl367_state *st, | 355 | static int adxl367_set_act_proc_mode(struct adxl367_state *st, |
| @@ -482,51 +477,45 @@ static int adxl367_set_fifo_watermark(struct adxl367_state *st, · 121 unmodified lines | |||
| 482 | static int adxl367_set_range(struct iio_dev *indio_dev, | 477 | static int adxl367_set_range(struct iio_dev *indio_dev, |
| 483 | enum adxl367_range range) | 478 | enum adxl367_range range) |
| 484 | { | 479 | { |
| 485 | struct adxl367_state *st = iio_priv(indio_dev); | 480 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 486 | int ret; | 481 | struct adxl367_state *st = iio_priv(indio_dev); |
| 482 | int ret; | ||
| 487 | 483 | ||
| 488 | ret = iio_device_claim_direct_mode(indio_dev); | 484 | guard(mutex)(&st->lock); |
| 489 | if (ret) | ||
| 490 | return ret; | ||
| 491 | |||
| 492 | mutex_lock(&st->lock); | ||
| 493 | |||
| 494 | ret = adxl367_set_measure_en(st, false); | ||
| 495 | if (ret) | ||
| 496 | goto out; | ||
| 497 | 485 | ||
| 498 | ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, | 486 | ret = adxl367_set_measure_en(st, false); |
| 499 | ADXL367_FILTER_CTL_RANGE_MASK, | 487 | if (ret) |
| 500 | FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, | 488 | return ret; |
| 501 | range)); | ||
| 502 | if (ret) | ||
| 503 | goto out; | ||
| 504 | 489 | ||
| 505 | adxl367_scale_act_thresholds(st, st->range, range); | 490 | ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL, |
| 491 | ADXL367_FILTER_CTL_RANGE_MASK, | ||
| 492 | FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK, | ||
| 493 | range)); | ||
| 494 | if (ret) | ||
| 495 | return ret; | ||
| 506 | 496 | ||
| 507 | /* Activity thresholds depend on range */ | 497 | adxl367_scale_act_thresholds(st, st->range, range); |
| 508 | ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, | ||
| 509 | st->act_threshold); | ||
| 510 | if (ret) | ||
| 511 | goto out; | ||
| 512 | 498 | ||
| 513 | ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, | 499 | /* Activity thresholds depend on range */ |
| 514 | st->inact_threshold); | 500 | ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY, |
| 515 | if (ret) | 501 | st->act_threshold); |
| 516 | goto out; | 502 | if (ret) |
| 517 | 503 | return ret; | |
| 518 | ret = adxl367_set_measure_en(st, true); | ||
| 519 | if (ret) | ||
| 520 | goto out; | ||
| 521 | 504 | ||
| 522 | st->range = range; | 505 | ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY, |
| 506 | st->inact_threshold); | ||
| 507 | if (ret) | ||
| 508 | return ret; | ||
| 523 | 509 | ||
| 524 | out: | 510 | ret = adxl367_set_measure_en(st, true); |
| 525 | mutex_unlock(&st->lock); | 511 | if (ret) |
| 512 | return ret; | ||
| 526 | 513 | ||
| 527 | iio_device_release_direct_mode(indio_dev); | 514 | st->range = range; |
| 528 | 515 | ||
| 529 | return ret; | 516 | return 0; |
| 517 | } | ||
| 518 | unreachable(); | ||
| 530 | } | 519 | } |
| 531 | 520 | ||
| 532 | static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) | 521 | static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms) |
| @@ -587,11 +576,11 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st, · 54 unmodified lines | |||
| 587 | { | 576 | { |
| 588 | int ret; | 577 | int ret; |
| 589 | 578 | ||
| 590 | mutex_lock(&st->lock); | 579 | guard(mutex)(&st->lock); |
| 591 | 580 | ||
| 592 | ret = adxl367_set_measure_en(st, false); | 581 | ret = adxl367_set_measure_en(st, false); |
| 593 | if (ret) | 582 | if (ret) |
| 594 | goto out; | 583 | return ret; |
| 595 | 584 | ||
| 596 | if (act == ADXL367_ACTIVITY) | 585 | if (act == ADXL367_ACTIVITY) |
| 597 | ret = _adxl367_set_act_time_ms(st, ms); | 586 | ret = _adxl367_set_act_time_ms(st, ms); |
| @@ -599,14 +588,9 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st, · 1 unmodified line | |||
| 599 | ret = _adxl367_set_inact_time_ms(st, ms); | 588 | ret = _adxl367_set_inact_time_ms(st, ms); |
| 600 | 589 | ||
| 601 | if (ret) | 590 | if (ret) |
| 602 | goto out; | 591 | return ret; |
| 603 | |||
| 604 | ret = adxl367_set_measure_en(st, true); | ||
| 605 | |||
| 606 | out: | ||
| 607 | mutex_unlock(&st->lock); | ||
| 608 | 592 | ||
| 609 | return ret; | 593 | return adxl367_set_measure_en(st, true); |
| 610 | } | 594 | } |
| 611 | 595 | ||
| 612 | static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) | 596 | static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) |
| @@ -636,31 +620,23 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) · 23 unmodified lines | |||
| 636 | 620 | ||
| 637 | static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) | 621 | static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) |
| 638 | { | 622 | { |
| 639 | struct adxl367_state *st = iio_priv(indio_dev); | 623 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 640 | int ret; | 624 | struct adxl367_state *st = iio_priv(indio_dev);; |
| 625 | int ret; | ||
| 641 | 626 | ||
| 642 | ret = iio_device_claim_direct_mode(indio_dev); | 627 | guard(mutex)(&st->lock); |
| 643 | if (ret) | ||
| 644 | return ret; | ||
| 645 | 628 | ||
| 646 | mutex_lock(&st->lock); | 629 | ret = adxl367_set_measure_en(st, false); |
| 647 | 630 | if (ret) | |
| 648 | ret = adxl367_set_measure_en(st, false); | 631 | return ret; |
| 649 | if (ret) | ||
| 650 | goto out; | ||
| 651 | |||
| 652 | ret = _adxl367_set_odr(st, odr); | ||
| 653 | if (ret) | ||
| 654 | goto out; | ||
| 655 | |||
| 656 | ret = adxl367_set_measure_en(st, true); | ||
| 657 | |||
| 658 | out: | ||
| 659 | mutex_unlock(&st->lock); | ||
| 660 | 632 | ||
| 661 | iio_device_release_direct_mode(indio_dev); | 633 | ret = _adxl367_set_odr(st, odr); |
| 634 | if (ret) | ||
| 635 | return ret; | ||
| 662 | 636 | ||
| 663 | return ret; | 637 | return adxl367_set_measure_en(st, true); |
| 638 | } | ||
| 639 | unreachable(); | ||
| 664 | } | 640 | } |
| 665 | 641 | ||
| 666 | static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, | 642 | static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg, |
| @@ -749,36 +725,32 @@ static int adxl367_read_sample(struct iio_dev *indio_dev, · 82 unmodified lines | |||
| 749 | struct iio_chan_spec const *chan, | 725 | struct iio_chan_spec const *chan, |
| 750 | int *val) | 726 | int *val) |
| 751 | { | 727 | { |
| 752 | struct adxl367_state *st = iio_priv(indio_dev); | 728 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 753 | u16 sample; | 729 | struct adxl367_state *st = iio_priv(indio_dev); |
| 754 | int ret; | 730 | u16 sample; |
| 731 | int ret; | ||
| 755 | 732 | ||
| 756 | ret = iio_device_claim_direct_mode(indio_dev); | 733 | guard(mutex)(&st->lock); |
| 757 | if (ret) | ||
| 758 | return ret; | ||
| 759 | 734 | ||
| 760 | mutex_lock(&st->lock); | 735 | ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); |
| 761 | 736 | if (ret) | |
| 762 | ret = adxl367_set_temp_adc_reg_en(st, chan->address, true); | 737 | return ret; |
| 763 | if (ret) | ||
| 764 | goto out; | ||
| 765 | |||
| 766 | ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, | ||
| 767 | sizeof(st->sample_buf)); | ||
| 768 | if (ret) | ||
| 769 | goto out; | ||
| 770 | |||
| 771 | sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); | ||
| 772 | *val = sign_extend32(sample, chan->scan_type.realbits - 1); | ||
| 773 | 738 | ||
| 774 | ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); | 739 | ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf, |
| 740 | sizeof(st->sample_buf)); | ||
| 741 | if (ret) | ||
| 742 | return ret; | ||
| 775 | 743 | ||
| 776 | out: | 744 | sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf)); |
| 777 | mutex_unlock(&st->lock); | 745 | *val = sign_extend32(sample, chan->scan_type.realbits - 1); |
| 778 | 746 | ||
| 779 | iio_device_release_direct_mode(indio_dev); | 747 | ret = adxl367_set_temp_adc_reg_en(st, chan->address, false); |
| 748 | if (ret) | ||
| 749 | return ret; | ||
| 780 | 750 | ||
| 781 | return ret ?: IIO_VAL_INT; | 751 | return IIO_VAL_INT; |
| 752 | } | ||
| 753 | unreachable(); | ||
| 782 | } | 754 | } |
| 783 | 755 | ||
| 784 | static int adxl367_get_status(struct adxl367_state *st, u8 *status, | 756 | static int adxl367_get_status(struct adxl367_state *st, u8 *status, |
| @@ -886,12 +858,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev, · 101 unmodified lines | |||
| 886 | return adxl367_read_sample(indio_dev, chan, val); | 858 | return adxl367_read_sample(indio_dev, chan, val); |
| 887 | case IIO_CHAN_INFO_SCALE: | 859 | case IIO_CHAN_INFO_SCALE: |
| 888 | switch (chan->type) { | 860 | switch (chan->type) { |
| 889 | case IIO_ACCEL: | 861 | case IIO_ACCEL: { |
| 890 | mutex_lock(&st->lock); | 862 | guard(mutex)(&st->lock); |
| 891 | *val = adxl367_range_scale_tbl[st->range][0]; | 863 | *val = adxl367_range_scale_tbl[st->range][0]; |
| 892 | *val2 = adxl367_range_scale_tbl[st->range][1]; | 864 | *val2 = adxl367_range_scale_tbl[st->range][1]; |
| 893 | mutex_unlock(&st->lock); | ||
| 894 | return IIO_VAL_INT_PLUS_NANO; | 865 | return IIO_VAL_INT_PLUS_NANO; |
| 866 | } | ||
| 895 | case IIO_TEMP: | 867 | case IIO_TEMP: |
| 896 | *val = 1000; | 868 | *val = 1000; |
| 897 | *val2 = ADXL367_TEMP_PER_C; | 869 | *val2 = ADXL367_TEMP_PER_C; |
| @@ -914,12 +886,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev, · 16 unmodified lines | |||
| 914 | default: | 886 | default: |
| 915 | return -EINVAL; | 887 | return -EINVAL; |
| 916 | } | 888 | } |
| 917 | case IIO_CHAN_INFO_SAMP_FREQ: | 889 | case IIO_CHAN_INFO_SAMP_FREQ: { |
| 918 | mutex_lock(&st->lock); | 890 | guard(mutex)(&st->lock); |
| 919 | *val = adxl367_samp_freq_tbl[st->odr][0]; | 891 | *val = adxl367_samp_freq_tbl[st->odr][0]; |
| 920 | *val2 = adxl367_samp_freq_tbl[st->odr][1]; | 892 | *val2 = adxl367_samp_freq_tbl[st->odr][1]; |
| 921 | mutex_unlock(&st->lock); | ||
| 922 | return IIO_VAL_INT_PLUS_MICRO; | 893 | return IIO_VAL_INT_PLUS_MICRO; |
| 894 | } | ||
| 923 | default: | 895 | default: |
| 924 | return -EINVAL; | 896 | return -EINVAL; |
| 925 | } | 897 | } |
| @@ -1004,18 +976,15 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev, · 78 unmodified lines | |||
| 1004 | { | 976 | { |
| 1005 | struct adxl367_state *st = iio_priv(indio_dev); | 977 | struct adxl367_state *st = iio_priv(indio_dev); |
| 1006 | 978 | ||
| 979 | guard(mutex)(&st->lock); | ||
| 1007 | switch (info) { | 980 | switch (info) { |
| 1008 | case IIO_EV_INFO_VALUE: { | 981 | case IIO_EV_INFO_VALUE: { |
| 1009 | switch (dir) { | 982 | switch (dir) { |
| 1010 | case IIO_EV_DIR_RISING: | 983 | case IIO_EV_DIR_RISING: |
| 1011 | mutex_lock(&st->lock); | ||
| 1012 | *val = st->act_threshold; | 984 | *val = st->act_threshold; |
| 1013 | mutex_unlock(&st->lock); | ||
| 1014 | return IIO_VAL_INT; | 985 | return IIO_VAL_INT; |
| 1015 | case IIO_EV_DIR_FALLING: | 986 | case IIO_EV_DIR_FALLING: |
| 1016 | mutex_lock(&st->lock); | ||
| 1017 | *val = st->inact_threshold; | 987 | *val = st->inact_threshold; |
| 1018 | mutex_unlock(&st->lock); | ||
| 1019 | return IIO_VAL_INT; | 988 | return IIO_VAL_INT; |
| 1020 | default: | 989 | default: |
| 1021 | return -EINVAL; | 990 | return -EINVAL; |
| @@ -1024,15 +993,11 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 1024 | case IIO_EV_INFO_PERIOD: | 993 | case IIO_EV_INFO_PERIOD: |
| 1025 | switch (dir) { | 994 | switch (dir) { |
| 1026 | case IIO_EV_DIR_RISING: | 995 | case IIO_EV_DIR_RISING: |
| 1027 | mutex_lock(&st->lock); | ||
| 1028 | *val = st->act_time_ms; | 996 | *val = st->act_time_ms; |
| 1029 | mutex_unlock(&st->lock); | ||
| 1030 | *val2 = 1000; | 997 | *val2 = 1000; |
| 1031 | return IIO_VAL_FRACTIONAL; | 998 | return IIO_VAL_FRACTIONAL; |
| 1032 | case IIO_EV_DIR_FALLING: | 999 | case IIO_EV_DIR_FALLING: |
| 1033 | mutex_lock(&st->lock); | ||
| 1034 | *val = st->inact_time_ms; | 1000 | *val = st->inact_time_ms; |
| 1035 | mutex_unlock(&st->lock); | ||
| 1036 | *val2 = 1000; | 1001 | *val2 = 1000; |
| 1037 | return IIO_VAL_FRACTIONAL; | 1002 | return IIO_VAL_FRACTIONAL; |
| 1038 | default: | 1003 | default: |
| @@ -1110,9 +1075,7 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev, · 71 unmodified lines | |||
| 1110 | enum iio_event_direction dir, | 1075 | enum iio_event_direction dir, |
| 1111 | int state) | 1076 | int state) |
| 1112 | { | 1077 | { |
| 1113 | struct adxl367_state *st = iio_priv(indio_dev); | ||
| 1114 | enum adxl367_activity_type act; | 1078 | enum adxl367_activity_type act; |
| 1115 | int ret; | ||
| 1116 | 1079 | ||
| 1117 | switch (dir) { | 1080 | switch (dir) { |
| 1118 | case IIO_EV_DIR_RISING: | 1081 | case IIO_EV_DIR_RISING: |
| @@ -1125,33 +1088,28 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 1125 | return -EINVAL; | 1088 | return -EINVAL; |
| 1126 | } | 1089 | } |
| 1127 | 1090 | ||
| 1128 | ret = iio_device_claim_direct_mode(indio_dev); | 1091 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 1129 | if (ret) | 1092 | struct adxl367_state *st = iio_priv(indio_dev); |
| 1130 | return ret; | 1093 | int ret; |
| 1131 | |||
| 1132 | mutex_lock(&st->lock); | ||
| 1133 | 1094 | ||
| 1134 | ret = adxl367_set_measure_en(st, false); | 1095 | guard(mutex)(&st->lock); |
| 1135 | if (ret) | ||
| 1136 | goto out; | ||
| 1137 | 1096 | ||
| 1138 | ret = adxl367_set_act_interrupt_en(st, act, state); | 1097 | ret = adxl367_set_measure_en(st, false); |
| 1139 | if (ret) | 1098 | if (ret) |
| 1140 | goto out; | 1099 | return ret; |
| 1141 | |||
| 1142 | ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED | ||
| 1143 | : ADXL367_ACT_DISABLED); | ||
| 1144 | if (ret) | ||
| 1145 | goto out; | ||
| 1146 | |||
| 1147 | ret = adxl367_set_measure_en(st, true); | ||
| 1148 | 1100 | ||
| 1149 | out: | 1101 | ret = adxl367_set_act_interrupt_en(st, act, state); |
| 1150 | mutex_unlock(&st->lock); | 1102 | if (ret) |
| 1103 | return ret; | ||
| 1151 | 1104 | ||
| 1152 | iio_device_release_direct_mode(indio_dev); | 1105 | ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED |
| 1106 | : ADXL367_ACT_DISABLED); | ||
| 1107 | if (ret) | ||
| 1108 | return ret; | ||
| 1153 | 1109 | ||
| 1154 | return ret; | 1110 | return adxl367_set_measure_en(st, true); |
| 1111 | } | ||
| 1112 | unreachable(); | ||
| 1155 | } | 1113 | } |
| 1156 | 1114 | ||
| 1157 | static ssize_t adxl367_get_fifo_enabled(struct device *dev, | 1115 | static ssize_t adxl367_get_fifo_enabled(struct device *dev, |
| @@ -1176,9 +1134,8 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev, · 18 unmodified lines | |||
| 1176 | struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); | 1134 | struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev)); |
| 1177 | unsigned int fifo_watermark; | 1135 | unsigned int fifo_watermark; |
| 1178 | 1136 | ||
| 1179 | mutex_lock(&st->lock); | 1137 | guard(mutex)(&st->lock); |
| 1180 | fifo_watermark = st->fifo_watermark; | 1138 | fifo_watermark = st->fifo_watermark; |
| 1181 | mutex_unlock(&st->lock); | ||
| 1182 | 1139 | ||
| 1183 | return sysfs_emit(buf, "%d\n", fifo_watermark); | 1140 | return sysfs_emit(buf, "%d\n", fifo_watermark); |
| 1184 | } | 1141 | } |
| @@ -1207,22 +1164,17 @@ static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val) · 22 unmodified lines | |||
| 1207 | if (val > ADXL367_FIFO_MAX_WATERMARK) | 1164 | if (val > ADXL367_FIFO_MAX_WATERMARK) |
| 1208 | return -EINVAL; | 1165 | return -EINVAL; |
| 1209 | 1166 | ||
| 1210 | mutex_lock(&st->lock); | 1167 | guard(mutex)(&st->lock); |
| 1211 | 1168 | ||
| 1212 | ret = adxl367_set_measure_en(st, false); | 1169 | ret = adxl367_set_measure_en(st, false); |
| 1213 | if (ret) | 1170 | if (ret) |
| 1214 | goto out; | 1171 | return ret; |
| 1215 | 1172 | ||
| 1216 | ret = adxl367_set_fifo_watermark(st, val); | 1173 | ret = adxl367_set_fifo_watermark(st, val); |
| 1217 | if (ret) | 1174 | if (ret) |
| 1218 | goto out; | 1175 | return ret; |
| 1219 | |||
| 1220 | ret = adxl367_set_measure_en(st, true); | ||
| 1221 | |||
| 1222 | out: | ||
| 1223 | mutex_unlock(&st->lock); | ||
| 1224 | 1176 | ||
| 1225 | return ret; | 1177 | return adxl367_set_measure_en(st, true); |
| 1226 | } | 1178 | } |
| 1227 | 1179 | ||
| 1228 | static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask, | 1180 | static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask, |
| @@ -1253,27 +1205,24 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev, · 24 unmodified lines | |||
| 1253 | if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format)) | 1205 | if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format)) |
| 1254 | return -EINVAL; | 1206 | return -EINVAL; |
| 1255 | 1207 | ||
| 1256 | mutex_lock(&st->lock); | 1208 | guard(mutex)(&st->lock); |
| 1257 | 1209 | ||
| 1258 | ret = adxl367_set_measure_en(st, false); | 1210 | ret = adxl367_set_measure_en(st, false); |
| 1259 | if (ret) | 1211 | if (ret) |
| 1260 | goto out; | 1212 | return ret; |
| 1261 | 1213 | ||
| 1262 | ret = adxl367_set_fifo_format(st, fifo_format); | 1214 | ret = adxl367_set_fifo_format(st, fifo_format); |
| 1263 | if (ret) | 1215 | if (ret) |
| 1264 | goto out; | 1216 | return ret; |
| 1265 | 1217 | ||
| 1266 | ret = adxl367_set_measure_en(st, true); | 1218 | ret = adxl367_set_measure_en(st, true); |
| 1267 | if (ret) | 1219 | if (ret) |
| 1268 | goto out; | 1220 | return ret; |
| 1269 | 1221 | ||
| 1270 | st->fifo_set_size = bitmap_weight(active_scan_mask, | 1222 | st->fifo_set_size = bitmap_weight(active_scan_mask, |
| 1271 | indio_dev->masklength); | 1223 | indio_dev->masklength); |
| 1272 | 1224 | ||
| 1273 | out: | 1225 | return 0; |
| 1274 | mutex_unlock(&st->lock); | ||
| 1275 | |||
| 1276 | return ret; | ||
| 1277 | } | 1226 | } |
| 1278 | 1227 | ||
| 1279 | static int adxl367_buffer_postenable(struct iio_dev *indio_dev) | 1228 | static int adxl367_buffer_postenable(struct iio_dev *indio_dev) |
| @@ -1281,31 +1230,26 @@ static int adxl367_buffer_postenable(struct iio_dev *indio_dev) · 1 unmodified line | |||
| 1281 | struct adxl367_state *st = iio_priv(indio_dev); | 1230 | struct adxl367_state *st = iio_priv(indio_dev); |
| 1282 | int ret; | 1231 | int ret; |
| 1283 | 1232 | ||
| 1284 | mutex_lock(&st->lock); | 1233 | guard(mutex)(&st->lock); |
| 1285 | 1234 | ||
| 1286 | ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, | 1235 | ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, |
| 1287 | true); | 1236 | true); |
| 1288 | if (ret) | 1237 | if (ret) |
| 1289 | goto out; | 1238 | return ret; |
| 1290 | 1239 | ||
| 1291 | ret = adxl367_set_measure_en(st, false); | 1240 | ret = adxl367_set_measure_en(st, false); |
| 1292 | if (ret) | 1241 | if (ret) |
| 1293 | goto out; | 1242 | return ret; |
| 1294 | 1243 | ||
| 1295 | ret = adxl367_set_fifo_watermark_interrupt_en(st, true); | 1244 | ret = adxl367_set_fifo_watermark_interrupt_en(st, true); |
| 1296 | if (ret) | 1245 | if (ret) |
| 1297 | goto out; | 1246 | return ret; |
| 1298 | 1247 | ||
| 1299 | ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM); | 1248 | ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM); |
| 1300 | if (ret) | 1249 | if (ret) |
| 1301 | goto out; | 1250 | return ret; |
| 1302 | |||
| 1303 | ret = adxl367_set_measure_en(st, true); | ||
| 1304 | |||
| 1305 | out: | ||
| 1306 | mutex_unlock(&st->lock); | ||
| 1307 | 1251 | ||
| 1308 | return ret; | 1252 | return adxl367_set_measure_en(st, true); |
| 1309 | } | 1253 | } |
| 1310 | 1254 | ||
| 1311 | static int adxl367_buffer_predisable(struct iio_dev *indio_dev) | 1255 | static int adxl367_buffer_predisable(struct iio_dev *indio_dev) |
| @@ -1313,31 +1257,26 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev) · 1 unmodified line | |||
| 1313 | struct adxl367_state *st = iio_priv(indio_dev); | 1257 | struct adxl367_state *st = iio_priv(indio_dev); |
| 1314 | int ret; | 1258 | int ret; |
| 1315 | 1259 | ||
| 1316 | mutex_lock(&st->lock); | 1260 | guard(mutex)(&st->lock); |
| 1317 | 1261 | ||
| 1318 | ret = adxl367_set_measure_en(st, false); | 1262 | ret = adxl367_set_measure_en(st, false); |
| 1319 | if (ret) | 1263 | if (ret) |
| 1320 | goto out; | 1264 | return ret; |
| 1321 | 1265 | ||
| 1322 | ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED); | 1266 | ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED); |
| 1323 | if (ret) | 1267 | if (ret) |
| 1324 | goto out; | 1268 | return ret; |
| 1325 | 1269 | ||
| 1326 | ret = adxl367_set_fifo_watermark_interrupt_en(st, false); | 1270 | ret = adxl367_set_fifo_watermark_interrupt_en(st, false); |
| 1327 | if (ret) | 1271 | if (ret) |
| 1328 | goto out; | 1272 | return ret; |
| 1329 | 1273 | ||
| 1330 | ret = adxl367_set_measure_en(st, true); | 1274 | ret = adxl367_set_measure_en(st, true); |
| 1331 | if (ret) | 1275 | if (ret) |
| 1332 | goto out; | 1276 | return ret; |
| 1333 | |||
| 1334 | ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, | ||
| 1335 | false); | ||
| 1336 | |||
| 1337 | out: | ||
| 1338 | mutex_unlock(&st->lock); | ||
| 1339 | 1277 | ||
| 1340 | return ret; | 1278 | return adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask, |
| 1279 | false); | ||
| 1341 | } | 1280 | } |
| 1342 | 1281 | ||
| 1343 | static const struct iio_buffer_setup_ops adxl367_buffer_ops = { | 1282 | static const struct iio_buffer_setup_ops adxl367_buffer_ops = { |
| @@ -6,8 +6,8 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/mod_devicetable.h> | ||
| 9 | #include <linux/regmap.h> | 10 | #include <linux/regmap.h> |
| 10 | #include <linux/of.h> | ||
| 11 | #include <linux/spi/spi.h> | 11 | #include <linux/spi/spi.h> |
| 12 | 12 | ||
| 13 | #include "adxl372.h" | 13 | #include "adxl372.h" |
| @@ -13,10 +13,10 @@ · 12 unmodified lines | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/mod_devicetable.h> | ||
| 16 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
| 17 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 18 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/bitops.h> | 20 | #include <linux/bitops.h> |
| 21 | #include <linux/regulator/consumer.h> | 21 | #include <linux/regulator/consumer.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| @@ -224,6 +224,19 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { · 223 unmodified lines | |||
| 224 | {"BMA250E"}, | 224 | {"BMA250E"}, |
| 225 | {"BMC150A"}, | 225 | {"BMC150A"}, |
| 226 | {"BMI055A"}, | 226 | {"BMI055A"}, |
| 227 | /* | ||
| 228 | * The "BOSC0200" identifier used here is not unique to devices using | ||
| 229 | * bmc150. The same "BOSC0200" identifier is found in the ACPI tables | ||
| 230 | * of the ASUS ROG ALLY and Ayaneo AIR Plus which both use a Bosch | ||
| 231 | * BMI323 chip. This creates a conflict with duplicate ACPI identifiers | ||
| 232 | * which multiple drivers want to use. Fortunately, when the bmc150 | ||
| 233 | * driver starts to load on the ASUS ROG ALLY, the chip ID check | ||
| 234 | * portion fails (correctly) because the chip IDs received (via i2c) | ||
| 235 | * are unique between bmc150 and bmi323 and a dmesg output similar to | ||
| 236 | * this: "bmc150_accel_i2c i2c-BOSC0200:00: Invalid chip 0" can be | ||
| 237 | * seen. This allows the bmi323 driver to take over for ASUS ROG ALLY, | ||
| 238 | * and other devices using the bmi323 chip. | ||
| 239 | */ | ||
| 227 | {"BOSC0200"}, | 240 | {"BOSC0200"}, |
| 228 | {"BSBA0150"}, | 241 | {"BSBA0150"}, |
| 229 | {"DUAL250E"}, | 242 | {"DUAL250E"}, |
| @@ -266,7 +279,7 @@ static struct i2c_driver bmc150_accel_driver = { · 36 unmodified lines | |||
| 266 | .driver = { | 279 | .driver = { |
| 267 | .name = "bmc150_accel_i2c", | 280 | .name = "bmc150_accel_i2c", |
| 268 | .of_match_table = bmc150_accel_of_match, | 281 | .of_match_table = bmc150_accel_of_match, |
| 269 | .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), | 282 | .acpi_match_table = bmc150_accel_acpi_match, |
| 270 | .pm = &bmc150_accel_pm_ops, | 283 | .pm = &bmc150_accel_pm_ops, |
| 271 | }, | 284 | }, |
| 272 | .probe = bmc150_accel_probe, | 285 | .probe = bmc150_accel_probe, |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <linux/device.h> | 7 | #include <linux/device.h> |
| 8 | #include <linux/mod_devicetable.h> | 8 | #include <linux/mod_devicetable.h> |
| 9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 10 | #include <linux/acpi.h> | ||
| 11 | #include <linux/regmap.h> | 10 | #include <linux/regmap.h> |
| 12 | #include <linux/spi/spi.h> | 11 | #include <linux/spi/spi.h> |
| 13 | 12 | ||
| @@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(spi, bmc150_accel_id); · 56 unmodified lines | |||
| 70 | static struct spi_driver bmc150_accel_driver = { | 69 | static struct spi_driver bmc150_accel_driver = { |
| 71 | .driver = { | 70 | .driver = { |
| 72 | .name = "bmc150_accel_spi", | 71 | .name = "bmc150_accel_spi", |
| 73 | .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), | 72 | .acpi_match_table = bmc150_accel_acpi_match, |
| 74 | .pm = &bmc150_accel_pm_ops, | 73 | .pm = &bmc150_accel_pm_ops, |
| 75 | }, | 74 | }, |
| 76 | .probe = bmc150_accel_probe, | 75 | .probe = bmc150_accel_probe, |
| @@ -0,0 +1,70 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: | ||
| 4 | * - BMI088 | ||
| 5 | * - BMI085 | ||
| 6 | * - BMI090L | ||
| 7 | * | ||
| 8 | * Copyright 2023 Jun Yan <jerrysteve1101@gmail.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/regmap.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | |||
| 17 | #include "bmi088-accel.h" | ||
| 18 | |||
| 19 | static int bmi088_accel_probe(struct i2c_client *i2c) | ||
| 20 | { | ||
| 21 | struct regmap *regmap; | ||
| 22 | const struct i2c_device_id *id = i2c_client_get_device_id(i2c); | ||
| 23 | |||
| 24 | regmap = devm_regmap_init_i2c(i2c, &bmi088_regmap_conf); | ||
| 25 | if (IS_ERR(regmap)) { | ||
| 26 | dev_err(&i2c->dev, "Failed to initialize i2c regmap\n"); | ||
| 27 | return PTR_ERR(regmap); | ||
| 28 | } | ||
| 29 | |||
| 30 | return bmi088_accel_core_probe(&i2c->dev, regmap, i2c->irq, | ||
| 31 | id->driver_data); | ||
| 32 | } | ||
| 33 | |||
| 34 | static void bmi088_accel_remove(struct i2c_client *i2c) | ||
| 35 | { | ||
| 36 | bmi088_accel_core_remove(&i2c->dev); | ||
| 37 | } | ||
| 38 | |||
| 39 | static const struct of_device_id bmi088_of_match[] = { | ||
| 40 | { .compatible = "bosch,bmi085-accel" }, | ||
| 41 | { .compatible = "bosch,bmi088-accel" }, | ||
| 42 | { .compatible = "bosch,bmi090l-accel" }, | ||
| 43 | {} | ||
| 44 | }; | ||
| 45 | MODULE_DEVICE_TABLE(of, bmi088_of_match); | ||
| 46 | |||
| 47 | static const struct i2c_device_id bmi088_accel_id[] = { | ||
| 48 | { "bmi085-accel", BOSCH_BMI085 }, | ||
| 49 | { "bmi088-accel", BOSCH_BMI088 }, | ||
| 50 | { "bmi090l-accel", BOSCH_BMI090L }, | ||
| 51 | {} | ||
| 52 | }; | ||
| 53 | MODULE_DEVICE_TABLE(i2c, bmi088_accel_id); | ||
| 54 | |||
| 55 | static struct i2c_driver bmi088_accel_driver = { | ||
| 56 | .driver = { | ||
| 57 | .name = "bmi088_accel_i2c", | ||
| 58 | .pm = pm_ptr(&bmi088_accel_pm_ops), | ||
| 59 | .of_match_table = bmi088_of_match, | ||
| 60 | }, | ||
| 61 | .probe = bmi088_accel_probe, | ||
| 62 | .remove = bmi088_accel_remove, | ||
| 63 | .id_table = bmi088_accel_id, | ||
| 64 | }; | ||
| 65 | module_i2c_driver(bmi088_accel_driver); | ||
| 66 | |||
| 67 | MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>"); | ||
| 68 | MODULE_LICENSE("GPL"); | ||
| 69 | MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)"); | ||
| 70 | MODULE_IMPORT_NS(IIO_BMI088); | ||
| @@ -23,8 +23,6 @@ · 22 unmodified lines | |||
| 23 | #define DA280_MODE_ENABLE 0x1e | 23 | #define DA280_MODE_ENABLE 0x1e |
| 24 | #define DA280_MODE_DISABLE 0x9e | 24 | #define DA280_MODE_DISABLE 0x9e |
| 25 | 25 | ||
| 26 | enum da280_chipset { da217, da226, da280 }; | ||
| 27 | |||
| 28 | /* | 26 | /* |
| 29 | * a value of + or -4096 corresponds to + or - 1G | 27 | * a value of + or -4096 corresponds to + or - 1G |
| 30 | * scale = 9.81 / 4096 = 0.002395019 | 28 | * scale = 9.81 / 4096 = 0.002395019 |
| @@ -47,6 +45,11 @@ static const struct iio_chan_spec da280_channels[] = { · 16 unmodified lines | |||
| 47 | DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), | 45 | DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), |
| 48 | }; | 46 | }; |
| 49 | 47 | ||
| 48 | struct da280_match_data { | ||
| 49 | const char *name; | ||
| 50 | int num_channels; | ||
| 51 | }; | ||
| 52 | |||
| 50 | struct da280_data { | 53 | struct da280_data { |
| 51 | struct i2c_client *client; | 54 | struct i2c_client *client; |
| 52 | }; | 55 | }; |
| @@ -89,17 +92,6 @@ static const struct iio_info da280_info = { · 36 unmodified lines | |||
| 89 | .read_raw = da280_read_raw, | 92 | .read_raw = da280_read_raw, |
| 90 | }; | 93 | }; |
| 91 | 94 | ||
| 92 | static enum da280_chipset da280_match_acpi_device(struct device *dev) | ||
| 93 | { | ||
| 94 | const struct acpi_device_id *id; | ||
| 95 | |||
| 96 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
| 97 | if (!id) | ||
| 98 | return -EINVAL; | ||
| 99 | |||
| 100 | return (enum da280_chipset) id->driver_data; | ||
| 101 | } | ||
| 102 | |||
| 103 | static void da280_disable(void *client) | 95 | static void da280_disable(void *client) |
| 104 | { | 96 | { |
| 105 | da280_enable(client, false); | 97 | da280_enable(client, false); |
| @@ -107,16 +99,21 @@ static void da280_disable(void *client) · 1 unmodified line | |||
| 107 | 99 | ||
| 108 | static int da280_probe(struct i2c_client *client) | 100 | static int da280_probe(struct i2c_client *client) |
| 109 | { | 101 | { |
| 110 | const struct i2c_device_id *id = i2c_client_get_device_id(client); | 102 | const struct da280_match_data *match_data; |
| 111 | int ret; | ||
| 112 | struct iio_dev *indio_dev; | 103 | struct iio_dev *indio_dev; |
| 113 | struct da280_data *data; | 104 | struct da280_data *data; |
| 114 | enum da280_chipset chip; | 105 | int ret; |
| 115 | 106 | ||
| 116 | ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); | 107 | ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); |
| 117 | if (ret != DA280_CHIP_ID) | 108 | if (ret != DA280_CHIP_ID) |
| 118 | return (ret < 0) ? ret : -ENODEV; | 109 | return (ret < 0) ? ret : -ENODEV; |
| 119 | 110 | ||
| 111 | match_data = i2c_get_match_data(client); | ||
| 112 | if (!match_data) { | ||
| 113 | dev_err(&client->dev, "Error match-data not set\n"); | ||
| 114 | return -EINVAL; | ||
| 115 | } | ||
| 116 | |||
| 120 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | 117 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
| 121 | if (!indio_dev) | 118 | if (!indio_dev) |
| 122 | return -ENOMEM; | 119 | return -ENOMEM; |
| @@ -127,23 +124,8 @@ static int da280_probe(struct i2c_client *client) · 4 unmodified lines | |||
| 127 | indio_dev->info = &da280_info; | 124 | indio_dev->info = &da280_info; |
| 128 | indio_dev->modes = INDIO_DIRECT_MODE; | 125 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 129 | indio_dev->channels = da280_channels; | 126 | indio_dev->channels = da280_channels; |
| 130 | 127 | indio_dev->num_channels = match_data->num_channels; | |
| 131 | if (ACPI_HANDLE(&client->dev)) { | 128 | indio_dev->name = match_data->name; |
| 132 | chip = da280_match_acpi_device(&client->dev); | ||
| 133 | } else { | ||
| 134 | chip = id->driver_data; | ||
| 135 | } | ||
| 136 | |||
| 137 | if (chip == da217) { | ||
| 138 | indio_dev->name = "da217"; | ||
| 139 | indio_dev->num_channels = 3; | ||
| 140 | } else if (chip == da226) { | ||
| 141 | indio_dev->name = "da226"; | ||
| 142 | indio_dev->num_channels = 2; | ||
| 143 | } else { | ||
| 144 | indio_dev->name = "da280"; | ||
| 145 | indio_dev->num_channels = 3; | ||
| 146 | } | ||
| 147 | 129 | ||
| 148 | ret = da280_enable(client, true); | 130 | ret = da280_enable(client, true); |
| 149 | if (ret < 0) | 131 | if (ret < 0) |
| @@ -168,17 +150,21 @@ static int da280_resume(struct device *dev) · 18 unmodified lines | |||
| 168 | 150 | ||
| 169 | static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); | 151 | static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); |
| 170 | 152 | ||
| 153 | static const struct da280_match_data da217_match_data = { "da217", 3 }; | ||
| 154 | static const struct da280_match_data da226_match_data = { "da226", 2 }; | ||
| 155 | static const struct da280_match_data da280_match_data = { "da280", 3 }; | ||
| 156 | |||
| 171 | static const struct acpi_device_id da280_acpi_match[] = { | 157 | static const struct acpi_device_id da280_acpi_match[] = { |
| 172 | {"NSA2513", da217}, | 158 | { "NSA2513", (kernel_ulong_t)&da217_match_data }, |
| 173 | {"MIRAACC", da280}, | 159 | { "MIRAACC", (kernel_ulong_t)&da280_match_data }, |
| 174 | {}, | 160 | {} |
| 175 | }; | 161 | }; |
| 176 | MODULE_DEVICE_TABLE(acpi, da280_acpi_match); | 162 | MODULE_DEVICE_TABLE(acpi, da280_acpi_match); |
| 177 | 163 | ||
| 178 | static const struct i2c_device_id da280_i2c_id[] = { | 164 | static const struct i2c_device_id da280_i2c_id[] = { |
| 179 | { "da217", da217 }, | 165 | { "da217", (kernel_ulong_t)&da217_match_data }, |
| 180 | { "da226", da226 }, | 166 | { "da226", (kernel_ulong_t)&da226_match_data }, |
| 181 | { "da280", da280 }, | 167 | { "da280", (kernel_ulong_t)&da280_match_data }, |
| 182 | {} | 168 | {} |
| 183 | }; | 169 | }; |
| 184 | MODULE_DEVICE_TABLE(i2c, da280_i2c_id); | 170 | MODULE_DEVICE_TABLE(i2c, da280_i2c_id); |
| @@ -186,7 +172,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id); · 1 unmodified line | |||
| 186 | static struct i2c_driver da280_driver = { | 172 | static struct i2c_driver da280_driver = { |
| 187 | .driver = { | 173 | .driver = { |
| 188 | .name = "da280", | 174 | .name = "da280", |
| 189 | .acpi_match_table = ACPI_PTR(da280_acpi_match), | 175 | .acpi_match_table = da280_acpi_match, |
| 190 | .pm = pm_sleep_ptr(&da280_pm_ops), | 176 | .pm = pm_sleep_ptr(&da280_pm_ops), |
| 191 | }, | 177 | }, |
| 192 | .probe = da280_probe, | 178 | .probe = da280_probe, |
| @@ -422,6 +422,23 @@ static int kiox010a_dsm(struct device *dev, int fn_index) · 421 unmodified lines | |||
| 422 | ACPI_FREE(obj); | 422 | ACPI_FREE(obj); |
| 423 | return 0; | 423 | return 0; |
| 424 | } | 424 | } |
| 425 | |||
| 426 | static const struct acpi_device_id kx_acpi_match[] = { | ||
| 427 | {"KXCJ1013", KXCJK1013}, | ||
| 428 | {"KXCJ1008", KXCJ91008}, | ||
| 429 | {"KXCJ9000", KXCJ91008}, | ||
| 430 | {"KIOX0008", KXCJ91008}, | ||
| 431 | {"KIOX0009", KXTJ21009}, | ||
| 432 | {"KIOX000A", KXCJ91008}, | ||
| 433 | {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ | ||
| 434 | {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ | ||
| 435 | {"KXTJ1009", KXTJ21009}, | ||
| 436 | {"KXJ2109", KXTJ21009}, | ||
| 437 | {"SMO8500", KXCJ91008}, | ||
| 438 | { } | ||
| 439 | }; | ||
| 440 | MODULE_DEVICE_TABLE(acpi, kx_acpi_match); | ||
| 441 | |||
| 425 | #endif | 442 | #endif |
| 426 | 443 | ||
| 427 | static int kxcjk1013_set_mode(struct kxcjk1013_data *data, | 444 | static int kxcjk1013_set_mode(struct kxcjk1013_data *data, |
| @@ -619,6 +636,84 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) · 191 unmodified lines | |||
| 619 | return 0; | 636 | return 0; |
| 620 | } | 637 | } |
| 621 | 638 | ||
| 639 | #ifdef CONFIG_ACPI | ||
| 640 | static bool kxj_acpi_orientation(struct device *dev, | ||
| 641 | struct iio_mount_matrix *orientation) | ||
| 642 | { | ||
| 643 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 644 | struct acpi_device *adev = ACPI_COMPANION(dev); | ||
| 645 | char *str; | ||
| 646 | union acpi_object *obj, *elements; | ||
| 647 | acpi_status status; | ||
| 648 | int i, j, val[3]; | ||
| 649 | bool ret = false; | ||
| 650 | |||
| 651 | if (!acpi_has_method(adev->handle, "ROTM")) | ||
| 652 | return false; | ||
| 653 | |||
| 654 | status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer); | ||
| 655 | if (ACPI_FAILURE(status)) { | ||
| 656 | dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); | ||
| 657 | return false; | ||
| 658 | } | ||
| 659 | |||
| 660 | obj = buffer.pointer; | ||
| 661 | if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { | ||
| 662 | dev_err(dev, "Unknown ACPI mount matrix package format\n"); | ||
| 663 | goto out_free_buffer; | ||
| 664 | } | ||
| 665 | |||
| 666 | elements = obj->package.elements; | ||
| 667 | for (i = 0; i < 3; i++) { | ||
| 668 | if (elements[i].type != ACPI_TYPE_STRING) { | ||
| 669 | dev_err(dev, "Unknown ACPI mount matrix element format\n"); | ||
| 670 | goto out_free_buffer; | ||
| 671 | } | ||
| 672 | |||
| 673 | str = elements[i].string.pointer; | ||
| 674 | if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) { | ||
| 675 | dev_err(dev, "Incorrect ACPI mount matrix string format\n"); | ||
| 676 | goto out_free_buffer; | ||
| 677 | } | ||
| 678 | |||
| 679 | for (j = 0; j < 3; j++) { | ||
| 680 | switch (val[j]) { | ||
| 681 | case -1: str = "-1"; break; | ||
| 682 | case 0: str = "0"; break; | ||
| 683 | case 1: str = "1"; break; | ||
| 684 | default: | ||
| 685 | dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]); | ||
| 686 | goto out_free_buffer; | ||
| 687 | } | ||
| 688 | orientation->rotation[i * 3 + j] = str; | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | ret = true; | ||
| 693 | |||
| 694 | out_free_buffer: | ||
| 695 | kfree(buffer.pointer); | ||
| 696 | return ret; | ||
| 697 | } | ||
| 698 | |||
| 699 | static bool kxj1009_apply_acpi_orientation(struct device *dev, | ||
| 700 | struct iio_mount_matrix *orientation) | ||
| 701 | { | ||
| 702 | struct acpi_device *adev = ACPI_COMPANION(dev); | ||
| 703 | |||
| 704 | if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL)) | ||
| 705 | return kxj_acpi_orientation(dev, orientation); | ||
| 706 | |||
| 707 | return false; | ||
| 708 | } | ||
| 709 | #else | ||
| 710 | static bool kxj1009_apply_acpi_orientation(struct device *dev, | ||
| 711 | struct iio_mount_matrix *orientation) | ||
| 712 | { | ||
| 713 | return false; | ||
| 714 | } | ||
| 715 | #endif | ||
| 716 | |||
| 622 | static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) | 717 | static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) |
| 623 | { | 718 | { |
| 624 | int ret; | 719 | int ret; |
| @@ -1449,9 +1544,12 @@ static int kxcjk1013_probe(struct i2c_client *client) · 824 unmodified lines | |||
| 1449 | } else { | 1544 | } else { |
| 1450 | data->active_high_intr = true; /* default polarity */ | 1545 | data->active_high_intr = true; /* default polarity */ |
| 1451 | 1546 | ||
| 1452 | ret = iio_read_mount_matrix(&client->dev, &data->orientation); | 1547 | if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) { |
| 1453 | if (ret) | 1548 | ret = iio_read_mount_matrix(&client->dev, &data->orientation); |
| 1454 | return ret; | 1549 | if (ret) |
| 1550 | return ret; | ||
| 1551 | } | ||
| 1552 | |||
| 1455 | } | 1553 | } |
| 1456 | 1554 | ||
| 1457 | ret = devm_regulator_bulk_get_enable(&client->dev, | 1555 | ret = devm_regulator_bulk_get_enable(&client->dev, |
| @@ -1687,22 +1785,6 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { · 229 unmodified lines | |||
| 1687 | kxcjk1013_runtime_resume, NULL) | 1785 | kxcjk1013_runtime_resume, NULL) |
| 1688 | }; | 1786 | }; |
| 1689 | 1787 | ||
| 1690 | static const struct acpi_device_id kx_acpi_match[] = { | ||
| 1691 | {"KXCJ1013", KXCJK1013}, | ||
| 1692 | {"KXCJ1008", KXCJ91008}, | ||
| 1693 | {"KXCJ9000", KXCJ91008}, | ||
| 1694 | {"KIOX0008", KXCJ91008}, | ||
| 1695 | {"KIOX0009", KXTJ21009}, | ||
| 1696 | {"KIOX000A", KXCJ91008}, | ||
| 1697 | {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ | ||
| 1698 | {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ | ||
| 1699 | {"KXTJ1009", KXTJ21009}, | ||
| 1700 | {"KXJ2109", KXTJ21009}, | ||
| 1701 | {"SMO8500", KXCJ91008}, | ||
| 1702 | { }, | ||
| 1703 | }; | ||
| 1704 | MODULE_DEVICE_TABLE(acpi, kx_acpi_match); | ||
| 1705 | |||
| 1706 | static const struct i2c_device_id kxcjk1013_id[] = { | 1788 | static const struct i2c_device_id kxcjk1013_id[] = { |
| 1707 | {"kxcjk1013", KXCJK1013}, | 1789 | {"kxcjk1013", KXCJK1013}, |
| 1708 | {"kxcj91008", KXCJ91008}, | 1790 | {"kxcj91008", KXCJ91008}, |
| @@ -1,9 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | #include <linux/device.h> | 2 | #include <linux/device.h> |
| 3 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
| 4 | #include <linux/of.h> | ||
| 5 | #include <linux/spi/spi.h> | 4 | #include <linux/spi/spi.h> |
| 6 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 6 | #include <linux/mod_devicetable.h> | ||
| 7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
| 8 | #include <linux/regmap.h> | 8 | #include <linux/regmap.h> |
| 9 | 9 | ||
| @@ -604,9 +604,9 @@ MODULE_DEVICE_TABLE(i2c, mma9551_id); · 603 unmodified lines | |||
| 604 | static struct i2c_driver mma9551_driver = { | 604 | static struct i2c_driver mma9551_driver = { |
| 605 | .driver = { | 605 | .driver = { |
| 606 | .name = MMA9551_DRV_NAME, | 606 | .name = MMA9551_DRV_NAME, |
| 607 | .acpi_match_table = ACPI_PTR(mma9551_acpi_match), | 607 | .acpi_match_table = mma9551_acpi_match, |
| 608 | .pm = pm_ptr(&mma9551_pm_ops), | 608 | .pm = pm_ptr(&mma9551_pm_ops), |
| 609 | }, | 609 | }, |
| 610 | .probe = mma9551_probe, | 610 | .probe = mma9551_probe, |
| 611 | .remove = mma9551_remove, | 611 | .remove = mma9551_remove, |
| 612 | .id_table = mma9551_id, | 612 | .id_table = mma9551_id, |
| @@ -1243,9 +1243,9 @@ MODULE_DEVICE_TABLE(i2c, mma9553_id); · 1242 unmodified lines | |||
| 1243 | static struct i2c_driver mma9553_driver = { | 1243 | static struct i2c_driver mma9553_driver = { |
| 1244 | .driver = { | 1244 | .driver = { |
| 1245 | .name = MMA9553_DRV_NAME, | 1245 | .name = MMA9553_DRV_NAME, |
| 1246 | .acpi_match_table = ACPI_PTR(mma9553_acpi_match), | 1246 | .acpi_match_table = mma9553_acpi_match, |
| 1247 | .pm = pm_ptr(&mma9553_pm_ops), | 1247 | .pm = pm_ptr(&mma9553_pm_ops), |
| 1248 | }, | 1248 | }, |
| 1249 | .probe = mma9553_probe, | 1249 | .probe = mma9553_probe, |
| 1250 | .remove = mma9553_remove, | 1250 | .remove = mma9553_remove, |
| 1251 | .id_table = mma9553_id, | 1251 | .id_table = mma9553_id, |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | |||
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/i2c.h> | 9 | #include <linux/i2c.h> |
| 10 | #include <linux/iio/iio.h> | 10 | #include <linux/iio/iio.h> |
| 11 | #include <linux/acpi.h> | 11 | #include <linux/mod_devicetable.h> |
| 12 | #include <linux/regmap.h> | 12 | #include <linux/regmap.h> |
| 13 | #include <linux/iio/sysfs.h> | 13 | #include <linux/iio/sysfs.h> |
| 14 | #include <linux/iio/trigger.h> | 14 | #include <linux/iio/trigger.h> |
| @@ -472,6 +472,7 @@ static int mxc4005_probe(struct i2c_client *client) · 457 unmodified lines | |||
| 472 | static const struct acpi_device_id mxc4005_acpi_match[] = { | 472 | static const struct acpi_device_id mxc4005_acpi_match[] = { |
| 473 | {"MXC4005", 0}, | 473 | {"MXC4005", 0}, |
| 474 | {"MXC6655", 0}, | 474 | {"MXC6655", 0}, |
| 475 | {"MDA6655", 0}, | ||
| 475 | { }, | 476 | { }, |
| 476 | }; | 477 | }; |
| 477 | MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); | 478 | MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); |
| @@ -493,7 +494,7 @@ MODULE_DEVICE_TABLE(i2c, mxc4005_id); · 15 unmodified lines | |||
| 493 | static struct i2c_driver mxc4005_driver = { | 494 | static struct i2c_driver mxc4005_driver = { |
| 494 | .driver = { | 495 | .driver = { |
| 495 | .name = MXC4005_DRV_NAME, | 496 | .name = MXC4005_DRV_NAME, |
| 496 | .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), | 497 | .acpi_match_table = mxc4005_acpi_match, |
| 497 | .of_match_table = mxc4005_of_match, | 498 | .of_match_table = mxc4005_of_match, |
| 498 | }, | 499 | }, |
| 499 | .probe = mxc4005_probe, | 500 | .probe = mxc4005_probe, |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/iio/iio.h> | 13 | #include <linux/iio/iio.h> |
| 14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
| 15 | #include <linux/acpi.h> | 15 | #include <linux/mod_devicetable.h> |
| 16 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
| 17 | #include <linux/iio/sysfs.h> | 17 | #include <linux/iio/sysfs.h> |
| 18 | 18 | ||
| @@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(i2c, mxc6255_id); · 162 unmodified lines | |||
| 181 | static struct i2c_driver mxc6255_driver = { | 181 | static struct i2c_driver mxc6255_driver = { |
| 182 | .driver = { | 182 | .driver = { |
| 183 | .name = MXC6255_DRV_NAME, | 183 | .name = MXC6255_DRV_NAME, |
| 184 | .acpi_match_table = ACPI_PTR(mxc6255_acpi_match), | 184 | .acpi_match_table = mxc6255_acpi_match, |
| 185 | }, | 185 | }, |
| 186 | .probe = mxc6255_probe, | 186 | .probe = mxc6255_probe, |
| 187 | .id_table = mxc6255_id, | 187 | .id_table = mxc6255_id, |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | |||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/mod_devicetable.h> | 12 | #include <linux/mod_devicetable.h> |
| 13 | #include <linux/acpi.h> | ||
| 14 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 15 | #include <linux/iio/iio.h> | 14 | #include <linux/iio/iio.h> |
| 16 | 15 | ||
| @@ -127,14 +126,12 @@ static const struct of_device_id st_accel_of_match[] = { · 110 unmodified lines | |||
| 127 | }; | 126 | }; |
| 128 | MODULE_DEVICE_TABLE(of, st_accel_of_match); | 127 | MODULE_DEVICE_TABLE(of, st_accel_of_match); |
| 129 | 128 | ||
| 130 | #ifdef CONFIG_ACPI | ||
| 131 | static const struct acpi_device_id st_accel_acpi_match[] = { | 129 | static const struct acpi_device_id st_accel_acpi_match[] = { |
| 132 | {"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME}, | 130 | {"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME}, |
| 133 | {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, | 131 | {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, |
| 134 | { }, | 132 | { }, |
| 135 | }; | 133 | }; |
| 136 | MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); | 134 | MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); |
| 137 | #endif | ||
| 138 | 135 | ||
| 139 | static const struct i2c_device_id st_accel_id_table[] = { | 136 | static const struct i2c_device_id st_accel_id_table[] = { |
| 140 | { LSM303DLH_ACCEL_DEV_NAME }, | 137 | { LSM303DLH_ACCEL_DEV_NAME }, |
| @@ -204,7 +201,7 @@ static struct i2c_driver st_accel_driver = { · 63 unmodified lines | |||
| 204 | .driver = { | 201 | .driver = { |
| 205 | .name = "st-accel-i2c", | 202 | .name = "st-accel-i2c", |
| 206 | .of_match_table = st_accel_of_match, | 203 | .of_match_table = st_accel_of_match, |
| 207 | .acpi_match_table = ACPI_PTR(st_accel_acpi_match), | 204 | .acpi_match_table = st_accel_acpi_match, |
| 208 | }, | 205 | }, |
| 209 | .probe = st_accel_i2c_probe, | 206 | .probe = st_accel_i2c_probe, |
| 210 | .id_table = st_accel_id_table, | 207 | .id_table = st_accel_id_table, |
| @@ -7,11 +7,11 @@ · 6 unmodified lines | |||
| 7 | * STK8BA50 7-bit I2C address: 0x18. | 7 | * STK8BA50 7-bit I2C address: 0x18. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/acpi.h> | ||
| 11 | #include <linux/i2c.h> | 10 | #include <linux/i2c.h> |
| 12 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| 13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/mod_devicetable.h> | ||
| 15 | #include <linux/iio/buffer.h> | 15 | #include <linux/iio/buffer.h> |
| 16 | #include <linux/iio/iio.h> | 16 | #include <linux/iio/iio.h> |
| 17 | #include <linux/iio/sysfs.h> | 17 | #include <linux/iio/sysfs.h> |
| @@ -541,7 +541,7 @@ static struct i2c_driver stk8ba50_driver = { · 523 unmodified lines | |||
| 541 | .driver = { | 541 | .driver = { |
| 542 | .name = "stk8ba50", | 542 | .name = "stk8ba50", |
| 543 | .pm = pm_sleep_ptr(&stk8ba50_pm_ops), | 543 | .pm = pm_sleep_ptr(&stk8ba50_pm_ops), |
| 544 | .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id), | 544 | .acpi_match_table = stk8ba50_acpi_id, |
| 545 | }, | 545 | }, |
| 546 | .probe = stk8ba50_probe, | 546 | .probe = stk8ba50_probe, |
| 547 | .remove = stk8ba50_remove, | 547 | .remove = stk8ba50_remove, |
| @@ -291,7 +291,7 @@ config AD799X · 290 unmodified lines | |||
| 291 | config AD9467 | 291 | config AD9467 |
| 292 | tristate "Analog Devices AD9467 High Speed ADC driver" | 292 | tristate "Analog Devices AD9467 High Speed ADC driver" |
| 293 | depends on SPI | 293 | depends on SPI |
| 294 | depends on ADI_AXI_ADC | 294 | select IIO_BACKEND |
| 295 | help | 295 | help |
| 296 | Say yes here to build support for Analog Devices: | 296 | Say yes here to build support for Analog Devices: |
| 297 | * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter | 297 | * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter |
| @@ -309,7 +309,7 @@ config ADI_AXI_ADC · 11 unmodified lines | |||
| 309 | select IIO_BUFFER_HW_CONSUMER | 309 | select IIO_BUFFER_HW_CONSUMER |
| 310 | select IIO_BUFFER_DMAENGINE | 310 | select IIO_BUFFER_DMAENGINE |
| 311 | select REGMAP_MMIO | 311 | select REGMAP_MMIO |
| 312 | depends on OF | 312 | select IIO_BACKEND |
| 313 | help | 313 | help |
| 314 | Say yes here to build support for Analog Devices Generic | 314 | Say yes here to build support for Analog Devices Generic |
| 315 | AXI ADC IP core. The IP core is used for interfacing with | 315 | AXI ADC IP core. The IP core is used for interfacing with |
| @@ -930,6 +930,17 @@ config NPCM_ADC · 614 unmodified lines | |||
| 930 | This driver can also be built as a module. If so, the module | 930 | This driver can also be built as a module. If so, the module |
| 931 | will be called npcm_adc. | 931 | will be called npcm_adc. |
| 932 | 932 | ||
| 933 | config PAC1934 | ||
| 934 | tristate "Microchip Technology PAC1934 driver" | ||
| 935 | depends on I2C | ||
| 936 | help | ||
| 937 | Say yes here to build support for Microchip Technology's PAC1931, | ||
| 938 | PAC1932, PAC1933, PAC1934 Single/Multi-Channel Power Monitor with | ||
| 939 | Accumulator. | ||
| 940 | |||
| 941 | This driver can also be built as a module. If so, the module | ||
| 942 | will be called pac1934. | ||
| 943 | |||
| 933 | config PALMAS_GPADC | 944 | config PALMAS_GPADC |
| 934 | tristate "TI Palmas General Purpose ADC" | 945 | tristate "TI Palmas General Purpose ADC" |
| 935 | depends on MFD_PALMAS | 946 | depends on MFD_PALMAS |
| @@ -1312,6 +1323,17 @@ config TI_ADS1100 · 376 unmodified lines | |||
| 1312 | This driver can also be built as a module. If so, the module will be | 1323 | This driver can also be built as a module. If so, the module will be |
| 1313 | called ti-ads1100. | 1324 | called ti-ads1100. |
| 1314 | 1325 | ||
| 1326 | config TI_ADS1298 | ||
| 1327 | tristate "Texas Instruments ADS1298" | ||
| 1328 | depends on SPI | ||
| 1329 | select IIO_BUFFER | ||
| 1330 | help | ||
| 1331 | If you say yes here you get support for Texas Instruments ADS1298 | ||
| 1332 | medical ADC chips | ||
| 1333 | |||
| 1334 | This driver can also be built as a module. If so, the module will be | ||
| 1335 | called ti-ads1298. | ||
| 1336 | |||
| 1315 | config TI_ADS7950 | 1337 | config TI_ADS7950 |
| 1316 | tristate "Texas Instruments ADS7950 ADC driver" | 1338 | tristate "Texas Instruments ADS7950 ADC driver" |
| 1317 | depends on SPI && GPIOLIB | 1339 | depends on SPI && GPIOLIB |
| @@ -86,6 +86,7 @@ obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o · 85 unmodified lines | |||
| 86 | obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o | 86 | obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o |
| 87 | obj-$(CONFIG_NAU7802) += nau7802.o | 87 | obj-$(CONFIG_NAU7802) += nau7802.o |
| 88 | obj-$(CONFIG_NPCM_ADC) += npcm_adc.o | 88 | obj-$(CONFIG_NPCM_ADC) += npcm_adc.o |
| 89 | obj-$(CONFIG_PAC1934) += pac1934.o | ||
| 89 | obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o | 90 | obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o |
| 90 | obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o | 91 | obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o |
| 91 | obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o | 92 | obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o |
| @@ -116,6 +117,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o · 24 unmodified lines | |||
| 116 | obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o | 117 | obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o |
| 117 | obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o | 118 | obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o |
| 118 | obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o | 119 | obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o |
| 120 | obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o | ||
| 119 | obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o | 121 | obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o |
| 120 | obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o | 122 | obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o |
| 121 | obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o | 123 | obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o |
| @@ -887,9 +887,9 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev, · 886 unmodified lines | |||
| 887 | unsigned int old_fs; | 887 | unsigned int old_fs; |
| 888 | int ret = 0; | 888 | int ret = 0; |
| 889 | 889 | ||
| 890 | mutex_lock(&st->lock); | 890 | guard(mutex)(&st->lock); |
| 891 | if (setup_info->filter_mode == val) | 891 | if (setup_info->filter_mode == val) |
| 892 | goto out; | 892 | return 0; |
| 893 | 893 | ||
| 894 | old_fs = setup_info->fs; | 894 | old_fs = setup_info->fs; |
| 895 | old_filter_mode = setup_info->filter_mode; | 895 | old_filter_mode = setup_info->filter_mode; |
| @@ -911,12 +911,10 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev, · 15 unmodified lines | |||
| 911 | if (ret) { | 911 | if (ret) { |
| 912 | setup_info->fs = old_fs; | 912 | setup_info->fs = old_fs; |
| 913 | setup_info->filter_mode = old_filter_mode; | 913 | setup_info->filter_mode = old_filter_mode; |
| 914 | return ret; | ||
| 914 | } | 915 | } |
| 915 | 916 | ||
| 916 | out: | 917 | return 0; |
| 917 | mutex_unlock(&st->lock); | ||
| 918 | |||
| 919 | return ret; | ||
| 920 | } | 918 | } |
| 921 | 919 | ||
| 922 | static int ad4130_get_filter_mode(struct iio_dev *indio_dev, | 920 | static int ad4130_get_filter_mode(struct iio_dev *indio_dev, |
| @@ -927,9 +925,8 @@ static int ad4130_get_filter_mode(struct iio_dev *indio_dev, · 4 unmodified lines | |||
| 927 | struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup; | 925 | struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup; |
| 928 | enum ad4130_filter_mode filter_mode; | 926 | enum ad4130_filter_mode filter_mode; |
| 929 | 927 | ||
| 930 | mutex_lock(&st->lock); | 928 | guard(mutex)(&st->lock); |
| 931 | filter_mode = setup_info->filter_mode; | 929 | filter_mode = setup_info->filter_mode; |
| 932 | mutex_unlock(&st->lock); | ||
| 933 | 930 | ||
| 934 | return filter_mode; | 931 | return filter_mode; |
| 935 | } | 932 | } |
| @@ -971,7 +968,7 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel, · 35 unmodified lines | |||
| 971 | struct ad4130_chan_info *chan_info = &st->chans_info[channel]; | 968 | struct ad4130_chan_info *chan_info = &st->chans_info[channel]; |
| 972 | struct ad4130_setup_info *setup_info = &chan_info->setup; | 969 | struct ad4130_setup_info *setup_info = &chan_info->setup; |
| 973 | unsigned int pga, old_pga; | 970 | unsigned int pga, old_pga; |
| 974 | int ret = 0; | 971 | int ret; |
| 975 | 972 | ||
| 976 | for (pga = 0; pga < AD4130_MAX_PGA; pga++) | 973 | for (pga = 0; pga < AD4130_MAX_PGA; pga++) |
| 977 | if (val == st->scale_tbls[setup_info->ref_sel][pga][0] && | 974 | if (val == st->scale_tbls[setup_info->ref_sel][pga][0] && |
| @@ -981,21 +978,20 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel, · 3 unmodified lines | |||
| 981 | if (pga == AD4130_MAX_PGA) | 978 | if (pga == AD4130_MAX_PGA) |
| 982 | return -EINVAL; | 979 | return -EINVAL; |
| 983 | 980 | ||
| 984 | mutex_lock(&st->lock); | 981 | guard(mutex)(&st->lock); |
| 985 | if (pga == setup_info->pga) | 982 | if (pga == setup_info->pga) |
| 986 | goto out; | 983 | return 0; |
| 987 | 984 | ||
| 988 | old_pga = setup_info->pga; | 985 | old_pga = setup_info->pga; |
| 989 | setup_info->pga = pga; | 986 | setup_info->pga = pga; |
| 990 | 987 | ||
| 991 | ret = ad4130_write_channel_setup(st, channel, false); | 988 | ret = ad4130_write_channel_setup(st, channel, false); |
| 992 | if (ret) | 989 | if (ret) { |
| 993 | setup_info->pga = old_pga; | 990 | setup_info->pga = old_pga; |
| 991 | return ret; | ||
| 992 | } | ||
| 994 | 993 | ||
| 995 | out: | 994 | return 0; |
| 996 | mutex_unlock(&st->lock); | ||
| 997 | |||
| 998 | return ret; | ||
| 999 | } | 995 | } |
| 1000 | 996 | ||
| 1001 | static int ad4130_set_channel_freq(struct ad4130_state *st, | 997 | static int ad4130_set_channel_freq(struct ad4130_state *st, |
| @@ -1004,26 +1000,25 @@ static int ad4130_set_channel_freq(struct ad4130_state *st, · 2 unmodified lines | |||
| 1004 | struct ad4130_chan_info *chan_info = &st->chans_info[channel]; | 1000 | struct ad4130_chan_info *chan_info = &st->chans_info[channel]; |
| 1005 | struct ad4130_setup_info *setup_info = &chan_info->setup; | 1001 | struct ad4130_setup_info *setup_info = &chan_info->setup; |
| 1006 | unsigned int fs, old_fs; | 1002 | unsigned int fs, old_fs; |
| 1007 | int ret = 0; | 1003 | int ret; |
| 1008 | 1004 | ||
| 1009 | mutex_lock(&st->lock); | 1005 | guard(mutex)(&st->lock); |
| 1010 | old_fs = setup_info->fs; | 1006 | old_fs = setup_info->fs; |
| 1011 | 1007 | ||
| 1012 | ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs); | 1008 | ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs); |
| 1013 | 1009 | ||
| 1014 | if (fs == setup_info->fs) | 1010 | if (fs == setup_info->fs) |
| 1015 | goto out; | 1011 | return 0; |
| 1016 | 1012 | ||
| 1017 | setup_info->fs = fs; | 1013 | setup_info->fs = fs; |
| 1018 | 1014 | ||
| 1019 | ret = ad4130_write_channel_setup(st, channel, false); | 1015 | ret = ad4130_write_channel_setup(st, channel, false); |
| 1020 | if (ret) | 1016 | if (ret) { |
| 1021 | setup_info->fs = old_fs; | 1017 | setup_info->fs = old_fs; |
| 1018 | return ret; | ||
| 1019 | } | ||
| 1022 | 1020 | ||
| 1023 | out: | 1021 | return 0; |
| 1024 | mutex_unlock(&st->lock); | ||
| 1025 | |||
| 1026 | return ret; | ||
| 1027 | } | 1022 | } |
| 1028 | 1023 | ||
| 1029 | static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, | 1024 | static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, |
| @@ -1065,20 +1060,13 @@ static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, · 35 unmodified lines | |||
| 1065 | static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, | 1060 | static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel, |
| 1066 | int *val) | 1061 | int *val) |
| 1067 | { | 1062 | { |
| 1068 | struct ad4130_state *st = iio_priv(indio_dev); | 1063 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 1069 | int ret; | 1064 | struct ad4130_state *st = iio_priv(indio_dev); |
| 1070 | |||
| 1071 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 1072 | if (ret) | ||
| 1073 | return ret; | ||
| 1074 | 1065 | ||
| 1075 | mutex_lock(&st->lock); | 1066 | guard(mutex)(&st->lock); |
| 1076 | ret = _ad4130_read_sample(indio_dev, channel, val); | 1067 | return _ad4130_read_sample(indio_dev, channel, val); |
| 1077 | mutex_unlock(&st->lock); | 1068 | } |
| 1078 | 1069 | unreachable(); | |
| 1079 | iio_device_release_direct_mode(indio_dev); | ||
| 1080 | |||
| 1081 | return ret; | ||
| 1082 | } | 1070 | } |
| 1083 | 1071 | ||
| 1084 | static int ad4130_read_raw(struct iio_dev *indio_dev, | 1072 | static int ad4130_read_raw(struct iio_dev *indio_dev, |
| @@ -1092,24 +1080,24 @@ static int ad4130_read_raw(struct iio_dev *indio_dev, · 7 unmodified lines | |||
| 1092 | switch (info) { | 1080 | switch (info) { |
| 1093 | case IIO_CHAN_INFO_RAW: | 1081 | case IIO_CHAN_INFO_RAW: |
| 1094 | return ad4130_read_sample(indio_dev, channel, val); | 1082 | return ad4130_read_sample(indio_dev, channel, val); |
| 1095 | case IIO_CHAN_INFO_SCALE: | 1083 | case IIO_CHAN_INFO_SCALE: { |
| 1096 | mutex_lock(&st->lock); | 1084 | guard(mutex)(&st->lock); |
| 1097 | *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0]; | 1085 | *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0]; |
| 1098 | *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1]; | 1086 | *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1]; |
| 1099 | mutex_unlock(&st->lock); | ||
| 1100 | 1087 | ||
| 1101 | return IIO_VAL_INT_PLUS_NANO; | 1088 | return IIO_VAL_INT_PLUS_NANO; |
| 1089 | } | ||
| 1102 | case IIO_CHAN_INFO_OFFSET: | 1090 | case IIO_CHAN_INFO_OFFSET: |
| 1103 | *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0; | 1091 | *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0; |
| 1104 | 1092 | ||
| 1105 | return IIO_VAL_INT; | 1093 | return IIO_VAL_INT; |
| 1106 | case IIO_CHAN_INFO_SAMP_FREQ: | 1094 | case IIO_CHAN_INFO_SAMP_FREQ: { |
| 1107 | mutex_lock(&st->lock); | 1095 | guard(mutex)(&st->lock); |
| 1108 | ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs, | 1096 | ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs, |
| 1109 | val, val2); | 1097 | val, val2); |
| 1110 | mutex_unlock(&st->lock); | ||
| 1111 | 1098 | ||
| 1112 | return IIO_VAL_INT_PLUS_NANO; | 1099 | return IIO_VAL_INT_PLUS_NANO; |
| 1100 | } | ||
| 1113 | default: | 1101 | default: |
| 1114 | return -EINVAL; | 1102 | return -EINVAL; |
| 1115 | } | 1103 | } |
| @@ -1134,9 +1122,9 @@ static int ad4130_read_avail(struct iio_dev *indio_dev, · 18 unmodified lines | |||
| 1134 | 1122 | ||
| 1135 | return IIO_AVAIL_LIST; | 1123 | return IIO_AVAIL_LIST; |
| 1136 | case IIO_CHAN_INFO_SAMP_FREQ: | 1124 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 1137 | mutex_lock(&st->lock); | 1125 | scoped_guard(mutex, &st->lock) { |
| 1138 | filter_config = &ad4130_filter_configs[setup_info->filter_mode]; | 1126 | filter_config = &ad4130_filter_configs[setup_info->filter_mode]; |
| 1139 | mutex_unlock(&st->lock); | 1127 | } |
| 1140 | 1128 | ||
| 1141 | *vals = (int *)filter_config->samp_freq_avail; | 1129 | *vals = (int *)filter_config->samp_freq_avail; |
| 1142 | *length = filter_config->samp_freq_avail_len * 2; | 1130 | *length = filter_config->samp_freq_avail_len * 2; |
| @@ -1197,21 +1185,18 @@ static int ad4130_update_scan_mode(struct iio_dev *indio_dev, · 54 unmodified lines | |||
| 1197 | unsigned int val = 0; | 1185 | unsigned int val = 0; |
| 1198 | int ret; | 1186 | int ret; |
| 1199 | 1187 | ||
| 1200 | mutex_lock(&st->lock); | 1188 | guard(mutex)(&st->lock); |
| 1201 | 1189 | ||
| 1202 | for_each_set_bit(channel, scan_mask, indio_dev->num_channels) { | 1190 | for_each_set_bit(channel, scan_mask, indio_dev->num_channels) { |
| 1203 | ret = ad4130_set_channel_enable(st, channel, true); | 1191 | ret = ad4130_set_channel_enable(st, channel, true); |
| 1204 | if (ret) | 1192 | if (ret) |
| 1205 | goto out; | 1193 | return ret; |
| 1206 | 1194 | ||
| 1207 | val++; | 1195 | val++; |
| 1208 | } | 1196 | } |
| 1209 | 1197 | ||
| 1210 | st->num_enabled_channels = val; | 1198 | st->num_enabled_channels = val; |
| 1211 | 1199 | ||
| 1212 | out: | ||
| 1213 | mutex_unlock(&st->lock); | ||
| 1214 | |||
| 1215 | return 0; | 1200 | return 0; |
| 1216 | } | 1201 | } |
| 1217 | 1202 | ||
| @@ -1232,22 +1217,19 @@ static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val · 14 unmodified lines | |||
| 1232 | */ | 1217 | */ |
| 1233 | eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels); | 1218 | eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels); |
| 1234 | 1219 | ||
| 1235 | mutex_lock(&st->lock); | 1220 | guard(mutex)(&st->lock); |
| 1236 | 1221 | ||
| 1237 | ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG, | 1222 | ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG, |
| 1238 | AD4130_FIFO_CONTROL_WM_MASK, | 1223 | AD4130_FIFO_CONTROL_WM_MASK, |
| 1239 | FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK, | 1224 | FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK, |
| 1240 | ad4130_watermark_reg_val(eff))); | 1225 | ad4130_watermark_reg_val(eff))); |
| 1241 | if (ret) | 1226 | if (ret) |
| 1242 | goto out; | 1227 | return ret; |
| 1243 | 1228 | ||
| 1244 | st->effective_watermark = eff; | 1229 | st->effective_watermark = eff; |
| 1245 | st->watermark = val; | 1230 | st->watermark = val; |
| 1246 | 1231 | ||
| 1247 | out: | 1232 | return 0; |
| 1248 | mutex_unlock(&st->lock); | ||
| 1249 | |||
| 1250 | return ret; | ||
| 1251 | } | 1233 | } |
| 1252 | 1234 | ||
| 1253 | static const struct iio_info ad4130_info = { | 1235 | static const struct iio_info ad4130_info = { |
| @@ -1265,26 +1247,21 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev) · 11 unmodified lines | |||
| 1265 | struct ad4130_state *st = iio_priv(indio_dev); | 1247 | struct ad4130_state *st = iio_priv(indio_dev); |
| 1266 | int ret; | 1248 | int ret; |
| 1267 | 1249 | ||
| 1268 | mutex_lock(&st->lock); | 1250 | guard(mutex)(&st->lock); |
| 1269 | 1251 | ||
| 1270 | ret = ad4130_set_watermark_interrupt_en(st, true); | 1252 | ret = ad4130_set_watermark_interrupt_en(st, true); |
| 1271 | if (ret) | 1253 | if (ret) |
| 1272 | goto out; | 1254 | return ret; |
| 1273 | 1255 | ||
| 1274 | ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); | 1256 | ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); |
| 1275 | if (ret) | 1257 | if (ret) |
| 1276 | goto out; | 1258 | return ret; |
| 1277 | 1259 | ||
| 1278 | ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); | 1260 | ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); |
| 1279 | if (ret) | 1261 | if (ret) |
| 1280 | goto out; | 1262 | return ret; |
| 1281 | |||
| 1282 | ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); | ||
| 1283 | |||
| 1284 | out: | ||
| 1285 | mutex_unlock(&st->lock); | ||
| 1286 | 1263 | ||
| 1287 | return ret; | 1264 | return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); |
| 1288 | } | 1265 | } |
| 1289 | 1266 | ||
| 1290 | static int ad4130_buffer_predisable(struct iio_dev *indio_dev) | 1267 | static int ad4130_buffer_predisable(struct iio_dev *indio_dev) |
| @@ -1293,23 +1270,23 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev) · 2 unmodified lines | |||
| 1293 | unsigned int i; | 1270 | unsigned int i; |
| 1294 | int ret; | 1271 | int ret; |
| 1295 | 1272 | ||
| 1296 | mutex_lock(&st->lock); | 1273 | guard(mutex)(&st->lock); |
| 1297 | 1274 | ||
| 1298 | ret = ad4130_set_mode(st, AD4130_MODE_IDLE); | 1275 | ret = ad4130_set_mode(st, AD4130_MODE_IDLE); |
| 1299 | if (ret) | 1276 | if (ret) |
| 1300 | goto out; | 1277 | return ret; |
| 1301 | 1278 | ||
| 1302 | ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); | 1279 | ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); |
| 1303 | if (ret) | 1280 | if (ret) |
| 1304 | goto out; | 1281 | return ret; |
| 1305 | 1282 | ||
| 1306 | ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); | 1283 | ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); |
| 1307 | if (ret) | 1284 | if (ret) |
| 1308 | goto out; | 1285 | return ret; |
| 1309 | 1286 | ||
| 1310 | ret = ad4130_set_watermark_interrupt_en(st, false); | 1287 | ret = ad4130_set_watermark_interrupt_en(st, false); |
| 1311 | if (ret) | 1288 | if (ret) |
| 1312 | goto out; | 1289 | return ret; |
| 1313 | 1290 | ||
| 1314 | /* | 1291 | /* |
| 1315 | * update_scan_mode() is not called in the disable path, disable all | 1292 | * update_scan_mode() is not called in the disable path, disable all |
| @@ -1318,13 +1295,10 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev) · 2 unmodified lines | |||
| 1318 | for (i = 0; i < indio_dev->num_channels; i++) { | 1295 | for (i = 0; i < indio_dev->num_channels; i++) { |
| 1319 | ret = ad4130_set_channel_enable(st, i, false); | 1296 | ret = ad4130_set_channel_enable(st, i, false); |
| 1320 | if (ret) | 1297 | if (ret) |
| 1321 | goto out; | 1298 | return ret; |
| 1322 | } | 1299 | } |
| 1323 | 1300 | ||
| 1324 | out: | 1301 | return 0; |
| 1325 | mutex_unlock(&st->lock); | ||
| 1326 | |||
| 1327 | return ret; | ||
| 1328 | } | 1302 | } |
| 1329 | 1303 | ||
| 1330 | static const struct iio_buffer_setup_ops ad4130_buffer_ops = { | 1304 | static const struct iio_buffer_setup_ops ad4130_buffer_ops = { |
| @@ -1338,9 +1312,8 @@ static ssize_t hwfifo_watermark_show(struct device *dev, · 7 unmodified lines | |||
| 1338 | struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev)); | 1312 | struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev)); |
| 1339 | unsigned int val; | 1313 | unsigned int val; |
| 1340 | 1314 | ||
| 1341 | mutex_lock(&st->lock); | 1315 | guard(mutex)(&st->lock); |
| 1342 | val = st->watermark; | 1316 | val = st->watermark; |
| 1343 | mutex_unlock(&st->lock); | ||
| 1344 | 1317 | ||
| 1345 | return sysfs_emit(buf, "%d\n", val); | 1318 | return sysfs_emit(buf, "%d\n", val); |
| 1346 | } | 1319 | } |
| @@ -86,28 +86,25 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, · 85 unmodified lines | |||
| 86 | unsigned int read_val; | 86 | unsigned int read_val; |
| 87 | int ret; | 87 | int ret; |
| 88 | 88 | ||
| 89 | mutex_lock(&st->lock); | 89 | guard(mutex)(&st->lock); |
| 90 | 90 | ||
| 91 | switch (m) { | 91 | switch (m) { |
| 92 | case IIO_CHAN_INFO_RAW: | 92 | case IIO_CHAN_INFO_RAW: |
| 93 | if (st->mode != AD7091R_MODE_COMMAND) { | 93 | if (st->mode != AD7091R_MODE_COMMAND) |
| 94 | ret = -EBUSY; | 94 | return -EBUSY; |
| 95 | goto unlock; | ||
| 96 | } | ||
| 97 | 95 | ||
| 98 | ret = ad7091r_read_one(iio_dev, chan->channel, &read_val); | 96 | ret = ad7091r_read_one(iio_dev, chan->channel, &read_val); |
| 99 | if (ret) | 97 | if (ret) |
| 100 | goto unlock; | 98 | return ret; |
| 101 | 99 | ||
| 102 | *val = read_val; | 100 | *val = read_val; |
| 103 | ret = IIO_VAL_INT; | 101 | return IIO_VAL_INT; |
| 104 | break; | ||
| 105 | 102 | ||
| 106 | case IIO_CHAN_INFO_SCALE: | 103 | case IIO_CHAN_INFO_SCALE: |
| 107 | if (st->vref) { | 104 | if (st->vref) { |
| 108 | ret = regulator_get_voltage(st->vref); | 105 | ret = regulator_get_voltage(st->vref); |
| 109 | if (ret < 0) | 106 | if (ret < 0) |
| 110 | goto unlock; | 107 | return ret; |
| 111 | 108 | ||
| 112 | *val = ret / 1000; | 109 | *val = ret / 1000; |
| 113 | } else { | 110 | } else { |
| @@ -115,17 +112,11 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, · 1 unmodified line | |||
| 115 | } | 112 | } |
| 116 | 113 | ||
| 117 | *val2 = chan->scan_type.realbits; | 114 | *val2 = chan->scan_type.realbits; |
| 118 | ret = IIO_VAL_FRACTIONAL_LOG2; | 115 | return IIO_VAL_FRACTIONAL_LOG2; |
| 119 | break; | ||
| 120 | 116 | ||
| 121 | default: | 117 | default: |
| 122 | ret = -EINVAL; | 118 | return -EINVAL; |
| 123 | break; | ||
| 124 | } | 119 | } |
| 125 | |||
| 126 | unlock: | ||
| 127 | mutex_unlock(&st->lock); | ||
| 128 | return ret; | ||
| 129 | } | 120 | } |
| 130 | 121 | ||
| 131 | static int ad7091r_read_event_config(struct iio_dev *indio_dev, | 122 | static int ad7091r_read_event_config(struct iio_dev *indio_dev, |
| @@ -17,13 +17,12 @@ · 16 unmodified lines | |||
| 17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | #include <linux/iio/backend.h> | ||
| 20 | #include <linux/iio/iio.h> | 21 | #include <linux/iio/iio.h> |
| 21 | #include <linux/iio/sysfs.h> | 22 | #include <linux/iio/sysfs.h> |
| 22 | 23 | ||
| 23 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
| 24 | 25 | ||
| 25 | #include <linux/iio/adc/adi-axi-adc.h> | ||
| 26 | |||
| 27 | /* | 26 | /* |
| 28 | * ADI High-Speed ADC common spi interface registers | 27 | * ADI High-Speed ADC common spi interface registers |
| 29 | * See Application-Note AN-877: | 28 | * See Application-Note AN-877: |
| @@ -102,15 +101,20 @@ · 72 unmodified lines | |||
| 102 | #define AD9467_REG_VREF_MASK 0x0F | 101 | #define AD9467_REG_VREF_MASK 0x0F |
| 103 | 102 | ||
| 104 | struct ad9467_chip_info { | 103 | struct ad9467_chip_info { |
| 105 | struct adi_axi_adc_chip_info axi_adc_info; | 104 | const char *name; |
| 106 | unsigned int default_output_mode; | 105 | unsigned int id; |
| 107 | unsigned int vref_mask; | 106 | const struct iio_chan_spec *channels; |
| 107 | unsigned int num_channels; | ||
| 108 | const unsigned int (*scale_table)[2]; | ||
| 109 | int num_scales; | ||
| 110 | unsigned long max_rate; | ||
| 111 | unsigned int default_output_mode; | ||
| 112 | unsigned int vref_mask; | ||
| 108 | }; | 113 | }; |
| 109 | 114 | ||
| 110 | #define to_ad9467_chip_info(_info) \ | ||
| 111 | container_of(_info, struct ad9467_chip_info, axi_adc_info) | ||
| 112 | |||
| 113 | struct ad9467_state { | 115 | struct ad9467_state { |
| 116 | const struct ad9467_chip_info *info; | ||
| 117 | struct iio_backend *back; | ||
| 114 | struct spi_device *spi; | 118 | struct spi_device *spi; |
| 115 | struct clk *clk; | 119 | struct clk *clk; |
| 116 | unsigned int output_mode; | 120 | unsigned int output_mode; |
| @@ -151,10 +155,10 @@ static int ad9467_spi_write(struct spi_device *spi, unsigned int reg, · 34 unmodified lines | |||
| 151 | return spi_write(spi, buf, ARRAY_SIZE(buf)); | 155 | return spi_write(spi, buf, ARRAY_SIZE(buf)); |
| 152 | } | 156 | } |
| 153 | 157 | ||
| 154 | static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg, | 158 | static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg, |
| 155 | unsigned int writeval, unsigned int *readval) | 159 | unsigned int writeval, unsigned int *readval) |
| 156 | { | 160 | { |
| 157 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | 161 | struct ad9467_state *st = iio_priv(indio_dev); |
| 158 | struct spi_device *spi = st->spi; | 162 | struct spi_device *spi = st->spi; |
| 159 | int ret; | 163 | int ret; |
| 160 | 164 | ||
| @@ -191,10 +195,10 @@ static const unsigned int ad9467_scale_table[][2] = { · 30 unmodified lines | |||
| 191 | {2300, 8}, {2400, 9}, {2500, 10}, | 195 | {2300, 8}, {2400, 9}, {2500, 10}, |
| 192 | }; | 196 | }; |
| 193 | 197 | ||
| 194 | static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index, | 198 | static void __ad9467_get_scale(struct ad9467_state *st, int index, |
| 195 | unsigned int *val, unsigned int *val2) | 199 | unsigned int *val, unsigned int *val2) |
| 196 | { | 200 | { |
| 197 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 201 | const struct ad9467_chip_info *info = st->info; |
| 198 | const struct iio_chan_spec *chan = &info->channels[0]; | 202 | const struct iio_chan_spec *chan = &info->channels[0]; |
| 199 | unsigned int tmp; | 203 | unsigned int tmp; |
| 200 | 204 | ||
| @@ -229,52 +233,44 @@ static const struct iio_chan_spec ad9467_channels[] = { · 28 unmodified lines | |||
| 229 | }; | 233 | }; |
| 230 | 234 | ||
| 231 | static const struct ad9467_chip_info ad9467_chip_tbl = { | 235 | static const struct ad9467_chip_info ad9467_chip_tbl = { |
| 232 | .axi_adc_info = { | 236 | .name = "ad9467", |
| 233 | .name = "ad9467", | 237 | .id = CHIPID_AD9467, |
| 234 | .id = CHIPID_AD9467, | 238 | .max_rate = 250000000UL, |
| 235 | .max_rate = 250000000UL, | 239 | .scale_table = ad9467_scale_table, |
| 236 | .scale_table = ad9467_scale_table, | 240 | .num_scales = ARRAY_SIZE(ad9467_scale_table), |
| 237 | .num_scales = ARRAY_SIZE(ad9467_scale_table), | 241 | .channels = ad9467_channels, |
| 238 | .channels = ad9467_channels, | 242 | .num_channels = ARRAY_SIZE(ad9467_channels), |
| 239 | .num_channels = ARRAY_SIZE(ad9467_channels), | ||
| 240 | }, | ||
| 241 | .default_output_mode = AD9467_DEF_OUTPUT_MODE, | 243 | .default_output_mode = AD9467_DEF_OUTPUT_MODE, |
| 242 | .vref_mask = AD9467_REG_VREF_MASK, | 244 | .vref_mask = AD9467_REG_VREF_MASK, |
| 243 | }; | 245 | }; |
| 244 | 246 | ||
| 245 | static const struct ad9467_chip_info ad9434_chip_tbl = { | 247 | static const struct ad9467_chip_info ad9434_chip_tbl = { |
| 246 | .axi_adc_info = { | 248 | .name = "ad9434", |
| 247 | .name = "ad9434", | 249 | .id = CHIPID_AD9434, |
| 248 | .id = CHIPID_AD9434, | 250 | .max_rate = 500000000UL, |
| 249 | .max_rate = 500000000UL, | 251 | .scale_table = ad9434_scale_table, |
| 250 | .scale_table = ad9434_scale_table, | 252 | .num_scales = ARRAY_SIZE(ad9434_scale_table), |
| 251 | .num_scales = ARRAY_SIZE(ad9434_scale_table), | 253 | .channels = ad9434_channels, |
| 252 | .channels = ad9434_channels, | 254 | .num_channels = ARRAY_SIZE(ad9434_channels), |
| 253 | .num_channels = ARRAY_SIZE(ad9434_channels), | ||
| 254 | }, | ||
| 255 | .default_output_mode = AD9434_DEF_OUTPUT_MODE, | 255 | .default_output_mode = AD9434_DEF_OUTPUT_MODE, |
| 256 | .vref_mask = AD9434_REG_VREF_MASK, | 256 | .vref_mask = AD9434_REG_VREF_MASK, |
| 257 | }; | 257 | }; |
| 258 | 258 | ||
| 259 | static const struct ad9467_chip_info ad9265_chip_tbl = { | 259 | static const struct ad9467_chip_info ad9265_chip_tbl = { |
| 260 | .axi_adc_info = { | 260 | .name = "ad9265", |
| 261 | .name = "ad9265", | 261 | .id = CHIPID_AD9265, |
| 262 | .id = CHIPID_AD9265, | 262 | .max_rate = 125000000UL, |
| 263 | .max_rate = 125000000UL, | 263 | .scale_table = ad9265_scale_table, |
| 264 | .scale_table = ad9265_scale_table, | 264 | .num_scales = ARRAY_SIZE(ad9265_scale_table), |
| 265 | .num_scales = ARRAY_SIZE(ad9265_scale_table), | 265 | .channels = ad9467_channels, |
| 266 | .channels = ad9467_channels, | 266 | .num_channels = ARRAY_SIZE(ad9467_channels), |
| 267 | .num_channels = ARRAY_SIZE(ad9467_channels), | ||
| 268 | }, | ||
| 269 | .default_output_mode = AD9265_DEF_OUTPUT_MODE, | 267 | .default_output_mode = AD9265_DEF_OUTPUT_MODE, |
| 270 | .vref_mask = AD9265_REG_VREF_MASK, | 268 | .vref_mask = AD9265_REG_VREF_MASK, |
| 271 | }; | 269 | }; |
| 272 | 270 | ||
| 273 | static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) | 271 | static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2) |
| 274 | { | 272 | { |
| 275 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 273 | const struct ad9467_chip_info *info = st->info; |
| 276 | const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info); | ||
| 277 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | ||
| 278 | unsigned int i, vref_val; | 274 | unsigned int i, vref_val; |
| 279 | int ret; | 275 | int ret; |
| 280 | 276 | ||
| @@ -282,7 +278,7 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) · 1 unmodified line | |||
| 282 | if (ret < 0) | 278 | if (ret < 0) |
| 283 | return ret; | 279 | return ret; |
| 284 | 280 | ||
| 285 | vref_val = ret & info1->vref_mask; | 281 | vref_val = ret & info->vref_mask; |
| 286 | 282 | ||
| 287 | for (i = 0; i < info->num_scales; i++) { | 283 | for (i = 0; i < info->num_scales; i++) { |
| 288 | if (vref_val == info->scale_table[i][1]) | 284 | if (vref_val == info->scale_table[i][1]) |
| @@ -292,15 +288,14 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) · 3 unmodified lines | |||
| 292 | if (i == info->num_scales) | 288 | if (i == info->num_scales) |
| 293 | return -ERANGE; | 289 | return -ERANGE; |
| 294 | 290 | ||
| 295 | __ad9467_get_scale(conv, i, val, val2); | 291 | __ad9467_get_scale(st, i, val, val2); |
| 296 | 292 | ||
| 297 | return IIO_VAL_INT_PLUS_MICRO; | 293 | return IIO_VAL_INT_PLUS_MICRO; |
| 298 | } | 294 | } |
| 299 | 295 | ||
| 300 | static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) | 296 | static int ad9467_set_scale(struct ad9467_state *st, int val, int val2) |
| 301 | { | 297 | { |
| 302 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 298 | const struct ad9467_chip_info *info = st->info; |
| 303 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | ||
| 304 | unsigned int scale_val[2]; | 299 | unsigned int scale_val[2]; |
| 305 | unsigned int i; | 300 | unsigned int i; |
| 306 | int ret; | 301 | int ret; |
| @@ -309,7 +304,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) · 2 unmodified lines | |||
| 309 | return -EINVAL; | 304 | return -EINVAL; |
| 310 | 305 | ||
| 311 | for (i = 0; i < info->num_scales; i++) { | 306 | for (i = 0; i < info->num_scales; i++) { |
| 312 | __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]); | 307 | __ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]); |
| 313 | if (scale_val[0] != val || scale_val[1] != val2) | 308 | if (scale_val[0] != val || scale_val[1] != val2) |
| 314 | continue; | 309 | continue; |
| 315 | 310 | ||
| @@ -326,15 +321,15 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) · 10 unmodified lines | |||
| 326 | return -EINVAL; | 321 | return -EINVAL; |
| 327 | } | 322 | } |
| 328 | 323 | ||
| 329 | static int ad9467_read_raw(struct adi_axi_adc_conv *conv, | 324 | static int ad9467_read_raw(struct iio_dev *indio_dev, |
| 330 | struct iio_chan_spec const *chan, | 325 | struct iio_chan_spec const *chan, |
| 331 | int *val, int *val2, long m) | 326 | int *val, int *val2, long m) |
| 332 | { | 327 | { |
| 333 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | 328 | struct ad9467_state *st = iio_priv(indio_dev); |
| 334 | 329 | ||
| 335 | switch (m) { | 330 | switch (m) { |
| 336 | case IIO_CHAN_INFO_SCALE: | 331 | case IIO_CHAN_INFO_SCALE: |
| 337 | return ad9467_get_scale(conv, val, val2); | 332 | return ad9467_get_scale(st, val, val2); |
| 338 | case IIO_CHAN_INFO_SAMP_FREQ: | 333 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 339 | *val = clk_get_rate(st->clk); | 334 | *val = clk_get_rate(st->clk); |
| 340 | 335 | ||
| @@ -344,17 +339,17 @@ static int ad9467_read_raw(struct adi_axi_adc_conv *conv, · 3 unmodified lines | |||
| 344 | } | 339 | } |
| 345 | } | 340 | } |
| 346 | 341 | ||
| 347 | static int ad9467_write_raw(struct adi_axi_adc_conv *conv, | 342 | static int ad9467_write_raw(struct iio_dev *indio_dev, |
| 348 | struct iio_chan_spec const *chan, | 343 | struct iio_chan_spec const *chan, |
| 349 | int val, int val2, long mask) | 344 | int val, int val2, long mask) |
| 350 | { | 345 | { |
| 351 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 346 | struct ad9467_state *st = iio_priv(indio_dev); |
| 352 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | 347 | const struct ad9467_chip_info *info = st->info; |
| 353 | long r_clk; | 348 | long r_clk; |
| 354 | 349 | ||
| 355 | switch (mask) { | 350 | switch (mask) { |
| 356 | case IIO_CHAN_INFO_SCALE: | 351 | case IIO_CHAN_INFO_SCALE: |
| 357 | return ad9467_set_scale(conv, val, val2); | 352 | return ad9467_set_scale(st, val, val2); |
| 358 | case IIO_CHAN_INFO_SAMP_FREQ: | 353 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 359 | r_clk = clk_round_rate(st->clk, val); | 354 | r_clk = clk_round_rate(st->clk, val); |
| 360 | if (r_clk < 0 || r_clk > info->max_rate) { | 355 | if (r_clk < 0 || r_clk > info->max_rate) { |
| @@ -369,13 +364,13 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv, · 8 unmodified lines | |||
| 369 | } | 364 | } |
| 370 | } | 365 | } |
| 371 | 366 | ||
| 372 | static int ad9467_read_avail(struct adi_axi_adc_conv *conv, | 367 | static int ad9467_read_avail(struct iio_dev *indio_dev, |
| 373 | struct iio_chan_spec const *chan, | 368 | struct iio_chan_spec const *chan, |
| 374 | const int **vals, int *type, int *length, | 369 | const int **vals, int *type, int *length, |
| 375 | long mask) | 370 | long mask) |
| 376 | { | 371 | { |
| 377 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 372 | struct ad9467_state *st = iio_priv(indio_dev); |
| 378 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | 373 | const struct ad9467_chip_info *info = st->info; |
| 379 | 374 | ||
| 380 | switch (mask) { | 375 | switch (mask) { |
| 381 | case IIO_CHAN_INFO_SCALE: | 376 | case IIO_CHAN_INFO_SCALE: |
| @@ -389,6 +384,33 @@ static int ad9467_read_avail(struct adi_axi_adc_conv *conv, · 7 unmodified lines | |||
| 389 | } | 384 | } |
| 390 | } | 385 | } |
| 391 | 386 | ||
| 387 | static int ad9467_update_scan_mode(struct iio_dev *indio_dev, | ||
| 388 | const unsigned long *scan_mask) | ||
| 389 | { | ||
| 390 | struct ad9467_state *st = iio_priv(indio_dev); | ||
| 391 | unsigned int c; | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | for (c = 0; c < st->info->num_channels; c++) { | ||
| 395 | if (test_bit(c, scan_mask)) | ||
| 396 | ret = iio_backend_chan_enable(st->back, c); | ||
| 397 | else | ||
| 398 | ret = iio_backend_chan_disable(st->back, c); | ||
| 399 | if (ret) | ||
| 400 | return ret; | ||
| 401 | } | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | static const struct iio_info ad9467_info = { | ||
| 407 | .read_raw = ad9467_read_raw, | ||
| 408 | .write_raw = ad9467_write_raw, | ||
| 409 | .update_scan_mode = ad9467_update_scan_mode, | ||
| 410 | .debugfs_reg_access = ad9467_reg_access, | ||
| 411 | .read_avail = ad9467_read_avail, | ||
| 412 | }; | ||
| 413 | |||
| 392 | static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) | 414 | static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) |
| 393 | { | 415 | { |
| 394 | int ret; | 416 | int ret; |
| @@ -401,10 +423,9 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) · 6 unmodified lines | |||
| 401 | AN877_ADC_TRANSFER_SYNC); | 423 | AN877_ADC_TRANSFER_SYNC); |
| 402 | } | 424 | } |
| 403 | 425 | ||
| 404 | static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) | 426 | static int ad9467_scale_fill(struct ad9467_state *st) |
| 405 | { | 427 | { |
| 406 | const struct adi_axi_adc_chip_info *info = conv->chip_info; | 428 | const struct ad9467_chip_info *info = st->info; |
| 407 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | ||
| 408 | unsigned int i, val1, val2; | 429 | unsigned int i, val1, val2; |
| 409 | 430 | ||
| 410 | st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales, | 431 | st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales, |
| @@ -413,7 +434,7 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) · 2 unmodified lines | |||
| 413 | return -ENOMEM; | 434 | return -ENOMEM; |
| 414 | 435 | ||
| 415 | for (i = 0; i < info->num_scales; i++) { | 436 | for (i = 0; i < info->num_scales; i++) { |
| 416 | __ad9467_get_scale(conv, i, &val1, &val2); | 437 | __ad9467_get_scale(st, i, &val1, &val2); |
| 417 | st->scales[i][0] = val1; | 438 | st->scales[i][0] = val1; |
| 418 | st->scales[i][1] = val2; | 439 | st->scales[i][1] = val2; |
| 419 | } | 440 | } |
| @@ -421,11 +442,27 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv) · 1 unmodified line | |||
| 421 | return 0; | 442 | return 0; |
| 422 | } | 443 | } |
| 423 | 444 | ||
| 424 | static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv) | 445 | static int ad9467_setup(struct ad9467_state *st) |
| 425 | { | 446 | { |
| 426 | struct ad9467_state *st = adi_axi_adc_conv_priv(conv); | 447 | struct iio_backend_data_fmt data = { |
| 448 | .sign_extend = true, | ||
| 449 | .enable = true, | ||
| 450 | }; | ||
| 451 | unsigned int c, mode; | ||
| 452 | int ret; | ||
| 453 | |||
| 454 | mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; | ||
| 455 | ret = ad9467_outputmode_set(st->spi, mode); | ||
| 456 | if (ret) | ||
| 457 | return ret; | ||
| 427 | 458 | ||
| 428 | return ad9467_outputmode_set(st->spi, st->output_mode); | 459 | for (c = 0; c < st->info->num_channels; c++) { |
| 460 | ret = iio_backend_data_format_set(st->back, c, &data); | ||
| 461 | if (ret) | ||
| 462 | return ret; | ||
| 463 | } | ||
| 464 | |||
| 465 | return 0; | ||
| 429 | } | 466 | } |
| 430 | 467 | ||
| 431 | static int ad9467_reset(struct device *dev) | 468 | static int ad9467_reset(struct device *dev) |
| @@ -443,25 +480,65 @@ static int ad9467_reset(struct device *dev) · 11 unmodified lines | |||
| 443 | return 0; | 480 | return 0; |
| 444 | } | 481 | } |
| 445 | 482 | ||
| 483 | static int ad9467_iio_backend_get(struct ad9467_state *st) | ||
| 484 | { | ||
| 485 | struct device *dev = &st->spi->dev; | ||
| 486 | struct device_node *__back; | ||
| 487 | |||
| 488 | st->back = devm_iio_backend_get(dev, NULL); | ||
| 489 | if (!IS_ERR(st->back)) | ||
| 490 | return 0; | ||
| 491 | /* If not found, don't error out as we might have legacy DT property */ | ||
| 492 | if (PTR_ERR(st->back) != -ENOENT) | ||
| 493 | return PTR_ERR(st->back); | ||
| 494 | |||
| 495 | /* | ||
| 496 | * if we don't get the backend using the normal API's, use the legacy | ||
| 497 | * 'adi,adc-dev' property. So we get all nodes with that property, and | ||
| 498 | * look for the one pointing at us. Then we directly lookup that fwnode | ||
| 499 | * on the backend list of registered devices. This is done so we don't | ||
| 500 | * make io-backends mandatory which would break DT ABI. | ||
| 501 | */ | ||
| 502 | for_each_node_with_property(__back, "adi,adc-dev") { | ||
| 503 | struct device_node *__me; | ||
| 504 | |||
| 505 | __me = of_parse_phandle(__back, "adi,adc-dev", 0); | ||
| 506 | if (!__me) | ||
| 507 | continue; | ||
| 508 | |||
| 509 | if (!device_match_of_node(dev, __me)) { | ||
| 510 | of_node_put(__me); | ||
| 511 | continue; | ||
| 512 | } | ||
| 513 | |||
| 514 | of_node_put(__me); | ||
| 515 | st->back = __devm_iio_backend_get_from_fwnode_lookup(dev, | ||
| 516 | of_fwnode_handle(__back)); | ||
| 517 | of_node_put(__back); | ||
| 518 | return PTR_ERR_OR_ZERO(st->back); | ||
| 519 | } | ||
| 520 | |||
| 521 | return -ENODEV; | ||
| 522 | } | ||
| 523 | |||
| 446 | static int ad9467_probe(struct spi_device *spi) | 524 | static int ad9467_probe(struct spi_device *spi) |
| 447 | { | 525 | { |
| 448 | const struct ad9467_chip_info *info; | 526 | struct iio_dev *indio_dev; |
| 449 | struct adi_axi_adc_conv *conv; | ||
| 450 | struct ad9467_state *st; | 527 | struct ad9467_state *st; |
| 451 | unsigned int id; | 528 | unsigned int id; |
| 452 | int ret; | 529 | int ret; |
| 453 | 530 | ||
| 454 | info = spi_get_device_match_data(spi); | 531 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
| 455 | if (!info) | 532 | if (!indio_dev) |
| 456 | return -ENODEV; | 533 | return -ENOMEM; |
| 457 | |||
| 458 | conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st)); | ||
| 459 | if (IS_ERR(conv)) | ||
| 460 | return PTR_ERR(conv); | ||
| 461 | 534 | ||
| 462 | st = adi_axi_adc_conv_priv(conv); | 535 | st = iio_priv(indio_dev); |
| 463 | st->spi = spi; | 536 | st->spi = spi; |
| 464 | 537 | ||
| 538 | st->info = spi_get_device_match_data(spi); | ||
| 539 | if (!st->info) | ||
| 540 | return -ENODEV; | ||
| 541 | |||
| 465 | st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk"); | 542 | st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk"); |
| 466 | if (IS_ERR(st->clk)) | 543 | if (IS_ERR(st->clk)) |
| 467 | return PTR_ERR(st->clk); | 544 | return PTR_ERR(st->clk); |
| @@ -475,29 +552,39 @@ static int ad9467_probe(struct spi_device *spi) · 7 unmodified lines | |||
| 475 | if (ret) | 552 | if (ret) |
| 476 | return ret; | 553 | return ret; |
| 477 | 554 | ||
| 478 | conv->chip_info = &info->axi_adc_info; | 555 | ret = ad9467_scale_fill(st); |
| 479 | |||
| 480 | ret = ad9467_scale_fill(conv); | ||
| 481 | if (ret) | 556 | if (ret) |
| 482 | return ret; | 557 | return ret; |
| 483 | 558 | ||
| 484 | id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); | 559 | id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); |
| 485 | if (id != conv->chip_info->id) { | 560 | if (id != st->info->id) { |
| 486 | dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", | 561 | dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", |
| 487 | id, conv->chip_info->id); | 562 | id, st->info->id); |
| 488 | return -ENODEV; | 563 | return -ENODEV; |
| 489 | } | 564 | } |
| 490 | 565 | ||
| 491 | conv->reg_access = ad9467_reg_access; | 566 | indio_dev->name = st->info->name; |
| 492 | conv->write_raw = ad9467_write_raw; | 567 | indio_dev->channels = st->info->channels; |
| 493 | conv->read_raw = ad9467_read_raw; | 568 | indio_dev->num_channels = st->info->num_channels; |
| 494 | conv->read_avail = ad9467_read_avail; | 569 | indio_dev->info = &ad9467_info; |
| 495 | conv->preenable_setup = ad9467_preenable_setup; | ||
| 496 | 570 | ||
| 497 | st->output_mode = info->default_output_mode | | 571 | ret = ad9467_iio_backend_get(st); |
| 498 | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; | 572 | if (ret) |
| 573 | return ret; | ||
| 499 | 574 | ||
| 500 | return 0; | 575 | ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev); |
| 576 | if (ret) | ||
| 577 | return ret; | ||
| 578 | |||
| 579 | ret = devm_iio_backend_enable(&spi->dev, st->back); | ||
| 580 | if (ret) | ||
| 581 | return ret; | ||
| 582 | |||
| 583 | ret = ad9467_setup(st); | ||
| 584 | if (ret) | ||
| 585 | return ret; | ||
| 586 | |||
| 587 | return devm_iio_device_register(&spi->dev, indio_dev); | ||
| 501 | } | 588 | } |
| 502 | 589 | ||
| 503 | static const struct of_device_id ad9467_of_match[] = { | 590 | static const struct of_device_id ad9467_of_match[] = { |
| @@ -529,4 +616,4 @@ module_spi_driver(ad9467_driver); · 25 unmodified lines | |||
| 529 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); | 616 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
| 530 | MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); | 617 | MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); |
| 531 | MODULE_LICENSE("GPL v2"); | 618 | MODULE_LICENSE("GPL v2"); |
| 532 | MODULE_IMPORT_NS(IIO_ADI_AXI); | 619 | MODULE_IMPORT_NS(IIO_BACKEND); |
| @@ -568,6 +568,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA); · 567 unmodified lines | |||
| 568 | static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) | 568 | static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) |
| 569 | { | 569 | { |
| 570 | struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); | 570 | struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); |
| 571 | unsigned long irq_flags = irq_get_trigger_type(sigma_delta->spi->irq); | ||
| 571 | int ret; | 572 | int ret; |
| 572 | 573 | ||
| 573 | if (dev != &sigma_delta->spi->dev) { | 574 | if (dev != &sigma_delta->spi->dev) { |
| @@ -588,9 +589,13 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de · 14 unmodified lines | |||
| 588 | /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */ | 589 | /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */ |
| 589 | irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY); | 590 | irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY); |
| 590 | 591 | ||
| 592 | /* Allow overwriting the flags from firmware */ | ||
| 593 | if (!irq_flags) | ||
| 594 | irq_flags = sigma_delta->info->irq_flags; | ||
| 595 | |||
| 591 | ret = devm_request_irq(dev, sigma_delta->spi->irq, | 596 | ret = devm_request_irq(dev, sigma_delta->spi->irq, |
| 592 | ad_sd_data_rdy_trig_poll, | 597 | ad_sd_data_rdy_trig_poll, |
| 593 | sigma_delta->info->irq_flags | IRQF_NO_AUTOEN, | 598 | irq_flags | IRQF_NO_AUTOEN, |
| 594 | indio_dev->name, | 599 | indio_dev->name, |
| 595 | sigma_delta); | 600 | sigma_delta); |
| 596 | if (ret) | 601 | if (ret) |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/bitfield.h> | 9 | #include <linux/bitfield.h> |
| 10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| 11 | #include <linux/err.h> | ||
| 11 | #include <linux/io.h> | 12 | #include <linux/io.h> |
| 12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| @@ -17,13 +18,12 @@ · 3 unmodified lines | |||
| 17 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| 18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 19 | 20 | ||
| 20 | #include <linux/iio/iio.h> | ||
| 21 | #include <linux/iio/sysfs.h> | ||
| 22 | #include <linux/iio/buffer.h> | ||
| 23 | #include <linux/iio/buffer-dmaengine.h> | ||
| 24 | |||
| 25 | #include <linux/fpga/adi-axi-common.h> | 21 | #include <linux/fpga/adi-axi-common.h> |
| 26 | #include <linux/iio/adc/adi-axi-adc.h> | 22 | |
| 23 | #include <linux/iio/backend.h> | ||
| 24 | #include <linux/iio/buffer-dmaengine.h> | ||
| 25 | #include <linux/iio/buffer.h> | ||
| 26 | #include <linux/iio/iio.h> | ||
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * Register definitions: | 29 | * Register definitions: |
| @@ -44,6 +44,7 @@ · 14 unmodified lines | |||
| 44 | #define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) | 44 | #define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) |
| 45 | #define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) | 45 | #define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) |
| 46 | #define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) | 46 | #define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) |
| 47 | #define ADI_AXI_REG_CHAN_CTRL_FMT_MASK GENMASK(6, 4) | ||
| 47 | #define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) | 48 | #define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) |
| 48 | #define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) | 49 | #define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) |
| 49 | #define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) | 50 | #define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) |
| @@ -55,286 +56,100 @@ · 5 unmodified lines | |||
| 55 | ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ | 56 | ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ |
| 56 | ADI_AXI_REG_CHAN_CTRL_ENABLE) | 57 | ADI_AXI_REG_CHAN_CTRL_ENABLE) |
| 57 | 58 | ||
| 58 | struct adi_axi_adc_core_info { | ||
| 59 | unsigned int version; | ||
| 60 | }; | ||
| 61 | |||
| 62 | struct adi_axi_adc_state { | 59 | struct adi_axi_adc_state { |
| 63 | struct mutex lock; | ||
| 64 | |||
| 65 | struct adi_axi_adc_client *client; | ||
| 66 | struct regmap *regmap; | 60 | struct regmap *regmap; |
| 67 | }; | ||
| 68 | |||
| 69 | struct adi_axi_adc_client { | ||
| 70 | struct list_head entry; | ||
| 71 | struct adi_axi_adc_conv conv; | ||
| 72 | struct adi_axi_adc_state *state; | ||
| 73 | struct device *dev; | 61 | struct device *dev; |
| 74 | const struct adi_axi_adc_core_info *info; | ||
| 75 | }; | 62 | }; |
| 76 | 63 | ||
| 77 | static LIST_HEAD(registered_clients); | 64 | static int axi_adc_enable(struct iio_backend *back) |
| 78 | static DEFINE_MUTEX(registered_clients_lock); | ||
| 79 | |||
| 80 | static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) | ||
| 81 | { | ||
| 82 | return container_of(conv, struct adi_axi_adc_client, conv); | ||
| 83 | } | ||
| 84 | |||
| 85 | void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) | ||
| 86 | { | ||
| 87 | struct adi_axi_adc_client *cl = conv_to_client(conv); | ||
| 88 | |||
| 89 | return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), | ||
| 90 | IIO_DMA_MINALIGN); | ||
| 91 | } | ||
| 92 | EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI); | ||
| 93 | |||
| 94 | static int adi_axi_adc_config_dma_buffer(struct device *dev, | ||
| 95 | struct iio_dev *indio_dev) | ||
| 96 | { | ||
| 97 | const char *dma_name; | ||
| 98 | |||
| 99 | if (!device_property_present(dev, "dmas")) | ||
| 100 | return 0; | ||
| 101 | |||
| 102 | if (device_property_read_string(dev, "dma-names", &dma_name)) | ||
| 103 | dma_name = "rx"; | ||
| 104 | |||
| 105 | return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, | ||
| 106 | indio_dev, dma_name); | ||
| 107 | } | ||
| 108 | |||
| 109 | static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, | ||
| 110 | struct iio_chan_spec const *chan, | ||
| 111 | int *val, int *val2, long mask) | ||
| 112 | { | ||
| 113 | struct adi_axi_adc_state *st = iio_priv(indio_dev); | ||
| 114 | struct adi_axi_adc_conv *conv = &st->client->conv; | ||
| 115 | |||
| 116 | if (!conv->read_raw) | ||
| 117 | return -EOPNOTSUPP; | ||
| 118 | |||
| 119 | return conv->read_raw(conv, chan, val, val2, mask); | ||
| 120 | } | ||
| 121 | |||
| 122 | static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, | ||
| 123 | struct iio_chan_spec const *chan, | ||
| 124 | int val, int val2, long mask) | ||
| 125 | { | ||
| 126 | struct adi_axi_adc_state *st = iio_priv(indio_dev); | ||
| 127 | struct adi_axi_adc_conv *conv = &st->client->conv; | ||
| 128 | |||
| 129 | if (!conv->write_raw) | ||
| 130 | return -EOPNOTSUPP; | ||
| 131 | |||
| 132 | return conv->write_raw(conv, chan, val, val2, mask); | ||
| 133 | } | ||
| 134 | |||
| 135 | static int adi_axi_adc_read_avail(struct iio_dev *indio_dev, | ||
| 136 | struct iio_chan_spec const *chan, | ||
| 137 | const int **vals, int *type, int *length, | ||
| 138 | long mask) | ||
| 139 | { | ||
| 140 | struct adi_axi_adc_state *st = iio_priv(indio_dev); | ||
| 141 | struct adi_axi_adc_conv *conv = &st->client->conv; | ||
| 142 | |||
| 143 | if (!conv->read_avail) | ||
| 144 | return -EOPNOTSUPP; | ||
| 145 | |||
| 146 | return conv->read_avail(conv, chan, vals, type, length, mask); | ||
| 147 | } | ||
| 148 | |||
| 149 | static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, | ||
| 150 | const unsigned long *scan_mask) | ||
| 151 | { | 65 | { |
| 152 | struct adi_axi_adc_state *st = iio_priv(indio_dev); | 66 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 153 | struct adi_axi_adc_conv *conv = &st->client->conv; | ||
| 154 | unsigned int i; | ||
| 155 | int ret; | 67 | int ret; |
| 156 | 68 | ||
| 157 | for (i = 0; i < conv->chip_info->num_channels; i++) { | 69 | ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, |
| 158 | if (test_bit(i, scan_mask)) | 70 | ADI_AXI_REG_RSTN_MMCM_RSTN); |
| 159 | ret = regmap_set_bits(st->regmap, | 71 | if (ret) |
| 160 | ADI_AXI_REG_CHAN_CTRL(i), | 72 | return ret; |
| 161 | ADI_AXI_REG_CHAN_CTRL_ENABLE); | ||
| 162 | else | ||
| 163 | ret = regmap_clear_bits(st->regmap, | ||
| 164 | ADI_AXI_REG_CHAN_CTRL(i), | ||
| 165 | ADI_AXI_REG_CHAN_CTRL_ENABLE); | ||
| 166 | if (ret) | ||
| 167 | return ret; | ||
| 168 | } | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, | ||
| 174 | size_t sizeof_priv) | ||
| 175 | { | ||
| 176 | struct adi_axi_adc_client *cl; | ||
| 177 | size_t alloc_size; | ||
| 178 | |||
| 179 | alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN); | ||
| 180 | if (sizeof_priv) | ||
| 181 | alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN); | ||
| 182 | |||
| 183 | cl = kzalloc(alloc_size, GFP_KERNEL); | ||
| 184 | if (!cl) | ||
| 185 | return ERR_PTR(-ENOMEM); | ||
| 186 | |||
| 187 | mutex_lock(®istered_clients_lock); | ||
| 188 | |||
| 189 | cl->dev = get_device(dev); | ||
| 190 | |||
| 191 | list_add_tail(&cl->entry, ®istered_clients); | ||
| 192 | |||
| 193 | mutex_unlock(®istered_clients_lock); | ||
| 194 | 73 | ||
| 195 | return &cl->conv; | 74 | fsleep(10000); |
| 75 | return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN, | ||
| 76 | ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); | ||
| 196 | } | 77 | } |
| 197 | 78 | ||
| 198 | static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) | 79 | static void axi_adc_disable(struct iio_backend *back) |
| 199 | { | 80 | { |
| 200 | struct adi_axi_adc_client *cl = conv_to_client(conv); | 81 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 201 | |||
| 202 | mutex_lock(®istered_clients_lock); | ||
| 203 | |||
| 204 | list_del(&cl->entry); | ||
| 205 | put_device(cl->dev); | ||
| 206 | 82 | ||
| 207 | mutex_unlock(®istered_clients_lock); | 83 | regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); |
| 208 | |||
| 209 | kfree(cl); | ||
| 210 | } | 84 | } |
| 211 | 85 | ||
| 212 | static void devm_adi_axi_adc_conv_release(void *conv) | 86 | static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan, |
| 87 | const struct iio_backend_data_fmt *data) | ||
| 213 | { | 88 | { |
| 214 | adi_axi_adc_conv_unregister(conv); | 89 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 90 | u32 val; | ||
| 91 | |||
| 92 | if (!data->enable) | ||
| 93 | return regmap_clear_bits(st->regmap, | ||
| 94 | ADI_AXI_REG_CHAN_CTRL(chan), | ||
| 95 | ADI_AXI_REG_CHAN_CTRL_FMT_EN); | ||
| 96 | |||
| 97 | val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true); | ||
| 98 | if (data->sign_extend) | ||
| 99 | val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true); | ||
| 100 | if (data->type == IIO_BACKEND_OFFSET_BINARY) | ||
| 101 | val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true); | ||
| 102 | |||
| 103 | return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), | ||
| 104 | ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val); | ||
| 215 | } | 105 | } |
| 216 | 106 | ||
| 217 | struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, | 107 | static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan) |
| 218 | size_t sizeof_priv) | ||
| 219 | { | 108 | { |
| 220 | struct adi_axi_adc_conv *conv; | 109 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 221 | int ret; | ||
| 222 | |||
| 223 | conv = adi_axi_adc_conv_register(dev, sizeof_priv); | ||
| 224 | if (IS_ERR(conv)) | ||
| 225 | return conv; | ||
| 226 | 110 | ||
| 227 | ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release, | 111 | return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), |
| 228 | conv); | 112 | ADI_AXI_REG_CHAN_CTRL_ENABLE); |
| 229 | if (ret) | ||
| 230 | return ERR_PTR(ret); | ||
| 231 | |||
| 232 | return conv; | ||
| 233 | } | 113 | } |
| 234 | EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI); | ||
| 235 | |||
| 236 | static const struct iio_info adi_axi_adc_info = { | ||
| 237 | .read_raw = &adi_axi_adc_read_raw, | ||
| 238 | .write_raw = &adi_axi_adc_write_raw, | ||
| 239 | .update_scan_mode = &adi_axi_adc_update_scan_mode, | ||
| 240 | .read_avail = &adi_axi_adc_read_avail, | ||
| 241 | }; | ||
| 242 | |||
| 243 | static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { | ||
| 244 | .version = ADI_AXI_PCORE_VER(10, 0, 'a'), | ||
| 245 | }; | ||
| 246 | 114 | ||
| 247 | static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) | 115 | static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan) |
| 248 | { | 116 | { |
| 249 | const struct adi_axi_adc_core_info *info; | 117 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 250 | struct adi_axi_adc_client *cl; | ||
| 251 | struct device_node *cln; | ||
| 252 | |||
| 253 | info = of_device_get_match_data(dev); | ||
| 254 | if (!info) | ||
| 255 | return ERR_PTR(-ENODEV); | ||
| 256 | |||
| 257 | cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); | ||
| 258 | if (!cln) { | ||
| 259 | dev_err(dev, "No 'adi,adc-dev' node defined\n"); | ||
| 260 | return ERR_PTR(-ENODEV); | ||
| 261 | } | ||
| 262 | |||
| 263 | mutex_lock(®istered_clients_lock); | ||
| 264 | |||
| 265 | list_for_each_entry(cl, ®istered_clients, entry) { | ||
| 266 | if (!cl->dev) | ||
| 267 | continue; | ||
| 268 | |||
| 269 | if (cl->dev->of_node != cln) | ||
| 270 | continue; | ||
| 271 | |||
| 272 | if (!try_module_get(cl->dev->driver->owner)) { | ||
| 273 | mutex_unlock(®istered_clients_lock); | ||
| 274 | of_node_put(cln); | ||
| 275 | return ERR_PTR(-ENODEV); | ||
| 276 | } | ||
| 277 | |||
| 278 | get_device(cl->dev); | ||
| 279 | cl->info = info; | ||
| 280 | mutex_unlock(®istered_clients_lock); | ||
| 281 | of_node_put(cln); | ||
| 282 | return cl; | ||
| 283 | } | ||
| 284 | 118 | ||
| 285 | mutex_unlock(®istered_clients_lock); | 119 | return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan), |
| 286 | of_node_put(cln); | 120 | ADI_AXI_REG_CHAN_CTRL_ENABLE); |
| 287 | |||
| 288 | return ERR_PTR(-EPROBE_DEFER); | ||
| 289 | } | 121 | } |
| 290 | 122 | ||
| 291 | static int adi_axi_adc_setup_channels(struct device *dev, | 123 | static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back, |
| 292 | struct adi_axi_adc_state *st) | 124 | struct iio_dev *indio_dev) |
| 293 | { | 125 | { |
| 294 | struct adi_axi_adc_conv *conv = &st->client->conv; | 126 | struct adi_axi_adc_state *st = iio_backend_get_priv(back); |
| 295 | int i, ret; | 127 | struct iio_buffer *buffer; |
| 128 | const char *dma_name; | ||
| 129 | int ret; | ||
| 296 | 130 | ||
| 297 | if (conv->preenable_setup) { | 131 | if (device_property_read_string(st->dev, "dma-names", &dma_name)) |
| 298 | ret = conv->preenable_setup(conv); | 132 | dma_name = "rx"; |
| 299 | if (ret) | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | 133 | ||
| 303 | for (i = 0; i < conv->chip_info->num_channels; i++) { | 134 | buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name); |
| 304 | ret = regmap_write(st->regmap, ADI_AXI_REG_CHAN_CTRL(i), | 135 | if (IS_ERR(buffer)) { |
| 305 | ADI_AXI_REG_CHAN_CTRL_DEFAULTS); | 136 | dev_err(st->dev, "Could not get DMA buffer, %ld\n", |
| 306 | if (ret) | 137 | PTR_ERR(buffer)); |
| 307 | return ret; | 138 | return ERR_CAST(buffer); |
| 308 | } | 139 | } |
| 309 | 140 | ||
| 310 | return 0; | 141 | indio_dev->modes |= INDIO_BUFFER_HARDWARE; |
| 311 | } | 142 | ret = iio_device_attach_buffer(indio_dev, buffer); |
| 312 | |||
| 313 | static int axi_adc_reset(struct adi_axi_adc_state *st) | ||
| 314 | { | ||
| 315 | int ret; | ||
| 316 | |||
| 317 | ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); | ||
| 318 | if (ret) | ||
| 319 | return ret; | ||
| 320 | |||
| 321 | mdelay(10); | ||
| 322 | ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, | ||
| 323 | ADI_AXI_REG_RSTN_MMCM_RSTN); | ||
| 324 | if (ret) | 143 | if (ret) |
| 325 | return ret; | 144 | return ERR_PTR(ret); |
| 326 | 145 | ||
| 327 | mdelay(10); | 146 | return buffer; |
| 328 | return regmap_write(st->regmap, ADI_AXI_REG_RSTN, | ||
| 329 | ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); | ||
| 330 | } | 147 | } |
| 331 | 148 | ||
| 332 | static void adi_axi_adc_cleanup(void *data) | 149 | static void axi_adc_free_buffer(struct iio_backend *back, |
| 150 | struct iio_buffer *buffer) | ||
| 333 | { | 151 | { |
| 334 | struct adi_axi_adc_client *cl = data; | 152 | iio_dmaengine_buffer_free(buffer); |
| 335 | |||
| 336 | put_device(cl->dev); | ||
| 337 | module_put(cl->dev->driver->owner); | ||
| 338 | } | 153 | } |
| 339 | 154 | ||
| 340 | static const struct regmap_config axi_adc_regmap_config = { | 155 | static const struct regmap_config axi_adc_regmap_config = { |
| @@ -344,45 +159,47 @@ static const struct regmap_config axi_adc_regmap_config = { · 3 unmodified lines | |||
| 344 | .max_register = 0x0800, | 159 | .max_register = 0x0800, |
| 345 | }; | 160 | }; |
| 346 | 161 | ||
| 162 | static const struct iio_backend_ops adi_axi_adc_generic = { | ||
| 163 | .enable = axi_adc_enable, | ||
| 164 | .disable = axi_adc_disable, | ||
| 165 | .data_format_set = axi_adc_data_format_set, | ||
| 166 | .chan_enable = axi_adc_chan_enable, | ||
| 167 | .chan_disable = axi_adc_chan_disable, | ||
| 168 | .request_buffer = axi_adc_request_buffer, | ||
| 169 | .free_buffer = axi_adc_free_buffer, | ||
| 170 | }; | ||
| 171 | |||
| 347 | static int adi_axi_adc_probe(struct platform_device *pdev) | 172 | static int adi_axi_adc_probe(struct platform_device *pdev) |
| 348 | { | 173 | { |
| 349 | struct adi_axi_adc_conv *conv; | 174 | const unsigned int *expected_ver; |
| 350 | struct iio_dev *indio_dev; | ||
| 351 | struct adi_axi_adc_client *cl; | ||
| 352 | struct adi_axi_adc_state *st; | 175 | struct adi_axi_adc_state *st; |
| 353 | void __iomem *base; | 176 | void __iomem *base; |
| 354 | unsigned int ver; | 177 | unsigned int ver; |
| 355 | int ret; | 178 | int ret; |
| 356 | 179 | ||
| 357 | cl = adi_axi_adc_attach_client(&pdev->dev); | 180 | st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); |
| 358 | if (IS_ERR(cl)) | 181 | if (!st) |
| 359 | return PTR_ERR(cl); | ||
| 360 | |||
| 361 | ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); | ||
| 362 | if (ret) | ||
| 363 | return ret; | ||
| 364 | |||
| 365 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); | ||
| 366 | if (indio_dev == NULL) | ||
| 367 | return -ENOMEM; | 182 | return -ENOMEM; |
| 368 | 183 | ||
| 369 | st = iio_priv(indio_dev); | ||
| 370 | st->client = cl; | ||
| 371 | cl->state = st; | ||
| 372 | mutex_init(&st->lock); | ||
| 373 | |||
| 374 | base = devm_platform_ioremap_resource(pdev, 0); | 184 | base = devm_platform_ioremap_resource(pdev, 0); |
| 375 | if (IS_ERR(base)) | 185 | if (IS_ERR(base)) |
| 376 | return PTR_ERR(base); | 186 | return PTR_ERR(base); |
| 377 | 187 | ||
| 188 | st->dev = &pdev->dev; | ||
| 378 | st->regmap = devm_regmap_init_mmio(&pdev->dev, base, | 189 | st->regmap = devm_regmap_init_mmio(&pdev->dev, base, |
| 379 | &axi_adc_regmap_config); | 190 | &axi_adc_regmap_config); |
| 380 | if (IS_ERR(st->regmap)) | 191 | if (IS_ERR(st->regmap)) |
| 381 | return PTR_ERR(st->regmap); | 192 | return PTR_ERR(st->regmap); |
| 382 | 193 | ||
| 383 | conv = &st->client->conv; | 194 | expected_ver = device_get_match_data(&pdev->dev); |
| 195 | if (!expected_ver) | ||
| 196 | return -ENODEV; | ||
| 384 | 197 | ||
| 385 | ret = axi_adc_reset(st); | 198 | /* |
| 199 | * Force disable the core. Up to the frontend to enable us. And we can | ||
| 200 | * still read/write registers... | ||
| 201 | */ | ||
| 202 | ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0); | ||
| 386 | if (ret) | 203 | if (ret) |
| 387 | return ret; | 204 | return ret; |
| 388 | 205 | ||
| @@ -390,33 +207,19 @@ static int adi_axi_adc_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 390 | if (ret) | 207 | if (ret) |
| 391 | return ret; | 208 | return ret; |
| 392 | 209 | ||
| 393 | if (cl->info->version > ver) { | 210 | if (*expected_ver > ver) { |
| 394 | dev_err(&pdev->dev, | 211 | dev_err(&pdev->dev, |
| 395 | "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", | 212 | "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", |
| 396 | ADI_AXI_PCORE_VER_MAJOR(cl->info->version), | 213 | ADI_AXI_PCORE_VER_MAJOR(*expected_ver), |
| 397 | ADI_AXI_PCORE_VER_MINOR(cl->info->version), | 214 | ADI_AXI_PCORE_VER_MINOR(*expected_ver), |
| 398 | ADI_AXI_PCORE_VER_PATCH(cl->info->version), | 215 | ADI_AXI_PCORE_VER_PATCH(*expected_ver), |
| 399 | ADI_AXI_PCORE_VER_MAJOR(ver), | 216 | ADI_AXI_PCORE_VER_MAJOR(ver), |
| 400 | ADI_AXI_PCORE_VER_MINOR(ver), | 217 | ADI_AXI_PCORE_VER_MINOR(ver), |
| 401 | ADI_AXI_PCORE_VER_PATCH(ver)); | 218 | ADI_AXI_PCORE_VER_PATCH(ver)); |
| 402 | return -ENODEV; | 219 | return -ENODEV; |
| 403 | } | 220 | } |
| 404 | 221 | ||
| 405 | indio_dev->info = &adi_axi_adc_info; | 222 | ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st); |
| 406 | indio_dev->name = "adi-axi-adc"; | ||
| 407 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 408 | indio_dev->num_channels = conv->chip_info->num_channels; | ||
| 409 | indio_dev->channels = conv->chip_info->channels; | ||
| 410 | |||
| 411 | ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); | ||
| 412 | if (ret) | ||
| 413 | return ret; | ||
| 414 | |||
| 415 | ret = adi_axi_adc_setup_channels(&pdev->dev, st); | ||
| 416 | if (ret) | ||
| 417 | return ret; | ||
| 418 | |||
| 419 | ret = devm_iio_device_register(&pdev->dev, indio_dev); | ||
| 420 | if (ret) | 223 | if (ret) |
| 421 | return ret; | 224 | return ret; |
| 422 | 225 | ||
| @@ -428,6 +231,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 428 | return 0; | 231 | return 0; |
| 429 | } | 232 | } |
| 430 | 233 | ||
| 234 | static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a'); | ||
| 235 | |||
| 431 | /* Match table for of_platform binding */ | 236 | /* Match table for of_platform binding */ |
| 432 | static const struct of_device_id adi_axi_adc_of_match[] = { | 237 | static const struct of_device_id adi_axi_adc_of_match[] = { |
| 433 | { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, | 238 | { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, |
| @@ -447,3 +252,5 @@ module_platform_driver(adi_axi_adc_driver); · 13 unmodified lines | |||
| 447 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); | 252 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
| 448 | MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); | 253 | MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); |
| 449 | MODULE_LICENSE("GPL v2"); | 254 | MODULE_LICENSE("GPL v2"); |
| 255 | MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); | ||
| 256 | MODULE_IMPORT_NS(IIO_BACKEND); | ||
| @@ -357,62 +357,55 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, · 356 unmodified lines | |||
| 357 | int *val, | 357 | int *val, |
| 358 | long m) | 358 | long m) |
| 359 | { | 359 | { |
| 360 | int ret = 0; | 360 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 361 | s32 data; | 361 | s32 data; |
| 362 | u8 rxbuf[2]; | 362 | u8 rxbuf[2]; |
| 363 | struct max1363_state *st = iio_priv(indio_dev); | 363 | struct max1363_state *st = iio_priv(indio_dev); |
| 364 | struct i2c_client *client = st->client; | 364 | struct i2c_client *client = st->client; |
| 365 | 365 | ||
| 366 | ret = iio_device_claim_direct_mode(indio_dev); | 366 | guard(mutex)(&st->lock); |
| 367 | if (ret) | 367 | |
| 368 | return ret; | 368 | /* |
| 369 | mutex_lock(&st->lock); | 369 | * If monitor mode is enabled, the method for reading a single |
| 370 | 370 | * channel will have to be rather different and has not yet | |
| 371 | /* | 371 | * been implemented. |
| 372 | * If monitor mode is enabled, the method for reading a single | 372 | * |
| 373 | * channel will have to be rather different and has not yet | 373 | * Also, cannot read directly if buffered capture enabled. |
| 374 | * been implemented. | 374 | */ |
| 375 | * | 375 | if (st->monitor_on) |
| 376 | * Also, cannot read directly if buffered capture enabled. | 376 | return -EBUSY; |
| 377 | */ | 377 | |
| 378 | if (st->monitor_on) { | 378 | /* Check to see if current scan mode is correct */ |
| 379 | ret = -EBUSY; | 379 | if (st->current_mode != &max1363_mode_table[chan->address]) { |
| 380 | goto error_ret; | 380 | int ret; |
| 381 | } | 381 | |
| 382 | 382 | /* Update scan mode if needed */ | |
| 383 | /* Check to see if current scan mode is correct */ | 383 | st->current_mode = &max1363_mode_table[chan->address]; |
| 384 | if (st->current_mode != &max1363_mode_table[chan->address]) { | 384 | ret = max1363_set_scan_mode(st); |
| 385 | /* Update scan mode if needed */ | 385 | if (ret < 0) |
| 386 | st->current_mode = &max1363_mode_table[chan->address]; | 386 | return ret; |
| 387 | ret = max1363_set_scan_mode(st); | ||
| 388 | if (ret < 0) | ||
| 389 | goto error_ret; | ||
| 390 | } | ||
| 391 | if (st->chip_info->bits != 8) { | ||
| 392 | /* Get reading */ | ||
| 393 | data = st->recv(client, rxbuf, 2); | ||
| 394 | if (data < 0) { | ||
| 395 | ret = data; | ||
| 396 | goto error_ret; | ||
| 397 | } | 387 | } |
| 398 | data = (rxbuf[1] | rxbuf[0] << 8) & | 388 | if (st->chip_info->bits != 8) { |
| 399 | ((1 << st->chip_info->bits) - 1); | 389 | /* Get reading */ |
| 400 | } else { | 390 | data = st->recv(client, rxbuf, 2); |
| 401 | /* Get reading */ | 391 | if (data < 0) |
| 402 | data = st->recv(client, rxbuf, 1); | 392 | return data; |
| 403 | if (data < 0) { | 393 | |
| 404 | ret = data; | 394 | data = (rxbuf[1] | rxbuf[0] << 8) & |
| 405 | goto error_ret; | 395 | ((1 << st->chip_info->bits) - 1); |
| 396 | } else { | ||
| 397 | /* Get reading */ | ||
| 398 | data = st->recv(client, rxbuf, 1); | ||
| 399 | if (data < 0) | ||
| 400 | return data; | ||
| 401 | |||
| 402 | data = rxbuf[0]; | ||
| 406 | } | 403 | } |
| 407 | data = rxbuf[0]; | 404 | *val = data; |
| 408 | } | ||
| 409 | *val = data; | ||
| 410 | |||
| 411 | error_ret: | ||
| 412 | mutex_unlock(&st->lock); | ||
| 413 | iio_device_release_direct_mode(indio_dev); | ||
| 414 | return ret; | ||
| 415 | 405 | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | unreachable(); | ||
| 416 | } | 409 | } |
| 417 | 410 | ||
| 418 | static int max1363_read_raw(struct iio_dev *indio_dev, | 411 | static int max1363_read_raw(struct iio_dev *indio_dev, |
| @@ -710,9 +703,8 @@ static ssize_t max1363_monitor_store_freq(struct device *dev, · 291 unmodified lines | |||
| 710 | if (!found) | 703 | if (!found) |
| 711 | return -EINVAL; | 704 | return -EINVAL; |
| 712 | 705 | ||
| 713 | mutex_lock(&st->lock); | 706 | scoped_guard(mutex, &st->lock) |
| 714 | st->monitor_speed = i; | 707 | st->monitor_speed = i; |
| 715 | mutex_unlock(&st->lock); | ||
| 716 | 708 | ||
| 717 | return 0; | 709 | return 0; |
| 718 | } | 710 | } |
| @@ -815,12 +807,11 @@ static int max1363_read_event_config(struct iio_dev *indio_dev, · 96 unmodified lines | |||
| 815 | int val; | 807 | int val; |
| 816 | int number = chan->channel; | 808 | int number = chan->channel; |
| 817 | 809 | ||
| 818 | mutex_lock(&st->lock); | 810 | guard(mutex)(&st->lock); |
| 819 | if (dir == IIO_EV_DIR_FALLING) | 811 | if (dir == IIO_EV_DIR_FALLING) |
| 820 | val = (1 << number) & st->mask_low; | 812 | val = (1 << number) & st->mask_low; |
| 821 | else | 813 | else |
| 822 | val = (1 << number) & st->mask_high; | 814 | val = (1 << number) & st->mask_high; |
| 823 | mutex_unlock(&st->lock); | ||
| 824 | 815 | ||
| 825 | return val; | 816 | return val; |
| 826 | } | 817 | } |
| @@ -962,46 +953,42 @@ static int max1363_write_event_config(struct iio_dev *indio_dev, · 135 unmodified lines | |||
| 962 | const struct iio_chan_spec *chan, enum iio_event_type type, | 953 | const struct iio_chan_spec *chan, enum iio_event_type type, |
| 963 | enum iio_event_direction dir, int state) | 954 | enum iio_event_direction dir, int state) |
| 964 | { | 955 | { |
| 965 | int ret = 0; | ||
| 966 | struct max1363_state *st = iio_priv(indio_dev); | 956 | struct max1363_state *st = iio_priv(indio_dev); |
| 967 | u16 unifiedmask; | ||
| 968 | int number = chan->channel; | ||
| 969 | 957 | ||
| 970 | ret = iio_device_claim_direct_mode(indio_dev); | 958 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 971 | if (ret) | 959 | int number = chan->channel; |
| 972 | return ret; | 960 | u16 unifiedmask; |
| 973 | mutex_lock(&st->lock); | 961 | int ret; |
| 974 | 962 | ||
| 975 | unifiedmask = st->mask_low | st->mask_high; | 963 | guard(mutex)(&st->lock); |
| 976 | if (dir == IIO_EV_DIR_FALLING) { | 964 | |
| 977 | 965 | unifiedmask = st->mask_low | st->mask_high; | |
| 978 | if (state == 0) | 966 | if (dir == IIO_EV_DIR_FALLING) { |
| 979 | st->mask_low &= ~(1 << number); | 967 | |
| 980 | else { | 968 | if (state == 0) |
| 981 | ret = __max1363_check_event_mask((1 << number), | 969 | st->mask_low &= ~(1 << number); |
| 982 | unifiedmask); | 970 | else { |
| 983 | if (ret) | 971 | ret = __max1363_check_event_mask((1 << number), |
| 984 | goto error_ret; | 972 | unifiedmask); |
| 985 | st->mask_low |= (1 << number); | 973 | if (ret) |
| 986 | } | 974 | return ret; |
| 987 | } else { | 975 | st->mask_low |= (1 << number); |
| 988 | if (state == 0) | 976 | } |
| 989 | st->mask_high &= ~(1 << number); | 977 | } else { |
| 990 | else { | 978 | if (state == 0) |
| 991 | ret = __max1363_check_event_mask((1 << number), | 979 | st->mask_high &= ~(1 << number); |
| 992 | unifiedmask); | 980 | else { |
| 993 | if (ret) | 981 | ret = __max1363_check_event_mask((1 << number), |
| 994 | goto error_ret; | 982 | unifiedmask); |
| 995 | st->mask_high |= (1 << number); | 983 | if (ret) |
| 984 | return ret; | ||
| 985 | st->mask_high |= (1 << number); | ||
| 986 | } | ||
| 996 | } | 987 | } |
| 997 | } | 988 | } |
| 998 | |||
| 999 | max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); | 989 | max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); |
| 1000 | error_ret: | ||
| 1001 | mutex_unlock(&st->lock); | ||
| 1002 | iio_device_release_direct_mode(indio_dev); | ||
| 1003 | 990 | ||
| 1004 | return ret; | 991 | return 0; |
| 1005 | } | 992 | } |
| 1006 | 993 | ||
| 1007 | /* | 994 | /* |
| @@ -371,6 +371,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = { · 370 unmodified lines | |||
| 371 | }, | 371 | }, |
| 372 | }; | 372 | }; |
| 373 | 373 | ||
| 374 | static void mcp320x_regulator_disable(void *reg) | ||
| 375 | { | ||
| 376 | regulator_disable(reg); | ||
| 377 | } | ||
| 378 | |||
| 374 | static int mcp320x_probe(struct spi_device *spi) | 379 | static int mcp320x_probe(struct spi_device *spi) |
| 375 | { | 380 | { |
| 376 | struct iio_dev *indio_dev; | 381 | struct iio_dev *indio_dev; |
| @@ -388,7 +393,6 @@ static int mcp320x_probe(struct spi_device *spi) · 11 unmodified lines | |||
| 388 | indio_dev->name = spi_get_device_id(spi)->name; | 393 | indio_dev->name = spi_get_device_id(spi)->name; |
| 389 | indio_dev->modes = INDIO_DIRECT_MODE; | 394 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 390 | indio_dev->info = &mcp320x_info; | 395 | indio_dev->info = &mcp320x_info; |
| 391 | spi_set_drvdata(spi, indio_dev); | ||
| 392 | 396 | ||
| 393 | device_index = spi_get_device_id(spi)->driver_data; | 397 | device_index = spi_get_device_id(spi)->driver_data; |
| 394 | chip_info = &mcp320x_chip_infos[device_index]; | 398 | chip_info = &mcp320x_chip_infos[device_index]; |
| @@ -445,27 +449,13 @@ static int mcp320x_probe(struct spi_device *spi) · 50 unmodified lines | |||
| 445 | if (ret < 0) | 449 | if (ret < 0) |
| 446 | return ret; | 450 | return ret; |
| 447 | 451 | ||
| 448 | mutex_init(&adc->lock); | 452 | ret = devm_add_action_or_reset(&spi->dev, mcp320x_regulator_disable, adc->reg); |
| 449 | |||
| 450 | ret = iio_device_register(indio_dev); | ||
| 451 | if (ret < 0) | 453 | if (ret < 0) |
| 452 | goto reg_disable; | 454 | return ret; |
| 453 | |||
| 454 | return 0; | ||
| 455 | |||
| 456 | reg_disable: | ||
| 457 | regulator_disable(adc->reg); | ||
| 458 | |||
| 459 | return ret; | ||
| 460 | } | ||
| 461 | 455 | ||
| 462 | static void mcp320x_remove(struct spi_device *spi) | 456 | mutex_init(&adc->lock); |
| 463 | { | ||
| 464 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 465 | struct mcp320x *adc = iio_priv(indio_dev); | ||
| 466 | 457 | ||
| 467 | iio_device_unregister(indio_dev); | 458 | return devm_iio_device_register(&spi->dev, indio_dev); |
| 468 | regulator_disable(adc->reg); | ||
| 469 | } | 459 | } |
| 470 | 460 | ||
| 471 | static const struct of_device_id mcp320x_dt_ids[] = { | 461 | static const struct of_device_id mcp320x_dt_ids[] = { |
| @@ -520,7 +510,6 @@ static struct spi_driver mcp320x_driver = { · 48 unmodified lines | |||
| 520 | .of_match_table = mcp320x_dt_ids, | 510 | .of_match_table = mcp320x_dt_ids, |
| 521 | }, | 511 | }, |
| 522 | .probe = mcp320x_probe, | 512 | .probe = mcp320x_probe, |
| 523 | .remove = mcp320x_remove, | ||
| 524 | .id_table = mcp320x_id, | 513 | .id_table = mcp320x_id, |
| 525 | }; | 514 | }; |
| 526 | module_spi_driver(mcp320x_driver); | 515 | module_spi_driver(mcp320x_driver); |
| @@ -0,0 +1,1636 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017-2024 Microchip Technology Inc. and its subsidiaries | ||
| 6 | * | ||
| 7 | * Author: Bogdan Bolocan <bogdan.bolocan@microchip.com> | ||
| 8 | * Author: Victor Tudose | ||
| 9 | * Author: Marius Cristea <marius.cristea@microchip.com> | ||
| 10 | * | ||
| 11 | * Datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here: | ||
| 12 | * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/acpi.h> | ||
| 16 | #include <linux/bitfield.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/i2c.h> | ||
| 20 | #include <linux/iio/iio.h> | ||
| 21 | #include <linux/iio/sysfs.h> | ||
| 22 | #include <asm/unaligned.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * maximum accumulation time should be (17 * 60 * 1000) around 17 minutes@1024 sps | ||
| 26 | * till PAC1934 accumulation registers starts to saturate | ||
| 27 | */ | ||
| 28 | #define PAC1934_MAX_RFSH_LIMIT_MS 60000 | ||
| 29 | /* 50msec is the timeout for validity of the cached registers */ | ||
| 30 | #define PAC1934_MIN_POLLING_TIME_MS 50 | ||
| 31 | /* | ||
| 32 | * 1000usec is the minimum wait time for normal conversions when sample | ||
| 33 | * rate doesn't change | ||
| 34 | */ | ||
| 35 | #define PAC1934_MIN_UPDATE_WAIT_TIME_US 1000 | ||
| 36 | |||
| 37 | /* 32000mV */ | ||
| 38 | #define PAC1934_VOLTAGE_MILLIVOLTS_MAX 32000 | ||
| 39 | /* voltage bits resolution when set for unsigned values */ | ||
| 40 | #define PAC1934_VOLTAGE_U_RES 16 | ||
| 41 | /* voltage bits resolution when set for signed values */ | ||
| 42 | #define PAC1934_VOLTAGE_S_RES 15 | ||
| 43 | |||
| 44 | /* | ||
| 45 | * max signed value that can be stored on 32 bits and 8 digits fractional value | ||
| 46 | * (2^31 - 1) * 10^8 + 99999999 | ||
| 47 | */ | ||
| 48 | #define PAC_193X_MAX_POWER_ACC 214748364799999999LL | ||
| 49 | /* | ||
| 50 | * min signed value that can be stored on 32 bits and 8 digits fractional value | ||
| 51 | * -(2^31) * 10^8 - 99999999 | ||
| 52 | */ | ||
| 53 | #define PAC_193X_MIN_POWER_ACC -214748364899999999LL | ||
| 54 | |||
| 55 | #define PAC1934_MAX_NUM_CHANNELS 4 | ||
| 56 | |||
| 57 | #define PAC1934_MEAS_REG_LEN 76 | ||
| 58 | #define PAC1934_CTRL_REG_LEN 12 | ||
| 59 | |||
| 60 | #define PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ 1024 | ||
| 61 | |||
| 62 | /* I2C address map */ | ||
| 63 | #define PAC1934_REFRESH_REG_ADDR 0x00 | ||
| 64 | #define PAC1934_CTRL_REG_ADDR 0x01 | ||
| 65 | #define PAC1934_ACC_COUNT_REG_ADDR 0x02 | ||
| 66 | #define PAC1934_VPOWER_ACC_1_ADDR 0x03 | ||
| 67 | #define PAC1934_VPOWER_ACC_2_ADDR 0x04 | ||
| 68 | #define PAC1934_VPOWER_ACC_3_ADDR 0x05 | ||
| 69 | #define PAC1934_VPOWER_ACC_4_ADDR 0x06 | ||
| 70 | #define PAC1934_VBUS_1_ADDR 0x07 | ||
| 71 | #define PAC1934_VBUS_2_ADDR 0x08 | ||
| 72 | #define PAC1934_VBUS_3_ADDR 0x09 | ||
| 73 | #define PAC1934_VBUS_4_ADDR 0x0A | ||
| 74 | #define PAC1934_VSENSE_1_ADDR 0x0B | ||
| 75 | #define PAC1934_VSENSE_2_ADDR 0x0C | ||
| 76 | #define PAC1934_VSENSE_3_ADDR 0x0D | ||
| 77 | #define PAC1934_VSENSE_4_ADDR 0x0E | ||
| 78 | #define PAC1934_VBUS_AVG_1_ADDR 0x0F | ||
| 79 | #define PAC1934_VBUS_AVG_2_ADDR 0x10 | ||
| 80 | #define PAC1934_VBUS_AVG_3_ADDR 0x11 | ||
| 81 | #define PAC1934_VBUS_AVG_4_ADDR 0x12 | ||
| 82 | #define PAC1934_VSENSE_AVG_1_ADDR 0x13 | ||
| 83 | #define PAC1934_VSENSE_AVG_2_ADDR 0x14 | ||
| 84 | #define PAC1934_VSENSE_AVG_3_ADDR 0x15 | ||
| 85 | #define PAC1934_VSENSE_AVG_4_ADDR 0x16 | ||
| 86 | #define PAC1934_VPOWER_1_ADDR 0x17 | ||
| 87 | #define PAC1934_VPOWER_2_ADDR 0x18 | ||
| 88 | #define PAC1934_VPOWER_3_ADDR 0x19 | ||
| 89 | #define PAC1934_VPOWER_4_ADDR 0x1A | ||
| 90 | #define PAC1934_REFRESH_V_REG_ADDR 0x1F | ||
| 91 | #define PAC1934_CTRL_STAT_REGS_ADDR 0x1C | ||
| 92 | #define PAC1934_PID_REG_ADDR 0xFD | ||
| 93 | #define PAC1934_MID_REG_ADDR 0xFE | ||
| 94 | #define PAC1934_RID_REG_ADDR 0xFF | ||
| 95 | |||
| 96 | /* PRODUCT ID REGISTER + MANUFACTURER ID REGISTER + REVISION ID REGISTER */ | ||
| 97 | #define PAC1934_ID_REG_LEN 3 | ||
| 98 | #define PAC1934_PID_IDX 0 | ||
| 99 | #define PAC1934_MID_IDX 1 | ||
| 100 | #define PAC1934_RID_IDX 2 | ||
| 101 | |||
| 102 | #define PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS 1 | ||
| 103 | #define PAC1934_ACPI_GET_UOHMS_VALS 2 | ||
| 104 | #define PAC1934_ACPI_GET_BIPOLAR_SETTINGS 4 | ||
| 105 | #define PAC1934_ACPI_GET_SAMP 5 | ||
| 106 | |||
| 107 | #define PAC1934_SAMPLE_RATE_SHIFT 6 | ||
| 108 | |||
| 109 | #define PAC1934_VBUS_SENSE_REG_LEN 2 | ||
| 110 | #define PAC1934_ACC_REG_LEN 3 | ||
| 111 | #define PAC1934_VPOWER_REG_LEN 4 | ||
| 112 | #define PAC1934_VPOWER_ACC_REG_LEN 6 | ||
| 113 | #define PAC1934_MAX_REGISTER_LENGTH 6 | ||
| 114 | |||
| 115 | #define PAC1934_CUSTOM_ATTR_FOR_CHANNEL 1 | ||
| 116 | |||
| 117 | /* | ||
| 118 | * relative offsets when using multi-byte reads/writes even though these | ||
| 119 | * bytes are read one after the other, they are not at adjacent memory | ||
| 120 | * locations within the I2C memory map. The chip can skip some addresses | ||
| 121 | */ | ||
| 122 | #define PAC1934_CHANNEL_DIS_REG_OFF 0 | ||
| 123 | #define PAC1934_NEG_PWR_REG_OFF 1 | ||
| 124 | |||
| 125 | /* | ||
| 126 | * when reading/writing multiple bytes from offset PAC1934_CHANNEL_DIS_REG_OFF, | ||
| 127 | * the chip jumps over the 0x1E (REFRESH_G) and 0x1F (REFRESH_V) offsets | ||
| 128 | */ | ||
| 129 | #define PAC1934_SLOW_REG_OFF 2 | ||
| 130 | #define PAC1934_CTRL_ACT_REG_OFF 3 | ||
| 131 | #define PAC1934_CHANNEL_DIS_ACT_REG_OFF 4 | ||
| 132 | #define PAC1934_NEG_PWR_ACT_REG_OFF 5 | ||
| 133 | #define PAC1934_CTRL_LAT_REG_OFF 6 | ||
| 134 | #define PAC1934_CHANNEL_DIS_LAT_REG_OFF 7 | ||
| 135 | #define PAC1934_NEG_PWR_LAT_REG_OFF 8 | ||
| 136 | #define PAC1934_PID_REG_OFF 9 | ||
| 137 | #define PAC1934_MID_REG_OFF 10 | ||
| 138 | #define PAC1934_REV_REG_OFF 11 | ||
| 139 | #define PAC1934_CTRL_STATUS_INFO_LEN 12 | ||
| 140 | |||
| 141 | #define PAC1934_MID 0x5D | ||
| 142 | #define PAC1931_PID 0x58 | ||
| 143 | #define PAC1932_PID 0x59 | ||
| 144 | #define PAC1933_PID 0x5A | ||
| 145 | #define PAC1934_PID 0x5B | ||
| 146 | |||
| 147 | /* Scale constant = (10^3 * 3.2 * 10^9 / 2^28) for mili Watt-second */ | ||
| 148 | #define PAC1934_SCALE_CONSTANT 11921 | ||
| 149 | |||
| 150 | #define PAC1934_MAX_VPOWER_RSHIFTED_BY_28B 11921 | ||
| 151 | #define PAC1934_MAX_VSENSE_RSHIFTED_BY_16B 1525 | ||
| 152 | |||
| 153 | #define PAC1934_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) | ||
| 154 | |||
| 155 | #define PAC1934_CRTL_SAMPLE_RATE_MASK GENMASK(7, 6) | ||
| 156 | #define PAC1934_CHAN_SLEEP_MASK BIT(5) | ||
| 157 | #define PAC1934_CHAN_SLEEP_SET BIT(5) | ||
| 158 | #define PAC1934_CHAN_SINGLE_MASK BIT(4) | ||
| 159 | #define PAC1934_CHAN_SINGLE_SHOT_SET BIT(4) | ||
| 160 | #define PAC1934_CHAN_ALERT_MASK BIT(3) | ||
| 161 | #define PAC1934_CHAN_ALERT_EN BIT(3) | ||
| 162 | #define PAC1934_CHAN_ALERT_CC_MASK BIT(2) | ||
| 163 | #define PAC1934_CHAN_ALERT_CC_EN BIT(2) | ||
| 164 | #define PAC1934_CHAN_OVF_ALERT_MASK BIT(1) | ||
| 165 | #define PAC1934_CHAN_OVF_ALERT_EN BIT(1) | ||
| 166 | #define PAC1934_CHAN_OVF_MASK BIT(0) | ||
| 167 | |||
| 168 | #define PAC1934_CHAN_DIS_CH1_OFF_MASK BIT(7) | ||
| 169 | #define PAC1934_CHAN_DIS_CH2_OFF_MASK BIT(6) | ||
| 170 | #define PAC1934_CHAN_DIS_CH3_OFF_MASK BIT(5) | ||
| 171 | #define PAC1934_CHAN_DIS_CH4_OFF_MASK BIT(4) | ||
| 172 | #define PAC1934_SMBUS_TIMEOUT_MASK BIT(3) | ||
| 173 | #define PAC1934_SMBUS_BYTECOUNT_MASK BIT(2) | ||
| 174 | #define PAC1934_SMBUS_NO_SKIP_MASK BIT(1) | ||
| 175 | |||
| 176 | #define PAC1934_NEG_PWR_CH1_BIDI_MASK BIT(7) | ||
| 177 | #define PAC1934_NEG_PWR_CH2_BIDI_MASK BIT(6) | ||
| 178 | #define PAC1934_NEG_PWR_CH3_BIDI_MASK BIT(5) | ||
| 179 | #define PAC1934_NEG_PWR_CH4_BIDI_MASK BIT(4) | ||
| 180 | #define PAC1934_NEG_PWR_CH1_BIDV_MASK BIT(3) | ||
| 181 | #define PAC1934_NEG_PWR_CH2_BIDV_MASK BIT(2) | ||
| 182 | #define PAC1934_NEG_PWR_CH3_BIDV_MASK BIT(1) | ||
| 183 | #define PAC1934_NEG_PWR_CH4_BIDV_MASK BIT(0) | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Universal Unique Identifier (UUID), | ||
| 187 | * 033771E0-1705-47B4-9535-D1BBE14D9A09, | ||
| 188 | * is reserved to Microchip for the PAC1934. | ||
| 189 | */ | ||
| 190 | #define PAC1934_DSM_UUID "033771E0-1705-47B4-9535-D1BBE14D9A09" | ||
| 191 | |||
| 192 | enum pac1934_ids { | ||
| 193 | PAC1931, | ||
| 194 | PAC1932, | ||
| 195 | PAC1933, | ||
| 196 | PAC1934 | ||
| 197 | }; | ||
| 198 | |||
| 199 | enum pac1934_samps { | ||
| 200 | PAC1934_SAMP_1024SPS, | ||
| 201 | PAC1934_SAMP_256SPS, | ||
| 202 | PAC1934_SAMP_64SPS, | ||
| 203 | PAC1934_SAMP_8SPS | ||
| 204 | }; | ||
| 205 | |||
| 206 | /* | ||
| 207 | * these indexes are exactly describing the element order within a single | ||
| 208 | * PAC1934 phys channel IIO channel descriptor; see the static const struct | ||
| 209 | * iio_chan_spec pac1934_single_channel[] declaration | ||
| 210 | */ | ||
| 211 | enum pac1934_ch_idx { | ||
| 212 | PAC1934_CH_ENERGY, | ||
| 213 | PAC1934_CH_POWER, | ||
| 214 | PAC1934_CH_VOLTAGE, | ||
| 215 | PAC1934_CH_CURRENT, | ||
| 216 | PAC1934_CH_VOLTAGE_AVERAGE, | ||
| 217 | PAC1934_CH_CURRENT_AVERAGE | ||
| 218 | }; | ||
| 219 | |||
| 220 | /** | ||
| 221 | * struct pac1934_features - features of a pac1934 instance | ||
| 222 | * @phys_channels: number of physical channels supported by the chip | ||
| 223 | * @name: chip's name | ||
| 224 | */ | ||
| 225 | struct pac1934_features { | ||
| 226 | u8 phys_channels; | ||
| 227 | const char *name; | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct samp_rate_mapping { | ||
| 231 | u16 samp_rate; | ||
| 232 | u8 shift2value; | ||
| 233 | }; | ||
| 234 | |||
| 235 | static const unsigned int samp_rate_map_tbl[] = { | ||
| 236 | [PAC1934_SAMP_1024SPS] = 1024, | ||
| 237 | [PAC1934_SAMP_256SPS] = 256, | ||
| 238 | [PAC1934_SAMP_64SPS] = 64, | ||
| 239 | [PAC1934_SAMP_8SPS] = 8, | ||
| 240 | }; | ||
| 241 | |||
| 242 | static const struct pac1934_features pac1934_chip_config[] = { | ||
| 243 | [PAC1931] = { | ||
| 244 | .phys_channels = 1, | ||
| 245 | .name = "pac1931", | ||
| 246 | }, | ||
| 247 | [PAC1932] = { | ||
| 248 | .phys_channels = 2, | ||
| 249 | .name = "pac1932", | ||
| 250 | }, | ||
| 251 | [PAC1933] = { | ||
| 252 | .phys_channels = 3, | ||
| 253 | .name = "pac1933", | ||
| 254 | }, | ||
| 255 | [PAC1934] = { | ||
| 256 | .phys_channels = 4, | ||
| 257 | .name = "pac1934", | ||
| 258 | }, | ||
| 259 | }; | ||
| 260 | |||
| 261 | /** | ||
| 262 | * struct reg_data - data from the registers | ||
| 263 | * @meas_regs: snapshot of raw measurements registers | ||
| 264 | * @ctrl_regs: snapshot of control registers | ||
| 265 | * @energy_sec_acc: snapshot of energy values | ||
| 266 | * @vpower_acc: accumulated vpower values | ||
| 267 | * @vpower: snapshot of vpower registers | ||
| 268 | * @vbus: snapshot of vbus registers | ||
| 269 | * @vbus_avg: averages of vbus registers | ||
| 270 | * @vsense: snapshot of vsense registers | ||
| 271 | * @vsense_avg: averages of vsense registers | ||
| 272 | * @num_enabled_channels: count of how many chip channels are currently enabled | ||
| 273 | */ | ||
| 274 | struct reg_data { | ||
| 275 | u8 meas_regs[PAC1934_MEAS_REG_LEN]; | ||
| 276 | u8 ctrl_regs[PAC1934_CTRL_REG_LEN]; | ||
| 277 | s64 energy_sec_acc[PAC1934_MAX_NUM_CHANNELS]; | ||
| 278 | s64 vpower_acc[PAC1934_MAX_NUM_CHANNELS]; | ||
| 279 | s32 vpower[PAC1934_MAX_NUM_CHANNELS]; | ||
| 280 | s32 vbus[PAC1934_MAX_NUM_CHANNELS]; | ||
| 281 | s32 vbus_avg[PAC1934_MAX_NUM_CHANNELS]; | ||
| 282 | s32 vsense[PAC1934_MAX_NUM_CHANNELS]; | ||
| 283 | s32 vsense_avg[PAC1934_MAX_NUM_CHANNELS]; | ||
| 284 | u8 num_enabled_channels; | ||
| 285 | }; | ||
| 286 | |||
| 287 | /** | ||
| 288 | * struct pac1934_chip_info - information about the chip | ||
| 289 | * @client: the i2c-client attached to the device | ||
| 290 | * @lock: synchronize access to driver's state members | ||
| 291 | * @work_chip_rfsh: work queue used for refresh commands | ||
| 292 | * @phys_channels: phys channels count | ||
| 293 | * @active_channels: array of values, true means that channel is active | ||
| 294 | * @enable_energy: array of values, true means that channel energy is measured | ||
| 295 | * @bi_dir: array of bools, true means that channel is bidirectional | ||
| 296 | * @chip_variant: chip variant | ||
| 297 | * @chip_revision: chip revision | ||
| 298 | * @shunts: shunts | ||
| 299 | * @chip_reg_data: chip reg data | ||
| 300 | * @sample_rate_value: sampling frequency | ||
| 301 | * @labels: table with channels labels | ||
| 302 | * @iio_info: iio_info | ||
| 303 | * @tstamp: chip's uptime | ||
| 304 | */ | ||
| 305 | struct pac1934_chip_info { | ||
| 306 | struct i2c_client *client; | ||
| 307 | struct mutex lock; /* synchronize access to driver's state members */ | ||
| 308 | struct delayed_work work_chip_rfsh; | ||
| 309 | u8 phys_channels; | ||
| 310 | bool active_channels[PAC1934_MAX_NUM_CHANNELS]; | ||
| 311 | bool enable_energy[PAC1934_MAX_NUM_CHANNELS]; | ||
| 312 | bool bi_dir[PAC1934_MAX_NUM_CHANNELS]; | ||
| 313 | u8 chip_variant; | ||
| 314 | u8 chip_revision; | ||
| 315 | u32 shunts[PAC1934_MAX_NUM_CHANNELS]; | ||
| 316 | struct reg_data chip_reg_data; | ||
| 317 | s32 sample_rate_value; | ||
| 318 | char *labels[PAC1934_MAX_NUM_CHANNELS]; | ||
| 319 | struct iio_info iio_info; | ||
| 320 | unsigned long tstamp; | ||
| 321 | }; | ||
| 322 | |||
| 323 | #define TO_PAC1934_CHIP_INFO(d) container_of(d, struct pac1934_chip_info, work_chip_rfsh) | ||
| 324 | |||
| 325 | #define PAC1934_VPOWER_ACC_CHANNEL(_index, _si, _address) { \ | ||
| 326 | .type = IIO_ENERGY, \ | ||
| 327 | .address = (_address), \ | ||
| 328 | .indexed = 1, \ | ||
| 329 | .channel = (_index), \ | ||
| 330 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 331 | BIT(IIO_CHAN_INFO_SCALE) | \ | ||
| 332 | BIT(IIO_CHAN_INFO_ENABLE), \ | ||
| 333 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 334 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 335 | .scan_index = (_si), \ | ||
| 336 | .scan_type = { \ | ||
| 337 | .sign = 'u', \ | ||
| 338 | .realbits = 48, \ | ||
| 339 | .storagebits = 64, \ | ||
| 340 | .endianness = IIO_CPU, \ | ||
| 341 | } \ | ||
| 342 | } | ||
| 343 | |||
| 344 | #define PAC1934_VBUS_CHANNEL(_index, _si, _address) { \ | ||
| 345 | .type = IIO_VOLTAGE, \ | ||
| 346 | .address = (_address), \ | ||
| 347 | .indexed = 1, \ | ||
| 348 | .channel = (_index), \ | ||
| 349 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 350 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 351 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 352 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 353 | .scan_index = (_si), \ | ||
| 354 | .scan_type = { \ | ||
| 355 | .sign = 'u', \ | ||
| 356 | .realbits = 16, \ | ||
| 357 | .storagebits = 16, \ | ||
| 358 | .endianness = IIO_CPU, \ | ||
| 359 | } \ | ||
| 360 | } | ||
| 361 | |||
| 362 | #define PAC1934_VBUS_AVG_CHANNEL(_index, _si, _address) { \ | ||
| 363 | .type = IIO_VOLTAGE, \ | ||
| 364 | .address = (_address), \ | ||
| 365 | .indexed = 1, \ | ||
| 366 | .channel = (_index), \ | ||
| 367 | .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ | ||
| 368 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 369 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 370 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 371 | .scan_index = (_si), \ | ||
| 372 | .scan_type = { \ | ||
| 373 | .sign = 'u', \ | ||
| 374 | .realbits = 16, \ | ||
| 375 | .storagebits = 16, \ | ||
| 376 | .endianness = IIO_CPU, \ | ||
| 377 | } \ | ||
| 378 | } | ||
| 379 | |||
| 380 | #define PAC1934_VSENSE_CHANNEL(_index, _si, _address) { \ | ||
| 381 | .type = IIO_CURRENT, \ | ||
| 382 | .address = (_address), \ | ||
| 383 | .indexed = 1, \ | ||
| 384 | .channel = (_index), \ | ||
| 385 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 386 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 387 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 388 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 389 | .scan_index = (_si), \ | ||
| 390 | .scan_type = { \ | ||
| 391 | .sign = 'u', \ | ||
| 392 | .realbits = 16, \ | ||
| 393 | .storagebits = 16, \ | ||
| 394 | .endianness = IIO_CPU, \ | ||
| 395 | } \ | ||
| 396 | } | ||
| 397 | |||
| 398 | #define PAC1934_VSENSE_AVG_CHANNEL(_index, _si, _address) { \ | ||
| 399 | .type = IIO_CURRENT, \ | ||
| 400 | .address = (_address), \ | ||
| 401 | .indexed = 1, \ | ||
| 402 | .channel = (_index), \ | ||
| 403 | .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ | ||
| 404 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 405 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 406 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 407 | .scan_index = (_si), \ | ||
| 408 | .scan_type = { \ | ||
| 409 | .sign = 'u', \ | ||
| 410 | .realbits = 16, \ | ||
| 411 | .storagebits = 16, \ | ||
| 412 | .endianness = IIO_CPU, \ | ||
| 413 | } \ | ||
| 414 | } | ||
| 415 | |||
| 416 | #define PAC1934_VPOWER_CHANNEL(_index, _si, _address) { \ | ||
| 417 | .type = IIO_POWER, \ | ||
| 418 | .address = (_address), \ | ||
| 419 | .indexed = 1, \ | ||
| 420 | .channel = (_index), \ | ||
| 421 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 422 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 423 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 424 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 425 | .scan_index = (_si), \ | ||
| 426 | .scan_type = { \ | ||
| 427 | .sign = 'u', \ | ||
| 428 | .realbits = 28, \ | ||
| 429 | .storagebits = 32, \ | ||
| 430 | .shift = 4, \ | ||
| 431 | .endianness = IIO_CPU, \ | ||
| 432 | } \ | ||
| 433 | } | ||
| 434 | |||
| 435 | static const struct iio_chan_spec pac1934_single_channel[] = { | ||
| 436 | PAC1934_VPOWER_ACC_CHANNEL(0, 0, PAC1934_VPOWER_ACC_1_ADDR), | ||
| 437 | PAC1934_VPOWER_CHANNEL(0, 0, PAC1934_VPOWER_1_ADDR), | ||
| 438 | PAC1934_VBUS_CHANNEL(0, 0, PAC1934_VBUS_1_ADDR), | ||
| 439 | PAC1934_VSENSE_CHANNEL(0, 0, PAC1934_VSENSE_1_ADDR), | ||
| 440 | PAC1934_VBUS_AVG_CHANNEL(0, 0, PAC1934_VBUS_AVG_1_ADDR), | ||
| 441 | PAC1934_VSENSE_AVG_CHANNEL(0, 0, PAC1934_VSENSE_AVG_1_ADDR), | ||
| 442 | }; | ||
| 443 | |||
| 444 | /* Low-level I2c functions used to transfer up to 76 bytes at once */ | ||
| 445 | static int pac1934_i2c_read(struct i2c_client *client, u8 reg_addr, | ||
| 446 | void *databuf, u8 len) | ||
| 447 | { | ||
| 448 | int ret; | ||
| 449 | struct i2c_msg msgs[2] = { | ||
| 450 | { | ||
| 451 | .addr = client->addr, | ||
| 452 | .len = 1, | ||
| 453 | .buf = (u8 *)®_addr, | ||
| 454 | }, | ||
| 455 | { | ||
| 456 | .addr = client->addr, | ||
| 457 | .len = len, | ||
| 458 | .buf = databuf, | ||
| 459 | .flags = I2C_M_RD | ||
| 460 | } | ||
| 461 | }; | ||
| 462 | |||
| 463 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
| 464 | if (ret < 0) | ||
| 465 | return ret; | ||
| 466 | |||
| 467 | return 0; | ||
| 468 | } | ||
| 469 | |||
| 470 | static int pac1934_get_samp_rate_idx(struct pac1934_chip_info *info, | ||
| 471 | u32 new_samp_rate) | ||
| 472 | { | ||
| 473 | int cnt; | ||
| 474 | |||
| 475 | for (cnt = 0; cnt < ARRAY_SIZE(samp_rate_map_tbl); cnt++) | ||
| 476 | if (new_samp_rate == samp_rate_map_tbl[cnt]) | ||
| 477 | return cnt; | ||
| 478 | |||
| 479 | /* not a valid sample rate value */ | ||
| 480 | return -EINVAL; | ||
| 481 | } | ||
| 482 | |||
| 483 | static ssize_t pac1934_shunt_value_show(struct device *dev, | ||
| 484 | struct device_attribute *attr, | ||
| 485 | char *buf) | ||
| 486 | { | ||
| 487 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
| 488 | struct pac1934_chip_info *info = iio_priv(indio_dev); | ||
| 489 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 490 | |||
| 491 | return sysfs_emit(buf, "%u\n", info->shunts[this_attr->address]); | ||
| 492 | } | ||
| 493 | |||
| 494 | static ssize_t pac1934_shunt_value_store(struct device *dev, | ||
| 495 | struct device_attribute *attr, | ||
| 496 | const char *buf, size_t count) | ||
| 497 | { | ||
| 498 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
| 499 | struct pac1934_chip_info *info = iio_priv(indio_dev); | ||
| 500 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 501 | int sh_val; | ||
| 502 | |||
| 503 | if (kstrtouint(buf, 10, &sh_val)) { | ||
| 504 | dev_err(dev, "Shunt value is not valid\n"); | ||
| 505 | return -EINVAL; | ||
| 506 | } | ||
| 507 | |||
| 508 | scoped_guard(mutex, &info->lock) | ||
| 509 | info->shunts[this_attr->address] = sh_val; | ||
| 510 | |||
| 511 | return count; | ||
| 512 | } | ||
| 513 | |||
| 514 | static int pac1934_read_avail(struct iio_dev *indio_dev, | ||
| 515 | struct iio_chan_spec const *channel, | ||
| 516 | const int **vals, int *type, int *length, long mask) | ||
| 517 | { | ||
| 518 | switch (mask) { | ||
| 519 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 520 | *type = IIO_VAL_INT; | ||
| 521 | *vals = samp_rate_map_tbl; | ||
| 522 | *length = ARRAY_SIZE(samp_rate_map_tbl); | ||
| 523 | return IIO_AVAIL_LIST; | ||
| 524 | } | ||
| 525 | |||
| 526 | return -EINVAL; | ||
| 527 | } | ||
| 528 | |||
| 529 | static int pac1934_send_refresh(struct pac1934_chip_info *info, | ||
| 530 | u8 refresh_cmd, u32 wait_time) | ||
| 531 | { | ||
| 532 | /* this function only sends REFRESH or REFRESH_V */ | ||
| 533 | struct i2c_client *client = info->client; | ||
| 534 | int ret; | ||
| 535 | u8 bidir_reg; | ||
| 536 | bool revision_bug = false; | ||
| 537 | |||
| 538 | if (info->chip_revision == 2 || info->chip_revision == 3) { | ||
| 539 | /* | ||
| 540 | * chip rev 2 and 3 bug workaround | ||
| 541 | * see: PAC1934 Family Data Sheet Errata DS80000836A.pdf | ||
| 542 | */ | ||
| 543 | revision_bug = true; | ||
| 544 | |||
| 545 | bidir_reg = | ||
| 546 | FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) | | ||
| 547 | FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) | | ||
| 548 | FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) | | ||
| 549 | FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) | | ||
| 550 | FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) | | ||
| 551 | FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) | | ||
| 552 | FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) | | ||
| 553 | FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]); | ||
| 554 | |||
| 555 | ret = i2c_smbus_write_byte_data(client, | ||
| 556 | PAC1934_CTRL_STAT_REGS_ADDR + | ||
| 557 | PAC1934_NEG_PWR_REG_OFF, | ||
| 558 | bidir_reg); | ||
| 559 | if (ret) | ||
| 560 | return ret; | ||
| 561 | } | ||
| 562 | |||
| 563 | ret = i2c_smbus_write_byte(client, refresh_cmd); | ||
| 564 | if (ret) { | ||
| 565 | dev_err(&client->dev, "%s - cannot send 0x%02X\n", | ||
| 566 | __func__, refresh_cmd); | ||
| 567 | return ret; | ||
| 568 | } | ||
| 569 | |||
| 570 | if (revision_bug) { | ||
| 571 | /* | ||
| 572 | * chip rev 2 and 3 bug workaround - write again the same | ||
| 573 | * register write the updated registers back | ||
| 574 | */ | ||
| 575 | ret = i2c_smbus_write_byte_data(client, | ||
| 576 | PAC1934_CTRL_STAT_REGS_ADDR + | ||
| 577 | PAC1934_NEG_PWR_REG_OFF, bidir_reg); | ||
| 578 | if (ret) | ||
| 579 | return ret; | ||
| 580 | } | ||
| 581 | |||
| 582 | /* register data retrieval timestamp */ | ||
| 583 | info->tstamp = jiffies; | ||
| 584 | |||
| 585 | /* wait till the data is available */ | ||
| 586 | usleep_range(wait_time, wait_time + 100); | ||
| 587 | |||
| 588 | return ret; | ||
| 589 | } | ||
| 590 | |||
| 591 | static int pac1934_reg_snapshot(struct pac1934_chip_info *info, | ||
| 592 | bool do_refresh, u8 refresh_cmd, u32 wait_time) | ||
| 593 | { | ||
| 594 | int ret; | ||
| 595 | struct i2c_client *client = info->client; | ||
| 596 | u8 samp_shift, ctrl_regs_tmp; | ||
| 597 | u8 *offset_reg_data_p; | ||
| 598 | u16 tmp_value; | ||
| 599 | u32 samp_rate, cnt, tmp; | ||
| 600 | s64 curr_energy, inc; | ||
| 601 | u64 tmp_energy; | ||
| 602 | struct reg_data *reg_data; | ||
| 603 | |||
| 604 | guard(mutex)(&info->lock); | ||
| 605 | |||
| 606 | if (do_refresh) { | ||
| 607 | ret = pac1934_send_refresh(info, refresh_cmd, wait_time); | ||
| 608 | if (ret < 0) { | ||
| 609 | dev_err(&client->dev, | ||
| 610 | "%s - cannot send refresh\n", | ||
| 611 | __func__); | ||
| 612 | return ret; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR, | ||
| 617 | PAC1934_CTRL_REG_LEN, | ||
| 618 | (u8 *)info->chip_reg_data.ctrl_regs); | ||
| 619 | if (ret < 0) { | ||
| 620 | dev_err(&client->dev, | ||
| 621 | "%s - cannot read ctrl/status registers\n", | ||
| 622 | __func__); | ||
| 623 | return ret; | ||
| 624 | } | ||
| 625 | |||
| 626 | reg_data = &info->chip_reg_data; | ||
| 627 | |||
| 628 | /* read the data registers */ | ||
| 629 | ret = pac1934_i2c_read(client, PAC1934_ACC_COUNT_REG_ADDR, | ||
| 630 | (u8 *)reg_data->meas_regs, PAC1934_MEAS_REG_LEN); | ||
| 631 | if (ret) { | ||
| 632 | dev_err(&client->dev, | ||
| 633 | "%s - cannot read ACC_COUNT register: %d:%d\n", | ||
| 634 | __func__, ret, PAC1934_MEAS_REG_LEN); | ||
| 635 | return ret; | ||
| 636 | } | ||
| 637 | |||
| 638 | /* see how much shift is required by the sample rate */ | ||
| 639 | samp_rate = samp_rate_map_tbl[((reg_data->ctrl_regs[PAC1934_CTRL_LAT_REG_OFF]) >> 6)]; | ||
| 640 | samp_shift = get_count_order(samp_rate); | ||
| 641 | |||
| 642 | ctrl_regs_tmp = reg_data->ctrl_regs[PAC1934_CHANNEL_DIS_LAT_REG_OFF]; | ||
| 643 | offset_reg_data_p = ®_data->meas_regs[PAC1934_ACC_REG_LEN]; | ||
| 644 | |||
| 645 | /* start with VPOWER_ACC */ | ||
| 646 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 647 | /* check if the channel is active, skip all fields if disabled */ | ||
| 648 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 649 | continue; | ||
| 650 | |||
| 651 | /* skip if the energy accumulation is disabled */ | ||
| 652 | if (info->enable_energy[cnt]) { | ||
| 653 | curr_energy = info->chip_reg_data.energy_sec_acc[cnt]; | ||
| 654 | |||
| 655 | tmp_energy = get_unaligned_be48(offset_reg_data_p); | ||
| 656 | |||
| 657 | if (info->bi_dir[cnt]) | ||
| 658 | reg_data->vpower_acc[cnt] = sign_extend64(tmp_energy, 47); | ||
| 659 | else | ||
| 660 | reg_data->vpower_acc[cnt] = tmp_energy; | ||
| 661 | |||
| 662 | /* | ||
| 663 | * compute the scaled to 1 second accumulated energy value; | ||
| 664 | * energy accumulator scaled to 1sec = VPOWER_ACC/2^samp_shift | ||
| 665 | * the chip's sampling rate is 2^samp_shift samples/sec | ||
| 666 | */ | ||
| 667 | inc = (reg_data->vpower_acc[cnt] >> samp_shift); | ||
| 668 | |||
| 669 | /* add the power_acc field */ | ||
| 670 | curr_energy += inc; | ||
| 671 | |||
| 672 | clamp(curr_energy, PAC_193X_MIN_POWER_ACC, PAC_193X_MAX_POWER_ACC); | ||
| 673 | |||
| 674 | reg_data->energy_sec_acc[cnt] = curr_energy; | ||
| 675 | } | ||
| 676 | |||
| 677 | offset_reg_data_p += PAC1934_VPOWER_ACC_REG_LEN; | ||
| 678 | } | ||
| 679 | |||
| 680 | /* continue with VBUS */ | ||
| 681 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 682 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 683 | continue; | ||
| 684 | |||
| 685 | tmp_value = get_unaligned_be16(offset_reg_data_p); | ||
| 686 | |||
| 687 | if (info->bi_dir[cnt]) | ||
| 688 | reg_data->vbus[cnt] = sign_extend32((u32)(tmp_value), 15); | ||
| 689 | else | ||
| 690 | reg_data->vbus[cnt] = tmp_value; | ||
| 691 | |||
| 692 | offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN; | ||
| 693 | } | ||
| 694 | |||
| 695 | /* VSENSE */ | ||
| 696 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 697 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 698 | continue; | ||
| 699 | |||
| 700 | tmp_value = get_unaligned_be16(offset_reg_data_p); | ||
| 701 | |||
| 702 | if (info->bi_dir[cnt]) | ||
| 703 | reg_data->vsense[cnt] = sign_extend32((u32)(tmp_value), 15); | ||
| 704 | else | ||
| 705 | reg_data->vsense[cnt] = tmp_value; | ||
| 706 | |||
| 707 | offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* VBUS_AVG */ | ||
| 711 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 712 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 713 | continue; | ||
| 714 | |||
| 715 | tmp_value = get_unaligned_be16(offset_reg_data_p); | ||
| 716 | |||
| 717 | if (info->bi_dir[cnt]) | ||
| 718 | reg_data->vbus_avg[cnt] = sign_extend32((u32)(tmp_value), 15); | ||
| 719 | else | ||
| 720 | reg_data->vbus_avg[cnt] = tmp_value; | ||
| 721 | |||
| 722 | offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN; | ||
| 723 | } | ||
| 724 | |||
| 725 | /* VSENSE_AVG */ | ||
| 726 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 727 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 728 | continue; | ||
| 729 | |||
| 730 | tmp_value = get_unaligned_be16(offset_reg_data_p); | ||
| 731 | |||
| 732 | if (info->bi_dir[cnt]) | ||
| 733 | reg_data->vsense_avg[cnt] = sign_extend32((u32)(tmp_value), 15); | ||
| 734 | else | ||
| 735 | reg_data->vsense_avg[cnt] = tmp_value; | ||
| 736 | |||
| 737 | offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN; | ||
| 738 | } | ||
| 739 | |||
| 740 | /* VPOWER */ | ||
| 741 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 742 | if ((ctrl_regs_tmp << cnt) & 0x80) | ||
| 743 | continue; | ||
| 744 | |||
| 745 | tmp = get_unaligned_be32(offset_reg_data_p) >> 4; | ||
| 746 | |||
| 747 | if (info->bi_dir[cnt]) | ||
| 748 | reg_data->vpower[cnt] = sign_extend32(tmp, 27); | ||
| 749 | else | ||
| 750 | reg_data->vpower[cnt] = tmp; | ||
| 751 | |||
| 752 | offset_reg_data_p += PAC1934_VPOWER_REG_LEN; | ||
| 753 | } | ||
| 754 | |||
| 755 | return 0; | ||
| 756 | } | ||
| 757 | |||
| 758 | static int pac1934_retrieve_data(struct pac1934_chip_info *info, | ||
| 759 | u32 wait_time) | ||
| 760 | { | ||
| 761 | int ret = 0; | ||
| 762 | |||
| 763 | /* | ||
| 764 | * check if the minimal elapsed time has passed and if so, | ||
| 765 | * re-read the chip, otherwise the cached info is just fine | ||
| 766 | */ | ||
| 767 | if (time_after(jiffies, info->tstamp + msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS))) { | ||
| 768 | ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR, | ||
| 769 | wait_time); | ||
| 770 | |||
| 771 | /* | ||
| 772 | * Re-schedule the work for the read registers on timeout | ||
| 773 | * (to prevent chip registers saturation) | ||
| 774 | */ | ||
| 775 | mod_delayed_work(system_wq, &info->work_chip_rfsh, | ||
| 776 | msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS)); | ||
| 777 | } | ||
| 778 | |||
| 779 | return ret; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int pac1934_read_raw(struct iio_dev *indio_dev, | ||
| 783 | struct iio_chan_spec const *chan, int *val, | ||
| 784 | int *val2, long mask) | ||
| 785 | { | ||
| 786 | struct pac1934_chip_info *info = iio_priv(indio_dev); | ||
| 787 | s64 curr_energy; | ||
| 788 | int ret, channel = chan->channel - 1; | ||
| 789 | |||
| 790 | ret = pac1934_retrieve_data(info, PAC1934_MIN_UPDATE_WAIT_TIME_US); | ||
| 791 | if (ret < 0) | ||
| 792 | return ret; | ||
| 793 | |||
| 794 | switch (mask) { | ||
| 795 | case IIO_CHAN_INFO_RAW: | ||
| 796 | switch (chan->type) { | ||
| 797 | case IIO_VOLTAGE: | ||
| 798 | *val = info->chip_reg_data.vbus[channel]; | ||
| 799 | return IIO_VAL_INT; | ||
| 800 | case IIO_CURRENT: | ||
| 801 | *val = info->chip_reg_data.vsense[channel]; | ||
| 802 | return IIO_VAL_INT; | ||
| 803 | case IIO_POWER: | ||
| 804 | *val = info->chip_reg_data.vpower[channel]; | ||
| 805 | return IIO_VAL_INT; | ||
| 806 | case IIO_ENERGY: | ||
| 807 | curr_energy = info->chip_reg_data.energy_sec_acc[channel]; | ||
| 808 | *val = (u32)curr_energy; | ||
| 809 | *val2 = (u32)(curr_energy >> 32); | ||
| 810 | return IIO_VAL_INT_64; | ||
| 811 | default: | ||
| 812 | return -EINVAL; | ||
| 813 | } | ||
| 814 | case IIO_CHAN_INFO_AVERAGE_RAW: | ||
| 815 | switch (chan->type) { | ||
| 816 | case IIO_VOLTAGE: | ||
| 817 | *val = info->chip_reg_data.vbus_avg[channel]; | ||
| 818 | return IIO_VAL_INT; | ||
| 819 | case IIO_CURRENT: | ||
| 820 | *val = info->chip_reg_data.vsense_avg[channel]; | ||
| 821 | return IIO_VAL_INT; | ||
| 822 | default: | ||
| 823 | return -EINVAL; | ||
| 824 | } | ||
| 825 | case IIO_CHAN_INFO_SCALE: | ||
| 826 | switch (chan->address) { | ||
| 827 | /* Voltages - scale for millivolts */ | ||
| 828 | case PAC1934_VBUS_1_ADDR: | ||
| 829 | case PAC1934_VBUS_2_ADDR: | ||
| 830 | case PAC1934_VBUS_3_ADDR: | ||
| 831 | case PAC1934_VBUS_4_ADDR: | ||
| 832 | case PAC1934_VBUS_AVG_1_ADDR: | ||
| 833 | case PAC1934_VBUS_AVG_2_ADDR: | ||
| 834 | case PAC1934_VBUS_AVG_3_ADDR: | ||
| 835 | case PAC1934_VBUS_AVG_4_ADDR: | ||
| 836 | *val = PAC1934_VOLTAGE_MILLIVOLTS_MAX; | ||
| 837 | if (chan->scan_type.sign == 'u') | ||
| 838 | *val2 = PAC1934_VOLTAGE_U_RES; | ||
| 839 | else | ||
| 840 | *val2 = PAC1934_VOLTAGE_S_RES; | ||
| 841 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 842 | /* | ||
| 843 | * Currents - scale for mA - depends on the | ||
| 844 | * channel's shunt value | ||
| 845 | * (100mV * 1000000) / (2^16 * shunt(uohm)) | ||
| 846 | */ | ||
| 847 | case PAC1934_VSENSE_1_ADDR: | ||
| 848 | case PAC1934_VSENSE_2_ADDR: | ||
| 849 | case PAC1934_VSENSE_3_ADDR: | ||
| 850 | case PAC1934_VSENSE_4_ADDR: | ||
| 851 | case PAC1934_VSENSE_AVG_1_ADDR: | ||
| 852 | case PAC1934_VSENSE_AVG_2_ADDR: | ||
| 853 | case PAC1934_VSENSE_AVG_3_ADDR: | ||
| 854 | case PAC1934_VSENSE_AVG_4_ADDR: | ||
| 855 | *val = PAC1934_MAX_VSENSE_RSHIFTED_BY_16B; | ||
| 856 | if (chan->scan_type.sign == 'u') | ||
| 857 | *val2 = info->shunts[channel]; | ||
| 858 | else | ||
| 859 | *val2 = info->shunts[channel] >> 1; | ||
| 860 | return IIO_VAL_FRACTIONAL; | ||
| 861 | /* | ||
| 862 | * Power - uW - it will use the combined scale | ||
| 863 | * for current and voltage | ||
| 864 | * current(mA) * voltage(mV) = power (uW) | ||
| 865 | */ | ||
| 866 | case PAC1934_VPOWER_1_ADDR: | ||
| 867 | case PAC1934_VPOWER_2_ADDR: | ||
| 868 | case PAC1934_VPOWER_3_ADDR: | ||
| 869 | case PAC1934_VPOWER_4_ADDR: | ||
| 870 | *val = PAC1934_MAX_VPOWER_RSHIFTED_BY_28B; | ||
| 871 | if (chan->scan_type.sign == 'u') | ||
| 872 | *val2 = info->shunts[channel]; | ||
| 873 | else | ||
| 874 | *val2 = info->shunts[channel] >> 1; | ||
| 875 | return IIO_VAL_FRACTIONAL; | ||
| 876 | case PAC1934_VPOWER_ACC_1_ADDR: | ||
| 877 | case PAC1934_VPOWER_ACC_2_ADDR: | ||
| 878 | case PAC1934_VPOWER_ACC_3_ADDR: | ||
| 879 | case PAC1934_VPOWER_ACC_4_ADDR: | ||
| 880 | /* | ||
| 881 | * expresses the 32 bit scale value here compute | ||
| 882 | * the scale for energy (miliWatt-second or miliJoule) | ||
| 883 | */ | ||
| 884 | *val = PAC1934_SCALE_CONSTANT; | ||
| 885 | |||
| 886 | if (chan->scan_type.sign == 'u') | ||
| 887 | *val2 = info->shunts[channel]; | ||
| 888 | else | ||
| 889 | *val2 = info->shunts[channel] >> 1; | ||
| 890 | return IIO_VAL_FRACTIONAL; | ||
| 891 | default: | ||
| 892 | return -EINVAL; | ||
| 893 | } | ||
| 894 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 895 | *val = info->sample_rate_value; | ||
| 896 | return IIO_VAL_INT; | ||
| 897 | case IIO_CHAN_INFO_ENABLE: | ||
| 898 | *val = info->enable_energy[channel]; | ||
| 899 | return IIO_VAL_INT; | ||
| 900 | default: | ||
| 901 | return -EINVAL; | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | static int pac1934_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, | ||
| 906 | int val, int val2, long mask) | ||
| 907 | { | ||
| 908 | struct pac1934_chip_info *info = iio_priv(indio_dev); | ||
| 909 | struct i2c_client *client = info->client; | ||
| 910 | int ret = -EINVAL; | ||
| 911 | s32 old_samp_rate; | ||
| 912 | u8 ctrl_reg; | ||
| 913 | |||
| 914 | switch (mask) { | ||
| 915 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 916 | ret = pac1934_get_samp_rate_idx(info, val); | ||
| 917 | if (ret < 0) | ||
| 918 | return ret; | ||
| 919 | |||
| 920 | /* write the new sampling value and trigger a snapshot(incl refresh) */ | ||
| 921 | scoped_guard(mutex, &info->lock) { | ||
| 922 | ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, ret); | ||
| 923 | ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg); | ||
| 924 | if (ret) { | ||
| 925 | dev_err(&client->dev, | ||
| 926 | "%s - can't update sample rate\n", | ||
| 927 | __func__); | ||
| 928 | return ret; | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 932 | old_samp_rate = info->sample_rate_value; | ||
| 933 | info->sample_rate_value = val; | ||
| 934 | |||
| 935 | /* | ||
| 936 | * now, force a snapshot with refresh - call retrieve | ||
| 937 | * data in order to update the refresh timer | ||
| 938 | * alter the timestamp in order to force trigger a | ||
| 939 | * register snapshot and a timestamp update | ||
| 940 | */ | ||
| 941 | info->tstamp -= msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS); | ||
| 942 | ret = pac1934_retrieve_data(info, (1024 / old_samp_rate) * 1000); | ||
| 943 | if (ret < 0) { | ||
| 944 | dev_err(&client->dev, | ||
| 945 | "%s - cannot snapshot ctrl and measurement regs\n", | ||
| 946 | __func__); | ||
| 947 | return ret; | ||
| 948 | } | ||
| 949 | |||
| 950 | return 0; | ||
| 951 | case IIO_CHAN_INFO_ENABLE: | ||
| 952 | scoped_guard(mutex, &info->lock) { | ||
| 953 | info->enable_energy[chan->channel - 1] = val ? true : false; | ||
| 954 | if (!val) | ||
| 955 | info->chip_reg_data.energy_sec_acc[chan->channel - 1] = 0; | ||
| 956 | } | ||
| 957 | |||
| 958 | return 0; | ||
| 959 | default: | ||
| 960 | return -EINVAL; | ||
| 961 | } | ||
| 962 | } | ||
| 963 | |||
| 964 | static int pac1934_read_label(struct iio_dev *indio_dev, | ||
| 965 | struct iio_chan_spec const *chan, char *label) | ||
| 966 | { | ||
| 967 | struct pac1934_chip_info *info = iio_priv(indio_dev); | ||
| 968 | |||
| 969 | switch (chan->address) { | ||
| 970 | case PAC1934_VBUS_1_ADDR: | ||
| 971 | case PAC1934_VBUS_2_ADDR: | ||
| 972 | case PAC1934_VBUS_3_ADDR: | ||
| 973 | case PAC1934_VBUS_4_ADDR: | ||
| 974 | return sysfs_emit(label, "%s_VBUS_%d\n", | ||
| 975 | info->labels[chan->scan_index], | ||
| 976 | chan->scan_index + 1); | ||
| 977 | case PAC1934_VBUS_AVG_1_ADDR: | ||
| 978 | case PAC1934_VBUS_AVG_2_ADDR: | ||
| 979 | case PAC1934_VBUS_AVG_3_ADDR: | ||
| 980 | case PAC1934_VBUS_AVG_4_ADDR: | ||
| 981 | return sysfs_emit(label, "%s_VBUS_AVG_%d\n", | ||
| 982 | info->labels[chan->scan_index], | ||
| 983 | chan->scan_index + 1); | ||
| 984 | case PAC1934_VSENSE_1_ADDR: | ||
| 985 | case PAC1934_VSENSE_2_ADDR: | ||
| 986 | case PAC1934_VSENSE_3_ADDR: | ||
| 987 | case PAC1934_VSENSE_4_ADDR: | ||
| 988 | return sysfs_emit(label, "%s_IBUS_%d\n", | ||
| 989 | info->labels[chan->scan_index], | ||
| 990 | chan->scan_index + 1); | ||
| 991 | case PAC1934_VSENSE_AVG_1_ADDR: | ||
| 992 | case PAC1934_VSENSE_AVG_2_ADDR: | ||
| 993 | case PAC1934_VSENSE_AVG_3_ADDR: | ||
| 994 | case PAC1934_VSENSE_AVG_4_ADDR: | ||
| 995 | return sysfs_emit(label, "%s_IBUS_AVG_%d\n", | ||
| 996 | info->labels[chan->scan_index], | ||
| 997 | chan->scan_index + 1); | ||
| 998 | case PAC1934_VPOWER_1_ADDR: | ||
| 999 | case PAC1934_VPOWER_2_ADDR: | ||
| 1000 | case PAC1934_VPOWER_3_ADDR: | ||
| 1001 | case PAC1934_VPOWER_4_ADDR: | ||
| 1002 | return sysfs_emit(label, "%s_POWER_%d\n", | ||
| 1003 | info->labels[chan->scan_index], | ||
| 1004 | chan->scan_index + 1); | ||
| 1005 | case PAC1934_VPOWER_ACC_1_ADDR: | ||
| 1006 | case PAC1934_VPOWER_ACC_2_ADDR: | ||
| 1007 | case PAC1934_VPOWER_ACC_3_ADDR: | ||
| 1008 | case PAC1934_VPOWER_ACC_4_ADDR: | ||
| 1009 | return sysfs_emit(label, "%s_ENERGY_%d\n", | ||
| 1010 | info->labels[chan->scan_index], | ||
| 1011 | chan->scan_index + 1); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | return 0; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | static void pac1934_work_periodic_rfsh(struct work_struct *work) | ||
| 1018 | { | ||
| 1019 | struct pac1934_chip_info *info = TO_PAC1934_CHIP_INFO((struct delayed_work *)work); | ||
| 1020 | struct device *dev = &info->client->dev; | ||
| 1021 | |||
| 1022 | dev_dbg(dev, "%s - Periodic refresh\n", __func__); | ||
| 1023 | |||
| 1024 | /* do a REFRESH, then read */ | ||
| 1025 | pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR, | ||
| 1026 | PAC1934_MIN_UPDATE_WAIT_TIME_US); | ||
| 1027 | |||
| 1028 | schedule_delayed_work(&info->work_chip_rfsh, | ||
| 1029 | msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS)); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static int pac1934_read_revision(struct pac1934_chip_info *info, u8 *buf) | ||
| 1033 | { | ||
| 1034 | int ret; | ||
| 1035 | struct i2c_client *client = info->client; | ||
| 1036 | |||
| 1037 | ret = i2c_smbus_read_i2c_block_data(client, PAC1934_PID_REG_ADDR, | ||
| 1038 | PAC1934_ID_REG_LEN, | ||
| 1039 | buf); | ||
| 1040 | if (ret < 0) { | ||
| 1041 | dev_err(&client->dev, "cannot read revision\n"); | ||
| 1042 | return ret; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | return 0; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static int pac1934_chip_identify(struct pac1934_chip_info *info) | ||
| 1049 | { | ||
| 1050 | u8 rev_info[PAC1934_ID_REG_LEN]; | ||
| 1051 | struct device *dev = &info->client->dev; | ||
| 1052 | int ret = 0; | ||
| 1053 | |||
| 1054 | ret = pac1934_read_revision(info, (u8 *)rev_info); | ||
| 1055 | if (ret) | ||
| 1056 | return ret; | ||
| 1057 | |||
| 1058 | info->chip_variant = rev_info[PAC1934_PID_IDX]; | ||
| 1059 | info->chip_revision = rev_info[PAC1934_RID_IDX]; | ||
| 1060 | |||
| 1061 | dev_dbg(dev, "Chip variant: 0x%02X\n", info->chip_variant); | ||
| 1062 | dev_dbg(dev, "Chip revision: 0x%02X\n", info->chip_revision); | ||
| 1063 | |||
| 1064 | switch (info->chip_variant) { | ||
| 1065 | case PAC1934_PID: | ||
| 1066 | return PAC1934; | ||
| 1067 | case PAC1933_PID: | ||
| 1068 | return PAC1933; | ||
| 1069 | case PAC1932_PID: | ||
| 1070 | return PAC1932; | ||
| 1071 | case PAC1931_PID: | ||
| 1072 | return PAC1931; | ||
| 1073 | default: | ||
| 1074 | return -EINVAL; | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* | ||
| 1079 | * documentation related to the ACPI device definition | ||
| 1080 | * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf | ||
| 1081 | */ | ||
| 1082 | static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, | ||
| 1083 | struct pac1934_chip_info *info) | ||
| 1084 | { | ||
| 1085 | acpi_handle handle; | ||
| 1086 | union acpi_object *rez; | ||
| 1087 | struct device *dev = &client->dev; | ||
| 1088 | unsigned short bi_dir_mask; | ||
| 1089 | int idx, i; | ||
| 1090 | guid_t guid; | ||
| 1091 | |||
| 1092 | handle = ACPI_HANDLE(dev); | ||
| 1093 | |||
| 1094 | guid_parse(PAC1934_DSM_UUID, &guid); | ||
| 1095 | |||
| 1096 | rez = acpi_evaluate_dsm(handle, &guid, 0, PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS, NULL); | ||
| 1097 | if (!rez) | ||
| 1098 | return false; | ||
| 1099 | |||
| 1100 | for (i = 0; i < rez->package.count; i += 2) { | ||
| 1101 | idx = i / 2; | ||
| 1102 | info->labels[idx] = | ||
| 1103 | devm_kmemdup(dev, rez->package.elements[i].string.pointer, | ||
| 1104 | (size_t)rez->package.elements[i].string.length + 1, | ||
| 1105 | GFP_KERNEL); | ||
| 1106 | info->labels[idx][rez->package.elements[i].string.length] = '\0'; | ||
| 1107 | info->shunts[idx] = rez->package.elements[i + 1].integer.value * 1000; | ||
| 1108 | info->active_channels[idx] = (info->shunts[idx] != 0); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | ACPI_FREE(rez); | ||
| 1112 | |||
| 1113 | rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_UOHMS_VALS, NULL); | ||
| 1114 | if (!rez) { | ||
| 1115 | /* | ||
| 1116 | * initializing with default values | ||
| 1117 | * we assume all channels are unidirectional(the mask is zero) | ||
| 1118 | * and assign the default sampling rate | ||
| 1119 | */ | ||
| 1120 | info->sample_rate_value = PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ; | ||
| 1121 | return true; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | for (i = 0; i < rez->package.count; i++) { | ||
| 1125 | idx = i; | ||
| 1126 | info->shunts[idx] = rez->package.elements[i].integer.value; | ||
| 1127 | info->active_channels[idx] = (info->shunts[idx] != 0); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | ACPI_FREE(rez); | ||
| 1131 | |||
| 1132 | rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_BIPOLAR_SETTINGS, NULL); | ||
| 1133 | if (!rez) | ||
| 1134 | return false; | ||
| 1135 | |||
| 1136 | bi_dir_mask = rez->package.elements[0].integer.value; | ||
| 1137 | info->bi_dir[0] = ((bi_dir_mask & (1 << 3)) | (bi_dir_mask & (1 << 7))) != 0; | ||
| 1138 | info->bi_dir[1] = ((bi_dir_mask & (1 << 2)) | (bi_dir_mask & (1 << 6))) != 0; | ||
| 1139 | info->bi_dir[2] = ((bi_dir_mask & (1 << 1)) | (bi_dir_mask & (1 << 5))) != 0; | ||
| 1140 | info->bi_dir[3] = ((bi_dir_mask & (1 << 0)) | (bi_dir_mask & (1 << 4))) != 0; | ||
| 1141 | |||
| 1142 | ACPI_FREE(rez); | ||
| 1143 | |||
| 1144 | rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_SAMP, NULL); | ||
| 1145 | if (!rez) | ||
| 1146 | return false; | ||
| 1147 | |||
| 1148 | info->sample_rate_value = rez->package.elements[0].integer.value; | ||
| 1149 | |||
| 1150 | ACPI_FREE(rez); | ||
| 1151 | |||
| 1152 | return true; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static bool pac1934_of_parse_channel_config(struct i2c_client *client, | ||
| 1156 | struct pac1934_chip_info *info) | ||
| 1157 | { | ||
| 1158 | struct fwnode_handle *node, *fwnode; | ||
| 1159 | struct device *dev = &client->dev; | ||
| 1160 | unsigned int current_channel; | ||
| 1161 | int idx, ret; | ||
| 1162 | |||
| 1163 | info->sample_rate_value = 1024; | ||
| 1164 | current_channel = 1; | ||
| 1165 | |||
| 1166 | fwnode = dev_fwnode(dev); | ||
| 1167 | fwnode_for_each_available_child_node(fwnode, node) { | ||
| 1168 | ret = fwnode_property_read_u32(node, "reg", &idx); | ||
| 1169 | if (ret) { | ||
| 1170 | dev_err_probe(dev, ret, | ||
| 1171 | "reading invalid channel index\n"); | ||
| 1172 | goto err_fwnode; | ||
| 1173 | } | ||
| 1174 | /* adjust idx to match channel index (1 to 4) from the datasheet */ | ||
| 1175 | idx--; | ||
| 1176 | |||
| 1177 | if (current_channel >= (info->phys_channels + 1) || | ||
| 1178 | idx >= info->phys_channels || idx < 0) { | ||
| 1179 | dev_err_probe(dev, -EINVAL, | ||
| 1180 | "%s: invalid channel_index %d value\n", | ||
| 1181 | fwnode_get_name(node), idx); | ||
| 1182 | goto err_fwnode; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | /* enable channel */ | ||
| 1186 | info->active_channels[idx] = true; | ||
| 1187 | |||
| 1188 | ret = fwnode_property_read_u32(node, "shunt-resistor-micro-ohms", | ||
| 1189 | &info->shunts[idx]); | ||
| 1190 | if (ret) { | ||
| 1191 | dev_err_probe(dev, ret, | ||
| 1192 | "%s: invalid shunt-resistor value: %d\n", | ||
| 1193 | fwnode_get_name(node), info->shunts[idx]); | ||
| 1194 | goto err_fwnode; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | if (fwnode_property_present(node, "label")) { | ||
| 1198 | ret = fwnode_property_read_string(node, "label", | ||
| 1199 | (const char **)&info->labels[idx]); | ||
| 1200 | if (ret) { | ||
| 1201 | dev_err_probe(dev, ret, | ||
| 1202 | "%s: invalid rail-name value\n", | ||
| 1203 | fwnode_get_name(node)); | ||
| 1204 | goto err_fwnode; | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | info->bi_dir[idx] = fwnode_property_read_bool(node, "bipolar"); | ||
| 1209 | |||
| 1210 | current_channel++; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | return true; | ||
| 1214 | |||
| 1215 | err_fwnode: | ||
| 1216 | fwnode_handle_put(node); | ||
| 1217 | |||
| 1218 | return false; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | static void pac1934_cancel_delayed_work(void *dwork) | ||
| 1222 | { | ||
| 1223 | cancel_delayed_work_sync(dwork); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | static int pac1934_chip_configure(struct pac1934_chip_info *info) | ||
| 1227 | { | ||
| 1228 | int cnt, ret; | ||
| 1229 | struct i2c_client *client = info->client; | ||
| 1230 | u8 regs[PAC1934_CTRL_STATUS_INFO_LEN], idx, ctrl_reg; | ||
| 1231 | u32 wait_time; | ||
| 1232 | |||
| 1233 | info->chip_reg_data.num_enabled_channels = 0; | ||
| 1234 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 1235 | if (info->active_channels[cnt]) | ||
| 1236 | info->chip_reg_data.num_enabled_channels++; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | /* | ||
| 1240 | * read whatever information was gathered before the driver was loaded | ||
| 1241 | * establish which channels are enabled/disabled and then establish the | ||
| 1242 | * information retrieval mode (using SKIP or no). | ||
| 1243 | * Read the chip ID values | ||
| 1244 | */ | ||
| 1245 | ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR, | ||
| 1246 | ARRAY_SIZE(regs), | ||
| 1247 | (u8 *)regs); | ||
| 1248 | if (ret < 0) { | ||
| 1249 | dev_err_probe(&client->dev, ret, | ||
| 1250 | "%s - cannot read regs from 0x%02X\n", | ||
| 1251 | __func__, PAC1934_CTRL_STAT_REGS_ADDR); | ||
| 1252 | return ret; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /* write the CHANNEL_DIS and the NEG_PWR registers */ | ||
| 1256 | regs[PAC1934_CHANNEL_DIS_REG_OFF] = | ||
| 1257 | FIELD_PREP(PAC1934_CHAN_DIS_CH1_OFF_MASK, info->active_channels[0] ? 0 : 1) | | ||
| 1258 | FIELD_PREP(PAC1934_CHAN_DIS_CH2_OFF_MASK, info->active_channels[1] ? 0 : 1) | | ||
| 1259 | FIELD_PREP(PAC1934_CHAN_DIS_CH3_OFF_MASK, info->active_channels[2] ? 0 : 1) | | ||
| 1260 | FIELD_PREP(PAC1934_CHAN_DIS_CH4_OFF_MASK, info->active_channels[3] ? 0 : 1) | | ||
| 1261 | FIELD_PREP(PAC1934_SMBUS_TIMEOUT_MASK, 0) | | ||
| 1262 | FIELD_PREP(PAC1934_SMBUS_BYTECOUNT_MASK, 0) | | ||
| 1263 | FIELD_PREP(PAC1934_SMBUS_NO_SKIP_MASK, 0); | ||
| 1264 | |||
| 1265 | regs[PAC1934_NEG_PWR_REG_OFF] = | ||
| 1266 | FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) | | ||
| 1267 | FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) | | ||
| 1268 | FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) | | ||
| 1269 | FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) | | ||
| 1270 | FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) | | ||
| 1271 | FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) | | ||
| 1272 | FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) | | ||
| 1273 | FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]); | ||
| 1274 | |||
| 1275 | /* no SLOW triggered REFRESH, clear POR */ | ||
| 1276 | regs[PAC1934_SLOW_REG_OFF] = 0; | ||
| 1277 | |||
| 1278 | ret = i2c_smbus_write_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR, | ||
| 1279 | ARRAY_SIZE(regs), (u8 *)regs); | ||
| 1280 | if (ret) | ||
| 1281 | return ret; | ||
| 1282 | |||
| 1283 | /* Default sampling rate */ | ||
| 1284 | ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, PAC1934_SAMP_1024SPS); | ||
| 1285 | |||
| 1286 | ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg); | ||
| 1287 | if (ret) | ||
| 1288 | return ret; | ||
| 1289 | |||
| 1290 | /* | ||
| 1291 | * send a REFRESH to the chip, so the new settings take place | ||
| 1292 | * as well as resetting the accumulators | ||
| 1293 | */ | ||
| 1294 | ret = i2c_smbus_write_byte(client, PAC1934_REFRESH_REG_ADDR); | ||
| 1295 | if (ret) { | ||
| 1296 | dev_err(&client->dev, | ||
| 1297 | "%s - cannot send 0x%02X\n", | ||
| 1298 | __func__, PAC1934_REFRESH_REG_ADDR); | ||
| 1299 | return ret; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /* | ||
| 1303 | * get the current(in the chip) sampling speed and compute the | ||
| 1304 | * required timeout based on its value | ||
| 1305 | * the timeout is 1/sampling_speed | ||
| 1306 | */ | ||
| 1307 | idx = regs[PAC1934_CTRL_ACT_REG_OFF] >> PAC1934_SAMPLE_RATE_SHIFT; | ||
| 1308 | wait_time = (1024 / samp_rate_map_tbl[idx]) * 1000; | ||
| 1309 | |||
| 1310 | /* | ||
| 1311 | * wait the maximum amount of time to be on the safe side | ||
| 1312 | * the maximum wait time is for 8sps | ||
| 1313 | */ | ||
| 1314 | usleep_range(wait_time, wait_time + 100); | ||
| 1315 | |||
| 1316 | INIT_DELAYED_WORK(&info->work_chip_rfsh, pac1934_work_periodic_rfsh); | ||
| 1317 | /* Setup the latest moment for reading the regs before saturation */ | ||
| 1318 | schedule_delayed_work(&info->work_chip_rfsh, | ||
| 1319 | msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS)); | ||
| 1320 | |||
| 1321 | return devm_add_action_or_reset(&client->dev, pac1934_cancel_delayed_work, | ||
| 1322 | &info->work_chip_rfsh); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_dev *indio_dev) | ||
| 1326 | { | ||
| 1327 | struct iio_chan_spec *ch_sp; | ||
| 1328 | int channel_size, attribute_count, cnt; | ||
| 1329 | void *dyn_ch_struct, *tmp_data; | ||
| 1330 | struct device *dev = &info->client->dev; | ||
| 1331 | |||
| 1332 | /* find out dynamically how many IIO channels we need */ | ||
| 1333 | attribute_count = 0; | ||
| 1334 | channel_size = 0; | ||
| 1335 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 1336 | if (!info->active_channels[cnt]) | ||
| 1337 | continue; | ||
| 1338 | |||
| 1339 | /* add the size of the properties of one chip physical channel */ | ||
| 1340 | channel_size += sizeof(pac1934_single_channel); | ||
| 1341 | /* count how many enabled channels we have */ | ||
| 1342 | attribute_count += ARRAY_SIZE(pac1934_single_channel); | ||
| 1343 | dev_dbg(dev, ":%s: Channel %d active\n", __func__, cnt + 1); | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL); | ||
| 1347 | if (!dyn_ch_struct) | ||
| 1348 | return -EINVAL; | ||
| 1349 | |||
| 1350 | tmp_data = dyn_ch_struct; | ||
| 1351 | |||
| 1352 | /* populate the dynamic channels and make all the adjustments */ | ||
| 1353 | for (cnt = 0; cnt < info->phys_channels; cnt++) { | ||
| 1354 | if (!info->active_channels[cnt]) | ||
| 1355 | continue; | ||
| 1356 | |||
| 1357 | memcpy(tmp_data, pac1934_single_channel, sizeof(pac1934_single_channel)); | ||
| 1358 | ch_sp = (struct iio_chan_spec *)tmp_data; | ||
| 1359 | ch_sp[PAC1934_CH_ENERGY].channel = cnt + 1; | ||
| 1360 | ch_sp[PAC1934_CH_ENERGY].scan_index = cnt; | ||
| 1361 | ch_sp[PAC1934_CH_ENERGY].address = cnt + PAC1934_VPOWER_ACC_1_ADDR; | ||
| 1362 | ch_sp[PAC1934_CH_POWER].channel = cnt + 1; | ||
| 1363 | ch_sp[PAC1934_CH_POWER].scan_index = cnt; | ||
| 1364 | ch_sp[PAC1934_CH_POWER].address = cnt + PAC1934_VPOWER_1_ADDR; | ||
| 1365 | ch_sp[PAC1934_CH_VOLTAGE].channel = cnt + 1; | ||
| 1366 | ch_sp[PAC1934_CH_VOLTAGE].scan_index = cnt; | ||
| 1367 | ch_sp[PAC1934_CH_VOLTAGE].address = cnt + PAC1934_VBUS_1_ADDR; | ||
| 1368 | ch_sp[PAC1934_CH_CURRENT].channel = cnt + 1; | ||
| 1369 | ch_sp[PAC1934_CH_CURRENT].scan_index = cnt; | ||
| 1370 | ch_sp[PAC1934_CH_CURRENT].address = cnt + PAC1934_VSENSE_1_ADDR; | ||
| 1371 | |||
| 1372 | /* | ||
| 1373 | * In order to be able to use labels for PAC1934_CH_VOLTAGE, and | ||
| 1374 | * PAC1934_CH_VOLTAGE_AVERAGE,respectively PAC1934_CH_CURRENT | ||
| 1375 | * and PAC1934_CH_CURRENT_AVERAGE we need to use different | ||
| 1376 | * channel numbers. We will add +5 (+1 to maximum PAC channels). | ||
| 1377 | */ | ||
| 1378 | ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].channel = cnt + 5; | ||
| 1379 | ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_index = cnt; | ||
| 1380 | ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].address = cnt + PAC1934_VBUS_AVG_1_ADDR; | ||
| 1381 | ch_sp[PAC1934_CH_CURRENT_AVERAGE].channel = cnt + 5; | ||
| 1382 | ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_index = cnt; | ||
| 1383 | ch_sp[PAC1934_CH_CURRENT_AVERAGE].address = cnt + PAC1934_VSENSE_AVG_1_ADDR; | ||
| 1384 | |||
| 1385 | /* | ||
| 1386 | * now modify the parameters in all channels if the | ||
| 1387 | * whole chip rail(channel) is bi-directional | ||
| 1388 | */ | ||
| 1389 | if (info->bi_dir[cnt]) { | ||
| 1390 | ch_sp[PAC1934_CH_ENERGY].scan_type.sign = 's'; | ||
| 1391 | ch_sp[PAC1934_CH_ENERGY].scan_type.realbits = 47; | ||
| 1392 | ch_sp[PAC1934_CH_POWER].scan_type.sign = 's'; | ||
| 1393 | ch_sp[PAC1934_CH_POWER].scan_type.realbits = 27; | ||
| 1394 | ch_sp[PAC1934_CH_VOLTAGE].scan_type.sign = 's'; | ||
| 1395 | ch_sp[PAC1934_CH_VOLTAGE].scan_type.realbits = 15; | ||
| 1396 | ch_sp[PAC1934_CH_CURRENT].scan_type.sign = 's'; | ||
| 1397 | ch_sp[PAC1934_CH_CURRENT].scan_type.realbits = 15; | ||
| 1398 | ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.sign = 's'; | ||
| 1399 | ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.realbits = 15; | ||
| 1400 | ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.sign = 's'; | ||
| 1401 | ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.realbits = 15; | ||
| 1402 | } | ||
| 1403 | tmp_data += sizeof(pac1934_single_channel); | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | /* | ||
| 1407 | * send the updated dynamic channel structure information towards IIO | ||
| 1408 | * prepare the required field for IIO class registration | ||
| 1409 | */ | ||
| 1410 | indio_dev->num_channels = attribute_count; | ||
| 1411 | indio_dev->channels = (const struct iio_chan_spec *)dyn_ch_struct; | ||
| 1412 | |||
| 1413 | return 0; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | static IIO_DEVICE_ATTR(in_shunt_resistor1, 0644, | ||
| 1417 | pac1934_shunt_value_show, pac1934_shunt_value_store, 0); | ||
| 1418 | static IIO_DEVICE_ATTR(in_shunt_resistor2, 0644, | ||
| 1419 | pac1934_shunt_value_show, pac1934_shunt_value_store, 1); | ||
| 1420 | static IIO_DEVICE_ATTR(in_shunt_resistor3, 0644, | ||
| 1421 | pac1934_shunt_value_show, pac1934_shunt_value_store, 2); | ||
| 1422 | static IIO_DEVICE_ATTR(in_shunt_resistor4, 0644, | ||
| 1423 | pac1934_shunt_value_show, pac1934_shunt_value_store, 3); | ||
| 1424 | |||
| 1425 | static int pac1934_prep_custom_attributes(struct pac1934_chip_info *info, | ||
| 1426 | struct iio_dev *indio_dev) | ||
| 1427 | { | ||
| 1428 | int i, active_channels_count = 0; | ||
| 1429 | struct attribute **pac1934_custom_attr; | ||
| 1430 | struct attribute_group *pac1934_group; | ||
| 1431 | struct device *dev = &info->client->dev; | ||
| 1432 | |||
| 1433 | for (i = 0 ; i < info->phys_channels; i++) | ||
| 1434 | if (info->active_channels[i]) | ||
| 1435 | active_channels_count++; | ||
| 1436 | |||
| 1437 | pac1934_group = devm_kzalloc(dev, sizeof(*pac1934_group), GFP_KERNEL); | ||
| 1438 | if (!pac1934_group) | ||
| 1439 | return -ENOMEM; | ||
| 1440 | |||
| 1441 | pac1934_custom_attr = devm_kzalloc(dev, | ||
| 1442 | (PAC1934_CUSTOM_ATTR_FOR_CHANNEL * | ||
| 1443 | active_channels_count) | ||
| 1444 | * sizeof(*pac1934_group) + 1, | ||
| 1445 | GFP_KERNEL); | ||
| 1446 | if (!pac1934_custom_attr) | ||
| 1447 | return -ENOMEM; | ||
| 1448 | |||
| 1449 | i = 0; | ||
| 1450 | if (info->active_channels[0]) | ||
| 1451 | pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor1); | ||
| 1452 | |||
| 1453 | if (info->active_channels[1]) | ||
| 1454 | pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor2); | ||
| 1455 | |||
| 1456 | if (info->active_channels[2]) | ||
| 1457 | pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor3); | ||
| 1458 | |||
| 1459 | if (info->active_channels[3]) | ||
| 1460 | pac1934_custom_attr[i] = PAC1934_DEV_ATTR(in_shunt_resistor4); | ||
| 1461 | |||
| 1462 | pac1934_group->attrs = pac1934_custom_attr; | ||
| 1463 | info->iio_info.attrs = pac1934_group; | ||
| 1464 | |||
| 1465 | return 0; | ||
| 1466 | } | ||
| 1467 | |||
| 1468 | static void pac1934_mutex_destroy(void *data) | ||
| 1469 | { | ||
| 1470 | struct mutex *lock = data; | ||
| 1471 | |||
| 1472 | mutex_destroy(lock); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | static const struct iio_info pac1934_info = { | ||
| 1476 | .read_raw = pac1934_read_raw, | ||
| 1477 | .write_raw = pac1934_write_raw, | ||
| 1478 | .read_avail = pac1934_read_avail, | ||
| 1479 | .read_label = pac1934_read_label, | ||
| 1480 | }; | ||
| 1481 | |||
| 1482 | static int pac1934_probe(struct i2c_client *client) | ||
| 1483 | { | ||
| 1484 | struct pac1934_chip_info *info; | ||
| 1485 | const struct pac1934_features *chip; | ||
| 1486 | struct iio_dev *indio_dev; | ||
| 1487 | int cnt, ret; | ||
| 1488 | bool match = false; | ||
| 1489 | struct device *dev = &client->dev; | ||
| 1490 | |||
| 1491 | indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); | ||
| 1492 | if (!indio_dev) | ||
| 1493 | return -ENOMEM; | ||
| 1494 | |||
| 1495 | info = iio_priv(indio_dev); | ||
| 1496 | |||
| 1497 | info->client = client; | ||
| 1498 | |||
| 1499 | /* always start with energy accumulation enabled */ | ||
| 1500 | for (cnt = 0; cnt < PAC1934_MAX_NUM_CHANNELS; cnt++) | ||
| 1501 | info->enable_energy[cnt] = true; | ||
| 1502 | |||
| 1503 | ret = pac1934_chip_identify(info); | ||
| 1504 | if (ret < 0) { | ||
| 1505 | /* | ||
| 1506 | * If failed to identify the hardware based on internal | ||
| 1507 | * registers, try using fallback compatible in device tree | ||
| 1508 | * to deal with some newer part number. | ||
| 1509 | */ | ||
| 1510 | chip = i2c_get_match_data(client); | ||
| 1511 | if (!chip) | ||
| 1512 | return -EINVAL; | ||
| 1513 | |||
| 1514 | info->phys_channels = chip->phys_channels; | ||
| 1515 | indio_dev->name = chip->name; | ||
| 1516 | } else { | ||
| 1517 | info->phys_channels = pac1934_chip_config[ret].phys_channels; | ||
| 1518 | indio_dev->name = pac1934_chip_config[ret].name; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | if (acpi_match_device(dev->driver->acpi_match_table, dev)) | ||
| 1522 | match = pac1934_acpi_parse_channel_config(client, info); | ||
| 1523 | else | ||
| 1524 | /* | ||
| 1525 | * This makes it possible to use also ACPI PRP0001 for | ||
| 1526 | * registering the device using device tree properties. | ||
| 1527 | */ | ||
| 1528 | match = pac1934_of_parse_channel_config(client, info); | ||
| 1529 | |||
| 1530 | if (!match) | ||
| 1531 | return dev_err_probe(dev, -EINVAL, | ||
| 1532 | "parameter parsing returned an error\n"); | ||
| 1533 | |||
| 1534 | mutex_init(&info->lock); | ||
| 1535 | ret = devm_add_action_or_reset(dev, pac1934_mutex_destroy, | ||
| 1536 | &info->lock); | ||
| 1537 | if (ret < 0) | ||
| 1538 | return ret; | ||
| 1539 | |||
| 1540 | /* | ||
| 1541 | * do now any chip specific initialization (e.g. read/write | ||
| 1542 | * some registers), enable/disable certain channels, change the sampling | ||
| 1543 | * rate to the requested value | ||
| 1544 | */ | ||
| 1545 | ret = pac1934_chip_configure(info); | ||
| 1546 | if (ret < 0) | ||
| 1547 | return ret; | ||
| 1548 | |||
| 1549 | /* prepare the channel information */ | ||
| 1550 | ret = pac1934_prep_iio_channels(info, indio_dev); | ||
| 1551 | if (ret < 0) | ||
| 1552 | return ret; | ||
| 1553 | |||
| 1554 | info->iio_info = pac1934_info; | ||
| 1555 | indio_dev->info = &info->iio_info; | ||
| 1556 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 1557 | |||
| 1558 | ret = pac1934_prep_custom_attributes(info, indio_dev); | ||
| 1559 | if (ret < 0) | ||
| 1560 | return dev_err_probe(dev, ret, | ||
| 1561 | "Can't configure custom attributes for PAC1934 device\n"); | ||
| 1562 | |||
| 1563 | /* | ||
| 1564 | * read whatever has been accumulated in the chip so far | ||
| 1565 | * and reset the accumulators | ||
| 1566 | */ | ||
| 1567 | ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR, | ||
| 1568 | PAC1934_MIN_UPDATE_WAIT_TIME_US); | ||
| 1569 | if (ret < 0) | ||
| 1570 | return ret; | ||
| 1571 | |||
| 1572 | ret = devm_iio_device_register(dev, indio_dev); | ||
| 1573 | if (ret < 0) | ||
| 1574 | return dev_err_probe(dev, ret, | ||
| 1575 | "Can't register IIO device\n"); | ||
| 1576 | |||
| 1577 | return 0; | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | static const struct i2c_device_id pac1934_id[] = { | ||
| 1581 | { .name = "pac1931", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1931] }, | ||
| 1582 | { .name = "pac1932", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1932] }, | ||
| 1583 | { .name = "pac1933", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1933] }, | ||
| 1584 | { .name = "pac1934", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] }, | ||
| 1585 | {} | ||
| 1586 | }; | ||
| 1587 | MODULE_DEVICE_TABLE(i2c, pac1934_id); | ||
| 1588 | |||
| 1589 | static const struct of_device_id pac1934_of_match[] = { | ||
| 1590 | { | ||
| 1591 | .compatible = "microchip,pac1931", | ||
| 1592 | .data = &pac1934_chip_config[PAC1931] | ||
| 1593 | }, | ||
| 1594 | { | ||
| 1595 | .compatible = "microchip,pac1932", | ||
| 1596 | .data = &pac1934_chip_config[PAC1932] | ||
| 1597 | }, | ||
| 1598 | { | ||
| 1599 | .compatible = "microchip,pac1933", | ||
| 1600 | .data = &pac1934_chip_config[PAC1933] | ||
| 1601 | }, | ||
| 1602 | { | ||
| 1603 | .compatible = "microchip,pac1934", | ||
| 1604 | .data = &pac1934_chip_config[PAC1934] | ||
| 1605 | }, | ||
| 1606 | {} | ||
| 1607 | }; | ||
| 1608 | MODULE_DEVICE_TABLE(of, pac1934_of_match); | ||
| 1609 | |||
| 1610 | /* | ||
| 1611 | * using MCHP1930 to be compatible with BIOS ACPI. See example: | ||
| 1612 | * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf | ||
| 1613 | */ | ||
| 1614 | static const struct acpi_device_id pac1934_acpi_match[] = { | ||
| 1615 | { "MCHP1930", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] }, | ||
| 1616 | {} | ||
| 1617 | }; | ||
| 1618 | MODULE_DEVICE_TABLE(acpi, pac1934_acpi_match); | ||
| 1619 | |||
| 1620 | static struct i2c_driver pac1934_driver = { | ||
| 1621 | .driver = { | ||
| 1622 | .name = "pac1934", | ||
| 1623 | .of_match_table = pac1934_of_match, | ||
| 1624 | .acpi_match_table = pac1934_acpi_match | ||
| 1625 | }, | ||
| 1626 | .probe = pac1934_probe, | ||
| 1627 | .id_table = pac1934_id, | ||
| 1628 | }; | ||
| 1629 | |||
| 1630 | module_i2c_driver(pac1934_driver); | ||
| 1631 | |||
| 1632 | MODULE_AUTHOR("Bogdan Bolocan <bogdan.bolocan@microchip.com>"); | ||
| 1633 | MODULE_AUTHOR("Victor Tudose"); | ||
| 1634 | MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>"); | ||
| 1635 | MODULE_DESCRIPTION("IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor"); | ||
| 1636 | MODULE_LICENSE("GPL"); | ||
| @@ -372,7 +372,6 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = { · 371 unmodified lines | |||
| 372 | * @name: name of this channel | 372 | * @name: name of this channel |
| 373 | * @hwchan: pointer to hardware channel information (muxing & scaling settings) | 373 | * @hwchan: pointer to hardware channel information (muxing & scaling settings) |
| 374 | * @calibration: whether to use absolute or ratiometric calibration | 374 | * @calibration: whether to use absolute or ratiometric calibration |
| 375 | * @scale_fn_type: scaling function type | ||
| 376 | * @decimation: 0,1,2,3 | 375 | * @decimation: 0,1,2,3 |
| 377 | * @amux_ip_rsv: ratiometric scale value if using ratiometric | 376 | * @amux_ip_rsv: ratiometric scale value if using ratiometric |
| 378 | * calibration: 0, 1, 2, 4, 5. | 377 | * calibration: 0, 1, 2, 4, 5. |
| @@ -52,7 +52,7 @@ · 51 unmodified lines | |||
| 52 | #define SARADC2_START BIT(4) | 52 | #define SARADC2_START BIT(4) |
| 53 | #define SARADC2_SINGLE_MODE BIT(5) | 53 | #define SARADC2_SINGLE_MODE BIT(5) |
| 54 | 54 | ||
| 55 | #define SARADC2_CONV_CHANNELS GENMASK(15, 0) | 55 | #define SARADC2_CONV_CHANNELS GENMASK(3, 0) |
| 56 | 56 | ||
| 57 | struct rockchip_saradc; | 57 | struct rockchip_saradc; |
| 58 | 58 | ||
| @@ -102,12 +102,12 @@ static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn) · 43 unmodified lines | |||
| 102 | writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC); | 102 | writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC); |
| 103 | writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC); | 103 | writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC); |
| 104 | val = FIELD_PREP(SARADC2_EN_END_INT, 1); | 104 | val = FIELD_PREP(SARADC2_EN_END_INT, 1); |
| 105 | val |= val << 16; | 105 | val |= SARADC2_EN_END_INT << 16; |
| 106 | writel_relaxed(val, info->regs + SARADC2_END_INT_EN); | 106 | writel_relaxed(val, info->regs + SARADC2_END_INT_EN); |
| 107 | val = FIELD_PREP(SARADC2_START, 1) | | 107 | val = FIELD_PREP(SARADC2_START, 1) | |
| 108 | FIELD_PREP(SARADC2_SINGLE_MODE, 1) | | 108 | FIELD_PREP(SARADC2_SINGLE_MODE, 1) | |
| 109 | FIELD_PREP(SARADC2_CONV_CHANNELS, chn); | 109 | FIELD_PREP(SARADC2_CONV_CHANNELS, chn); |
| 110 | val |= val << 16; | 110 | val |= (SARADC2_START | SARADC2_SINGLE_MODE | SARADC2_CONV_CHANNELS) << 16; |
| 111 | writel(val, info->regs + SARADC2_CONV_CON); | 111 | writel(val, info->regs + SARADC2_CONV_CON); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| @@ -450,16 +450,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev) · 336 unmodified lines | |||
| 450 | * The reset should be an optional property, as it should work | 450 | * The reset should be an optional property, as it should work |
| 451 | * with old devicetrees as well | 451 | * with old devicetrees as well |
| 452 | */ | 452 | */ |
| 453 | info->reset = devm_reset_control_get_exclusive(&pdev->dev, | 453 | info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, |
| 454 | "saradc-apb"); | 454 | "saradc-apb"); |
| 455 | if (IS_ERR(info->reset)) { | 455 | if (IS_ERR(info->reset)) { |
| 456 | ret = PTR_ERR(info->reset); | 456 | ret = PTR_ERR(info->reset); |
| 457 | if (ret != -ENOENT) | 457 | return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n"); |
| 458 | return dev_err_probe(&pdev->dev, ret, | ||
| 459 | "failed to get saradc-apb\n"); | ||
| 460 | |||
| 461 | dev_dbg(&pdev->dev, "no reset control found\n"); | ||
| 462 | info->reset = NULL; | ||
| 463 | } | 458 | } |
| 464 | 459 | ||
| 465 | init_completion(&info->completion); | 460 | init_completion(&info->completion); |
| @@ -39,6 +39,10 @@ · 38 unmodified lines | |||
| 39 | #define RTQ6056_DEFAULT_CONFIG 0x4127 | 39 | #define RTQ6056_DEFAULT_CONFIG 0x4127 |
| 40 | #define RTQ6056_CONT_ALLON 7 | 40 | #define RTQ6056_CONT_ALLON 7 |
| 41 | 41 | ||
| 42 | #define RTQ6059_DEFAULT_CONFIG 0x3C47 | ||
| 43 | #define RTQ6059_VBUS_LSB_OFFSET 3 | ||
| 44 | #define RTQ6059_AVG_BASE 8 | ||
| 45 | |||
| 42 | enum { | 46 | enum { |
| 43 | RTQ6056_CH_VSHUNT = 0, | 47 | RTQ6056_CH_VSHUNT = 0, |
| 44 | RTQ6056_CH_VBUS, | 48 | RTQ6056_CH_VBUS, |
| @@ -47,19 +51,46 @@ enum { · 2 unmodified lines | |||
| 47 | RTQ6056_MAX_CHANNEL | 51 | RTQ6056_MAX_CHANNEL |
| 48 | }; | 52 | }; |
| 49 | 53 | ||
| 54 | /* | ||
| 55 | * The enum is to present the 0x00 CONFIG RG bitfield for the 16bit RG value | ||
| 56 | * field value order from LSB to MSB | ||
| 57 | * RTQ6053/6 is OPMODE->VSHUNTCT->VBUSCT->AVG->RESET | ||
| 58 | * RTQ6059 is OPMODE->SADC->BADC->PGA->RESET | ||
| 59 | */ | ||
| 50 | enum { | 60 | enum { |
| 51 | F_OPMODE = 0, | 61 | F_OPMODE = 0, |
| 52 | F_VSHUNTCT, | 62 | F_VSHUNTCT, |
| 63 | F_RTQ6059_SADC = F_VSHUNTCT, | ||
| 53 | F_VBUSCT, | 64 | F_VBUSCT, |
| 65 | F_RTQ6059_BADC = F_VBUSCT, | ||
| 54 | F_AVG, | 66 | F_AVG, |
| 67 | F_RTQ6059_PGA = F_AVG, | ||
| 55 | F_RESET, | 68 | F_RESET, |
| 56 | F_MAX_FIELDS | 69 | F_MAX_FIELDS |
| 57 | }; | 70 | }; |
| 58 | 71 | ||
| 72 | struct rtq6056_priv; | ||
| 73 | |||
| 74 | struct richtek_dev_data { | ||
| 75 | bool fixed_samp_freq; | ||
| 76 | u8 vbus_offset; | ||
| 77 | int default_conv_time_us; | ||
| 78 | unsigned int default_config; | ||
| 79 | unsigned int calib_coefficient; | ||
| 80 | const int *avg_sample_list; | ||
| 81 | int avg_sample_list_length; | ||
| 82 | const struct reg_field *reg_fields; | ||
| 83 | const struct iio_chan_spec *channels; | ||
| 84 | int num_channels; | ||
| 85 | int (*read_scale)(struct iio_chan_spec const *ch, int *val, int *val2); | ||
| 86 | int (*set_average)(struct rtq6056_priv *priv, int val); | ||
| 87 | }; | ||
| 88 | |||
| 59 | struct rtq6056_priv { | 89 | struct rtq6056_priv { |
| 60 | struct device *dev; | 90 | struct device *dev; |
| 61 | struct regmap *regmap; | 91 | struct regmap *regmap; |
| 62 | struct regmap_field *rm_fields[F_MAX_FIELDS]; | 92 | struct regmap_field *rm_fields[F_MAX_FIELDS]; |
| 93 | const struct richtek_dev_data *devdata; | ||
| 63 | u32 shunt_resistor_uohm; | 94 | u32 shunt_resistor_uohm; |
| 64 | int vshuntct_us; | 95 | int vshuntct_us; |
| 65 | int vbusct_us; | 96 | int vbusct_us; |
| @@ -74,6 +105,14 @@ static const struct reg_field rtq6056_reg_fields[F_MAX_FIELDS] = { · 8 unmodified lines | |||
| 74 | [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15), | 105 | [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15), |
| 75 | }; | 106 | }; |
| 76 | 107 | ||
| 108 | static const struct reg_field rtq6059_reg_fields[F_MAX_FIELDS] = { | ||
| 109 | [F_OPMODE] = REG_FIELD(RTQ6056_REG_CONFIG, 0, 2), | ||
| 110 | [F_RTQ6059_SADC] = REG_FIELD(RTQ6056_REG_CONFIG, 3, 6), | ||
| 111 | [F_RTQ6059_BADC] = REG_FIELD(RTQ6056_REG_CONFIG, 7, 10), | ||
| 112 | [F_RTQ6059_PGA] = REG_FIELD(RTQ6056_REG_CONFIG, 11, 12), | ||
| 113 | [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15), | ||
| 114 | }; | ||
| 115 | |||
| 77 | static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = { | 116 | static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = { |
| 78 | { | 117 | { |
| 79 | .type = IIO_VOLTAGE, | 118 | .type = IIO_VOLTAGE, |
| @@ -151,10 +190,93 @@ static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = { · 71 unmodified lines | |||
| 151 | IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL), | 190 | IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL), |
| 152 | }; | 191 | }; |
| 153 | 192 | ||
| 193 | /* | ||
| 194 | * Difference between RTQ6056 and RTQ6059 | ||
| 195 | * - Fixed sampling conversion time | ||
| 196 | * - Average sample numbers | ||
| 197 | * - Channel scale | ||
| 198 | * - calibration coefficient | ||
| 199 | */ | ||
| 200 | static const struct iio_chan_spec rtq6059_channels[RTQ6056_MAX_CHANNEL + 1] = { | ||
| 201 | { | ||
| 202 | .type = IIO_VOLTAGE, | ||
| 203 | .indexed = 1, | ||
| 204 | .channel = 0, | ||
| 205 | .address = RTQ6056_REG_SHUNTVOLT, | ||
| 206 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 207 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 208 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 209 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 210 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 211 | .scan_index = 0, | ||
| 212 | .scan_type = { | ||
| 213 | .sign = 's', | ||
| 214 | .realbits = 16, | ||
| 215 | .storagebits = 16, | ||
| 216 | .endianness = IIO_CPU, | ||
| 217 | }, | ||
| 218 | }, | ||
| 219 | { | ||
| 220 | .type = IIO_VOLTAGE, | ||
| 221 | .indexed = 1, | ||
| 222 | .channel = 1, | ||
| 223 | .address = RTQ6056_REG_BUSVOLT, | ||
| 224 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 225 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 226 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 227 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 228 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 229 | .scan_index = 1, | ||
| 230 | .scan_type = { | ||
| 231 | .sign = 'u', | ||
| 232 | .realbits = 16, | ||
| 233 | .storagebits = 16, | ||
| 234 | .endianness = IIO_CPU, | ||
| 235 | }, | ||
| 236 | }, | ||
| 237 | { | ||
| 238 | .type = IIO_POWER, | ||
| 239 | .indexed = 1, | ||
| 240 | .channel = 2, | ||
| 241 | .address = RTQ6056_REG_POWER, | ||
| 242 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 243 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 244 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 245 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 246 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 247 | .scan_index = 2, | ||
| 248 | .scan_type = { | ||
| 249 | .sign = 'u', | ||
| 250 | .realbits = 16, | ||
| 251 | .storagebits = 16, | ||
| 252 | .endianness = IIO_CPU, | ||
| 253 | }, | ||
| 254 | }, | ||
| 255 | { | ||
| 256 | .type = IIO_CURRENT, | ||
| 257 | .indexed = 1, | ||
| 258 | .channel = 3, | ||
| 259 | .address = RTQ6056_REG_CURRENT, | ||
| 260 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 261 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 262 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 263 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), | ||
| 264 | .scan_index = 3, | ||
| 265 | .scan_type = { | ||
| 266 | .sign = 's', | ||
| 267 | .realbits = 16, | ||
| 268 | .storagebits = 16, | ||
| 269 | .endianness = IIO_CPU, | ||
| 270 | }, | ||
| 271 | }, | ||
| 272 | IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL), | ||
| 273 | }; | ||
| 274 | |||
| 154 | static int rtq6056_adc_read_channel(struct rtq6056_priv *priv, | 275 | static int rtq6056_adc_read_channel(struct rtq6056_priv *priv, |
| 155 | struct iio_chan_spec const *ch, | 276 | struct iio_chan_spec const *ch, |
| 156 | int *val) | 277 | int *val) |
| 157 | { | 278 | { |
| 279 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 158 | struct device *dev = priv->dev; | 280 | struct device *dev = priv->dev; |
| 159 | unsigned int addr = ch->address; | 281 | unsigned int addr = ch->address; |
| 160 | unsigned int regval; | 282 | unsigned int regval; |
| @@ -168,12 +290,21 @@ static int rtq6056_adc_read_channel(struct rtq6056_priv *priv, · 7 unmodified lines | |||
| 168 | return ret; | 290 | return ret; |
| 169 | 291 | ||
| 170 | /* Power and VBUS is unsigned 16-bit, others are signed 16-bit */ | 292 | /* Power and VBUS is unsigned 16-bit, others are signed 16-bit */ |
| 171 | if (addr == RTQ6056_REG_BUSVOLT || addr == RTQ6056_REG_POWER) | 293 | switch (addr) { |
| 294 | case RTQ6056_REG_BUSVOLT: | ||
| 295 | regval >>= devdata->vbus_offset; | ||
| 172 | *val = regval; | 296 | *val = regval; |
| 173 | else | 297 | return IIO_VAL_INT; |
| 298 | case RTQ6056_REG_POWER: | ||
| 299 | *val = regval; | ||
| 300 | return IIO_VAL_INT; | ||
| 301 | case RTQ6056_REG_SHUNTVOLT: | ||
| 302 | case RTQ6056_REG_CURRENT: | ||
| 174 | *val = sign_extend32(regval, 16); | 303 | *val = sign_extend32(regval, 16); |
| 175 | 304 | return IIO_VAL_INT; | |
| 176 | return IIO_VAL_INT; | 305 | default: |
| 306 | return -EINVAL; | ||
| 307 | } | ||
| 177 | } | 308 | } |
| 178 | 309 | ||
| 179 | static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val, | 310 | static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val, |
| @@ -199,6 +330,28 @@ static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val, · 19 unmodified lines | |||
| 199 | } | 330 | } |
| 200 | } | 331 | } |
| 201 | 332 | ||
| 333 | static int rtq6059_adc_read_scale(struct iio_chan_spec const *ch, int *val, | ||
| 334 | int *val2) | ||
| 335 | { | ||
| 336 | switch (ch->address) { | ||
| 337 | case RTQ6056_REG_SHUNTVOLT: | ||
| 338 | /* VSHUNT lsb 10uV */ | ||
| 339 | *val = 10000; | ||
| 340 | *val2 = 1000000; | ||
| 341 | return IIO_VAL_FRACTIONAL; | ||
| 342 | case RTQ6056_REG_BUSVOLT: | ||
| 343 | /* VBUS lsb 4mV */ | ||
| 344 | *val = 4; | ||
| 345 | return IIO_VAL_INT; | ||
| 346 | case RTQ6056_REG_POWER: | ||
| 347 | /* Power lsb 20mW */ | ||
| 348 | *val = 20; | ||
| 349 | return IIO_VAL_INT; | ||
| 350 | default: | ||
| 351 | return -EINVAL; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 202 | /* | 355 | /* |
| 203 | * Sample frequency for channel VSHUNT and VBUS. The indices correspond | 356 | * Sample frequency for channel VSHUNT and VBUS. The indices correspond |
| 204 | * with the bit value expected by the chip. And it can be found at | 357 | * with the bit value expected by the chip. And it can be found at |
| @@ -248,6 +401,10 @@ static const int rtq6056_avg_sample_list[] = { · 43 unmodified lines | |||
| 248 | 1, 4, 16, 64, 128, 256, 512, 1024, | 401 | 1, 4, 16, 64, 128, 256, 512, 1024, |
| 249 | }; | 402 | }; |
| 250 | 403 | ||
| 404 | static const int rtq6059_avg_sample_list[] = { | ||
| 405 | 1, 2, 4, 8, 16, 32, 64, 128, | ||
| 406 | }; | ||
| 407 | |||
| 251 | static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val) | 408 | static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val) |
| 252 | { | 409 | { |
| 253 | unsigned int selector; | 410 | unsigned int selector; |
| @@ -268,6 +425,30 @@ static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val) · 14 unmodified lines | |||
| 268 | return 0; | 425 | return 0; |
| 269 | } | 426 | } |
| 270 | 427 | ||
| 428 | static int rtq6059_adc_set_average(struct rtq6056_priv *priv, int val) | ||
| 429 | { | ||
| 430 | unsigned int selector; | ||
| 431 | int ret; | ||
| 432 | |||
| 433 | if (val > 128 || val < 1) | ||
| 434 | return -EINVAL; | ||
| 435 | |||
| 436 | /* The supported average sample is 2^x (x from 0 to 7) */ | ||
| 437 | selector = fls(val) - 1; | ||
| 438 | |||
| 439 | ret = regmap_field_write(priv->rm_fields[F_RTQ6059_BADC], | ||
| 440 | RTQ6059_AVG_BASE + selector); | ||
| 441 | if (ret) | ||
| 442 | return ret; | ||
| 443 | |||
| 444 | ret = regmap_field_write(priv->rm_fields[F_RTQ6059_SADC], | ||
| 445 | RTQ6059_AVG_BASE + selector); | ||
| 446 | |||
| 447 | priv->avg_sample = BIT(selector); | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 271 | static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv, | 452 | static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv, |
| 272 | struct iio_chan_spec const *ch, int *val) | 453 | struct iio_chan_spec const *ch, int *val) |
| 273 | { | 454 | { |
| @@ -292,12 +473,13 @@ static int rtq6056_adc_read_raw(struct iio_dev *indio_dev, · 18 unmodified lines | |||
| 292 | int *val2, long mask) | 473 | int *val2, long mask) |
| 293 | { | 474 | { |
| 294 | struct rtq6056_priv *priv = iio_priv(indio_dev); | 475 | struct rtq6056_priv *priv = iio_priv(indio_dev); |
| 476 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 295 | 477 | ||
| 296 | switch (mask) { | 478 | switch (mask) { |
| 297 | case IIO_CHAN_INFO_RAW: | 479 | case IIO_CHAN_INFO_RAW: |
| 298 | return rtq6056_adc_read_channel(priv, chan, val); | 480 | return rtq6056_adc_read_channel(priv, chan, val); |
| 299 | case IIO_CHAN_INFO_SCALE: | 481 | case IIO_CHAN_INFO_SCALE: |
| 300 | return rtq6056_adc_read_scale(chan, val, val2); | 482 | return devdata->read_scale(chan, val, val2); |
| 301 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 483 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 302 | *val = priv->avg_sample; | 484 | *val = priv->avg_sample; |
| 303 | return IIO_VAL_INT; | 485 | return IIO_VAL_INT; |
| @@ -313,6 +495,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev, · 9 unmodified lines | |||
| 313 | const int **vals, int *type, int *length, | 495 | const int **vals, int *type, int *length, |
| 314 | long mask) | 496 | long mask) |
| 315 | { | 497 | { |
| 498 | struct rtq6056_priv *priv = iio_priv(indio_dev); | ||
| 499 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 500 | |||
| 316 | switch (mask) { | 501 | switch (mask) { |
| 317 | case IIO_CHAN_INFO_SAMP_FREQ: | 502 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 318 | *vals = rtq6056_samp_freq_list; | 503 | *vals = rtq6056_samp_freq_list; |
| @@ -320,9 +505,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 320 | *length = ARRAY_SIZE(rtq6056_samp_freq_list); | 505 | *length = ARRAY_SIZE(rtq6056_samp_freq_list); |
| 321 | return IIO_AVAIL_LIST; | 506 | return IIO_AVAIL_LIST; |
| 322 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 507 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 323 | *vals = rtq6056_avg_sample_list; | 508 | *vals = devdata->avg_sample_list; |
| 509 | *length = devdata->avg_sample_list_length; | ||
| 324 | *type = IIO_VAL_INT; | 510 | *type = IIO_VAL_INT; |
| 325 | *length = ARRAY_SIZE(rtq6056_avg_sample_list); | ||
| 326 | return IIO_AVAIL_LIST; | 511 | return IIO_AVAIL_LIST; |
| 327 | default: | 512 | default: |
| 328 | return -EINVAL; | 513 | return -EINVAL; |
| @@ -334,6 +519,7 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev, · 5 unmodified lines | |||
| 334 | int val2, long mask) | 519 | int val2, long mask) |
| 335 | { | 520 | { |
| 336 | struct rtq6056_priv *priv = iio_priv(indio_dev); | 521 | struct rtq6056_priv *priv = iio_priv(indio_dev); |
| 522 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 337 | int ret; | 523 | int ret; |
| 338 | 524 | ||
| 339 | ret = iio_device_claim_direct_mode(indio_dev); | 525 | ret = iio_device_claim_direct_mode(indio_dev); |
| @@ -342,10 +528,15 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 342 | 528 | ||
| 343 | switch (mask) { | 529 | switch (mask) { |
| 344 | case IIO_CHAN_INFO_SAMP_FREQ: | 530 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 531 | if (devdata->fixed_samp_freq) { | ||
| 532 | ret = -EINVAL; | ||
| 533 | break; | ||
| 534 | } | ||
| 535 | |||
| 345 | ret = rtq6056_adc_set_samp_freq(priv, chan, val); | 536 | ret = rtq6056_adc_set_samp_freq(priv, chan, val); |
| 346 | break; | 537 | break; |
| 347 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 538 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 348 | ret = rtq6056_adc_set_average(priv, val); | 539 | ret = devdata->set_average(priv, val); |
| 349 | break; | 540 | break; |
| 350 | default: | 541 | default: |
| 351 | ret = -EINVAL; | 542 | ret = -EINVAL; |
| @@ -374,6 +565,7 @@ static int rtq6056_adc_read_label(struct iio_dev *indio_dev, · 22 unmodified lines | |||
| 374 | static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv, | 565 | static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv, |
| 375 | int resistor_uohm) | 566 | int resistor_uohm) |
| 376 | { | 567 | { |
| 568 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 377 | unsigned int calib_val; | 569 | unsigned int calib_val; |
| 378 | int ret; | 570 | int ret; |
| 379 | 571 | ||
| @@ -382,8 +574,8 @@ static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv, · 2 unmodified lines | |||
| 382 | return -EINVAL; | 574 | return -EINVAL; |
| 383 | } | 575 | } |
| 384 | 576 | ||
| 385 | /* calibration = 5120000 / (Rshunt (uOhm) * current lsb (1mA)) */ | 577 | /* calibration = coefficient / (Rshunt (uOhm) * current lsb (1mA)) */ |
| 386 | calib_val = 5120000 / resistor_uohm; | 578 | calib_val = devdata->calib_coefficient / resistor_uohm; |
| 387 | ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val); | 579 | ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val); |
| 388 | if (ret) | 580 | if (ret) |
| 389 | return ret; | 581 | return ret; |
| @@ -450,6 +642,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) · 60 unmodified lines | |||
| 450 | struct iio_poll_func *pf = p; | 642 | struct iio_poll_func *pf = p; |
| 451 | struct iio_dev *indio_dev = pf->indio_dev; | 643 | struct iio_dev *indio_dev = pf->indio_dev; |
| 452 | struct rtq6056_priv *priv = iio_priv(indio_dev); | 644 | struct rtq6056_priv *priv = iio_priv(indio_dev); |
| 645 | const struct richtek_dev_data *devdata = priv->devdata; | ||
| 453 | struct device *dev = priv->dev; | 646 | struct device *dev = priv->dev; |
| 454 | struct { | 647 | struct { |
| 455 | u16 vals[RTQ6056_MAX_CHANNEL]; | 648 | u16 vals[RTQ6056_MAX_CHANNEL]; |
| @@ -469,6 +662,9 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) · 13 unmodified lines | |||
| 469 | if (ret) | 662 | if (ret) |
| 470 | goto out; | 663 | goto out; |
| 471 | 664 | ||
| 665 | if (addr == RTQ6056_REG_BUSVOLT) | ||
| 666 | raw >>= devdata->vbus_offset; | ||
| 667 | |||
| 472 | data.vals[i++] = raw; | 668 | data.vals[i++] = raw; |
| 473 | } | 669 | } |
| 474 | 670 | ||
| @@ -528,20 +724,26 @@ static int rtq6056_probe(struct i2c_client *i2c) · 53 unmodified lines | |||
| 528 | struct rtq6056_priv *priv; | 724 | struct rtq6056_priv *priv; |
| 529 | struct device *dev = &i2c->dev; | 725 | struct device *dev = &i2c->dev; |
| 530 | struct regmap *regmap; | 726 | struct regmap *regmap; |
| 727 | const struct richtek_dev_data *devdata; | ||
| 531 | unsigned int vendor_id, shunt_resistor_uohm; | 728 | unsigned int vendor_id, shunt_resistor_uohm; |
| 532 | int ret; | 729 | int ret; |
| 533 | 730 | ||
| 534 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) | 731 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) |
| 535 | return -EOPNOTSUPP; | 732 | return -EOPNOTSUPP; |
| 536 | 733 | ||
| 734 | devdata = device_get_match_data(dev); | ||
| 735 | if (!devdata) | ||
| 736 | return dev_err_probe(dev, -EINVAL, "Invalid dev data\n"); | ||
| 737 | |||
| 537 | indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); | 738 | indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); |
| 538 | if (!indio_dev) | 739 | if (!indio_dev) |
| 539 | return -ENOMEM; | 740 | return -ENOMEM; |
| 540 | 741 | ||
| 541 | priv = iio_priv(indio_dev); | 742 | priv = iio_priv(indio_dev); |
| 542 | priv->dev = dev; | 743 | priv->dev = dev; |
| 543 | priv->vshuntct_us = priv->vbusct_us = 1037; | 744 | priv->vshuntct_us = priv->vbusct_us = devdata->default_conv_time_us; |
| 544 | priv->avg_sample = 1; | 745 | priv->avg_sample = 1; |
| 746 | priv->devdata = devdata; | ||
| 545 | i2c_set_clientdata(i2c, priv); | 747 | i2c_set_clientdata(i2c, priv); |
| 546 | 748 | ||
| 547 | regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config); | 749 | regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config); |
| @@ -561,15 +763,11 @@ static int rtq6056_probe(struct i2c_client *i2c) · 13 unmodified lines | |||
| 561 | "Invalid vendor id 0x%04x\n", vendor_id); | 763 | "Invalid vendor id 0x%04x\n", vendor_id); |
| 562 | 764 | ||
| 563 | ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields, | 765 | ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields, |
| 564 | rtq6056_reg_fields, F_MAX_FIELDS); | 766 | devdata->reg_fields, F_MAX_FIELDS); |
| 565 | if (ret) | 767 | if (ret) |
| 566 | return dev_err_probe(dev, ret, "Failed to init regmap field\n"); | 768 | return dev_err_probe(dev, ret, "Failed to init regmap field\n"); |
| 567 | 769 | ||
| 568 | /* | 770 | ret = regmap_write(regmap, RTQ6056_REG_CONFIG, devdata->default_config); |
| 569 | * By default, configure average sample as 1, bus and shunt conversion | ||
| 570 | * time as 1037 microsecond, and operating mode to all on. | ||
| 571 | */ | ||
| 572 | ret = regmap_write(regmap, RTQ6056_REG_CONFIG, RTQ6056_DEFAULT_CONFIG); | ||
| 573 | if (ret) | 771 | if (ret) |
| 574 | return dev_err_probe(dev, ret, | 772 | return dev_err_probe(dev, ret, |
| 575 | "Failed to enable continuous sensing\n"); | 773 | "Failed to enable continuous sensing\n"); |
| @@ -598,8 +796,8 @@ static int rtq6056_probe(struct i2c_client *i2c) · 22 unmodified lines | |||
| 598 | 796 | ||
| 599 | indio_dev->name = "rtq6056"; | 797 | indio_dev->name = "rtq6056"; |
| 600 | indio_dev->modes = INDIO_DIRECT_MODE; | 798 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 601 | indio_dev->channels = rtq6056_channels; | 799 | indio_dev->channels = devdata->channels; |
| 602 | indio_dev->num_channels = ARRAY_SIZE(rtq6056_channels); | 800 | indio_dev->num_channels = devdata->num_channels; |
| 603 | indio_dev->info = &rtq6056_info; | 801 | indio_dev->info = &rtq6056_info; |
| 604 | 802 | ||
| 605 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, | 803 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, |
| @@ -640,8 +838,45 @@ static int rtq6056_runtime_resume(struct device *dev) · 34 unmodified lines | |||
| 640 | static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend, | 838 | static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend, |
| 641 | rtq6056_runtime_resume, NULL); | 839 | rtq6056_runtime_resume, NULL); |
| 642 | 840 | ||
| 841 | static const struct richtek_dev_data rtq6056_devdata = { | ||
| 842 | .default_conv_time_us = 1037, | ||
| 843 | .calib_coefficient = 5120000, | ||
| 844 | /* | ||
| 845 | * By default, configure average sample as 1, bus and shunt conversion | ||
| 846 | * time as 1037 microsecond, and operating mode to all on. | ||
| 847 | */ | ||
| 848 | .default_config = RTQ6056_DEFAULT_CONFIG, | ||
| 849 | .avg_sample_list = rtq6056_avg_sample_list, | ||
| 850 | .avg_sample_list_length = ARRAY_SIZE(rtq6056_avg_sample_list), | ||
| 851 | .reg_fields = rtq6056_reg_fields, | ||
| 852 | .channels = rtq6056_channels, | ||
| 853 | .num_channels = ARRAY_SIZE(rtq6056_channels), | ||
| 854 | .read_scale = rtq6056_adc_read_scale, | ||
| 855 | .set_average = rtq6056_adc_set_average, | ||
| 856 | }; | ||
| 857 | |||
| 858 | static const struct richtek_dev_data rtq6059_devdata = { | ||
| 859 | .fixed_samp_freq = true, | ||
| 860 | .vbus_offset = RTQ6059_VBUS_LSB_OFFSET, | ||
| 861 | .default_conv_time_us = 532, | ||
| 862 | .calib_coefficient = 40960000, | ||
| 863 | /* | ||
| 864 | * By default, configure average sample as 1, bus and shunt conversion | ||
| 865 | * time as 532 microsecond, and operating mode to all on. | ||
| 866 | */ | ||
| 867 | .default_config = RTQ6059_DEFAULT_CONFIG, | ||
| 868 | .avg_sample_list = rtq6059_avg_sample_list, | ||
| 869 | .avg_sample_list_length = ARRAY_SIZE(rtq6059_avg_sample_list), | ||
| 870 | .reg_fields = rtq6059_reg_fields, | ||
| 871 | .channels = rtq6059_channels, | ||
| 872 | .num_channels = ARRAY_SIZE(rtq6059_channels), | ||
| 873 | .read_scale = rtq6059_adc_read_scale, | ||
| 874 | .set_average = rtq6059_adc_set_average, | ||
| 875 | }; | ||
| 876 | |||
| 643 | static const struct of_device_id rtq6056_device_match[] = { | 877 | static const struct of_device_id rtq6056_device_match[] = { |
| 644 | { .compatible = "richtek,rtq6056" }, | 878 | { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata }, |
| 879 | { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata }, | ||
| 645 | {} | 880 | {} |
| 646 | }; | 881 | }; |
| 647 | MODULE_DEVICE_TABLE(of, rtq6056_device_match); | 882 | MODULE_DEVICE_TABLE(of, rtq6056_device_match); |
| @@ -293,13 +293,11 @@ static const struct of_device_id adc108s102_of_match[] = { · 292 unmodified lines | |||
| 293 | }; | 293 | }; |
| 294 | MODULE_DEVICE_TABLE(of, adc108s102_of_match); | 294 | MODULE_DEVICE_TABLE(of, adc108s102_of_match); |
| 295 | 295 | ||
| 296 | #ifdef CONFIG_ACPI | ||
| 297 | static const struct acpi_device_id adc108s102_acpi_ids[] = { | 296 | static const struct acpi_device_id adc108s102_acpi_ids[] = { |
| 298 | { "INT3495", 0 }, | 297 | { "INT3495", 0 }, |
| 299 | { } | 298 | { } |
| 300 | }; | 299 | }; |
| 301 | MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); | 300 | MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); |
| 302 | #endif | ||
| 303 | 301 | ||
| 304 | static const struct spi_device_id adc108s102_id[] = { | 302 | static const struct spi_device_id adc108s102_id[] = { |
| 305 | { "adc108s102", 0 }, | 303 | { "adc108s102", 0 }, |
| @@ -311,7 +309,7 @@ static struct spi_driver adc108s102_driver = { · 5 unmodified lines | |||
| 311 | .driver = { | 309 | .driver = { |
| 312 | .name = "adc108s102", | 310 | .name = "adc108s102", |
| 313 | .of_match_table = adc108s102_of_match, | 311 | .of_match_table = adc108s102_of_match, |
| 314 | .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids), | 312 | .acpi_match_table = adc108s102_acpi_ids, |
| 315 | }, | 313 | }, |
| 316 | .probe = adc108s102_probe, | 314 | .probe = adc108s102_probe, |
| 317 | .id_table = adc108s102_id, | 315 | .id_table = adc108s102_id, |
| @@ -925,7 +925,7 @@ static int ads1015_client_get_channels_config(struct i2c_client *client) · 924 unmodified lines | |||
| 925 | 925 | ||
| 926 | if (!fwnode_property_read_u32(node, "ti,gain", &pval)) { | 926 | if (!fwnode_property_read_u32(node, "ti,gain", &pval)) { |
| 927 | pga = pval; | 927 | pga = pval; |
| 928 | if (pga > 6) { | 928 | if (pga > 5) { |
| 929 | dev_err(dev, "invalid gain on %pfw\n", node); | 929 | dev_err(dev, "invalid gain on %pfw\n", node); |
| 930 | fwnode_handle_put(node); | 930 | fwnode_handle_put(node); |
| 931 | return -EINVAL; | 931 | return -EINVAL; |
| @@ -0,0 +1,771 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* TI ADS1298 chip family driver | ||
| 3 | * Copyright (C) 2023 - 2024 Topic Embedded Products | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/bitfield.h> | ||
| 7 | #include <linux/cleanup.h> | ||
| 8 | #include <linux/clk.h> | ||
| 9 | #include <linux/err.h> | ||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/gpio/consumer.h> | ||
| 13 | #include <linux/log2.h> | ||
| 14 | #include <linux/math.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/spi/spi.h> | ||
| 20 | #include <linux/units.h> | ||
| 21 | |||
| 22 | #include <linux/iio/iio.h> | ||
| 23 | #include <linux/iio/buffer.h> | ||
| 24 | #include <linux/iio/kfifo_buf.h> | ||
| 25 | |||
| 26 | #include <asm/unaligned.h> | ||
| 27 | |||
| 28 | /* Commands */ | ||
| 29 | #define ADS1298_CMD_WAKEUP 0x02 | ||
| 30 | #define ADS1298_CMD_STANDBY 0x04 | ||
| 31 | #define ADS1298_CMD_RESET 0x06 | ||
| 32 | #define ADS1298_CMD_START 0x08 | ||
| 33 | #define ADS1298_CMD_STOP 0x0a | ||
| 34 | #define ADS1298_CMD_RDATAC 0x10 | ||
| 35 | #define ADS1298_CMD_SDATAC 0x11 | ||
| 36 | #define ADS1298_CMD_RDATA 0x12 | ||
| 37 | #define ADS1298_CMD_RREG 0x20 | ||
| 38 | #define ADS1298_CMD_WREG 0x40 | ||
| 39 | |||
| 40 | /* Registers */ | ||
| 41 | #define ADS1298_REG_ID 0x00 | ||
| 42 | #define ADS1298_MASK_ID_FAMILY GENMASK(7, 3) | ||
| 43 | #define ADS1298_MASK_ID_CHANNELS GENMASK(2, 0) | ||
| 44 | #define ADS1298_ID_FAMILY_ADS129X 0x90 | ||
| 45 | #define ADS1298_ID_FAMILY_ADS129XR 0xd0 | ||
| 46 | |||
| 47 | #define ADS1298_REG_CONFIG1 0x01 | ||
| 48 | #define ADS1298_MASK_CONFIG1_HR BIT(7) | ||
| 49 | #define ADS1298_MASK_CONFIG1_DR GENMASK(2, 0) | ||
| 50 | #define ADS1298_SHIFT_DR_HR 6 | ||
| 51 | #define ADS1298_SHIFT_DR_LP 7 | ||
| 52 | #define ADS1298_LOWEST_DR 0x06 | ||
| 53 | |||
| 54 | #define ADS1298_REG_CONFIG2 0x02 | ||
| 55 | #define ADS1298_MASK_CONFIG2_RESERVED BIT(6) | ||
| 56 | #define ADS1298_MASK_CONFIG2_WCT_CHOP BIT(5) | ||
| 57 | #define ADS1298_MASK_CONFIG2_INT_TEST BIT(4) | ||
| 58 | #define ADS1298_MASK_CONFIG2_TEST_AMP BIT(2) | ||
| 59 | #define ADS1298_MASK_CONFIG2_TEST_FREQ_DC GENMASK(1, 0) | ||
| 60 | #define ADS1298_MASK_CONFIG2_TEST_FREQ_SLOW 0 | ||
| 61 | #define ADS1298_MASK_CONFIG2_TEST_FREQ_FAST BIT(0) | ||
| 62 | |||
| 63 | #define ADS1298_REG_CONFIG3 0x03 | ||
| 64 | #define ADS1298_MASK_CONFIG3_PWR_REFBUF BIT(7) | ||
| 65 | #define ADS1298_MASK_CONFIG3_RESERVED BIT(6) | ||
| 66 | #define ADS1298_MASK_CONFIG3_VREF_4V BIT(5) | ||
| 67 | |||
| 68 | #define ADS1298_REG_LOFF 0x04 | ||
| 69 | #define ADS1298_REG_CHnSET(n) (0x05 + n) | ||
| 70 | #define ADS1298_MASK_CH_PD BIT(7) | ||
| 71 | #define ADS1298_MASK_CH_PGA GENMASK(6, 4) | ||
| 72 | #define ADS1298_MASK_CH_MUX GENMASK(2, 0) | ||
| 73 | |||
| 74 | #define ADS1298_REG_LOFF_STATP 0x12 | ||
| 75 | #define ADS1298_REG_LOFF_STATN 0x13 | ||
| 76 | #define ADS1298_REG_CONFIG4 0x17 | ||
| 77 | #define ADS1298_MASK_CONFIG4_SINGLE_SHOT BIT(3) | ||
| 78 | |||
| 79 | #define ADS1298_REG_WCT1 0x18 | ||
| 80 | #define ADS1298_REG_WCT2 0x19 | ||
| 81 | |||
| 82 | #define ADS1298_MAX_CHANNELS 8 | ||
| 83 | #define ADS1298_BITS_PER_SAMPLE 24 | ||
| 84 | #define ADS1298_CLK_RATE_HZ 2048000 | ||
| 85 | #define ADS1298_CLOCKS_TO_USECS(x) \ | ||
| 86 | (DIV_ROUND_UP((x) * MICROHZ_PER_HZ, ADS1298_CLK_RATE_HZ)) | ||
| 87 | /* | ||
| 88 | * Read/write register commands require 4 clocks to decode, for speeds above | ||
| 89 | * 2x the clock rate, this would require extra time between the command byte and | ||
| 90 | * the data. Much simpler is to just limit the SPI transfer speed while doing | ||
| 91 | * register access. | ||
| 92 | */ | ||
| 93 | #define ADS1298_SPI_BUS_SPEED_SLOW ADS1298_CLK_RATE_HZ | ||
| 94 | /* For reading and writing registers, we need a 3-byte buffer */ | ||
| 95 | #define ADS1298_SPI_CMD_BUFFER_SIZE 3 | ||
| 96 | /* Outputs status word and 'n' 24-bit samples, plus the command byte */ | ||
| 97 | #define ADS1298_SPI_RDATA_BUFFER_SIZE(n) (((n) + 1) * 3 + 1) | ||
| 98 | #define ADS1298_SPI_RDATA_BUFFER_SIZE_MAX \ | ||
| 99 | ADS1298_SPI_RDATA_BUFFER_SIZE(ADS1298_MAX_CHANNELS) | ||
| 100 | |||
| 101 | struct ads1298_private { | ||
| 102 | const struct ads1298_chip_info *chip_info; | ||
| 103 | struct spi_device *spi; | ||
| 104 | struct regulator *reg_avdd; | ||
| 105 | struct regulator *reg_vref; | ||
| 106 | struct clk *clk; | ||
| 107 | struct regmap *regmap; | ||
| 108 | struct completion completion; | ||
| 109 | struct iio_trigger *trig; | ||
| 110 | struct spi_transfer rdata_xfer; | ||
| 111 | struct spi_message rdata_msg; | ||
| 112 | spinlock_t irq_busy_lock; /* Handshake between SPI and DRDY irqs */ | ||
| 113 | /* | ||
| 114 | * rdata_xfer_busy increments when a DRDY occurs and decrements when SPI | ||
| 115 | * completion is reported. Hence its meaning is: | ||
| 116 | * 0 = Waiting for DRDY interrupt | ||
| 117 | * 1 = SPI transfer in progress | ||
| 118 | * 2 = DRDY during SPI transfer, start another transfer on completion | ||
| 119 | * >2 = Multiple DRDY during transfer, lost rdata_xfer_busy - 2 samples | ||
| 120 | */ | ||
| 121 | unsigned int rdata_xfer_busy; | ||
| 122 | |||
| 123 | /* Temporary storage for demuxing data after SPI transfer */ | ||
| 124 | u32 bounce_buffer[ADS1298_MAX_CHANNELS]; | ||
| 125 | |||
| 126 | /* For synchronous SPI exchanges (read/write registers) */ | ||
| 127 | u8 cmd_buffer[ADS1298_SPI_CMD_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN); | ||
| 128 | |||
| 129 | /* Buffer used for incoming SPI data */ | ||
| 130 | u8 rx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX]; | ||
| 131 | /* Contains the RDATA command and zeroes to clock out */ | ||
| 132 | u8 tx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX]; | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* Three bytes per sample in RX buffer, starting at offset 4 */ | ||
| 136 | #define ADS1298_OFFSET_IN_RX_BUFFER(index) (3 * (index) + 4) | ||
| 137 | |||
| 138 | #define ADS1298_CHAN(index) \ | ||
| 139 | { \ | ||
| 140 | .type = IIO_VOLTAGE, \ | ||
| 141 | .indexed = 1, \ | ||
| 142 | .channel = index, \ | ||
| 143 | .address = ADS1298_OFFSET_IN_RX_BUFFER(index), \ | ||
| 144 | .info_mask_separate = \ | ||
| 145 | BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 146 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 147 | .info_mask_shared_by_all = \ | ||
| 148 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ | ||
| 149 | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ | ||
| 150 | .scan_index = index, \ | ||
| 151 | .scan_type = { \ | ||
| 152 | .sign = 's', \ | ||
| 153 | .realbits = ADS1298_BITS_PER_SAMPLE, \ | ||
| 154 | .storagebits = 32, \ | ||
| 155 | .endianness = IIO_CPU, \ | ||
| 156 | }, \ | ||
| 157 | } | ||
| 158 | |||
| 159 | static const struct iio_chan_spec ads1298_channels[] = { | ||
| 160 | ADS1298_CHAN(0), | ||
| 161 | ADS1298_CHAN(1), | ||
| 162 | ADS1298_CHAN(2), | ||
| 163 | ADS1298_CHAN(3), | ||
| 164 | ADS1298_CHAN(4), | ||
| 165 | ADS1298_CHAN(5), | ||
| 166 | ADS1298_CHAN(6), | ||
| 167 | ADS1298_CHAN(7), | ||
| 168 | }; | ||
| 169 | |||
| 170 | static int ads1298_write_cmd(struct ads1298_private *priv, u8 command) | ||
| 171 | { | ||
| 172 | struct spi_transfer xfer = { | ||
| 173 | .tx_buf = priv->cmd_buffer, | ||
| 174 | .rx_buf = priv->cmd_buffer, | ||
| 175 | .len = 1, | ||
| 176 | .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, | ||
| 177 | .delay = { | ||
| 178 | .value = 2, | ||
| 179 | .unit = SPI_DELAY_UNIT_USECS, | ||
| 180 | }, | ||
| 181 | }; | ||
| 182 | |||
| 183 | priv->cmd_buffer[0] = command; | ||
| 184 | |||
| 185 | return spi_sync_transfer(priv->spi, &xfer, 1); | ||
| 186 | } | ||
| 187 | |||
| 188 | static int ads1298_read_one(struct ads1298_private *priv, int chan_index) | ||
| 189 | { | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | /* Enable the channel */ | ||
| 193 | ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(chan_index), | ||
| 194 | ADS1298_MASK_CH_PD, 0); | ||
| 195 | if (ret) | ||
| 196 | return ret; | ||
| 197 | |||
| 198 | /* Enable single-shot mode, so we don't need to send a STOP */ | ||
| 199 | ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4, | ||
| 200 | ADS1298_MASK_CONFIG4_SINGLE_SHOT, | ||
| 201 | ADS1298_MASK_CONFIG4_SINGLE_SHOT); | ||
| 202 | if (ret) | ||
| 203 | return ret; | ||
| 204 | |||
| 205 | reinit_completion(&priv->completion); | ||
| 206 | |||
| 207 | ret = ads1298_write_cmd(priv, ADS1298_CMD_START); | ||
| 208 | if (ret < 0) { | ||
| 209 | dev_err(&priv->spi->dev, "CMD_START error: %d\n", ret); | ||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Cannot take longer than 40ms (250Hz) */ | ||
| 214 | ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50)); | ||
| 215 | if (!ret) | ||
| 216 | return -ETIMEDOUT; | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int ads1298_get_samp_freq(struct ads1298_private *priv, int *val) | ||
| 222 | { | ||
| 223 | unsigned long rate; | ||
| 224 | unsigned int cfg; | ||
| 225 | int ret; | ||
| 226 | |||
| 227 | ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, &cfg); | ||
| 228 | if (ret) | ||
| 229 | return ret; | ||
| 230 | |||
| 231 | if (priv->clk) | ||
| 232 | rate = clk_get_rate(priv->clk); | ||
| 233 | else | ||
| 234 | rate = ADS1298_CLK_RATE_HZ; | ||
| 235 | if (!rate) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | /* Data rate shift depends on HR/LP mode */ | ||
| 239 | if (cfg & ADS1298_MASK_CONFIG1_HR) | ||
| 240 | rate >>= ADS1298_SHIFT_DR_HR; | ||
| 241 | else | ||
| 242 | rate >>= ADS1298_SHIFT_DR_LP; | ||
| 243 | |||
| 244 | *val = rate >> (cfg & ADS1298_MASK_CONFIG1_DR); | ||
| 245 | |||
| 246 | return IIO_VAL_INT; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int ads1298_set_samp_freq(struct ads1298_private *priv, int val) | ||
| 250 | { | ||
| 251 | unsigned long rate; | ||
| 252 | unsigned int factor; | ||
| 253 | unsigned int cfg; | ||
| 254 | |||
| 255 | if (priv->clk) | ||
| 256 | rate = clk_get_rate(priv->clk); | ||
| 257 | else | ||
| 258 | rate = ADS1298_CLK_RATE_HZ; | ||
| 259 | if (!rate) | ||
| 260 | return -EINVAL; | ||
| 261 | if (val <= 0) | ||
| 262 | return -EINVAL; | ||
| 263 | |||
| 264 | factor = (rate >> ADS1298_SHIFT_DR_HR) / val; | ||
| 265 | if (factor >= BIT(ADS1298_SHIFT_DR_LP)) | ||
| 266 | cfg = ADS1298_LOWEST_DR; | ||
| 267 | else if (factor) | ||
| 268 | cfg = ADS1298_MASK_CONFIG1_HR | ilog2(factor); /* Use HR mode */ | ||
| 269 | else | ||
| 270 | cfg = ADS1298_MASK_CONFIG1_HR; /* Fastest possible */ | ||
| 271 | |||
| 272 | return regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG1, | ||
| 273 | ADS1298_MASK_CONFIG1_HR | ADS1298_MASK_CONFIG1_DR, | ||
| 274 | cfg); | ||
| 275 | } | ||
| 276 | |||
| 277 | static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 }; | ||
| 278 | |||
| 279 | static int ads1298_get_scale(struct ads1298_private *priv, | ||
| 280 | int channel, int *val, int *val2) | ||
| 281 | { | ||
| 282 | int ret; | ||
| 283 | unsigned int regval; | ||
| 284 | u8 gain; | ||
| 285 | |||
| 286 | if (priv->reg_vref) { | ||
| 287 | ret = regulator_get_voltage(priv->reg_vref); | ||
| 288 | if (ret < 0) | ||
| 289 | return ret; | ||
| 290 | |||
| 291 | *val = ret / MILLI; /* Convert to millivolts */ | ||
| 292 | } else { | ||
| 293 | ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG3, ®val); | ||
| 294 | if (ret) | ||
| 295 | return ret; | ||
| 296 | |||
| 297 | /* Refererence in millivolts */ | ||
| 298 | *val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400; | ||
| 299 | } | ||
| 300 | |||
| 301 | ret = regmap_read(priv->regmap, ADS1298_REG_CHnSET(channel), ®val); | ||
| 302 | if (ret) | ||
| 303 | return ret; | ||
| 304 | |||
| 305 | gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)]; | ||
| 306 | *val /= gain; /* Full scale is VREF / gain */ | ||
| 307 | |||
| 308 | *val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */ | ||
| 309 | |||
| 310 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int ads1298_read_raw(struct iio_dev *indio_dev, | ||
| 314 | struct iio_chan_spec const *chan, | ||
| 315 | int *val, int *val2, long mask) | ||
| 316 | { | ||
| 317 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 318 | int ret; | ||
| 319 | |||
| 320 | switch (mask) { | ||
| 321 | case IIO_CHAN_INFO_RAW: | ||
| 322 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 323 | if (ret) | ||
| 324 | return ret; | ||
| 325 | |||
| 326 | ret = ads1298_read_one(priv, chan->scan_index); | ||
| 327 | |||
| 328 | iio_device_release_direct_mode(indio_dev); | ||
| 329 | |||
| 330 | if (ret) | ||
| 331 | return ret; | ||
| 332 | |||
| 333 | *val = sign_extend32(get_unaligned_be24(priv->rx_buffer + chan->address), | ||
| 334 | ADS1298_BITS_PER_SAMPLE - 1); | ||
| 335 | return IIO_VAL_INT; | ||
| 336 | case IIO_CHAN_INFO_SCALE: | ||
| 337 | return ads1298_get_scale(priv, chan->channel, val, val2); | ||
| 338 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 339 | return ads1298_get_samp_freq(priv, val); | ||
| 340 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | ||
| 341 | ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, val); | ||
| 342 | if (ret) | ||
| 343 | return ret; | ||
| 344 | |||
| 345 | *val = 16 << (*val & ADS1298_MASK_CONFIG1_DR); | ||
| 346 | return IIO_VAL_INT; | ||
| 347 | default: | ||
| 348 | return -EINVAL; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | static int ads1298_write_raw(struct iio_dev *indio_dev, | ||
| 353 | struct iio_chan_spec const *chan, int val, | ||
| 354 | int val2, long mask) | ||
| 355 | { | ||
| 356 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 357 | |||
| 358 | switch (mask) { | ||
| 359 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 360 | return ads1298_set_samp_freq(priv, val); | ||
| 361 | default: | ||
| 362 | return -EINVAL; | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | static int ads1298_reg_write(void *context, unsigned int reg, unsigned int val) | ||
| 367 | { | ||
| 368 | struct ads1298_private *priv = context; | ||
| 369 | struct spi_transfer reg_write_xfer = { | ||
| 370 | .tx_buf = priv->cmd_buffer, | ||
| 371 | .rx_buf = priv->cmd_buffer, | ||
| 372 | .len = 3, | ||
| 373 | .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, | ||
| 374 | .delay = { | ||
| 375 | .value = 2, | ||
| 376 | .unit = SPI_DELAY_UNIT_USECS, | ||
| 377 | }, | ||
| 378 | }; | ||
| 379 | |||
| 380 | priv->cmd_buffer[0] = ADS1298_CMD_WREG | reg; | ||
| 381 | priv->cmd_buffer[1] = 0; /* Number of registers to be written - 1 */ | ||
| 382 | priv->cmd_buffer[2] = val; | ||
| 383 | |||
| 384 | return spi_sync_transfer(priv->spi, ®_write_xfer, 1); | ||
| 385 | } | ||
| 386 | |||
| 387 | static int ads1298_reg_read(void *context, unsigned int reg, unsigned int *val) | ||
| 388 | { | ||
| 389 | struct ads1298_private *priv = context; | ||
| 390 | struct spi_transfer reg_read_xfer = { | ||
| 391 | .tx_buf = priv->cmd_buffer, | ||
| 392 | .rx_buf = priv->cmd_buffer, | ||
| 393 | .len = 3, | ||
| 394 | .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW, | ||
| 395 | .delay = { | ||
| 396 | .value = 2, | ||
| 397 | .unit = SPI_DELAY_UNIT_USECS, | ||
| 398 | }, | ||
| 399 | }; | ||
| 400 | int ret; | ||
| 401 | |||
| 402 | priv->cmd_buffer[0] = ADS1298_CMD_RREG | reg; | ||
| 403 | priv->cmd_buffer[1] = 0; /* Number of registers to be read - 1 */ | ||
| 404 | priv->cmd_buffer[2] = 0; | ||
| 405 | |||
| 406 | ret = spi_sync_transfer(priv->spi, ®_read_xfer, 1); | ||
| 407 | if (ret) | ||
| 408 | return ret; | ||
| 409 | |||
| 410 | *val = priv->cmd_buffer[2]; | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int ads1298_reg_access(struct iio_dev *indio_dev, unsigned int reg, | ||
| 416 | unsigned int writeval, unsigned int *readval) | ||
| 417 | { | ||
| 418 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 419 | |||
| 420 | if (readval) | ||
| 421 | return regmap_read(priv->regmap, reg, readval); | ||
| 422 | |||
| 423 | return regmap_write(priv->regmap, reg, writeval); | ||
| 424 | } | ||
| 425 | |||
| 426 | static void ads1298_rdata_unmark_busy(struct ads1298_private *priv) | ||
| 427 | { | ||
| 428 | /* Notify we're no longer waiting for the SPI transfer to complete */ | ||
| 429 | guard(spinlock_irqsave)(&priv->irq_busy_lock); | ||
| 430 | priv->rdata_xfer_busy = 0; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int ads1298_update_scan_mode(struct iio_dev *indio_dev, | ||
| 434 | const unsigned long *scan_mask) | ||
| 435 | { | ||
| 436 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 437 | unsigned int val; | ||
| 438 | int ret; | ||
| 439 | int i; | ||
| 440 | |||
| 441 | /* Make the interrupt routines start with a clean slate */ | ||
| 442 | ads1298_rdata_unmark_busy(priv); | ||
| 443 | |||
| 444 | /* Configure power-down bits to match scan mask */ | ||
| 445 | for (i = 0; i < indio_dev->num_channels; i++) { | ||
| 446 | val = test_bit(i, scan_mask) ? 0 : ADS1298_MASK_CH_PD; | ||
| 447 | ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(i), | ||
| 448 | ADS1298_MASK_CH_PD, val); | ||
| 449 | if (ret) | ||
| 450 | return ret; | ||
| 451 | } | ||
| 452 | |||
| 453 | return 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | static const struct iio_info ads1298_info = { | ||
| 457 | .read_raw = &ads1298_read_raw, | ||
| 458 | .write_raw = &ads1298_write_raw, | ||
| 459 | .update_scan_mode = &ads1298_update_scan_mode, | ||
| 460 | .debugfs_reg_access = &ads1298_reg_access, | ||
| 461 | }; | ||
| 462 | |||
| 463 | static void ads1298_rdata_release_busy_or_restart(struct ads1298_private *priv) | ||
| 464 | { | ||
| 465 | guard(spinlock_irqsave)(&priv->irq_busy_lock); | ||
| 466 | |||
| 467 | if (priv->rdata_xfer_busy > 1) { | ||
| 468 | /* | ||
| 469 | * DRDY interrupt occurred before SPI completion. Start a new | ||
| 470 | * SPI transaction now to retrieve the data that wasn't latched | ||
| 471 | * into the ADS1298 chip's transfer buffer yet. | ||
| 472 | */ | ||
| 473 | spi_async(priv->spi, &priv->rdata_msg); | ||
| 474 | /* | ||
| 475 | * If more than one DRDY took place, there was an overrun. Since | ||
| 476 | * the sample is already lost, reset the counter to 1 so that | ||
| 477 | * we will wait for a DRDY interrupt after this SPI transaction. | ||
| 478 | */ | ||
| 479 | priv->rdata_xfer_busy = 1; | ||
| 480 | } else { | ||
| 481 | /* No pending data, wait for DRDY */ | ||
| 482 | priv->rdata_xfer_busy = 0; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | /* Called from SPI completion interrupt handler */ | ||
| 487 | static void ads1298_rdata_complete(void *context) | ||
| 488 | { | ||
| 489 | struct iio_dev *indio_dev = context; | ||
| 490 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 491 | int scan_index; | ||
| 492 | u32 *bounce = priv->bounce_buffer; | ||
| 493 | |||
| 494 | if (!iio_buffer_enabled(indio_dev)) { | ||
| 495 | /* | ||
| 496 | * for a single transfer mode we're kept in direct_mode until | ||
| 497 | * completion, avoiding a race with buffered IO. | ||
| 498 | */ | ||
| 499 | ads1298_rdata_unmark_busy(priv); | ||
| 500 | complete(&priv->completion); | ||
| 501 | return; | ||
| 502 | } | ||
| 503 | |||
| 504 | /* Demux the channel data into our bounce buffer */ | ||
| 505 | for_each_set_bit(scan_index, indio_dev->active_scan_mask, | ||
| 506 | indio_dev->masklength) { | ||
| 507 | const struct iio_chan_spec *scan_chan = | ||
| 508 | &indio_dev->channels[scan_index]; | ||
| 509 | const u8 *data = priv->rx_buffer + scan_chan->address; | ||
| 510 | |||
| 511 | *bounce++ = get_unaligned_be24(data); | ||
| 512 | } | ||
| 513 | |||
| 514 | /* rx_buffer can be overwritten from this point on */ | ||
| 515 | ads1298_rdata_release_busy_or_restart(priv); | ||
| 516 | |||
| 517 | iio_push_to_buffers(indio_dev, priv->bounce_buffer); | ||
| 518 | } | ||
| 519 | |||
| 520 | static irqreturn_t ads1298_interrupt(int irq, void *dev_id) | ||
| 521 | { | ||
| 522 | struct iio_dev *indio_dev = dev_id; | ||
| 523 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 524 | unsigned int wasbusy; | ||
| 525 | |||
| 526 | guard(spinlock_irqsave)(&priv->irq_busy_lock); | ||
| 527 | |||
| 528 | wasbusy = priv->rdata_xfer_busy++; | ||
| 529 | /* When no SPI transfer in transit, start one now */ | ||
| 530 | if (!wasbusy) | ||
| 531 | spi_async(priv->spi, &priv->rdata_msg); | ||
| 532 | |||
| 533 | return IRQ_HANDLED; | ||
| 534 | }; | ||
| 535 | |||
| 536 | static int ads1298_buffer_postenable(struct iio_dev *indio_dev) | ||
| 537 | { | ||
| 538 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 539 | int ret; | ||
| 540 | |||
| 541 | /* Disable single-shot mode */ | ||
| 542 | ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4, | ||
| 543 | ADS1298_MASK_CONFIG4_SINGLE_SHOT, 0); | ||
| 544 | if (ret) | ||
| 545 | return ret; | ||
| 546 | |||
| 547 | return ads1298_write_cmd(priv, ADS1298_CMD_START); | ||
| 548 | } | ||
| 549 | |||
| 550 | static int ads1298_buffer_predisable(struct iio_dev *indio_dev) | ||
| 551 | { | ||
| 552 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 553 | |||
| 554 | return ads1298_write_cmd(priv, ADS1298_CMD_STOP); | ||
| 555 | } | ||
| 556 | |||
| 557 | static const struct iio_buffer_setup_ops ads1298_setup_ops = { | ||
| 558 | .postenable = &ads1298_buffer_postenable, | ||
| 559 | .predisable = &ads1298_buffer_predisable, | ||
| 560 | }; | ||
| 561 | |||
| 562 | static void ads1298_reg_disable(void *reg) | ||
| 563 | { | ||
| 564 | regulator_disable(reg); | ||
| 565 | } | ||
| 566 | |||
| 567 | static const struct regmap_range ads1298_regmap_volatile_range[] = { | ||
| 568 | regmap_reg_range(ADS1298_REG_LOFF_STATP, ADS1298_REG_LOFF_STATN), | ||
| 569 | }; | ||
| 570 | |||
| 571 | static const struct regmap_access_table ads1298_regmap_volatile = { | ||
| 572 | .yes_ranges = ads1298_regmap_volatile_range, | ||
| 573 | .n_yes_ranges = ARRAY_SIZE(ads1298_regmap_volatile_range), | ||
| 574 | }; | ||
| 575 | |||
| 576 | static const struct regmap_config ads1298_regmap_config = { | ||
| 577 | .reg_bits = 8, | ||
| 578 | .val_bits = 8, | ||
| 579 | .reg_read = ads1298_reg_read, | ||
| 580 | .reg_write = ads1298_reg_write, | ||
| 581 | .max_register = ADS1298_REG_WCT2, | ||
| 582 | .volatile_table = &ads1298_regmap_volatile, | ||
| 583 | .cache_type = REGCACHE_MAPLE, | ||
| 584 | }; | ||
| 585 | |||
| 586 | static int ads1298_init(struct iio_dev *indio_dev) | ||
| 587 | { | ||
| 588 | struct ads1298_private *priv = iio_priv(indio_dev); | ||
| 589 | struct device *dev = &priv->spi->dev; | ||
| 590 | const char *suffix; | ||
| 591 | unsigned int val; | ||
| 592 | int ret; | ||
| 593 | |||
| 594 | /* Device initializes into RDATAC mode, which we don't want */ | ||
| 595 | ret = ads1298_write_cmd(priv, ADS1298_CMD_SDATAC); | ||
| 596 | if (ret) | ||
| 597 | return ret; | ||
| 598 | |||
| 599 | ret = regmap_read(priv->regmap, ADS1298_REG_ID, &val); | ||
| 600 | if (ret) | ||
| 601 | return ret; | ||
| 602 | |||
| 603 | /* Fill in name and channel count based on what the chip told us */ | ||
| 604 | indio_dev->num_channels = 4 + 2 * (val & ADS1298_MASK_ID_CHANNELS); | ||
| 605 | switch (val & ADS1298_MASK_ID_FAMILY) { | ||
| 606 | case ADS1298_ID_FAMILY_ADS129X: | ||
| 607 | suffix = ""; | ||
| 608 | break; | ||
| 609 | case ADS1298_ID_FAMILY_ADS129XR: | ||
| 610 | suffix = "r"; | ||
| 611 | break; | ||
| 612 | default: | ||
| 613 | return dev_err_probe(dev, -ENODEV, "Unknown ID: 0x%x\n", val); | ||
| 614 | } | ||
| 615 | indio_dev->name = devm_kasprintf(dev, GFP_KERNEL, "ads129%u%s", | ||
| 616 | indio_dev->num_channels, suffix); | ||
| 617 | |||
| 618 | /* Enable internal test signal, double amplitude, double frequency */ | ||
| 619 | ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2, | ||
| 620 | ADS1298_MASK_CONFIG2_RESERVED | | ||
| 621 | ADS1298_MASK_CONFIG2_INT_TEST | | ||
| 622 | ADS1298_MASK_CONFIG2_TEST_AMP | | ||
| 623 | ADS1298_MASK_CONFIG2_TEST_FREQ_FAST); | ||
| 624 | if (ret) | ||
| 625 | return ret; | ||
| 626 | |||
| 627 | val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */ | ||
| 628 | if (!priv->reg_vref) { | ||
| 629 | /* Enable internal reference */ | ||
| 630 | val |= ADS1298_MASK_CONFIG3_PWR_REFBUF; | ||
| 631 | /* Use 4V VREF when power supply is at least 4.4V */ | ||
| 632 | if (regulator_get_voltage(priv->reg_avdd) >= 4400000) | ||
| 633 | val |= ADS1298_MASK_CONFIG3_VREF_4V; | ||
| 634 | } | ||
| 635 | return regmap_write(priv->regmap, ADS1298_REG_CONFIG3, val); | ||
| 636 | } | ||
| 637 | |||
| 638 | static int ads1298_probe(struct spi_device *spi) | ||
| 639 | { | ||
| 640 | struct ads1298_private *priv; | ||
| 641 | struct iio_dev *indio_dev; | ||
| 642 | struct device *dev = &spi->dev; | ||
| 643 | struct gpio_desc *reset_gpio; | ||
| 644 | int ret; | ||
| 645 | |||
| 646 | indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); | ||
| 647 | if (!indio_dev) | ||
| 648 | return -ENOMEM; | ||
| 649 | |||
| 650 | priv = iio_priv(indio_dev); | ||
| 651 | |||
| 652 | /* Reset to be asserted before enabling clock and power */ | ||
| 653 | reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); | ||
| 654 | if (IS_ERR(reset_gpio)) | ||
| 655 | return dev_err_probe(dev, PTR_ERR(reset_gpio), | ||
| 656 | "Cannot get reset GPIO\n"); | ||
| 657 | |||
| 658 | /* VREF can be supplied externally, otherwise use internal reference */ | ||
| 659 | priv->reg_vref = devm_regulator_get_optional(dev, "vref"); | ||
| 660 | if (IS_ERR(priv->reg_vref)) { | ||
| 661 | if (PTR_ERR(priv->reg_vref) != -ENODEV) | ||
| 662 | return dev_err_probe(dev, PTR_ERR(priv->reg_vref), | ||
| 663 | "Failed to get vref regulator\n"); | ||
| 664 | |||
| 665 | priv->reg_vref = NULL; | ||
| 666 | } else { | ||
| 667 | ret = regulator_enable(priv->reg_vref); | ||
| 668 | if (ret) | ||
| 669 | return ret; | ||
| 670 | |||
| 671 | ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_vref); | ||
| 672 | if (ret) | ||
| 673 | return ret; | ||
| 674 | } | ||
| 675 | |||
| 676 | priv->clk = devm_clk_get_optional_enabled(dev, "clk"); | ||
| 677 | if (IS_ERR(priv->clk)) | ||
| 678 | return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clk\n"); | ||
| 679 | |||
| 680 | priv->reg_avdd = devm_regulator_get(dev, "avdd"); | ||
| 681 | if (IS_ERR(priv->reg_avdd)) | ||
| 682 | return dev_err_probe(dev, PTR_ERR(priv->reg_avdd), | ||
| 683 | "Failed to get avdd regulator\n"); | ||
| 684 | |||
| 685 | ret = regulator_enable(priv->reg_avdd); | ||
| 686 | if (ret) | ||
| 687 | return dev_err_probe(dev, ret, "Failed to enable avdd regulator\n"); | ||
| 688 | |||
| 689 | ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_avdd); | ||
| 690 | if (ret) | ||
| 691 | return ret; | ||
| 692 | |||
| 693 | priv->spi = spi; | ||
| 694 | init_completion(&priv->completion); | ||
| 695 | spin_lock_init(&priv->irq_busy_lock); | ||
| 696 | priv->regmap = devm_regmap_init(dev, NULL, priv, &ads1298_regmap_config); | ||
| 697 | if (IS_ERR(priv->regmap)) | ||
| 698 | return PTR_ERR(priv->regmap); | ||
| 699 | |||
| 700 | indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; | ||
| 701 | indio_dev->channels = ads1298_channels; | ||
| 702 | indio_dev->info = &ads1298_info; | ||
| 703 | |||
| 704 | if (reset_gpio) { | ||
| 705 | /* | ||
| 706 | * Deassert reset now that clock and power are active. | ||
| 707 | * Minimum reset pulsewidth is 2 clock cycles. | ||
| 708 | */ | ||
| 709 | fsleep(ADS1298_CLOCKS_TO_USECS(2)); | ||
| 710 | gpiod_set_value_cansleep(reset_gpio, 0); | ||
| 711 | } else { | ||
| 712 | ret = ads1298_write_cmd(priv, ADS1298_CMD_RESET); | ||
| 713 | if (ret) | ||
| 714 | return dev_err_probe(dev, ret, "RESET failed\n"); | ||
| 715 | } | ||
| 716 | /* Wait 18 clock cycles for reset command to complete */ | ||
| 717 | fsleep(ADS1298_CLOCKS_TO_USECS(18)); | ||
| 718 | |||
| 719 | ret = ads1298_init(indio_dev); | ||
| 720 | if (ret) | ||
| 721 | return dev_err_probe(dev, ret, "Init failed\n"); | ||
| 722 | |||
| 723 | priv->tx_buffer[0] = ADS1298_CMD_RDATA; | ||
| 724 | priv->rdata_xfer.tx_buf = priv->tx_buffer; | ||
| 725 | priv->rdata_xfer.rx_buf = priv->rx_buffer; | ||
| 726 | priv->rdata_xfer.len = ADS1298_SPI_RDATA_BUFFER_SIZE(indio_dev->num_channels); | ||
| 727 | /* Must keep CS low for 4 clocks */ | ||
| 728 | priv->rdata_xfer.delay.value = 2; | ||
| 729 | priv->rdata_xfer.delay.unit = SPI_DELAY_UNIT_USECS; | ||
| 730 | spi_message_init_with_transfers(&priv->rdata_msg, &priv->rdata_xfer, 1); | ||
| 731 | priv->rdata_msg.complete = &ads1298_rdata_complete; | ||
| 732 | priv->rdata_msg.context = indio_dev; | ||
| 733 | |||
| 734 | ret = devm_request_irq(dev, spi->irq, &ads1298_interrupt, | ||
| 735 | IRQF_TRIGGER_FALLING, indio_dev->name, | ||
| 736 | indio_dev); | ||
| 737 | if (ret) | ||
| 738 | return ret; | ||
| 739 | |||
| 740 | ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &ads1298_setup_ops); | ||
| 741 | if (ret) | ||
| 742 | return ret; | ||
| 743 | |||
| 744 | return devm_iio_device_register(dev, indio_dev); | ||
| 745 | } | ||
| 746 | |||
| 747 | static const struct spi_device_id ads1298_id[] = { | ||
| 748 | { "ads1298" }, | ||
| 749 | { } | ||
| 750 | }; | ||
| 751 | MODULE_DEVICE_TABLE(spi, ads1298_id); | ||
| 752 | |||
| 753 | static const struct of_device_id ads1298_of_table[] = { | ||
| 754 | { .compatible = "ti,ads1298" }, | ||
| 755 | { } | ||
| 756 | }; | ||
| 757 | MODULE_DEVICE_TABLE(of, ads1298_of_table); | ||
| 758 | |||
| 759 | static struct spi_driver ads1298_driver = { | ||
| 760 | .driver = { | ||
| 761 | .name = "ads1298", | ||
| 762 | .of_match_table = ads1298_of_table, | ||
| 763 | }, | ||
| 764 | .probe = ads1298_probe, | ||
| 765 | .id_table = ads1298_id, | ||
| 766 | }; | ||
| 767 | module_spi_driver(ads1298_driver); | ||
| 768 | |||
| 769 | MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); | ||
| 770 | MODULE_DESCRIPTION("TI ADS1298 ADC"); | ||
| 771 | MODULE_LICENSE("GPL"); | ||
| @@ -11,7 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <linux/regulator/consumer.h> | 11 | #include <linux/regulator/consumer.h> |
| 12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/of.h> | 14 | #include <linux/mod_devicetable.h> |
| 15 | 15 | ||
| 16 | #include <linux/iio/iio.h> | 16 | #include <linux/iio/iio.h> |
| 17 | #include <linux/iio/buffer.h> | 17 | #include <linux/iio/buffer.h> |
| @@ -2,9 +2,10 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * HMC425A and similar Gain Amplifiers | 3 | * HMC425A and similar Gain Amplifiers |
| 4 | * | 4 | * |
| 5 | * Copyright 2020 Analog Devices Inc. | 5 | * Copyright 2020, 2024 Analog Devices Inc. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/bits.h> | ||
| 8 | #include <linux/bitops.h> | 9 | #include <linux/bitops.h> |
| 9 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| @@ -12,6 +13,7 @@ · 1 unmodified line | |||
| 12 | #include <linux/iio/iio.h> | 13 | #include <linux/iio/iio.h> |
| 13 | #include <linux/iio/sysfs.h> | 14 | #include <linux/iio/sysfs.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/math.h> | ||
| 15 | #include <linux/mod_devicetable.h> | 17 | #include <linux/mod_devicetable.h> |
| 16 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 17 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| @@ -20,10 +22,24 @@ · 2 unmodified lines | |||
| 20 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
| 21 | #include <linux/sysfs.h> | 23 | #include <linux/sysfs.h> |
| 22 | 24 | ||
| 25 | /* | ||
| 26 | * The LTC6373 amplifier supports configuring gain using GPIO's with the following | ||
| 27 | * values (OUTPUT_V / INPUT_V): 0(shutdown), 0.25, 0.5, 1, 2, 4, 8, 16 | ||
| 28 | * | ||
| 29 | * Except for the shutdown value, all can be converted to dB using 20 * log10(x) | ||
| 30 | * From here, it is observed that all values are multiples of the '2' gain setting, | ||
| 31 | * with the correspondent of 6.020dB. | ||
| 32 | */ | ||
| 33 | #define LTC6373_CONVERSION_CONSTANT 6020 | ||
| 34 | #define LTC6373_MIN_GAIN_CODE 0x6 | ||
| 35 | #define LTC6373_CONVERSION_MASK GENMASK(2, 0) | ||
| 36 | #define LTC6373_SHUTDOWN GENMASK(2, 0) | ||
| 37 | |||
| 23 | enum hmc425a_type { | 38 | enum hmc425a_type { |
| 24 | ID_HMC425A, | 39 | ID_HMC425A, |
| 25 | ID_HMC540S, | 40 | ID_HMC540S, |
| 26 | ID_ADRF5740 | 41 | ID_ADRF5740, |
| 42 | ID_LTC6373, | ||
| 27 | }; | 43 | }; |
| 28 | 44 | ||
| 29 | struct hmc425a_chip_info { | 45 | struct hmc425a_chip_info { |
| @@ -34,16 +50,110 @@ struct hmc425a_chip_info { · 4 unmodified lines | |||
| 34 | int gain_min; | 50 | int gain_min; |
| 35 | int gain_max; | 51 | int gain_max; |
| 36 | int default_gain; | 52 | int default_gain; |
| 53 | int powerdown_val; | ||
| 54 | bool has_powerdown; | ||
| 55 | |||
| 56 | int (*gain_dB_to_code)(int gain, int *code); | ||
| 57 | int (*code_to_gain_dB)(int code, int *val, int *val2); | ||
| 37 | }; | 58 | }; |
| 38 | 59 | ||
| 39 | struct hmc425a_state { | 60 | struct hmc425a_state { |
| 40 | struct mutex lock; /* protect sensor state */ | 61 | struct mutex lock; /* protect sensor state */ |
| 41 | struct hmc425a_chip_info *chip_info; | 62 | const struct hmc425a_chip_info *chip_info; |
| 42 | struct gpio_descs *gpios; | 63 | struct gpio_descs *gpios; |
| 43 | enum hmc425a_type type; | ||
| 44 | u32 gain; | 64 | u32 gain; |
| 65 | bool powerdown; | ||
| 45 | }; | 66 | }; |
| 46 | 67 | ||
| 68 | static int gain_dB_to_code(struct hmc425a_state *st, int val, int val2, int *code) | ||
| 69 | { | ||
| 70 | const struct hmc425a_chip_info *inf = st->chip_info; | ||
| 71 | int gain; | ||
| 72 | |||
| 73 | if (val < 0) | ||
| 74 | gain = (val * 1000) - (val2 / 1000); | ||
| 75 | else | ||
| 76 | gain = (val * 1000) + (val2 / 1000); | ||
| 77 | |||
| 78 | if (gain > inf->gain_max || gain < inf->gain_min) | ||
| 79 | return -EINVAL; | ||
| 80 | if (st->powerdown) | ||
| 81 | return -EPERM; | ||
| 82 | |||
| 83 | return st->chip_info->gain_dB_to_code(gain, code); | ||
| 84 | } | ||
| 85 | |||
| 86 | static int hmc425a_gain_dB_to_code(int gain, int *code) | ||
| 87 | { | ||
| 88 | *code = ~((abs(gain) / 500) & 0x3F); | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int hmc540s_gain_dB_to_code(int gain, int *code) | ||
| 93 | { | ||
| 94 | *code = ~((abs(gain) / 1000) & 0xF); | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int adrf5740_gain_dB_to_code(int gain, int *code) | ||
| 99 | { | ||
| 100 | int temp = (abs(gain) / 2000) & 0xF; | ||
| 101 | |||
| 102 | /* Bit [0-3]: 2dB 4dB 8dB 8dB */ | ||
| 103 | *code = temp & BIT(3) ? temp | BIT(2) : temp; | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int ltc6373_gain_dB_to_code(int gain, int *code) | ||
| 108 | { | ||
| 109 | *code = ~(DIV_ROUND_CLOSEST(gain, LTC6373_CONVERSION_CONSTANT) + 3) | ||
| 110 | & LTC6373_CONVERSION_MASK; | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int code_to_gain_dB(struct hmc425a_state *st, int *val, int *val2) | ||
| 115 | { | ||
| 116 | if (st->powerdown) | ||
| 117 | return -EPERM; | ||
| 118 | return st->chip_info->code_to_gain_dB(st->gain, val, val2); | ||
| 119 | } | ||
| 120 | |||
| 121 | static int hmc425a_code_to_gain_dB(int code, int *val, int *val2) | ||
| 122 | { | ||
| 123 | *val = (~code * -500) / 1000; | ||
| 124 | *val2 = ((~code * -500) % 1000) * 1000; | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static int hmc540s_code_to_gain_dB(int code, int *val, int *val2) | ||
| 129 | { | ||
| 130 | *val = (~code * -1000) / 1000; | ||
| 131 | *val2 = ((~code * -1000) % 1000) * 1000; | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int adrf5740_code_to_gain_dB(int code, int *val, int *val2) | ||
| 136 | { | ||
| 137 | /* | ||
| 138 | * Bit [0-3]: 2dB 4dB 8dB 8dB | ||
| 139 | * When BIT(3) is set, unset BIT(2) and use 3 as double the place value | ||
| 140 | */ | ||
| 141 | code = code & BIT(3) ? code & ~BIT(2) : code; | ||
| 142 | *val = (code * -2000) / 1000; | ||
| 143 | *val2 = ((code * -2000) % 1000) * 1000; | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int ltc6373_code_to_gain_dB(int code, int *val, int *val2) | ||
| 148 | { | ||
| 149 | int gain = ((~code & LTC6373_CONVERSION_MASK) - 3) * | ||
| 150 | LTC6373_CONVERSION_CONSTANT; | ||
| 151 | |||
| 152 | *val = gain / 1000; | ||
| 153 | *val2 = (gain % 1000) * 1000; | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 47 | static int hmc425a_write(struct iio_dev *indio_dev, u32 value) | 157 | static int hmc425a_write(struct iio_dev *indio_dev, u32 value) |
| 48 | { | 158 | { |
| 49 | struct hmc425a_state *st = iio_priv(indio_dev); | 159 | struct hmc425a_state *st = iio_priv(indio_dev); |
| @@ -61,30 +171,14 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev, · 11 unmodified lines | |||
| 61 | int *val2, long m) | 171 | int *val2, long m) |
| 62 | { | 172 | { |
| 63 | struct hmc425a_state *st = iio_priv(indio_dev); | 173 | struct hmc425a_state *st = iio_priv(indio_dev); |
| 64 | int code, gain = 0; | ||
| 65 | int ret; | 174 | int ret; |
| 66 | 175 | ||
| 67 | mutex_lock(&st->lock); | 176 | mutex_lock(&st->lock); |
| 68 | switch (m) { | 177 | switch (m) { |
| 69 | case IIO_CHAN_INFO_HARDWAREGAIN: | 178 | case IIO_CHAN_INFO_HARDWAREGAIN: |
| 70 | code = st->gain; | 179 | ret = code_to_gain_dB(st, val, val2); |
| 71 | 180 | if (ret) | |
| 72 | switch (st->type) { | ||
| 73 | case ID_HMC425A: | ||
| 74 | gain = ~code * -500; | ||
| 75 | break; | 181 | break; |
| 76 | case ID_HMC540S: | ||
| 77 | gain = ~code * -1000; | ||
| 78 | break; | ||
| 79 | case ID_ADRF5740: | ||
| 80 | code = code & BIT(3) ? code & ~BIT(2) : code; | ||
| 81 | gain = code * -2000; | ||
| 82 | break; | ||
| 83 | } | ||
| 84 | |||
| 85 | *val = gain / 1000; | ||
| 86 | *val2 = (gain % 1000) * 1000; | ||
| 87 | |||
| 88 | ret = IIO_VAL_INT_PLUS_MICRO_DB; | 182 | ret = IIO_VAL_INT_PLUS_MICRO_DB; |
| 89 | break; | 183 | break; |
| 90 | default: | 184 | default: |
| @@ -100,34 +194,14 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev, · 9 unmodified lines | |||
| 100 | int val2, long mask) | 194 | int val2, long mask) |
| 101 | { | 195 | { |
| 102 | struct hmc425a_state *st = iio_priv(indio_dev); | 196 | struct hmc425a_state *st = iio_priv(indio_dev); |
| 103 | struct hmc425a_chip_info *inf = st->chip_info; | 197 | int code = 0, ret; |
| 104 | int code = 0, gain; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | if (val < 0) | ||
| 108 | gain = (val * 1000) - (val2 / 1000); | ||
| 109 | else | ||
| 110 | gain = (val * 1000) + (val2 / 1000); | ||
| 111 | |||
| 112 | if (gain > inf->gain_max || gain < inf->gain_min) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | switch (st->type) { | ||
| 116 | case ID_HMC425A: | ||
| 117 | code = ~((abs(gain) / 500) & 0x3F); | ||
| 118 | break; | ||
| 119 | case ID_HMC540S: | ||
| 120 | code = ~((abs(gain) / 1000) & 0xF); | ||
| 121 | break; | ||
| 122 | case ID_ADRF5740: | ||
| 123 | code = (abs(gain) / 2000) & 0xF; | ||
| 124 | code = code & BIT(3) ? code | BIT(2) : code; | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | 198 | ||
| 128 | mutex_lock(&st->lock); | 199 | mutex_lock(&st->lock); |
| 129 | switch (mask) { | 200 | switch (mask) { |
| 130 | case IIO_CHAN_INFO_HARDWAREGAIN: | 201 | case IIO_CHAN_INFO_HARDWAREGAIN: |
| 202 | ret = gain_dB_to_code(st, val, val2, &code); | ||
| 203 | if (ret) | ||
| 204 | break; | ||
| 131 | st->gain = code; | 205 | st->gain = code; |
| 132 | 206 | ||
| 133 | ret = hmc425a_write(indio_dev, st->gain); | 207 | ret = hmc425a_write(indio_dev, st->gain); |
| @@ -158,6 +232,48 @@ static const struct iio_info hmc425a_info = { · 24 unmodified lines | |||
| 158 | .write_raw_get_fmt = &hmc425a_write_raw_get_fmt, | 232 | .write_raw_get_fmt = &hmc425a_write_raw_get_fmt, |
| 159 | }; | 233 | }; |
| 160 | 234 | ||
| 235 | static ssize_t ltc6373_read_powerdown(struct iio_dev *indio_dev, | ||
| 236 | uintptr_t private, | ||
| 237 | const struct iio_chan_spec *chan, | ||
| 238 | char *buf) | ||
| 239 | { | ||
| 240 | struct hmc425a_state *st = iio_priv(indio_dev); | ||
| 241 | |||
| 242 | return sysfs_emit(buf, "%d\n", st->powerdown); | ||
| 243 | } | ||
| 244 | |||
| 245 | static ssize_t ltc6373_write_powerdown(struct iio_dev *indio_dev, | ||
| 246 | uintptr_t private, | ||
| 247 | const struct iio_chan_spec *chan, | ||
| 248 | const char *buf, | ||
| 249 | size_t len) | ||
| 250 | { | ||
| 251 | struct hmc425a_state *st = iio_priv(indio_dev); | ||
| 252 | bool powerdown; | ||
| 253 | int code, ret; | ||
| 254 | |||
| 255 | ret = kstrtobool(buf, &powerdown); | ||
| 256 | if (ret) | ||
| 257 | return ret; | ||
| 258 | |||
| 259 | mutex_lock(&st->lock); | ||
| 260 | st->powerdown = powerdown; | ||
| 261 | code = (powerdown) ? LTC6373_SHUTDOWN : st->gain; | ||
| 262 | hmc425a_write(indio_dev, code); | ||
| 263 | mutex_unlock(&st->lock); | ||
| 264 | return len; | ||
| 265 | } | ||
| 266 | |||
| 267 | static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = { | ||
| 268 | { | ||
| 269 | .name = "powerdown", | ||
| 270 | .read = ltc6373_read_powerdown, | ||
| 271 | .write = ltc6373_write_powerdown, | ||
| 272 | .shared = IIO_SEPARATE, | ||
| 273 | }, | ||
| 274 | {} | ||
| 275 | }; | ||
| 276 | |||
| 161 | #define HMC425A_CHAN(_channel) \ | 277 | #define HMC425A_CHAN(_channel) \ |
| 162 | { \ | 278 | { \ |
| 163 | .type = IIO_VOLTAGE, \ | 279 | .type = IIO_VOLTAGE, \ |
| @@ -167,20 +283,25 @@ static const struct iio_info hmc425a_info = { · 3 unmodified lines | |||
| 167 | .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ | 283 | .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ |
| 168 | } | 284 | } |
| 169 | 285 | ||
| 286 | #define LTC6373_CHAN(_channel) \ | ||
| 287 | { \ | ||
| 288 | .type = IIO_VOLTAGE, \ | ||
| 289 | .output = 1, \ | ||
| 290 | .indexed = 1, \ | ||
| 291 | .channel = _channel, \ | ||
| 292 | .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ | ||
| 293 | .ext_info = ltc6373_ext_info, \ | ||
| 294 | } | ||
| 295 | |||
| 170 | static const struct iio_chan_spec hmc425a_channels[] = { | 296 | static const struct iio_chan_spec hmc425a_channels[] = { |
| 171 | HMC425A_CHAN(0), | 297 | HMC425A_CHAN(0), |
| 172 | }; | 298 | }; |
| 173 | 299 | ||
| 174 | /* Match table for of_platform binding */ | 300 | static const struct iio_chan_spec ltc6373_channels[] = { |
| 175 | static const struct of_device_id hmc425a_of_match[] = { | 301 | LTC6373_CHAN(0), |
| 176 | { .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A }, | ||
| 177 | { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S }, | ||
| 178 | { .compatible = "adi,adrf5740", .data = (void *)ID_ADRF5740 }, | ||
| 179 | {}, | ||
| 180 | }; | 302 | }; |
| 181 | MODULE_DEVICE_TABLE(of, hmc425a_of_match); | ||
| 182 | 303 | ||
| 183 | static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { | 304 | static const struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { |
| 184 | [ID_HMC425A] = { | 305 | [ID_HMC425A] = { |
| 185 | .name = "hmc425a", | 306 | .name = "hmc425a", |
| 186 | .channels = hmc425a_channels, | 307 | .channels = hmc425a_channels, |
| @@ -189,6 +310,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { · 2 unmodified lines | |||
| 189 | .gain_min = -31500, | 310 | .gain_min = -31500, |
| 190 | .gain_max = 0, | 311 | .gain_max = 0, |
| 191 | .default_gain = -0x40, /* set default gain -31.5db*/ | 312 | .default_gain = -0x40, /* set default gain -31.5db*/ |
| 313 | .gain_dB_to_code = hmc425a_gain_dB_to_code, | ||
| 314 | .code_to_gain_dB = hmc425a_code_to_gain_dB, | ||
| 192 | }, | 315 | }, |
| 193 | [ID_HMC540S] = { | 316 | [ID_HMC540S] = { |
| 194 | .name = "hmc540s", | 317 | .name = "hmc540s", |
| @@ -198,6 +321,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { · 3 unmodified lines | |||
| 198 | .gain_min = -15000, | 321 | .gain_min = -15000, |
| 199 | .gain_max = 0, | 322 | .gain_max = 0, |
| 200 | .default_gain = -0x10, /* set default gain -15.0db*/ | 323 | .default_gain = -0x10, /* set default gain -15.0db*/ |
| 324 | .gain_dB_to_code = hmc540s_gain_dB_to_code, | ||
| 325 | .code_to_gain_dB = hmc540s_code_to_gain_dB, | ||
| 201 | }, | 326 | }, |
| 202 | [ID_ADRF5740] = { | 327 | [ID_ADRF5740] = { |
| 203 | .name = "adrf5740", | 328 | .name = "adrf5740", |
| @@ -207,6 +332,21 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { · 3 unmodified lines | |||
| 207 | .gain_min = -22000, | 332 | .gain_min = -22000, |
| 208 | .gain_max = 0, | 333 | .gain_max = 0, |
| 209 | .default_gain = 0xF, /* set default gain -22.0db*/ | 334 | .default_gain = 0xF, /* set default gain -22.0db*/ |
| 335 | .gain_dB_to_code = adrf5740_gain_dB_to_code, | ||
| 336 | .code_to_gain_dB = adrf5740_code_to_gain_dB, | ||
| 337 | }, | ||
| 338 | [ID_LTC6373] = { | ||
| 339 | .name = "ltc6373", | ||
| 340 | .channels = ltc6373_channels, | ||
| 341 | .num_channels = ARRAY_SIZE(ltc6373_channels), | ||
| 342 | .num_gpios = 3, | ||
| 343 | .gain_min = -12041, /* gain setting x0.25*/ | ||
| 344 | .gain_max = 24082, /* gain setting x16 */ | ||
| 345 | .default_gain = LTC6373_MIN_GAIN_CODE, | ||
| 346 | .powerdown_val = LTC6373_SHUTDOWN, | ||
| 347 | .has_powerdown = true, | ||
| 348 | .gain_dB_to_code = ltc6373_gain_dB_to_code, | ||
| 349 | .code_to_gain_dB = ltc6373_code_to_gain_dB, | ||
| 210 | }, | 350 | }, |
| 211 | }; | 351 | }; |
| 212 | 352 | ||
| @@ -221,9 +361,8 @@ static int hmc425a_probe(struct platform_device *pdev) · 8 unmodified lines | |||
| 221 | return -ENOMEM; | 361 | return -ENOMEM; |
| 222 | 362 | ||
| 223 | st = iio_priv(indio_dev); | 363 | st = iio_priv(indio_dev); |
| 224 | st->type = (uintptr_t)device_get_match_data(&pdev->dev); | ||
| 225 | 364 | ||
| 226 | st->chip_info = &hmc425a_chip_info_tbl[st->type]; | 365 | st->chip_info = device_get_match_data(&pdev->dev); |
| 227 | indio_dev->num_channels = st->chip_info->num_channels; | 366 | indio_dev->num_channels = st->chip_info->num_channels; |
| 228 | indio_dev->channels = st->chip_info->channels; | 367 | indio_dev->channels = st->chip_info->channels; |
| 229 | indio_dev->name = st->chip_info->name; | 368 | indio_dev->name = st->chip_info->name; |
| @@ -249,12 +388,31 @@ static int hmc425a_probe(struct platform_device *pdev) · 19 unmodified lines | |||
| 249 | indio_dev->info = &hmc425a_info; | 388 | indio_dev->info = &hmc425a_info; |
| 250 | indio_dev->modes = INDIO_DIRECT_MODE; | 389 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 251 | 390 | ||
| 252 | /* Set default gain */ | 391 | if (st->chip_info->has_powerdown) { |
| 253 | hmc425a_write(indio_dev, st->gain); | 392 | st->powerdown = true; |
| 393 | hmc425a_write(indio_dev, st->chip_info->powerdown_val); | ||
| 394 | } else { | ||
| 395 | /* Set default gain */ | ||
| 396 | hmc425a_write(indio_dev, st->gain); | ||
| 397 | } | ||
| 254 | 398 | ||
| 255 | return devm_iio_device_register(&pdev->dev, indio_dev); | 399 | return devm_iio_device_register(&pdev->dev, indio_dev); |
| 256 | } | 400 | } |
| 257 | 401 | ||
| 402 | /* Match table for of_platform binding */ | ||
| 403 | static const struct of_device_id hmc425a_of_match[] = { | ||
| 404 | { .compatible = "adi,hmc425a", | ||
| 405 | .data = &hmc425a_chip_info_tbl[ID_HMC425A]}, | ||
| 406 | { .compatible = "adi,hmc540s", | ||
| 407 | .data = &hmc425a_chip_info_tbl[ID_HMC540S]}, | ||
| 408 | { .compatible = "adi,adrf5740", | ||
| 409 | .data = &hmc425a_chip_info_tbl[ID_ADRF5740]}, | ||
| 410 | { .compatible = "adi,ltc6373", | ||
| 411 | .data = &hmc425a_chip_info_tbl[ID_LTC6373]}, | ||
| 412 | {} | ||
| 413 | }; | ||
| 414 | MODULE_DEVICE_TABLE(of, hmc425a_of_match); | ||
| 415 | |||
| 258 | static struct platform_driver hmc425a_driver = { | 416 | static struct platform_driver hmc425a_driver = { |
| 259 | .driver = { | 417 | .driver = { |
| 260 | .name = KBUILD_MODNAME, | 418 | .name = KBUILD_MODNAME, |
| @@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = { · 158 unmodified lines | |||
| 159 | * Once done using the buffer iio_dmaengine_buffer_free() should be used to | 159 | * Once done using the buffer iio_dmaengine_buffer_free() should be used to |
| 160 | * release it. | 160 | * release it. |
| 161 | */ | 161 | */ |
| 162 | static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, | 162 | struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, |
| 163 | const char *channel) | 163 | const char *channel) |
| 164 | { | 164 | { |
| 165 | struct dmaengine_buffer *dmaengine_buffer; | 165 | struct dmaengine_buffer *dmaengine_buffer; |
| @@ -210,6 +210,7 @@ err_free: · 44 unmodified lines | |||
| 210 | kfree(dmaengine_buffer); | 210 | kfree(dmaengine_buffer); |
| 211 | return ERR_PTR(ret); | 211 | return ERR_PTR(ret); |
| 212 | } | 212 | } |
| 213 | EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER); | ||
| 213 | 214 | ||
| 214 | /** | 215 | /** |
| 215 | * iio_dmaengine_buffer_free() - Free dmaengine buffer | 216 | * iio_dmaengine_buffer_free() - Free dmaengine buffer |
| @@ -217,7 +218,7 @@ err_free: · 1 unmodified line | |||
| 217 | * | 218 | * |
| 218 | * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc(). | 219 | * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc(). |
| 219 | */ | 220 | */ |
| 220 | static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) | 221 | void iio_dmaengine_buffer_free(struct iio_buffer *buffer) |
| 221 | { | 222 | { |
| 222 | struct dmaengine_buffer *dmaengine_buffer = | 223 | struct dmaengine_buffer *dmaengine_buffer = |
| 223 | iio_buffer_to_dmaengine_buffer(buffer); | 224 | iio_buffer_to_dmaengine_buffer(buffer); |
| @@ -227,6 +228,7 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) · 3 unmodified lines | |||
| 227 | 228 | ||
| 228 | iio_buffer_put(buffer); | 229 | iio_buffer_put(buffer); |
| 229 | } | 230 | } |
| 231 | EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); | ||
| 230 | 232 | ||
| 231 | static void __devm_iio_dmaengine_buffer_free(void *buffer) | 233 | static void __devm_iio_dmaengine_buffer_free(void *buffer) |
| 232 | { | 234 | { |
| @@ -279,8 +281,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, · 46 unmodified lines | |||
| 279 | { | 281 | { |
| 280 | struct iio_buffer *buffer; | 282 | struct iio_buffer *buffer; |
| 281 | 283 | ||
| 282 | buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, | 284 | buffer = devm_iio_dmaengine_buffer_alloc(dev, channel); |
| 283 | channel); | ||
| 284 | if (IS_ERR(buffer)) | 285 | if (IS_ERR(buffer)) |
| 285 | return PTR_ERR(buffer); | 286 | return PTR_ERR(buffer); |
| 286 | 287 | ||
| @@ -288,7 +289,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, · 1 unmodified line | |||
| 288 | 289 | ||
| 289 | return iio_device_attach_buffer(indio_dev, buffer); | 290 | return iio_device_attach_buffer(indio_dev, buffer); |
| 290 | } | 291 | } |
| 291 | EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup); | 292 | EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); |
| 292 | 293 | ||
| 293 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 294 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
| 294 | MODULE_DESCRIPTION("DMA buffer for the IIO framework"); | 295 | MODULE_DESCRIPTION("DMA buffer for the IIO framework"); |
| @@ -126,7 +126,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, · 125 unmodified lines | |||
| 126 | struct inv_sensors_timestamp_interval *it; | 126 | struct inv_sensors_timestamp_interval *it; |
| 127 | int64_t delta, interval; | 127 | int64_t delta, interval; |
| 128 | const uint32_t fifo_mult = fifo_period / ts->chip.clock_period; | 128 | const uint32_t fifo_mult = fifo_period / ts->chip.clock_period; |
| 129 | uint32_t period = ts->period; | 129 | uint32_t period; |
| 130 | bool valid = false; | 130 | bool valid = false; |
| 131 | 131 | ||
| 132 | if (fifo_nb == 0) | 132 | if (fifo_nb == 0) |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/of.h> | 20 | #include <linux/mod_devicetable.h> |
| 21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
| 22 | 22 | ||
| 23 | #include <linux/iio/iio.h> | 23 | #include <linux/iio/iio.h> |
| @@ -31,8 +31,6 @@ · 30 unmodified lines | |||
| 31 | * @regs: irq regs we are faking | 31 | * @regs: irq regs we are faking |
| 32 | * @lock: protect the evgen state | 32 | * @lock: protect the evgen state |
| 33 | * @inuse: mask of which irqs are connected | 33 | * @inuse: mask of which irqs are connected |
| 34 | * @irq_sim: interrupt simulator | ||
| 35 | * @base: base of irq range | ||
| 36 | * @irq_sim_domain: irq simulator domain | 34 | * @irq_sim_domain: irq simulator domain |
| 37 | */ | 35 | */ |
| 38 | struct iio_dummy_eventgen { | 36 | struct iio_dummy_eventgen { |
| @@ -283,65 +283,63 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, · 282 unmodified lines | |||
| 283 | long mask) | 283 | long mask) |
| 284 | { | 284 | { |
| 285 | struct iio_dummy_state *st = iio_priv(indio_dev); | 285 | struct iio_dummy_state *st = iio_priv(indio_dev); |
| 286 | int ret = -EINVAL; | ||
| 287 | 286 | ||
| 288 | mutex_lock(&st->lock); | ||
| 289 | switch (mask) { | 287 | switch (mask) { |
| 290 | case IIO_CHAN_INFO_RAW: /* magic value - channel value read */ | 288 | case IIO_CHAN_INFO_RAW: /* magic value - channel value read */ |
| 291 | switch (chan->type) { | 289 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 292 | case IIO_VOLTAGE: | 290 | guard(mutex)(&st->lock); |
| 293 | if (chan->output) { | 291 | switch (chan->type) { |
| 294 | /* Set integer part to cached value */ | 292 | case IIO_VOLTAGE: |
| 295 | *val = st->dac_val; | 293 | if (chan->output) { |
| 296 | ret = IIO_VAL_INT; | 294 | /* Set integer part to cached value */ |
| 297 | } else if (chan->differential) { | 295 | *val = st->dac_val; |
| 298 | if (chan->channel == 1) | 296 | return IIO_VAL_INT; |
| 299 | *val = st->differential_adc_val[0]; | 297 | } else if (chan->differential) { |
| 300 | else | 298 | if (chan->channel == 1) |
| 301 | *val = st->differential_adc_val[1]; | 299 | *val = st->differential_adc_val[0]; |
| 302 | ret = IIO_VAL_INT; | 300 | else |
| 303 | } else { | 301 | *val = st->differential_adc_val[1]; |
| 304 | *val = st->single_ended_adc_val; | 302 | return IIO_VAL_INT; |
| 305 | ret = IIO_VAL_INT; | 303 | } else { |
| 304 | *val = st->single_ended_adc_val; | ||
| 305 | return IIO_VAL_INT; | ||
| 306 | } | ||
| 307 | |||
| 308 | case IIO_ACCEL: | ||
| 309 | *val = st->accel_val; | ||
| 310 | return IIO_VAL_INT; | ||
| 311 | default: | ||
| 312 | return -EINVAL; | ||
| 306 | } | 313 | } |
| 307 | break; | ||
| 308 | case IIO_ACCEL: | ||
| 309 | *val = st->accel_val; | ||
| 310 | ret = IIO_VAL_INT; | ||
| 311 | break; | ||
| 312 | default: | ||
| 313 | break; | ||
| 314 | } | 314 | } |
| 315 | break; | 315 | unreachable(); |
| 316 | case IIO_CHAN_INFO_PROCESSED: | 316 | case IIO_CHAN_INFO_PROCESSED: |
| 317 | switch (chan->type) { | 317 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { |
| 318 | case IIO_STEPS: | 318 | guard(mutex)(&st->lock); |
| 319 | *val = st->steps; | 319 | switch (chan->type) { |
| 320 | ret = IIO_VAL_INT; | 320 | case IIO_STEPS: |
| 321 | break; | 321 | *val = st->steps; |
| 322 | case IIO_ACTIVITY: | 322 | return IIO_VAL_INT; |
| 323 | switch (chan->channel2) { | 323 | case IIO_ACTIVITY: |
| 324 | case IIO_MOD_RUNNING: | 324 | switch (chan->channel2) { |
| 325 | *val = st->activity_running; | 325 | case IIO_MOD_RUNNING: |
| 326 | ret = IIO_VAL_INT; | 326 | *val = st->activity_running; |
| 327 | break; | 327 | return IIO_VAL_INT; |
| 328 | case IIO_MOD_WALKING: | 328 | case IIO_MOD_WALKING: |
| 329 | *val = st->activity_walking; | 329 | *val = st->activity_walking; |
| 330 | ret = IIO_VAL_INT; | 330 | return IIO_VAL_INT; |
| 331 | break; | 331 | default: |
| 332 | return -EINVAL; | ||
| 333 | } | ||
| 332 | default: | 334 | default: |
| 333 | break; | 335 | return -EINVAL; |
| 334 | } | 336 | } |
| 335 | break; | ||
| 336 | default: | ||
| 337 | break; | ||
| 338 | } | 337 | } |
| 339 | break; | 338 | unreachable(); |
| 340 | case IIO_CHAN_INFO_OFFSET: | 339 | case IIO_CHAN_INFO_OFFSET: |
| 341 | /* only single ended adc -> 7 */ | 340 | /* only single ended adc -> 7 */ |
| 342 | *val = 7; | 341 | *val = 7; |
| 343 | ret = IIO_VAL_INT; | 342 | return IIO_VAL_INT; |
| 344 | break; | ||
| 345 | case IIO_CHAN_INFO_SCALE: | 343 | case IIO_CHAN_INFO_SCALE: |
| 346 | switch (chan->type) { | 344 | switch (chan->type) { |
| 347 | case IIO_VOLTAGE: | 345 | case IIO_VOLTAGE: |
| @@ -350,60 +348,57 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 350 | /* only single ended adc -> 0.001333 */ | 348 | /* only single ended adc -> 0.001333 */ |
| 351 | *val = 0; | 349 | *val = 0; |
| 352 | *val2 = 1333; | 350 | *val2 = 1333; |
| 353 | ret = IIO_VAL_INT_PLUS_MICRO; | 351 | return IIO_VAL_INT_PLUS_MICRO; |
| 354 | break; | ||
| 355 | case 1: | 352 | case 1: |
| 356 | /* all differential adc -> 0.000001344 */ | 353 | /* all differential adc -> 0.000001344 */ |
| 357 | *val = 0; | 354 | *val = 0; |
| 358 | *val2 = 1344; | 355 | *val2 = 1344; |
| 359 | ret = IIO_VAL_INT_PLUS_NANO; | 356 | return IIO_VAL_INT_PLUS_NANO; |
| 357 | default: | ||
| 358 | return -EINVAL; | ||
| 360 | } | 359 | } |
| 361 | break; | ||
| 362 | default: | 360 | default: |
| 363 | break; | 361 | return -EINVAL; |
| 364 | } | 362 | } |
| 365 | break; | 363 | case IIO_CHAN_INFO_CALIBBIAS: { |
| 366 | case IIO_CHAN_INFO_CALIBBIAS: | 364 | guard(mutex)(&st->lock); |
| 367 | /* only the acceleration axis - read from cache */ | 365 | /* only the acceleration axis - read from cache */ |
| 368 | *val = st->accel_calibbias; | 366 | *val = st->accel_calibbias; |
| 369 | ret = IIO_VAL_INT; | 367 | return IIO_VAL_INT; |
| 370 | break; | 368 | } |
| 371 | case IIO_CHAN_INFO_CALIBSCALE: | 369 | case IIO_CHAN_INFO_CALIBSCALE: { |
| 370 | guard(mutex)(&st->lock); | ||
| 372 | *val = st->accel_calibscale->val; | 371 | *val = st->accel_calibscale->val; |
| 373 | *val2 = st->accel_calibscale->val2; | 372 | *val2 = st->accel_calibscale->val2; |
| 374 | ret = IIO_VAL_INT_PLUS_MICRO; | 373 | return IIO_VAL_INT_PLUS_MICRO; |
| 375 | break; | 374 | } |
| 376 | case IIO_CHAN_INFO_SAMP_FREQ: | 375 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 377 | *val = 3; | 376 | *val = 3; |
| 378 | *val2 = 33; | 377 | *val2 = 33; |
| 379 | ret = IIO_VAL_INT_PLUS_NANO; | 378 | return IIO_VAL_INT_PLUS_NANO; |
| 380 | break; | 379 | case IIO_CHAN_INFO_ENABLE: { |
| 381 | case IIO_CHAN_INFO_ENABLE: | 380 | guard(mutex)(&st->lock); |
| 382 | switch (chan->type) { | 381 | switch (chan->type) { |
| 383 | case IIO_STEPS: | 382 | case IIO_STEPS: |
| 384 | *val = st->steps_enabled; | 383 | *val = st->steps_enabled; |
| 385 | ret = IIO_VAL_INT; | 384 | return IIO_VAL_INT; |
| 386 | break; | ||
| 387 | default: | 385 | default: |
| 388 | break; | 386 | return -EINVAL; |
| 389 | } | 387 | } |
| 390 | break; | 388 | } |
| 391 | case IIO_CHAN_INFO_CALIBHEIGHT: | 389 | case IIO_CHAN_INFO_CALIBHEIGHT: { |
| 390 | guard(mutex)(&st->lock); | ||
| 392 | switch (chan->type) { | 391 | switch (chan->type) { |
| 393 | case IIO_STEPS: | 392 | case IIO_STEPS: |
| 394 | *val = st->height; | 393 | *val = st->height; |
| 395 | ret = IIO_VAL_INT; | 394 | return IIO_VAL_INT; |
| 396 | break; | ||
| 397 | default: | 395 | default: |
| 398 | break; | 396 | return -EINVAL; |
| 399 | } | 397 | } |
| 400 | break; | 398 | } |
| 401 | |||
| 402 | default: | 399 | default: |
| 403 | break; | 400 | return -EINVAL; |
| 404 | } | 401 | } |
| 405 | mutex_unlock(&st->lock); | ||
| 406 | return ret; | ||
| 407 | } | 402 | } |
| 408 | 403 | ||
| 409 | /** | 404 | /** |
| @@ -426,7 +421,6 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, · 16 unmodified lines | |||
| 426 | long mask) | 421 | long mask) |
| 427 | { | 422 | { |
| 428 | int i; | 423 | int i; |
| 429 | int ret = 0; | ||
| 430 | struct iio_dummy_state *st = iio_priv(indio_dev); | 424 | struct iio_dummy_state *st = iio_priv(indio_dev); |
| 431 | 425 | ||
| 432 | switch (mask) { | 426 | switch (mask) { |
| @@ -436,10 +430,10 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 436 | if (chan->output == 0) | 430 | if (chan->output == 0) |
| 437 | return -EINVAL; | 431 | return -EINVAL; |
| 438 | 432 | ||
| 439 | /* Locking not required as writing single value */ | 433 | scoped_guard(mutex, &st->lock) { |
| 440 | mutex_lock(&st->lock); | 434 | /* Locking not required as writing single value */ |
| 441 | st->dac_val = val; | 435 | st->dac_val = val; |
| 442 | mutex_unlock(&st->lock); | 436 | } |
| 443 | return 0; | 437 | return 0; |
| 444 | default: | 438 | default: |
| 445 | return -EINVAL; | 439 | return -EINVAL; |
| @@ -447,9 +441,9 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 447 | case IIO_CHAN_INFO_PROCESSED: | 441 | case IIO_CHAN_INFO_PROCESSED: |
| 448 | switch (chan->type) { | 442 | switch (chan->type) { |
| 449 | case IIO_STEPS: | 443 | case IIO_STEPS: |
| 450 | mutex_lock(&st->lock); | 444 | scoped_guard(mutex, &st->lock) { |
| 451 | st->steps = val; | 445 | st->steps = val; |
| 452 | mutex_unlock(&st->lock); | 446 | } |
| 453 | return 0; | 447 | return 0; |
| 454 | case IIO_ACTIVITY: | 448 | case IIO_ACTIVITY: |
| 455 | if (val < 0) | 449 | if (val < 0) |
| @@ -470,30 +464,29 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, · 14 unmodified lines | |||
| 470 | default: | 464 | default: |
| 471 | return -EINVAL; | 465 | return -EINVAL; |
| 472 | } | 466 | } |
| 473 | case IIO_CHAN_INFO_CALIBSCALE: | 467 | case IIO_CHAN_INFO_CALIBSCALE: { |
| 474 | mutex_lock(&st->lock); | 468 | guard(mutex)(&st->lock); |
| 475 | /* Compare against table - hard matching here */ | 469 | /* Compare against table - hard matching here */ |
| 476 | for (i = 0; i < ARRAY_SIZE(dummy_scales); i++) | 470 | for (i = 0; i < ARRAY_SIZE(dummy_scales); i++) |
| 477 | if (val == dummy_scales[i].val && | 471 | if (val == dummy_scales[i].val && |
| 478 | val2 == dummy_scales[i].val2) | 472 | val2 == dummy_scales[i].val2) |
| 479 | break; | 473 | break; |
| 480 | if (i == ARRAY_SIZE(dummy_scales)) | 474 | if (i == ARRAY_SIZE(dummy_scales)) |
| 481 | ret = -EINVAL; | 475 | return -EINVAL; |
| 482 | else | 476 | st->accel_calibscale = &dummy_scales[i]; |
| 483 | st->accel_calibscale = &dummy_scales[i]; | 477 | return 0; |
| 484 | mutex_unlock(&st->lock); | 478 | } |
| 485 | return ret; | ||
| 486 | case IIO_CHAN_INFO_CALIBBIAS: | 479 | case IIO_CHAN_INFO_CALIBBIAS: |
| 487 | mutex_lock(&st->lock); | 480 | scoped_guard(mutex, &st->lock) { |
| 488 | st->accel_calibbias = val; | 481 | st->accel_calibbias = val; |
| 489 | mutex_unlock(&st->lock); | 482 | } |
| 490 | return 0; | 483 | return 0; |
| 491 | case IIO_CHAN_INFO_ENABLE: | 484 | case IIO_CHAN_INFO_ENABLE: |
| 492 | switch (chan->type) { | 485 | switch (chan->type) { |
| 493 | case IIO_STEPS: | 486 | case IIO_STEPS: |
| 494 | mutex_lock(&st->lock); | 487 | scoped_guard(mutex, &st->lock) { |
| 495 | st->steps_enabled = val; | 488 | st->steps_enabled = val; |
| 496 | mutex_unlock(&st->lock); | 489 | } |
| 497 | return 0; | 490 | return 0; |
| 498 | default: | 491 | default: |
| 499 | return -EINVAL; | 492 | return -EINVAL; |
| @@ -60,6 +60,16 @@ config ADF4377 · 59 unmodified lines | |||
| 60 | To compile this driver as a module, choose M here: the | 60 | To compile this driver as a module, choose M here: the |
| 61 | module will be called adf4377. | 61 | module will be called adf4377. |
| 62 | 62 | ||
| 63 | config ADMFM2000 | ||
| 64 | tristate "Analog Devices ADMFM2000 Dual Microwave Down Converter" | ||
| 65 | depends on GPIOLIB | ||
| 66 | help | ||
| 67 | Say yes here to build support for Analog Devices ADMFM2000 Dual | ||
| 68 | Microwave Down Converter. | ||
| 69 | |||
| 70 | To compile this driver as a module, choose M here: the | ||
| 71 | module will be called admfm2000. | ||
| 72 | |||
| 63 | config ADMV1013 | 73 | config ADMV1013 |
| 64 | tristate "Analog Devices ADMV1013 Microwave Upconverter" | 74 | tristate "Analog Devices ADMV1013 Microwave Upconverter" |
| 65 | depends on SPI && COMMON_CLK | 75 | depends on SPI && COMMON_CLK |
| @@ -8,6 +8,7 @@ obj-$(CONFIG_AD9523) += ad9523.o · 7 unmodified lines | |||
| 8 | obj-$(CONFIG_ADF4350) += adf4350.o | 8 | obj-$(CONFIG_ADF4350) += adf4350.o |
| 9 | obj-$(CONFIG_ADF4371) += adf4371.o | 9 | obj-$(CONFIG_ADF4371) += adf4371.o |
| 10 | obj-$(CONFIG_ADF4377) += adf4377.o | 10 | obj-$(CONFIG_ADF4377) += adf4377.o |
| 11 | obj-$(CONFIG_ADMFM2000) += admfm2000.o | ||
| 11 | obj-$(CONFIG_ADMV1013) += admv1013.o | 12 | obj-$(CONFIG_ADMV1013) += admv1013.o |
| 12 | obj-$(CONFIG_ADMV1014) += admv1014.o | 13 | obj-$(CONFIG_ADMV1014) += admv1014.o |
| 13 | obj-$(CONFIG_ADMV4420) += admv4420.o | 14 | obj-$(CONFIG_ADMV4420) += admv4420.o |
| @@ -0,0 +1,282 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * ADMFM2000 Dual Microwave Down Converter | ||
| 4 | * | ||
| 5 | * Copyright 2024 Analog Devices Inc. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/err.h> | ||
| 10 | #include <linux/gpio/consumer.h> | ||
| 11 | #include <linux/iio/iio.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/mod_devicetable.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/property.h> | ||
| 17 | |||
| 18 | #define ADMFM2000_MIXER_MODE 0 | ||
| 19 | #define ADMFM2000_DIRECT_IF_MODE 1 | ||
| 20 | #define ADMFM2000_DSA_GPIOS 5 | ||
| 21 | #define ADMFM2000_MODE_GPIOS 2 | ||
| 22 | #define ADMFM2000_MAX_GAIN 0 | ||
| 23 | #define ADMFM2000_MIN_GAIN -31000 | ||
| 24 | #define ADMFM2000_DEFAULT_GAIN -0x20 | ||
| 25 | |||
| 26 | struct admfm2000_state { | ||
| 27 | struct mutex lock; /* protect sensor state */ | ||
| 28 | struct gpio_desc *sw1_ch[2]; | ||
| 29 | struct gpio_desc *sw2_ch[2]; | ||
| 30 | struct gpio_desc *dsa1_gpios[5]; | ||
| 31 | struct gpio_desc *dsa2_gpios[5]; | ||
| 32 | u32 gain[2]; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static int admfm2000_mode(struct iio_dev *indio_dev, u32 chan, u32 mode) | ||
| 36 | { | ||
| 37 | struct admfm2000_state *st = iio_priv(indio_dev); | ||
| 38 | int i; | ||
| 39 | |||
| 40 | switch (mode) { | ||
| 41 | case ADMFM2000_MIXER_MODE: | ||
| 42 | for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { | ||
| 43 | gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 1 : 0); | ||
| 44 | gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 0 : 1); | ||
| 45 | } | ||
| 46 | return 0; | ||
| 47 | case ADMFM2000_DIRECT_IF_MODE: | ||
| 48 | for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { | ||
| 49 | gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 0 : 1); | ||
| 50 | gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 1 : 0); | ||
| 51 | } | ||
| 52 | return 0; | ||
| 53 | default: | ||
| 54 | return -EINVAL; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | static int admfm2000_attenuation(struct iio_dev *indio_dev, u32 chan, u32 value) | ||
| 59 | { | ||
| 60 | struct admfm2000_state *st = iio_priv(indio_dev); | ||
| 61 | int i; | ||
| 62 | |||
| 63 | switch (chan) { | ||
| 64 | case 0: | ||
| 65 | for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) | ||
| 66 | gpiod_set_value_cansleep(st->dsa1_gpios[i], value & (1 << i)); | ||
| 67 | return 0; | ||
| 68 | case 1: | ||
| 69 | for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) | ||
| 70 | gpiod_set_value_cansleep(st->dsa2_gpios[i], value & (1 << i)); | ||
| 71 | return 0; | ||
| 72 | default: | ||
| 73 | return -EINVAL; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | static int admfm2000_read_raw(struct iio_dev *indio_dev, | ||
| 78 | struct iio_chan_spec const *chan, int *val, | ||
| 79 | int *val2, long mask) | ||
| 80 | { | ||
| 81 | struct admfm2000_state *st = iio_priv(indio_dev); | ||
| 82 | int gain; | ||
| 83 | |||
| 84 | switch (mask) { | ||
| 85 | case IIO_CHAN_INFO_HARDWAREGAIN: | ||
| 86 | mutex_lock(&st->lock); | ||
| 87 | gain = ~(st->gain[chan->channel]) * -1000; | ||
| 88 | *val = gain / 1000; | ||
| 89 | *val2 = (gain % 1000) * 1000; | ||
| 90 | mutex_unlock(&st->lock); | ||
| 91 | |||
| 92 | return IIO_VAL_INT_PLUS_MICRO_DB; | ||
| 93 | default: | ||
| 94 | return -EINVAL; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | static int admfm2000_write_raw(struct iio_dev *indio_dev, | ||
| 99 | struct iio_chan_spec const *chan, int val, | ||
| 100 | int val2, long mask) | ||
| 101 | { | ||
| 102 | struct admfm2000_state *st = iio_priv(indio_dev); | ||
| 103 | int gain, ret; | ||
| 104 | |||
| 105 | if (val < 0) | ||
| 106 | gain = (val * 1000) - (val2 / 1000); | ||
| 107 | else | ||
| 108 | gain = (val * 1000) + (val2 / 1000); | ||
| 109 | |||
| 110 | if (gain > ADMFM2000_MAX_GAIN || gain < ADMFM2000_MIN_GAIN) | ||
| 111 | return -EINVAL; | ||
| 112 | |||
| 113 | switch (mask) { | ||
| 114 | case IIO_CHAN_INFO_HARDWAREGAIN: | ||
| 115 | mutex_lock(&st->lock); | ||
| 116 | st->gain[chan->channel] = ~((abs(gain) / 1000) & 0x1F); | ||
| 117 | |||
| 118 | ret = admfm2000_attenuation(indio_dev, chan->channel, | ||
| 119 | st->gain[chan->channel]); | ||
| 120 | mutex_unlock(&st->lock); | ||
| 121 | return ret; | ||
| 122 | default: | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | static int admfm2000_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 128 | struct iio_chan_spec const *chan, | ||
| 129 | long mask) | ||
| 130 | { | ||
| 131 | switch (mask) { | ||
| 132 | case IIO_CHAN_INFO_HARDWAREGAIN: | ||
| 133 | return IIO_VAL_INT_PLUS_MICRO_DB; | ||
| 134 | default: | ||
| 135 | return -EINVAL; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static const struct iio_info admfm2000_info = { | ||
| 140 | .read_raw = &admfm2000_read_raw, | ||
| 141 | .write_raw = &admfm2000_write_raw, | ||
| 142 | .write_raw_get_fmt = &admfm2000_write_raw_get_fmt, | ||
| 143 | }; | ||
| 144 | |||
| 145 | #define ADMFM2000_CHAN(_channel) { \ | ||
| 146 | .type = IIO_VOLTAGE, \ | ||
| 147 | .output = 1, \ | ||
| 148 | .indexed = 1, \ | ||
| 149 | .channel = _channel, \ | ||
| 150 | .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ | ||
| 151 | } | ||
| 152 | |||
| 153 | static const struct iio_chan_spec admfm2000_channels[] = { | ||
| 154 | ADMFM2000_CHAN(0), | ||
| 155 | ADMFM2000_CHAN(1), | ||
| 156 | }; | ||
| 157 | |||
| 158 | static int admfm2000_channel_config(struct admfm2000_state *st, | ||
| 159 | struct iio_dev *indio_dev) | ||
| 160 | { | ||
| 161 | struct platform_device *pdev = to_platform_device(indio_dev->dev.parent); | ||
| 162 | struct device *dev = &pdev->dev; | ||
| 163 | struct fwnode_handle *child; | ||
| 164 | struct gpio_desc **dsa; | ||
| 165 | struct gpio_desc **sw; | ||
| 166 | int ret, i; | ||
| 167 | bool mode; | ||
| 168 | u32 reg; | ||
| 169 | |||
| 170 | device_for_each_child_node(dev, child) { | ||
| 171 | ret = fwnode_property_read_u32(child, "reg", ®); | ||
| 172 | if (ret) { | ||
| 173 | fwnode_handle_put(child); | ||
| 174 | return dev_err_probe(dev, ret, | ||
| 175 | "Failed to get reg property\n"); | ||
| 176 | } | ||
| 177 | |||
| 178 | if (reg >= indio_dev->num_channels) { | ||
| 179 | fwnode_handle_put(child); | ||
| 180 | return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n", | ||
| 181 | indio_dev->num_channels); | ||
| 182 | } | ||
| 183 | |||
| 184 | if (fwnode_property_present(child, "adi,mixer-mode")) | ||
| 185 | mode = ADMFM2000_MIXER_MODE; | ||
| 186 | else | ||
| 187 | mode = ADMFM2000_DIRECT_IF_MODE; | ||
| 188 | |||
| 189 | switch (reg) { | ||
| 190 | case 0: | ||
| 191 | sw = st->sw1_ch; | ||
| 192 | dsa = st->dsa1_gpios; | ||
| 193 | break; | ||
| 194 | case 1: | ||
| 195 | sw = st->sw2_ch; | ||
| 196 | dsa = st->dsa2_gpios; | ||
| 197 | break; | ||
| 198 | default: | ||
| 199 | fwnode_handle_put(child); | ||
| 200 | return -EINVAL; | ||
| 201 | } | ||
| 202 | |||
| 203 | for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { | ||
| 204 | sw[i] = devm_fwnode_gpiod_get_index(dev, child, "switch", | ||
| 205 | i, GPIOD_OUT_LOW, NULL); | ||
| 206 | if (IS_ERR(sw[i])) { | ||
| 207 | fwnode_handle_put(child); | ||
| 208 | return dev_err_probe(dev, PTR_ERR(sw[i]), | ||
| 209 | "Failed to get gpios\n"); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { | ||
| 214 | dsa[i] = devm_fwnode_gpiod_get_index(dev, child, | ||
| 215 | "attenuation", i, | ||
| 216 | GPIOD_OUT_LOW, NULL); | ||
| 217 | if (IS_ERR(dsa[i])) { | ||
| 218 | fwnode_handle_put(child); | ||
| 219 | return dev_err_probe(dev, PTR_ERR(dsa[i]), | ||
| 220 | "Failed to get gpios\n"); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | ret = admfm2000_mode(indio_dev, reg, mode); | ||
| 225 | if (ret) { | ||
| 226 | fwnode_handle_put(child); | ||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int admfm2000_probe(struct platform_device *pdev) | ||
| 235 | { | ||
| 236 | struct device *dev = &pdev->dev; | ||
| 237 | struct admfm2000_state *st; | ||
| 238 | struct iio_dev *indio_dev; | ||
| 239 | int ret; | ||
| 240 | |||
| 241 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); | ||
| 242 | if (!indio_dev) | ||
| 243 | return -ENOMEM; | ||
| 244 | |||
| 245 | st = iio_priv(indio_dev); | ||
| 246 | |||
| 247 | indio_dev->name = "admfm2000"; | ||
| 248 | indio_dev->num_channels = ARRAY_SIZE(admfm2000_channels); | ||
| 249 | indio_dev->channels = admfm2000_channels; | ||
| 250 | indio_dev->info = &admfm2000_info; | ||
| 251 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 252 | |||
| 253 | st->gain[0] = ADMFM2000_DEFAULT_GAIN; | ||
| 254 | st->gain[1] = ADMFM2000_DEFAULT_GAIN; | ||
| 255 | |||
| 256 | mutex_init(&st->lock); | ||
| 257 | |||
| 258 | ret = admfm2000_channel_config(st, indio_dev); | ||
| 259 | if (ret) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | return devm_iio_device_register(dev, indio_dev); | ||
| 263 | } | ||
| 264 | |||
| 265 | static const struct of_device_id admfm2000_of_match[] = { | ||
| 266 | { .compatible = "adi,admfm2000" }, | ||
| 267 | { } | ||
| 268 | }; | ||
| 269 | MODULE_DEVICE_TABLE(of, admfm2000_of_match); | ||
| 270 | |||
| 271 | static struct platform_driver admfm2000_driver = { | ||
| 272 | .driver = { | ||
| 273 | .name = "admfm2000", | ||
| 274 | .of_match_table = admfm2000_of_match, | ||
| 275 | }, | ||
| 276 | .probe = admfm2000_probe, | ||
| 277 | }; | ||
| 278 | module_platform_driver(admfm2000_driver); | ||
| 279 | |||
| 280 | MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); | ||
| 281 | MODULE_DESCRIPTION("ADMFM2000 Dual Microwave Down Converter"); | ||
| 282 | MODULE_LICENSE("GPL"); | ||
| @@ -3,7 +3,7 @@ · 2 unmodified lines | |||
| 3 | #include <linux/regmap.h> | 3 | #include <linux/regmap.h> |
| 4 | #include <linux/iio/iio.h> | 4 | #include <linux/iio/iio.h> |
| 5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 6 | #include <linux/acpi.h> | 6 | #include <linux/mod_devicetable.h> |
| 7 | 7 | ||
| 8 | #include "bmg160.h" | 8 | #include "bmg160.h" |
| 9 | 9 | ||
| @@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(of, bmg160_of_match); · 56 unmodified lines | |||
| 66 | static struct i2c_driver bmg160_i2c_driver = { | 66 | static struct i2c_driver bmg160_i2c_driver = { |
| 67 | .driver = { | 67 | .driver = { |
| 68 | .name = "bmg160_i2c", | 68 | .name = "bmg160_i2c", |
| 69 | .acpi_match_table = ACPI_PTR(bmg160_acpi_match), | 69 | .acpi_match_table = bmg160_acpi_match, |
| 70 | .of_match_table = bmg160_of_match, | 70 | .of_match_table = bmg160_of_match, |
| 71 | .pm = &bmg160_pm_ops, | 71 | .pm = &bmg160_pm_ops, |
| 72 | }, | 72 | }, |
| @@ -346,6 +346,13 @@ err: · 345 unmodified lines | |||
| 346 | return IRQ_HANDLED; | 346 | return IRQ_HANDLED; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | static void afe4403_regulator_disable(void *data) | ||
| 350 | { | ||
| 351 | struct regulator *regulator = data; | ||
| 352 | |||
| 353 | regulator_disable(regulator); | ||
| 354 | } | ||
| 355 | |||
| 349 | #define AFE4403_TIMING_PAIRS \ | 356 | #define AFE4403_TIMING_PAIRS \ |
| 350 | { AFE440X_LED2STC, 0x000050 }, \ | 357 | { AFE440X_LED2STC, 0x000050 }, \ |
| 351 | { AFE440X_LED2ENDC, 0x0003e7 }, \ | 358 | { AFE440X_LED2ENDC, 0x0003e7 }, \ |
| @@ -495,19 +502,24 @@ static int afe4403_probe(struct spi_device *spi) · 143 unmodified lines | |||
| 495 | dev_err(afe->dev, "Unable to enable regulator\n"); | 502 | dev_err(afe->dev, "Unable to enable regulator\n"); |
| 496 | return ret; | 503 | return ret; |
| 497 | } | 504 | } |
| 505 | ret = devm_add_action_or_reset(afe->dev, afe4403_regulator_disable, afe->regulator); | ||
| 506 | if (ret) { | ||
| 507 | dev_err(afe->dev, "Unable to add regulator disable action\n"); | ||
| 508 | return ret; | ||
| 509 | } | ||
| 498 | 510 | ||
| 499 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, | 511 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, |
| 500 | AFE440X_CONTROL0_SW_RESET); | 512 | AFE440X_CONTROL0_SW_RESET); |
| 501 | if (ret) { | 513 | if (ret) { |
| 502 | dev_err(afe->dev, "Unable to reset device\n"); | 514 | dev_err(afe->dev, "Unable to reset device\n"); |
| 503 | goto err_disable_reg; | 515 | return ret; |
| 504 | } | 516 | } |
| 505 | 517 | ||
| 506 | ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences, | 518 | ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences, |
| 507 | ARRAY_SIZE(afe4403_reg_sequences)); | 519 | ARRAY_SIZE(afe4403_reg_sequences)); |
| 508 | if (ret) { | 520 | if (ret) { |
| 509 | dev_err(afe->dev, "Unable to set register defaults\n"); | 521 | dev_err(afe->dev, "Unable to set register defaults\n"); |
| 510 | goto err_disable_reg; | 522 | return ret; |
| 511 | } | 523 | } |
| 512 | 524 | ||
| 513 | indio_dev->modes = INDIO_DIRECT_MODE; | 525 | indio_dev->modes = INDIO_DIRECT_MODE; |
| @@ -523,16 +535,15 @@ static int afe4403_probe(struct spi_device *spi) · 9 unmodified lines | |||
| 523 | iio_device_id(indio_dev)); | 535 | iio_device_id(indio_dev)); |
| 524 | if (!afe->trig) { | 536 | if (!afe->trig) { |
| 525 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); | 537 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); |
| 526 | ret = -ENOMEM; | 538 | return -ENOMEM; |
| 527 | goto err_disable_reg; | ||
| 528 | } | 539 | } |
| 529 | 540 | ||
| 530 | iio_trigger_set_drvdata(afe->trig, indio_dev); | 541 | iio_trigger_set_drvdata(afe->trig, indio_dev); |
| 531 | 542 | ||
| 532 | ret = iio_trigger_register(afe->trig); | 543 | ret = devm_iio_trigger_register(afe->dev, afe->trig); |
| 533 | if (ret) { | 544 | if (ret) { |
| 534 | dev_err(afe->dev, "Unable to register IIO trigger\n"); | 545 | dev_err(afe->dev, "Unable to register IIO trigger\n"); |
| 535 | goto err_disable_reg; | 546 | return ret; |
| 536 | } | 547 | } |
| 537 | 548 | ||
| 538 | ret = devm_request_threaded_irq(afe->dev, afe->irq, | 549 | ret = devm_request_threaded_irq(afe->dev, afe->irq, |
| @@ -542,52 +553,25 @@ static int afe4403_probe(struct spi_device *spi) · 3 unmodified lines | |||
| 542 | afe->trig); | 553 | afe->trig); |
| 543 | if (ret) { | 554 | if (ret) { |
| 544 | dev_err(afe->dev, "Unable to request IRQ\n"); | 555 | dev_err(afe->dev, "Unable to request IRQ\n"); |
| 545 | goto err_trig; | 556 | return ret; |
| 546 | } | 557 | } |
| 547 | } | 558 | } |
| 548 | 559 | ||
| 549 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | 560 | ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, |
| 550 | afe4403_trigger_handler, NULL); | 561 | &iio_pollfunc_store_time, |
| 562 | afe4403_trigger_handler, NULL); | ||
| 551 | if (ret) { | 563 | if (ret) { |
| 552 | dev_err(afe->dev, "Unable to setup buffer\n"); | 564 | dev_err(afe->dev, "Unable to setup buffer\n"); |
| 553 | goto err_trig; | 565 | return ret; |
| 554 | } | 566 | } |
| 555 | 567 | ||
| 556 | ret = iio_device_register(indio_dev); | 568 | ret = devm_iio_device_register(afe->dev, indio_dev); |
| 557 | if (ret) { | 569 | if (ret) { |
| 558 | dev_err(afe->dev, "Unable to register IIO device\n"); | 570 | dev_err(afe->dev, "Unable to register IIO device\n"); |
| 559 | goto err_buff; | 571 | return ret; |
| 560 | } | 572 | } |
| 561 | 573 | ||
| 562 | return 0; | 574 | return 0; |
| 563 | |||
| 564 | err_buff: | ||
| 565 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 566 | err_trig: | ||
| 567 | if (afe->irq > 0) | ||
| 568 | iio_trigger_unregister(afe->trig); | ||
| 569 | err_disable_reg: | ||
| 570 | regulator_disable(afe->regulator); | ||
| 571 | |||
| 572 | return ret; | ||
| 573 | } | ||
| 574 | |||
| 575 | static void afe4403_remove(struct spi_device *spi) | ||
| 576 | { | ||
| 577 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 578 | struct afe4403_data *afe = iio_priv(indio_dev); | ||
| 579 | int ret; | ||
| 580 | |||
| 581 | iio_device_unregister(indio_dev); | ||
| 582 | |||
| 583 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 584 | |||
| 585 | if (afe->irq > 0) | ||
| 586 | iio_trigger_unregister(afe->trig); | ||
| 587 | |||
| 588 | ret = regulator_disable(afe->regulator); | ||
| 589 | if (ret) | ||
| 590 | dev_warn(afe->dev, "Unable to disable regulator\n"); | ||
| 591 | } | 575 | } |
| 592 | 576 | ||
| 593 | static const struct spi_device_id afe4403_ids[] = { | 577 | static const struct spi_device_id afe4403_ids[] = { |
| @@ -603,7 +587,6 @@ static struct spi_driver afe4403_spi_driver = { · 9 unmodified lines | |||
| 603 | .pm = pm_sleep_ptr(&afe4403_pm_ops), | 587 | .pm = pm_sleep_ptr(&afe4403_pm_ops), |
| 604 | }, | 588 | }, |
| 605 | .probe = afe4403_probe, | 589 | .probe = afe4403_probe, |
| 606 | .remove = afe4403_remove, | ||
| 607 | .id_table = afe4403_ids, | 590 | .id_table = afe4403_ids, |
| 608 | }; | 591 | }; |
| 609 | module_spi_driver(afe4403_spi_driver); | 592 | module_spi_driver(afe4403_spi_driver); |
| @@ -349,6 +349,13 @@ err: · 348 unmodified lines | |||
| 349 | return IRQ_HANDLED; | 349 | return IRQ_HANDLED; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | static void afe4404_regulator_disable(void *data) | ||
| 353 | { | ||
| 354 | struct regulator *regulator = data; | ||
| 355 | |||
| 356 | regulator_disable(regulator); | ||
| 357 | } | ||
| 358 | |||
| 352 | /* Default timings from data-sheet */ | 359 | /* Default timings from data-sheet */ |
| 353 | #define AFE4404_TIMING_PAIRS \ | 360 | #define AFE4404_TIMING_PAIRS \ |
| 354 | { AFE440X_PRPCOUNT, 39999 }, \ | 361 | { AFE440X_PRPCOUNT, 39999 }, \ |
| @@ -502,19 +509,24 @@ static int afe4404_probe(struct i2c_client *client) · 147 unmodified lines | |||
| 502 | dev_err(afe->dev, "Unable to enable regulator\n"); | 509 | dev_err(afe->dev, "Unable to enable regulator\n"); |
| 503 | return ret; | 510 | return ret; |
| 504 | } | 511 | } |
| 512 | ret = devm_add_action_or_reset(afe->dev, afe4404_regulator_disable, afe->regulator); | ||
| 513 | if (ret) { | ||
| 514 | dev_err(afe->dev, "Unable to enable regulator\n"); | ||
| 515 | return ret; | ||
| 516 | } | ||
| 505 | 517 | ||
| 506 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, | 518 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, |
| 507 | AFE440X_CONTROL0_SW_RESET); | 519 | AFE440X_CONTROL0_SW_RESET); |
| 508 | if (ret) { | 520 | if (ret) { |
| 509 | dev_err(afe->dev, "Unable to reset device\n"); | 521 | dev_err(afe->dev, "Unable to reset device\n"); |
| 510 | goto disable_reg; | 522 | return ret; |
| 511 | } | 523 | } |
| 512 | 524 | ||
| 513 | ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences, | 525 | ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences, |
| 514 | ARRAY_SIZE(afe4404_reg_sequences)); | 526 | ARRAY_SIZE(afe4404_reg_sequences)); |
| 515 | if (ret) { | 527 | if (ret) { |
| 516 | dev_err(afe->dev, "Unable to set register defaults\n"); | 528 | dev_err(afe->dev, "Unable to set register defaults\n"); |
| 517 | goto disable_reg; | 529 | return ret; |
| 518 | } | 530 | } |
| 519 | 531 | ||
| 520 | indio_dev->modes = INDIO_DIRECT_MODE; | 532 | indio_dev->modes = INDIO_DIRECT_MODE; |
| @@ -530,16 +542,15 @@ static int afe4404_probe(struct i2c_client *client) · 9 unmodified lines | |||
| 530 | iio_device_id(indio_dev)); | 542 | iio_device_id(indio_dev)); |
| 531 | if (!afe->trig) { | 543 | if (!afe->trig) { |
| 532 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); | 544 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); |
| 533 | ret = -ENOMEM; | 545 | return -ENOMEM; |
| 534 | goto disable_reg; | ||
| 535 | } | 546 | } |
| 536 | 547 | ||
| 537 | iio_trigger_set_drvdata(afe->trig, indio_dev); | 548 | iio_trigger_set_drvdata(afe->trig, indio_dev); |
| 538 | 549 | ||
| 539 | ret = iio_trigger_register(afe->trig); | 550 | ret = devm_iio_trigger_register(afe->dev, afe->trig); |
| 540 | if (ret) { | 551 | if (ret) { |
| 541 | dev_err(afe->dev, "Unable to register IIO trigger\n"); | 552 | dev_err(afe->dev, "Unable to register IIO trigger\n"); |
| 542 | goto disable_reg; | 553 | return ret; |
| 543 | } | 554 | } |
| 544 | 555 | ||
| 545 | ret = devm_request_threaded_irq(afe->dev, afe->irq, | 556 | ret = devm_request_threaded_irq(afe->dev, afe->irq, |
| @@ -549,52 +560,25 @@ static int afe4404_probe(struct i2c_client *client) · 3 unmodified lines | |||
| 549 | afe->trig); | 560 | afe->trig); |
| 550 | if (ret) { | 561 | if (ret) { |
| 551 | dev_err(afe->dev, "Unable to request IRQ\n"); | 562 | dev_err(afe->dev, "Unable to request IRQ\n"); |
| 552 | goto disable_reg; | 563 | return ret; |
| 553 | } | 564 | } |
| 554 | } | 565 | } |
| 555 | 566 | ||
| 556 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | 567 | ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, |
| 557 | afe4404_trigger_handler, NULL); | 568 | &iio_pollfunc_store_time, |
| 569 | afe4404_trigger_handler, NULL); | ||
| 558 | if (ret) { | 570 | if (ret) { |
| 559 | dev_err(afe->dev, "Unable to setup buffer\n"); | 571 | dev_err(afe->dev, "Unable to setup buffer\n"); |
| 560 | goto unregister_trigger; | 572 | return ret; |
| 561 | } | 573 | } |
| 562 | 574 | ||
| 563 | ret = iio_device_register(indio_dev); | 575 | ret = devm_iio_device_register(afe->dev, indio_dev); |
| 564 | if (ret) { | 576 | if (ret) { |
| 565 | dev_err(afe->dev, "Unable to register IIO device\n"); | 577 | dev_err(afe->dev, "Unable to register IIO device\n"); |
| 566 | goto unregister_triggered_buffer; | 578 | return ret; |
| 567 | } | 579 | } |
| 568 | 580 | ||
| 569 | return 0; | 581 | return 0; |
| 570 | |||
| 571 | unregister_triggered_buffer: | ||
| 572 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 573 | unregister_trigger: | ||
| 574 | if (afe->irq > 0) | ||
| 575 | iio_trigger_unregister(afe->trig); | ||
| 576 | disable_reg: | ||
| 577 | regulator_disable(afe->regulator); | ||
| 578 | |||
| 579 | return ret; | ||
| 580 | } | ||
| 581 | |||
| 582 | static void afe4404_remove(struct i2c_client *client) | ||
| 583 | { | ||
| 584 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 585 | struct afe4404_data *afe = iio_priv(indio_dev); | ||
| 586 | int ret; | ||
| 587 | |||
| 588 | iio_device_unregister(indio_dev); | ||
| 589 | |||
| 590 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 591 | |||
| 592 | if (afe->irq > 0) | ||
| 593 | iio_trigger_unregister(afe->trig); | ||
| 594 | |||
| 595 | ret = regulator_disable(afe->regulator); | ||
| 596 | if (ret) | ||
| 597 | dev_err(afe->dev, "Unable to disable regulator\n"); | ||
| 598 | } | 582 | } |
| 599 | 583 | ||
| 600 | static const struct i2c_device_id afe4404_ids[] = { | 584 | static const struct i2c_device_id afe4404_ids[] = { |
| @@ -610,7 +594,6 @@ static struct i2c_driver afe4404_i2c_driver = { · 9 unmodified lines | |||
| 610 | .pm = pm_sleep_ptr(&afe4404_pm_ops), | 594 | .pm = pm_sleep_ptr(&afe4404_pm_ops), |
| 611 | }, | 595 | }, |
| 612 | .probe = afe4404_probe, | 596 | .probe = afe4404_probe, |
| 613 | .remove = afe4404_remove, | ||
| 614 | .id_table = afe4404_ids, | 597 | .id_table = afe4404_ids, |
| 615 | }; | 598 | }; |
| 616 | module_i2c_driver(afe4404_i2c_driver); | 599 | module_i2c_driver(afe4404_i2c_driver); |
| @@ -5,41 +5,66 @@ · 4 unmodified lines | |||
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2023 | 6 | * Copyright (C) 2023 |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH | ||
| 9 | * | ||
| 8 | * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf | 10 | * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf |
| 9 | */ | 11 | */ |
| 10 | 12 | ||
| 13 | #include <linux/bitfield.h> | ||
| 11 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
| 12 | #include <linux/cleanup.h> | 15 | #include <linux/cleanup.h> |
| 13 | #include <linux/crc8.h> | 16 | #include <linux/crc8.h> |
| 14 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 15 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 16 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 18 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
| 23 | #include <linux/units.h> | ||
| 19 | 24 | ||
| 20 | #include <asm/unaligned.h> | 25 | #include <asm/unaligned.h> |
| 21 | 26 | ||
| 27 | #include <linux/iio/events.h> | ||
| 22 | #include <linux/iio/iio.h> | 28 | #include <linux/iio/iio.h> |
| 23 | 29 | ||
| 24 | #define HDC3020_HEATER_CMD_MSB 0x30 /* shared by all heater commands */ | 30 | #define HDC3020_S_AUTO_10HZ_MOD0 0x2737 |
| 25 | #define HDC3020_HEATER_ENABLE 0x6D | 31 | #define HDC3020_S_STATUS 0x3041 |
| 26 | #define HDC3020_HEATER_DISABLE 0x66 | 32 | #define HDC3020_HEATER_DISABLE 0x3066 |
| 27 | #define HDC3020_HEATER_CONFIG 0x6E | 33 | #define HDC3020_HEATER_ENABLE 0x306D |
| 34 | #define HDC3020_HEATER_CONFIG 0x306E | ||
| 35 | #define HDC3020_EXIT_AUTO 0x3093 | ||
| 36 | #define HDC3020_S_T_RH_THRESH_LOW 0x6100 | ||
| 37 | #define HDC3020_S_T_RH_THRESH_LOW_CLR 0x610B | ||
| 38 | #define HDC3020_S_T_RH_THRESH_HIGH_CLR 0x6116 | ||
| 39 | #define HDC3020_S_T_RH_THRESH_HIGH 0x611D | ||
| 40 | #define HDC3020_R_T_RH_AUTO 0xE000 | ||
| 41 | #define HDC3020_R_T_LOW_AUTO 0xE002 | ||
| 42 | #define HDC3020_R_T_HIGH_AUTO 0xE003 | ||
| 43 | #define HDC3020_R_RH_LOW_AUTO 0xE004 | ||
| 44 | #define HDC3020_R_RH_HIGH_AUTO 0xE005 | ||
| 45 | #define HDC3020_R_T_RH_THRESH_LOW 0xE102 | ||
| 46 | #define HDC3020_R_T_RH_THRESH_LOW_CLR 0xE109 | ||
| 47 | #define HDC3020_R_T_RH_THRESH_HIGH_CLR 0xE114 | ||
| 48 | #define HDC3020_R_T_RH_THRESH_HIGH 0xE11F | ||
| 49 | #define HDC3020_R_STATUS 0xF32D | ||
| 50 | |||
| 51 | #define HDC3020_THRESH_TEMP_MASK GENMASK(8, 0) | ||
| 52 | #define HDC3020_THRESH_TEMP_TRUNC_SHIFT 7 | ||
| 53 | #define HDC3020_THRESH_HUM_MASK GENMASK(15, 9) | ||
| 54 | #define HDC3020_THRESH_HUM_TRUNC_SHIFT 9 | ||
| 55 | |||
| 56 | #define HDC3020_STATUS_T_LOW_ALERT BIT(6) | ||
| 57 | #define HDC3020_STATUS_T_HIGH_ALERT BIT(7) | ||
| 58 | #define HDC3020_STATUS_RH_LOW_ALERT BIT(8) | ||
| 59 | #define HDC3020_STATUS_RH_HIGH_ALERT BIT(9) | ||
| 28 | 60 | ||
| 29 | #define HDC3020_READ_RETRY_TIMES 10 | 61 | #define HDC3020_READ_RETRY_TIMES 10 |
| 30 | #define HDC3020_BUSY_DELAY_MS 10 | 62 | #define HDC3020_BUSY_DELAY_MS 10 |
| 31 | 63 | ||
| 32 | #define HDC3020_CRC8_POLYNOMIAL 0x31 | 64 | #define HDC3020_CRC8_POLYNOMIAL 0x31 |
| 33 | 65 | ||
| 34 | static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 }; | 66 | #define HDC3020_MIN_TEMP -40 |
| 35 | 67 | #define HDC3020_MAX_TEMP 125 | |
| 36 | static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 }; | ||
| 37 | |||
| 38 | static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 }; | ||
| 39 | static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 }; | ||
| 40 | static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 }; | ||
| 41 | static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 }; | ||
| 42 | static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 }; | ||
| 43 | 68 | ||
| 44 | struct hdc3020_data { | 69 | struct hdc3020_data { |
| 45 | struct i2c_client *client; | 70 | struct i2c_client *client; |
| @@ -54,18 +79,37 @@ struct hdc3020_data { · 8 unmodified lines | |||
| 54 | 79 | ||
| 55 | static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF}; | 80 | static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF}; |
| 56 | 81 | ||
| 82 | static const struct iio_event_spec hdc3020_t_rh_event[] = { | ||
| 83 | { | ||
| 84 | .type = IIO_EV_TYPE_THRESH, | ||
| 85 | .dir = IIO_EV_DIR_RISING, | ||
| 86 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | ||
| 87 | BIT(IIO_EV_INFO_HYSTERESIS), | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | .type = IIO_EV_TYPE_THRESH, | ||
| 91 | .dir = IIO_EV_DIR_FALLING, | ||
| 92 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | ||
| 93 | BIT(IIO_EV_INFO_HYSTERESIS), | ||
| 94 | }, | ||
| 95 | }; | ||
| 96 | |||
| 57 | static const struct iio_chan_spec hdc3020_channels[] = { | 97 | static const struct iio_chan_spec hdc3020_channels[] = { |
| 58 | { | 98 | { |
| 59 | .type = IIO_TEMP, | 99 | .type = IIO_TEMP, |
| 60 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | 100 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 61 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | | 101 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | |
| 62 | BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET), | 102 | BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET), |
| 103 | .event_spec = hdc3020_t_rh_event, | ||
| 104 | .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event), | ||
| 63 | }, | 105 | }, |
| 64 | { | 106 | { |
| 65 | .type = IIO_HUMIDITYRELATIVE, | 107 | .type = IIO_HUMIDITYRELATIVE, |
| 66 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | 108 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 67 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | | 109 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) | |
| 68 | BIT(IIO_CHAN_INFO_TROUGH), | 110 | BIT(IIO_CHAN_INFO_TROUGH), |
| 111 | .event_spec = hdc3020_t_rh_event, | ||
| 112 | .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event), | ||
| 69 | }, | 113 | }, |
| 70 | { | 114 | { |
| 71 | /* | 115 | /* |
| @@ -82,7 +126,7 @@ static const struct iio_chan_spec hdc3020_channels[] = { · 10 unmodified lines | |||
| 82 | 126 | ||
| 83 | DECLARE_CRC8_TABLE(hdc3020_crc8_table); | 127 | DECLARE_CRC8_TABLE(hdc3020_crc8_table); |
| 84 | 128 | ||
| 85 | static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) | 129 | static int hdc3020_write_bytes(struct hdc3020_data *data, u8 *buf, u8 len) |
| 86 | { | 130 | { |
| 87 | struct i2c_client *client = data->client; | 131 | struct i2c_client *client = data->client; |
| 88 | struct i2c_msg msg; | 132 | struct i2c_msg msg; |
| @@ -90,7 +134,7 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) · 1 unmodified line | |||
| 90 | 134 | ||
| 91 | msg.addr = client->addr; | 135 | msg.addr = client->addr; |
| 92 | msg.flags = 0; | 136 | msg.flags = 0; |
| 93 | msg.buf = (char *)buf; | 137 | msg.buf = buf; |
| 94 | msg.len = len; | 138 | msg.len = len; |
| 95 | 139 | ||
| 96 | /* | 140 | /* |
| @@ -109,26 +153,28 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len) · 12 unmodified lines | |||
| 109 | return -ETIMEDOUT; | 153 | return -ETIMEDOUT; |
| 110 | } | 154 | } |
| 111 | 155 | ||
| 112 | static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf, | 156 | static |
| 113 | void *val, int len) | 157 | int hdc3020_read_bytes(struct hdc3020_data *data, u16 reg, u8 *buf, int len) |
| 114 | { | 158 | { |
| 159 | u8 reg_buf[2]; | ||
| 115 | int ret, cnt; | 160 | int ret, cnt; |
| 116 | struct i2c_client *client = data->client; | 161 | struct i2c_client *client = data->client; |
| 117 | struct i2c_msg msg[2] = { | 162 | struct i2c_msg msg[2] = { |
| 118 | [0] = { | 163 | [0] = { |
| 119 | .addr = client->addr, | 164 | .addr = client->addr, |
| 120 | .flags = 0, | 165 | .flags = 0, |
| 121 | .buf = (char *)buf, | 166 | .buf = reg_buf, |
| 122 | .len = 2, | 167 | .len = 2, |
| 123 | }, | 168 | }, |
| 124 | [1] = { | 169 | [1] = { |
| 125 | .addr = client->addr, | 170 | .addr = client->addr, |
| 126 | .flags = I2C_M_RD, | 171 | .flags = I2C_M_RD, |
| 127 | .buf = val, | 172 | .buf = buf, |
| 128 | .len = len, | 173 | .len = len, |
| 129 | }, | 174 | }, |
| 130 | }; | 175 | }; |
| 131 | 176 | ||
| 177 | put_unaligned_be16(reg, reg_buf); | ||
| 132 | /* | 178 | /* |
| 133 | * During the measurement process, HDC3020 will not return data. | 179 | * During the measurement process, HDC3020 will not return data. |
| 134 | * So wait for a while and try again | 180 | * So wait for a while and try again |
| @@ -145,48 +191,12 @@ static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf, · 10 unmodified lines | |||
| 145 | return -ETIMEDOUT; | 191 | return -ETIMEDOUT; |
| 146 | } | 192 | } |
| 147 | 193 | ||
| 148 | static int hdc3020_read_measurement(struct hdc3020_data *data, | 194 | static int hdc3020_read_be16(struct hdc3020_data *data, u16 reg) |
| 149 | enum iio_chan_type type, int *val) | ||
| 150 | { | ||
| 151 | u8 crc, buf[6]; | ||
| 152 | int ret; | ||
| 153 | |||
| 154 | ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6); | ||
| 155 | if (ret < 0) | ||
| 156 | return ret; | ||
| 157 | |||
| 158 | /* CRC check of the temperature measurement */ | ||
| 159 | crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); | ||
| 160 | if (crc != buf[2]) | ||
| 161 | return -EINVAL; | ||
| 162 | |||
| 163 | /* CRC check of the relative humidity measurement */ | ||
| 164 | crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE); | ||
| 165 | if (crc != buf[5]) | ||
| 166 | return -EINVAL; | ||
| 167 | |||
| 168 | if (type == IIO_TEMP) | ||
| 169 | *val = get_unaligned_be16(buf); | ||
| 170 | else if (type == IIO_HUMIDITYRELATIVE) | ||
| 171 | *val = get_unaligned_be16(&buf[3]); | ||
| 172 | else | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* | ||
| 179 | * After exiting the automatic measurement mode or resetting, the peak | ||
| 180 | * value will be reset to the default value | ||
| 181 | * This method is used to get the highest temp measured during automatic | ||
| 182 | * measurement | ||
| 183 | */ | ||
| 184 | static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val) | ||
| 185 | { | 195 | { |
| 186 | u8 crc, buf[3]; | 196 | u8 crc, buf[3]; |
| 187 | int ret; | 197 | int ret; |
| 188 | 198 | ||
| 189 | ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3); | 199 | ret = hdc3020_read_bytes(data, reg, buf, 3); |
| 190 | if (ret < 0) | 200 | if (ret < 0) |
| 191 | return ret; | 201 | return ret; |
| 192 | 202 | ||
| @@ -194,73 +204,43 @@ static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val) · 1 unmodified line | |||
| 194 | if (crc != buf[2]) | 204 | if (crc != buf[2]) |
| 195 | return -EINVAL; | 205 | return -EINVAL; |
| 196 | 206 | ||
| 197 | *val = get_unaligned_be16(buf); | 207 | return get_unaligned_be16(buf); |
| 198 | |||
| 199 | return 0; | ||
| 200 | } | 208 | } |
| 201 | 209 | ||
| 202 | /* | 210 | static int hdc3020_exec_cmd(struct hdc3020_data *data, u16 reg) |
| 203 | * This method is used to get the lowest temp measured during automatic | ||
| 204 | * measurement | ||
| 205 | */ | ||
| 206 | static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val) | ||
| 207 | { | 211 | { |
| 208 | u8 crc, buf[3]; | 212 | u8 reg_buf[2]; |
| 209 | int ret; | ||
| 210 | 213 | ||
| 211 | ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3); | 214 | put_unaligned_be16(reg, reg_buf); |
| 212 | if (ret < 0) | 215 | return hdc3020_write_bytes(data, reg_buf, 2); |
| 213 | return ret; | ||
| 214 | |||
| 215 | crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); | ||
| 216 | if (crc != buf[2]) | ||
| 217 | return -EINVAL; | ||
| 218 | |||
| 219 | *val = get_unaligned_be16(buf); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | 216 | } |
| 223 | 217 | ||
| 224 | /* | 218 | static int hdc3020_read_measurement(struct hdc3020_data *data, |
| 225 | * This method is used to get the highest humidity measured during automatic | 219 | enum iio_chan_type type, int *val) |
| 226 | * measurement | ||
| 227 | */ | ||
| 228 | static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val) | ||
| 229 | { | 220 | { |
| 230 | u8 crc, buf[3]; | 221 | u8 crc, buf[6]; |
| 231 | int ret; | 222 | int ret; |
| 232 | 223 | ||
| 233 | ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3); | 224 | ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6); |
| 234 | if (ret < 0) | 225 | if (ret < 0) |
| 235 | return ret; | 226 | return ret; |
| 236 | 227 | ||
| 228 | /* CRC check of the temperature measurement */ | ||
| 237 | crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); | 229 | crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); |
| 238 | if (crc != buf[2]) | 230 | if (crc != buf[2]) |
| 239 | return -EINVAL; | 231 | return -EINVAL; |
| 240 | 232 | ||
| 241 | *val = get_unaligned_be16(buf); | 233 | /* CRC check of the relative humidity measurement */ |
| 242 | 234 | crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE); | |
| 243 | return 0; | 235 | if (crc != buf[5]) |
| 244 | } | ||
| 245 | |||
| 246 | /* | ||
| 247 | * This method is used to get the lowest humidity measured during automatic | ||
| 248 | * measurement | ||
| 249 | */ | ||
| 250 | static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val) | ||
| 251 | { | ||
| 252 | u8 crc, buf[3]; | ||
| 253 | int ret; | ||
| 254 | |||
| 255 | ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3); | ||
| 256 | if (ret < 0) | ||
| 257 | return ret; | ||
| 258 | |||
| 259 | crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE); | ||
| 260 | if (crc != buf[2]) | ||
| 261 | return -EINVAL; | 236 | return -EINVAL; |
| 262 | 237 | ||
| 263 | *val = get_unaligned_be16(buf); | 238 | if (type == IIO_TEMP) |
| 239 | *val = get_unaligned_be16(buf); | ||
| 240 | else if (type == IIO_HUMIDITYRELATIVE) | ||
| 241 | *val = get_unaligned_be16(&buf[3]); | ||
| 242 | else | ||
| 243 | return -EINVAL; | ||
| 264 | 244 | ||
| 265 | return 0; | 245 | return 0; |
| 266 | } | 246 | } |
| @@ -286,28 +266,28 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev, · 19 unmodified lines | |||
| 286 | } | 266 | } |
| 287 | case IIO_CHAN_INFO_PEAK: { | 267 | case IIO_CHAN_INFO_PEAK: { |
| 288 | guard(mutex)(&data->lock); | 268 | guard(mutex)(&data->lock); |
| 289 | if (chan->type == IIO_TEMP) { | 269 | if (chan->type == IIO_TEMP) |
| 290 | ret = hdc3020_read_high_peak_t(data, val); | 270 | ret = hdc3020_read_be16(data, HDC3020_R_T_HIGH_AUTO); |
| 291 | if (ret < 0) | 271 | else |
| 292 | return ret; | 272 | ret = hdc3020_read_be16(data, HDC3020_R_RH_HIGH_AUTO); |
| 293 | } else { | 273 | |
| 294 | ret = hdc3020_read_high_peak_rh(data, val); | 274 | if (ret < 0) |
| 295 | if (ret < 0) | 275 | return ret; |
| 296 | return ret; | 276 | |
| 297 | } | 277 | *val = ret; |
| 298 | return IIO_VAL_INT; | 278 | return IIO_VAL_INT; |
| 299 | } | 279 | } |
| 300 | case IIO_CHAN_INFO_TROUGH: { | 280 | case IIO_CHAN_INFO_TROUGH: { |
| 301 | guard(mutex)(&data->lock); | 281 | guard(mutex)(&data->lock); |
| 302 | if (chan->type == IIO_TEMP) { | 282 | if (chan->type == IIO_TEMP) |
| 303 | ret = hdc3020_read_low_peak_t(data, val); | 283 | ret = hdc3020_read_be16(data, HDC3020_R_T_LOW_AUTO); |
| 304 | if (ret < 0) | 284 | else |
| 305 | return ret; | 285 | ret = hdc3020_read_be16(data, HDC3020_R_RH_LOW_AUTO); |
| 306 | } else { | 286 | |
| 307 | ret = hdc3020_read_low_peak_rh(data, val); | 287 | if (ret < 0) |
| 308 | if (ret < 0) | 288 | return ret; |
| 309 | return ret; | 289 | |
| 310 | } | 290 | *val = ret; |
| 311 | return IIO_VAL_INT; | 291 | return IIO_VAL_INT; |
| 312 | } | 292 | } |
| 313 | case IIO_CHAN_INFO_SCALE: | 293 | case IIO_CHAN_INFO_SCALE: |
| @@ -352,23 +332,17 @@ static int hdc3020_update_heater(struct hdc3020_data *data, int val) · 38 unmodified lines | |||
| 352 | if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2]) | 332 | if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2]) |
| 353 | return -EINVAL; | 333 | return -EINVAL; |
| 354 | 334 | ||
| 355 | buf[0] = HDC3020_HEATER_CMD_MSB; | 335 | if (!val) |
| 336 | hdc3020_exec_cmd(data, HDC3020_HEATER_DISABLE); | ||
| 356 | 337 | ||
| 357 | if (!val) { | 338 | put_unaligned_be16(HDC3020_HEATER_CONFIG, buf); |
| 358 | buf[1] = HDC3020_HEATER_DISABLE; | ||
| 359 | return hdc3020_write_bytes(data, buf, 2); | ||
| 360 | } | ||
| 361 | |||
| 362 | buf[1] = HDC3020_HEATER_CONFIG; | ||
| 363 | put_unaligned_be16(val & GENMASK(13, 0), &buf[2]); | 339 | put_unaligned_be16(val & GENMASK(13, 0), &buf[2]); |
| 364 | buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE); | 340 | buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE); |
| 365 | ret = hdc3020_write_bytes(data, buf, 5); | 341 | ret = hdc3020_write_bytes(data, buf, 5); |
| 366 | if (ret < 0) | 342 | if (ret < 0) |
| 367 | return ret; | 343 | return ret; |
| 368 | 344 | ||
| 369 | buf[1] = HDC3020_HEATER_ENABLE; | 345 | return hdc3020_exec_cmd(data, HDC3020_HEATER_ENABLE); |
| 370 | |||
| 371 | return hdc3020_write_bytes(data, buf, 2); | ||
| 372 | } | 346 | } |
| 373 | 347 | ||
| 374 | static int hdc3020_write_raw(struct iio_dev *indio_dev, | 348 | static int hdc3020_write_raw(struct iio_dev *indio_dev, |
| @@ -389,15 +363,197 @@ static int hdc3020_write_raw(struct iio_dev *indio_dev, · 14 unmodified lines | |||
| 389 | return -EINVAL; | 363 | return -EINVAL; |
| 390 | } | 364 | } |
| 391 | 365 | ||
| 366 | static int hdc3020_write_thresh(struct iio_dev *indio_dev, | ||
| 367 | const struct iio_chan_spec *chan, | ||
| 368 | enum iio_event_type type, | ||
| 369 | enum iio_event_direction dir, | ||
| 370 | enum iio_event_info info, | ||
| 371 | int val, int val2) | ||
| 372 | { | ||
| 373 | struct hdc3020_data *data = iio_priv(indio_dev); | ||
| 374 | u8 buf[5]; | ||
| 375 | u64 tmp; | ||
| 376 | u16 reg; | ||
| 377 | int ret; | ||
| 378 | |||
| 379 | /* Supported temperature range is from –40 to 125 degree celsius */ | ||
| 380 | if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP) | ||
| 381 | return -EINVAL; | ||
| 382 | |||
| 383 | /* Select threshold register */ | ||
| 384 | if (info == IIO_EV_INFO_VALUE) { | ||
| 385 | if (dir == IIO_EV_DIR_RISING) | ||
| 386 | reg = HDC3020_S_T_RH_THRESH_HIGH; | ||
| 387 | else | ||
| 388 | reg = HDC3020_S_T_RH_THRESH_LOW; | ||
| 389 | } else { | ||
| 390 | if (dir == IIO_EV_DIR_RISING) | ||
| 391 | reg = HDC3020_S_T_RH_THRESH_HIGH_CLR; | ||
| 392 | else | ||
| 393 | reg = HDC3020_S_T_RH_THRESH_LOW_CLR; | ||
| 394 | } | ||
| 395 | |||
| 396 | guard(mutex)(&data->lock); | ||
| 397 | ret = hdc3020_read_be16(data, reg); | ||
| 398 | if (ret < 0) | ||
| 399 | return ret; | ||
| 400 | |||
| 401 | switch (chan->type) { | ||
| 402 | case IIO_TEMP: | ||
| 403 | /* | ||
| 404 | * Calculate temperature threshold, shift it down to get the | ||
| 405 | * truncated threshold representation in the 9LSBs while keeping | ||
| 406 | * the current humidity threshold in the 7 MSBs. | ||
| 407 | */ | ||
| 408 | tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL; | ||
| 409 | tmp = div_u64(tmp, MICRO * 175); | ||
| 410 | val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT; | ||
| 411 | val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val); | ||
| 412 | val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) << | ||
| 413 | HDC3020_THRESH_HUM_TRUNC_SHIFT); | ||
| 414 | break; | ||
| 415 | case IIO_HUMIDITYRELATIVE: | ||
| 416 | /* | ||
| 417 | * Calculate humidity threshold, shift it down and up to get the | ||
| 418 | * truncated threshold representation in the 7MSBs while keeping | ||
| 419 | * the current temperature threshold in the 9 LSBs. | ||
| 420 | */ | ||
| 421 | tmp = ((u64)((val * MICRO) + val2)) * 65535ULL; | ||
| 422 | tmp = div_u64(tmp, MICRO * 100); | ||
| 423 | val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT; | ||
| 424 | val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val); | ||
| 425 | val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); | ||
| 426 | break; | ||
| 427 | default: | ||
| 428 | return -EOPNOTSUPP; | ||
| 429 | } | ||
| 430 | |||
| 431 | put_unaligned_be16(reg, buf); | ||
| 432 | put_unaligned_be16(val, buf + 2); | ||
| 433 | buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE); | ||
| 434 | return hdc3020_write_bytes(data, buf, 5); | ||
| 435 | } | ||
| 436 | |||
| 437 | static int hdc3020_read_thresh(struct iio_dev *indio_dev, | ||
| 438 | const struct iio_chan_spec *chan, | ||
| 439 | enum iio_event_type type, | ||
| 440 | enum iio_event_direction dir, | ||
| 441 | enum iio_event_info info, | ||
| 442 | int *val, int *val2) | ||
| 443 | { | ||
| 444 | struct hdc3020_data *data = iio_priv(indio_dev); | ||
| 445 | u16 reg; | ||
| 446 | int ret; | ||
| 447 | |||
| 448 | /* Select threshold register */ | ||
| 449 | if (info == IIO_EV_INFO_VALUE) { | ||
| 450 | if (dir == IIO_EV_DIR_RISING) | ||
| 451 | reg = HDC3020_R_T_RH_THRESH_HIGH; | ||
| 452 | else | ||
| 453 | reg = HDC3020_R_T_RH_THRESH_LOW; | ||
| 454 | } else { | ||
| 455 | if (dir == IIO_EV_DIR_RISING) | ||
| 456 | reg = HDC3020_R_T_RH_THRESH_HIGH_CLR; | ||
| 457 | else | ||
| 458 | reg = HDC3020_R_T_RH_THRESH_LOW_CLR; | ||
| 459 | } | ||
| 460 | |||
| 461 | guard(mutex)(&data->lock); | ||
| 462 | ret = hdc3020_read_be16(data, reg); | ||
| 463 | if (ret < 0) | ||
| 464 | return ret; | ||
| 465 | |||
| 466 | switch (chan->type) { | ||
| 467 | case IIO_TEMP: | ||
| 468 | /* | ||
| 469 | * Get the temperature threshold from 9 LSBs, shift them to get | ||
| 470 | * the truncated temperature threshold representation and | ||
| 471 | * calculate the threshold according to the formula in the | ||
| 472 | * datasheet. | ||
| 473 | */ | ||
| 474 | *val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret); | ||
| 475 | *val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT; | ||
| 476 | *val = -2949075 + (175 * (*val)); | ||
| 477 | *val2 = 65535; | ||
| 478 | return IIO_VAL_FRACTIONAL; | ||
| 479 | case IIO_HUMIDITYRELATIVE: | ||
| 480 | /* | ||
| 481 | * Get the humidity threshold from 7 MSBs, shift them to get the | ||
| 482 | * truncated humidity threshold representation and calculate the | ||
| 483 | * threshold according to the formula in the datasheet. | ||
| 484 | */ | ||
| 485 | *val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret); | ||
| 486 | *val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100; | ||
| 487 | *val2 = 65535; | ||
| 488 | return IIO_VAL_FRACTIONAL; | ||
| 489 | default: | ||
| 490 | return -EOPNOTSUPP; | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | static irqreturn_t hdc3020_interrupt_handler(int irq, void *private) | ||
| 495 | { | ||
| 496 | struct iio_dev *indio_dev = private; | ||
| 497 | struct hdc3020_data *data; | ||
| 498 | s64 time; | ||
| 499 | int ret; | ||
| 500 | |||
| 501 | data = iio_priv(indio_dev); | ||
| 502 | ret = hdc3020_read_be16(data, HDC3020_R_STATUS); | ||
| 503 | if (ret < 0) | ||
| 504 | return IRQ_HANDLED; | ||
| 505 | |||
| 506 | if (!(ret & (HDC3020_STATUS_T_HIGH_ALERT | HDC3020_STATUS_T_LOW_ALERT | | ||
| 507 | HDC3020_STATUS_RH_HIGH_ALERT | HDC3020_STATUS_RH_LOW_ALERT))) | ||
| 508 | return IRQ_NONE; | ||
| 509 | |||
| 510 | time = iio_get_time_ns(indio_dev); | ||
| 511 | if (ret & HDC3020_STATUS_T_HIGH_ALERT) | ||
| 512 | iio_push_event(indio_dev, | ||
| 513 | IIO_MOD_EVENT_CODE(IIO_TEMP, 0, | ||
| 514 | IIO_NO_MOD, | ||
| 515 | IIO_EV_TYPE_THRESH, | ||
| 516 | IIO_EV_DIR_RISING), | ||
| 517 | time); | ||
| 518 | |||
| 519 | if (ret & HDC3020_STATUS_T_LOW_ALERT) | ||
| 520 | iio_push_event(indio_dev, | ||
| 521 | IIO_MOD_EVENT_CODE(IIO_TEMP, 0, | ||
| 522 | IIO_NO_MOD, | ||
| 523 | IIO_EV_TYPE_THRESH, | ||
| 524 | IIO_EV_DIR_FALLING), | ||
| 525 | time); | ||
| 526 | |||
| 527 | if (ret & HDC3020_STATUS_RH_HIGH_ALERT) | ||
| 528 | iio_push_event(indio_dev, | ||
| 529 | IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0, | ||
| 530 | IIO_NO_MOD, | ||
| 531 | IIO_EV_TYPE_THRESH, | ||
| 532 | IIO_EV_DIR_RISING), | ||
| 533 | time); | ||
| 534 | |||
| 535 | if (ret & HDC3020_STATUS_RH_LOW_ALERT) | ||
| 536 | iio_push_event(indio_dev, | ||
| 537 | IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0, | ||
| 538 | IIO_NO_MOD, | ||
| 539 | IIO_EV_TYPE_THRESH, | ||
| 540 | IIO_EV_DIR_FALLING), | ||
| 541 | time); | ||
| 542 | |||
| 543 | return IRQ_HANDLED; | ||
| 544 | } | ||
| 545 | |||
| 392 | static const struct iio_info hdc3020_info = { | 546 | static const struct iio_info hdc3020_info = { |
| 393 | .read_raw = hdc3020_read_raw, | 547 | .read_raw = hdc3020_read_raw, |
| 394 | .write_raw = hdc3020_write_raw, | 548 | .write_raw = hdc3020_write_raw, |
| 395 | .read_avail = hdc3020_read_available, | 549 | .read_avail = hdc3020_read_available, |
| 550 | .read_event_value = hdc3020_read_thresh, | ||
| 551 | .write_event_value = hdc3020_write_thresh, | ||
| 396 | }; | 552 | }; |
| 397 | 553 | ||
| 398 | static void hdc3020_stop(void *data) | 554 | static void hdc3020_stop(void *data) |
| 399 | { | 555 | { |
| 400 | hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2); | 556 | hdc3020_exec_cmd((struct hdc3020_data *)data, HDC3020_EXIT_AUTO); |
| 401 | } | 557 | } |
| 402 | 558 | ||
| 403 | static int hdc3020_probe(struct i2c_client *client) | 559 | static int hdc3020_probe(struct i2c_client *client) |
| @@ -424,8 +580,25 @@ static int hdc3020_probe(struct i2c_client *client) · 20 unmodified lines | |||
| 424 | indio_dev->info = &hdc3020_info; | 580 | indio_dev->info = &hdc3020_info; |
| 425 | indio_dev->channels = hdc3020_channels; | 581 | indio_dev->channels = hdc3020_channels; |
| 426 | indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels); | 582 | indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels); |
| 583 | if (client->irq) { | ||
| 584 | ret = devm_request_threaded_irq(&client->dev, client->irq, | ||
| 585 | NULL, hdc3020_interrupt_handler, | ||
| 586 | IRQF_ONESHOT, "hdc3020", | ||
| 587 | indio_dev); | ||
| 588 | if (ret) | ||
| 589 | return dev_err_probe(&client->dev, ret, | ||
| 590 | "Failed to request IRQ\n"); | ||
| 591 | |||
| 592 | /* | ||
| 593 | * The alert output is activated by default upon power up, | ||
| 594 | * hardware reset, and soft reset. Clear the status register. | ||
| 595 | */ | ||
| 596 | ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS); | ||
| 597 | if (ret) | ||
| 598 | return ret; | ||
| 599 | } | ||
| 427 | 600 | ||
| 428 | ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2); | 601 | ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0); |
| 429 | if (ret) | 602 | if (ret) |
| 430 | return dev_err_probe(&client->dev, ret, | 603 | return dev_err_probe(&client->dev, ret, |
| 431 | "Unable to set up measurement\n"); | 604 | "Unable to set up measurement\n"); |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/acpi.h> | 12 | #include <linux/mod_devicetable.h> |
| 13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
| @@ -63,7 +63,7 @@ static struct i2c_driver hts221_driver = { · 47 unmodified lines | |||
| 63 | .name = "hts221_i2c", | 63 | .name = "hts221_i2c", |
| 64 | .pm = pm_sleep_ptr(&hts221_pm_ops), | 64 | .pm = pm_sleep_ptr(&hts221_pm_ops), |
| 65 | .of_match_table = hts221_i2c_of_match, | 65 | .of_match_table = hts221_i2c_of_match, |
| 66 | .acpi_match_table = ACPI_PTR(hts221_acpi_match), | 66 | .acpi_match_table = hts221_acpi_match, |
| 67 | }, | 67 | }, |
| 68 | .probe = hts221_i2c_probe, | 68 | .probe = hts221_i2c_probe, |
| 69 | .id_table = hts221_i2c_id_table, | 69 | .id_table = hts221_i2c_id_table, |
| @@ -1363,22 +1363,16 @@ static int adis16475_config_sync_mode(struct adis16475 *st) · 1362 unmodified lines | |||
| 1363 | static int adis16475_config_irq_pin(struct adis16475 *st) | 1363 | static int adis16475_config_irq_pin(struct adis16475 *st) |
| 1364 | { | 1364 | { |
| 1365 | int ret; | 1365 | int ret; |
| 1366 | struct irq_data *desc; | ||
| 1367 | u32 irq_type; | 1366 | u32 irq_type; |
| 1368 | u16 val = 0; | 1367 | u16 val = 0; |
| 1369 | u8 polarity; | 1368 | u8 polarity; |
| 1370 | struct spi_device *spi = st->adis.spi; | 1369 | struct spi_device *spi = st->adis.spi; |
| 1371 | 1370 | ||
| 1372 | desc = irq_get_irq_data(spi->irq); | ||
| 1373 | if (!desc) { | ||
| 1374 | dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq); | ||
| 1375 | return -EINVAL; | ||
| 1376 | } | ||
| 1377 | /* | 1371 | /* |
| 1378 | * It is possible to configure the data ready polarity. Furthermore, we | 1372 | * It is possible to configure the data ready polarity. Furthermore, we |
| 1379 | * need to update the adis struct if we want data ready as active low. | 1373 | * need to update the adis struct if we want data ready as active low. |
| 1380 | */ | 1374 | */ |
| 1381 | irq_type = irqd_get_trigger_type(desc); | 1375 | irq_type = irq_get_trigger_type(spi->irq); |
| 1382 | if (irq_type == IRQ_TYPE_EDGE_RISING) { | 1376 | if (irq_type == IRQ_TYPE_EDGE_RISING) { |
| 1383 | polarity = 1; | 1377 | polarity = 1; |
| 1384 | st->adis.irq_flag = IRQF_TRIGGER_RISING; | 1378 | st->adis.irq_flag = IRQF_TRIGGER_RISING; |
| @@ -1246,18 +1246,11 @@ static int adis16480_config_irq_pin(struct adis16480 *st) · 1245 unmodified lines | |||
| 1246 | { | 1246 | { |
| 1247 | struct device *dev = &st->adis.spi->dev; | 1247 | struct device *dev = &st->adis.spi->dev; |
| 1248 | struct fwnode_handle *fwnode = dev_fwnode(dev); | 1248 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
| 1249 | struct irq_data *desc; | ||
| 1250 | enum adis16480_int_pin pin; | 1249 | enum adis16480_int_pin pin; |
| 1251 | unsigned int irq_type; | 1250 | unsigned int irq_type; |
| 1252 | uint16_t val; | 1251 | uint16_t val; |
| 1253 | int i, irq = 0; | 1252 | int i, irq = 0; |
| 1254 | 1253 | ||
| 1255 | desc = irq_get_irq_data(st->adis.spi->irq); | ||
| 1256 | if (!desc) { | ||
| 1257 | dev_err(dev, "Could not find IRQ %d\n", irq); | ||
| 1258 | return -EINVAL; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /* Disable data ready since the default after reset is on */ | 1254 | /* Disable data ready since the default after reset is on */ |
| 1262 | val = ADIS16480_DRDY_EN(0); | 1255 | val = ADIS16480_DRDY_EN(0); |
| 1263 | 1256 | ||
| @@ -1285,7 +1278,7 @@ static int adis16480_config_irq_pin(struct adis16480 *st) · 21 unmodified lines | |||
| 1285 | * configured as positive or negative, corresponding to | 1278 | * configured as positive or negative, corresponding to |
| 1286 | * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. | 1279 | * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. |
| 1287 | */ | 1280 | */ |
| 1288 | irq_type = irqd_get_trigger_type(desc); | 1281 | irq_type = irq_get_trigger_type(st->adis.spi->irq); |
| 1289 | if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ | 1282 | if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ |
| 1290 | val |= ADIS16480_DRDY_POL(1); | 1283 | val |= ADIS16480_DRDY_POL(1); |
| 1291 | } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { | 1284 | } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { |
| @@ -43,6 +43,15 @@ static const struct i2c_device_id bmi160_i2c_id[] = { · 42 unmodified lines | |||
| 43 | MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); | 43 | MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); |
| 44 | 44 | ||
| 45 | static const struct acpi_device_id bmi160_acpi_match[] = { | 45 | static const struct acpi_device_id bmi160_acpi_match[] = { |
| 46 | /* | ||
| 47 | * FIRMWARE BUG WORKAROUND | ||
| 48 | * Some manufacturers like GPD, Lenovo or Aya used the incorrect | ||
| 49 | * ID "10EC5280" for bmi160 in their DSDT. A fixed firmware is not | ||
| 50 | * available as of Feb 2024 after trying to work with OEMs, and | ||
| 51 | * this is not expected to change anymore since at least some of | ||
| 52 | * the affected devices are from 2021/2022. | ||
| 53 | */ | ||
| 54 | {"10EC5280", 0}, | ||
| 46 | {"BMI0160", 0}, | 55 | {"BMI0160", 0}, |
| 47 | { }, | 56 | { }, |
| 48 | }; | 57 | }; |
| @@ -1668,52 +1668,41 @@ static int bmi323_write_raw(struct iio_dev *indio_dev, · 1667 unmodified lines | |||
| 1668 | int val2, long mask) | 1668 | int val2, long mask) |
| 1669 | { | 1669 | { |
| 1670 | struct bmi323_data *data = iio_priv(indio_dev); | 1670 | struct bmi323_data *data = iio_priv(indio_dev); |
| 1671 | int ret; | ||
| 1672 | 1671 | ||
| 1673 | switch (mask) { | 1672 | switch (mask) { |
| 1674 | case IIO_CHAN_INFO_SAMP_FREQ: | 1673 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 1675 | ret = iio_device_claim_direct_mode(indio_dev); | 1674 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 1676 | if (ret) | 1675 | return bmi323_set_odr(data, |
| 1677 | return ret; | 1676 | bmi323_iio_to_sensor(chan->type), |
| 1678 | 1677 | val, val2); | |
| 1679 | ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type), | 1678 | unreachable(); |
| 1680 | val, val2); | ||
| 1681 | iio_device_release_direct_mode(indio_dev); | ||
| 1682 | return ret; | ||
| 1683 | case IIO_CHAN_INFO_SCALE: | 1679 | case IIO_CHAN_INFO_SCALE: |
| 1684 | ret = iio_device_claim_direct_mode(indio_dev); | 1680 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 1685 | if (ret) | 1681 | return bmi323_set_scale(data, |
| 1686 | return ret; | 1682 | bmi323_iio_to_sensor(chan->type), |
| 1687 | 1683 | val, val2); | |
| 1688 | ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type), | 1684 | unreachable(); |
| 1689 | val, val2); | ||
| 1690 | iio_device_release_direct_mode(indio_dev); | ||
| 1691 | return ret; | ||
| 1692 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 1685 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 1693 | ret = iio_device_claim_direct_mode(indio_dev); | 1686 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 1694 | if (ret) | 1687 | return bmi323_set_average(data, |
| 1695 | return ret; | 1688 | bmi323_iio_to_sensor(chan->type), |
| 1696 | 1689 | val); | |
| 1697 | ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type), | 1690 | unreachable(); |
| 1698 | val); | ||
| 1699 | |||
| 1700 | iio_device_release_direct_mode(indio_dev); | ||
| 1701 | return ret; | ||
| 1702 | case IIO_CHAN_INFO_ENABLE: | 1691 | case IIO_CHAN_INFO_ENABLE: |
| 1703 | return bmi323_enable_steps(data, val); | 1692 | return bmi323_enable_steps(data, val); |
| 1704 | case IIO_CHAN_INFO_PROCESSED: | 1693 | case IIO_CHAN_INFO_PROCESSED: { |
| 1705 | scoped_guard(mutex, &data->mutex) { | 1694 | guard(mutex)(&data->mutex); |
| 1706 | if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, | ||
| 1707 | data->feature_events)) | ||
| 1708 | return -EINVAL; | ||
| 1709 | 1695 | ||
| 1710 | /* Clear step counter value */ | 1696 | if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, |
| 1711 | ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, | 1697 | data->feature_events)) |
| 1712 | BMI323_STEP_SC1_RST_CNT_MSK, | 1698 | return -EINVAL; |
| 1713 | FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, | 1699 | |
| 1714 | 1)); | 1700 | /* Clear step counter value */ |
| 1715 | } | 1701 | return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, |
| 1716 | return ret; | 1702 | BMI323_STEP_SC1_RST_CNT_MSK, |
| 1703 | FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, | ||
| 1704 | 1)); | ||
| 1705 | } | ||
| 1717 | default: | 1706 | default: |
| 1718 | return -EINVAL; | 1707 | return -EINVAL; |
| 1719 | } | 1708 | } |
| @@ -1724,7 +1713,6 @@ static int bmi323_read_raw(struct iio_dev *indio_dev, · 4 unmodified lines | |||
| 1724 | int *val2, long mask) | 1713 | int *val2, long mask) |
| 1725 | { | 1714 | { |
| 1726 | struct bmi323_data *data = iio_priv(indio_dev); | 1715 | struct bmi323_data *data = iio_priv(indio_dev); |
| 1727 | int ret; | ||
| 1728 | 1716 | ||
| 1729 | switch (mask) { | 1717 | switch (mask) { |
| 1730 | case IIO_CHAN_INFO_PROCESSED: | 1718 | case IIO_CHAN_INFO_PROCESSED: |
| @@ -1733,14 +1721,10 @@ static int bmi323_read_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 1733 | switch (chan->type) { | 1721 | switch (chan->type) { |
| 1734 | case IIO_ACCEL: | 1722 | case IIO_ACCEL: |
| 1735 | case IIO_ANGL_VEL: | 1723 | case IIO_ANGL_VEL: |
| 1736 | ret = iio_device_claim_direct_mode(indio_dev); | 1724 | iio_device_claim_direct_scoped(return -EBUSY, |
| 1737 | if (ret) | 1725 | indio_dev) |
| 1738 | return ret; | 1726 | return bmi323_read_axis(data, chan, val); |
| 1739 | 1727 | unreachable(); | |
| 1740 | ret = bmi323_read_axis(data, chan, val); | ||
| 1741 | |||
| 1742 | iio_device_release_direct_mode(indio_dev); | ||
| 1743 | return ret; | ||
| 1744 | case IIO_TEMP: | 1728 | case IIO_TEMP: |
| 1745 | return bmi323_get_temp_data(data, val); | 1729 | return bmi323_get_temp_data(data, val); |
| 1746 | default: | 1730 | default: |
| @@ -93,6 +93,26 @@ static int bmi323_i2c_probe(struct i2c_client *i2c) · 92 unmodified lines | |||
| 93 | return bmi323_core_probe(dev); | 93 | return bmi323_core_probe(dev); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | static const struct acpi_device_id bmi323_acpi_match[] = { | ||
| 97 | /* | ||
| 98 | * The "BOSC0200" identifier used here is not unique to bmi323 devices. | ||
| 99 | * The same "BOSC0200" identifier is found in the ACPI tables of devices | ||
| 100 | * using the bmc150 chip. This creates a conflict with duplicate ACPI | ||
| 101 | * identifiers which multiple drivers want to use. If a non-bmi323 | ||
| 102 | * device starts to load with this "BOSC0200" ACPI match here, then the | ||
| 103 | * chip ID check portion should fail because the chip IDs received (via | ||
| 104 | * i2c) are unique between bmc150 and bmi323 and the driver should | ||
| 105 | * relinquish the device. If and when a different driver (such as | ||
| 106 | * bmc150) starts to load with the "BOSC0200" ACPI match, a short reset | ||
| 107 | * should ensure that the device is not in a bad state during that | ||
| 108 | * driver initialization. This device reset does occur in both the | ||
| 109 | * bmi323 and bmc150 init sequences. | ||
| 110 | */ | ||
| 111 | { "BOSC0200" }, | ||
| 112 | { } | ||
| 113 | }; | ||
| 114 | MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); | ||
| 115 | |||
| 96 | static const struct i2c_device_id bmi323_i2c_ids[] = { | 116 | static const struct i2c_device_id bmi323_i2c_ids[] = { |
| 97 | { "bmi323" }, | 117 | { "bmi323" }, |
| 98 | { } | 118 | { } |
| @@ -109,6 +129,7 @@ static struct i2c_driver bmi323_i2c_driver = { · 10 unmodified lines | |||
| 109 | .driver = { | 129 | .driver = { |
| 110 | .name = "bmi323", | 130 | .name = "bmi323", |
| 111 | .of_match_table = bmi323_of_i2c_match, | 131 | .of_match_table = bmi323_of_i2c_match, |
| 132 | .acpi_match_table = bmi323_acpi_match, | ||
| 112 | }, | 133 | }, |
| 113 | .probe = bmi323_i2c_probe, | 134 | .probe = bmi323_i2c_probe, |
| 114 | .id_table = bmi323_i2c_ids, | 135 | .id_table = bmi323_i2c_ids, |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | |||
| 10 | * 1 | 0 | 0x1C | 10 | * 1 | 0 | 0x1C |
| 11 | * 1 | 1 | 0x1F | 11 | * 1 | 1 | 0x1F |
| 12 | */ | 12 | */ |
| 13 | #include <linux/acpi.h> | ||
| 14 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 16 | #include <linux/mod_devicetable.h> | 15 | #include <linux/mod_devicetable.h> |
| @@ -57,7 +56,7 @@ MODULE_DEVICE_TABLE(of, fxos8700_of_match); · 40 unmodified lines | |||
| 57 | static struct i2c_driver fxos8700_i2c_driver = { | 56 | static struct i2c_driver fxos8700_i2c_driver = { |
| 58 | .driver = { | 57 | .driver = { |
| 59 | .name = "fxos8700_i2c", | 58 | .name = "fxos8700_i2c", |
| 60 | .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), | 59 | .acpi_match_table = fxos8700_acpi_match, |
| 61 | .of_match_table = fxos8700_of_match, | 60 | .of_match_table = fxos8700_of_match, |
| 62 | }, | 61 | }, |
| 63 | .probe = fxos8700_i2c_probe, | 62 | .probe = fxos8700_i2c_probe, |
| @@ -2,7 +2,6 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * FXOS8700 - NXP IMU, SPI bits | 3 | * FXOS8700 - NXP IMU, SPI bits |
| 4 | */ | 4 | */ |
| 5 | #include <linux/acpi.h> | ||
| 6 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 7 | #include <linux/mod_devicetable.h> | 6 | #include <linux/mod_devicetable.h> |
| 8 | #include <linux/regmap.h> | 7 | #include <linux/regmap.h> |
| @@ -46,7 +45,7 @@ static struct spi_driver fxos8700_spi_driver = { · 37 unmodified lines | |||
| 46 | .probe = fxos8700_spi_probe, | 45 | .probe = fxos8700_spi_probe, |
| 47 | .id_table = fxos8700_spi_id, | 46 | .id_table = fxos8700_spi_id, |
| 48 | .driver = { | 47 | .driver = { |
| 49 | .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), | 48 | .acpi_match_table = fxos8700_acpi_match, |
| 50 | .of_match_table = fxos8700_of_match, | 49 | .of_match_table = fxos8700_of_match, |
| 51 | .name = "fxos8700_spi", | 50 | .name = "fxos8700_spi", |
| 52 | }, | 51 | }, |
| @@ -1514,7 +1514,7 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id); · 1513 unmodified lines | |||
| 1514 | static struct i2c_driver kmx61_driver = { | 1514 | static struct i2c_driver kmx61_driver = { |
| 1515 | .driver = { | 1515 | .driver = { |
| 1516 | .name = KMX61_DRV_NAME, | 1516 | .name = KMX61_DRV_NAME, |
| 1517 | .acpi_match_table = ACPI_PTR(kmx61_acpi_match), | 1517 | .acpi_match_table = kmx61_acpi_match, |
| 1518 | .pm = pm_ptr(&kmx61_pm_ops), | 1518 | .pm = pm_ptr(&kmx61_pm_ops), |
| 1519 | }, | 1519 | }, |
| 1520 | .probe = kmx61_probe, | 1520 | .probe = kmx61_probe, |
| @@ -11,11 +11,32 @@ config IIO_ST_LSM6DSX · 10 unmodified lines | |||
| 11 | select IIO_ST_LSM6DSX_I3C if (I3C) | 11 | select IIO_ST_LSM6DSX_I3C if (I3C) |
| 12 | help | 12 | help |
| 13 | Say yes here to build support for STMicroelectronics LSM6DSx imu | 13 | Say yes here to build support for STMicroelectronics LSM6DSx imu |
| 14 | sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, | 14 | sensor. |
| 15 | ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr, | 15 | Supported devices: |
| 16 | lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx, | 16 | - asm330lhb |
| 17 | lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst | 17 | - asm330lhh |
| 18 | and the accelerometer/gyroscope of lsm9ds1. | 18 | - asm330lhhx |
| 19 | - asm330lhhxg1 | ||
| 20 | - ism330dhcx | ||
| 21 | - ism330dlc | ||
| 22 | - ism330is | ||
| 23 | - lsm6ds0 | ||
| 24 | - lsm6ds3 | ||
| 25 | - lsm6ds3h | ||
| 26 | - lsm6ds3tr-c | ||
| 27 | - lsm6dsl | ||
| 28 | - lsm6dsm | ||
| 29 | - lsm6dso | ||
| 30 | - lsm6dso16is | ||
| 31 | - lsm6dsop | ||
| 32 | - lsm6dsox | ||
| 33 | - lsm6dsr | ||
| 34 | - lsm6dsrx | ||
| 35 | - lsm6dst | ||
| 36 | - lsm6dstx | ||
| 37 | - lsm6dsv | ||
| 38 | - lsm6dsv16x | ||
| 39 | - lsm9ds1 | ||
| 19 | 40 | ||
| 20 | To compile this driver as a module, choose M here: the module | 41 | To compile this driver as a module, choose M here: the module |
| 21 | will be called st_lsm6dsx. | 42 | will be called st_lsm6dsx. |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | |||
| 38 | #define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is" | 38 | #define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is" |
| 39 | #define ST_ISM330IS_DEV_NAME "ism330is" | 39 | #define ST_ISM330IS_DEV_NAME "ism330is" |
| 40 | #define ST_ASM330LHB_DEV_NAME "asm330lhb" | 40 | #define ST_ASM330LHB_DEV_NAME "asm330lhb" |
| 41 | #define ST_ASM330LHHXG1_DEV_NAME "asm330lhhxg1" | ||
| 41 | 42 | ||
| 42 | enum st_lsm6dsx_hw_id { | 43 | enum st_lsm6dsx_hw_id { |
| 43 | ST_LSM6DS3_ID = 1, | 44 | ST_LSM6DS3_ID = 1, |
| @@ -63,6 +64,7 @@ enum st_lsm6dsx_hw_id { · 19 unmodified lines | |||
| 63 | ST_LSM6DSO16IS_ID, | 64 | ST_LSM6DSO16IS_ID, |
| 64 | ST_ISM330IS_ID, | 65 | ST_ISM330IS_ID, |
| 65 | ST_ASM330LHB_ID, | 66 | ST_ASM330LHB_ID, |
| 67 | ST_ASM330LHHXG1_ID, | ||
| 66 | ST_LSM6DSX_MAX_ID, | 68 | ST_LSM6DSX_MAX_ID, |
| 67 | }; | 69 | }; |
| 68 | 70 | ||
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * STMicroelectronics st_lsm6dsx FIFO buffer library driver | 3 | * STMicroelectronics st_lsm6dsx FIFO buffer library driver |
| 4 | * | 4 | * |
| 5 | * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: | 5 | * Pattern FIFO: |
| 6 | * The FIFO buffer can be configured to store data from gyroscope and | 6 | * The FIFO buffer can be configured to store data from gyroscope and |
| 7 | * accelerometer. Samples are queued without any tag according to a | 7 | * accelerometer. Samples are queued without any tag according to a |
| 8 | * specific pattern based on 'FIFO data sets' (6 bytes each): | 8 | * specific pattern based on 'FIFO data sets' (6 bytes each): |
| @@ -14,12 +14,34 @@ · 5 unmodified lines | |||
| 14 | * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the | 14 | * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the |
| 15 | * value of the decimation factor and ODR set for each FIFO data set. | 15 | * value of the decimation factor and ODR set for each FIFO data set. |
| 16 | * | 16 | * |
| 17 | * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/ | 17 | * Supported devices: |
| 18 | * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB: | 18 | * - ISM330DLC |
| 19 | * - LSM6DS3 | ||
| 20 | * - LSM6DS3H | ||
| 21 | * - LSM6DS3TR-C | ||
| 22 | * - LSM6DSL | ||
| 23 | * - LSM6DSM | ||
| 24 | * | ||
| 25 | * Tagged FIFO: | ||
| 19 | * The FIFO buffer can be configured to store data from gyroscope and | 26 | * The FIFO buffer can be configured to store data from gyroscope and |
| 20 | * accelerometer. Each sample is queued with a tag (1B) indicating data | 27 | * accelerometer. Each sample is queued with a tag (1B) indicating data |
| 21 | * source (gyroscope, accelerometer, hw timer). | 28 | * source (gyroscope, accelerometer, hw timer). |
| 22 | * | 29 | * |
| 30 | * Supported devices: | ||
| 31 | * - ASM330LHB | ||
| 32 | * - ASM330LHH | ||
| 33 | * - ASM330LHHX | ||
| 34 | * - ASM330LHHXG1 | ||
| 35 | * - ISM330DHCX | ||
| 36 | * - LSM6DSO | ||
| 37 | * - LSM6DSOP | ||
| 38 | * - LSM6DSOX | ||
| 39 | * - LSM6DSR | ||
| 40 | * - LSM6DSRX | ||
| 41 | * - LSM6DST | ||
| 42 | * - LSM6DSTX | ||
| 43 | * - LSM6DSV | ||
| 44 | * | ||
| 23 | * FIFO supported modes: | 45 | * FIFO supported modes: |
| 24 | * - BYPASS: FIFO disabled | 46 | * - BYPASS: FIFO disabled |
| 25 | * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index | 47 | * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index |
| @@ -14,34 +14,51 @@ · 13 unmodified lines | |||
| 14 | * by a different driver. | 14 | * by a different driver. |
| 15 | * | 15 | * |
| 16 | * Supported sensors: | 16 | * Supported sensors: |
| 17 | * - LSM6DS3: | 17 | * |
| 18 | * - LSM6DS3 | ||
| 18 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 | 19 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 |
| 19 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 20 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 20 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 | 21 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 |
| 21 | * - FIFO size: 8KB | 22 | * - FIFO size: 8KB |
| 22 | * | 23 | * |
| 23 | * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: | 24 | * - ISM330DLC |
| 25 | * - LSM6DS3H | ||
| 26 | * - LSM6DS3TR-C | ||
| 27 | * - LSM6DSL | ||
| 28 | * - LSM6DSM | ||
| 24 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 | 29 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 |
| 25 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 30 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 26 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 | 31 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 |
| 27 | * - FIFO size: 4KB | 32 | * - FIFO size: 4KB |
| 28 | * | 33 | * |
| 29 | * - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/ | 34 | * - ASM330LHH |
| 30 | * LSM6DSTX/LSM6DSO16IS/ISM330IS: | 35 | * - ASM330LHHX |
| 36 | * - ASM330LHHXG1 | ||
| 37 | * - ISM330DHCX | ||
| 38 | * - ISM330IS | ||
| 39 | * - LSM6DSO | ||
| 40 | * - LSM6DSO16IS | ||
| 41 | * - LSM6DSOP | ||
| 42 | * - LSM6DSOX | ||
| 43 | * - LSM6DSR | ||
| 44 | * - LSM6DST | ||
| 45 | * - LSM6DSTX | ||
| 31 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416, | 46 | * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416, |
| 32 | * 833 | 47 | * 833 |
| 33 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 48 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 34 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 | 49 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 |
| 35 | * - FIFO size: 3KB | 50 | * - FIFO size: 3KB |
| 36 | * | 51 | * |
| 37 | * - LSM6DSV/LSM6DSV16X: | 52 | * - LSM6DSV |
| 53 | * - LSM6DSV16X | ||
| 38 | * - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240, | 54 | * - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240, |
| 39 | * 480, 960 | 55 | * 480, 960 |
| 40 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 56 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 41 | * - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000 | 57 | * - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000 |
| 42 | * - FIFO size: 3KB | 58 | * - FIFO size: 3KB |
| 43 | * | 59 | * |
| 44 | * - LSM9DS1/LSM6DS0: | 60 | * - LSM6DS0 |
| 61 | * - LSM9DS1 | ||
| 45 | * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 | 62 | * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 |
| 46 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 63 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 47 | * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 | 64 | * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 |
| @@ -820,6 +837,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { · 772 unmodified lines | |||
| 820 | .hw_id = ST_ASM330LHHX_ID, | 837 | .hw_id = ST_ASM330LHHX_ID, |
| 821 | .name = ST_ASM330LHHX_DEV_NAME, | 838 | .name = ST_ASM330LHHX_DEV_NAME, |
| 822 | .wai = 0x6b, | 839 | .wai = 0x6b, |
| 840 | }, { | ||
| 841 | .hw_id = ST_ASM330LHHXG1_ID, | ||
| 842 | .name = ST_ASM330LHHXG1_DEV_NAME, | ||
| 843 | .wai = 0x6b, | ||
| 823 | }, { | 844 | }, { |
| 824 | .hw_id = ST_LSM6DSTX_ID, | 845 | .hw_id = ST_LSM6DSTX_ID, |
| 825 | .name = ST_LSM6DSTX_DEV_NAME, | 846 | .name = ST_LSM6DSTX_DEV_NAME, |
| @@ -134,6 +134,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { · 133 unmodified lines | |||
| 134 | .compatible = "st,asm330lhb", | 134 | .compatible = "st,asm330lhb", |
| 135 | .data = (void *)ST_ASM330LHB_ID, | 135 | .data = (void *)ST_ASM330LHB_ID, |
| 136 | }, | 136 | }, |
| 137 | { | ||
| 138 | .compatible = "st,asm330lhhxg1", | ||
| 139 | .data = (void *)ST_ASM330LHHXG1_ID, | ||
| 140 | }, | ||
| 137 | {}, | 141 | {}, |
| 138 | }; | 142 | }; |
| 139 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); | 143 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); |
| @@ -168,6 +172,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { · 28 unmodified lines | |||
| 168 | { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, | 172 | { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, |
| 169 | { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, | 173 | { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, |
| 170 | { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, | 174 | { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, |
| 175 | { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, | ||
| 171 | {}, | 176 | {}, |
| 172 | }; | 177 | }; |
| 173 | MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); | 178 | MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); |
| @@ -129,6 +129,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { · 128 unmodified lines | |||
| 129 | .compatible = "st,asm330lhb", | 129 | .compatible = "st,asm330lhb", |
| 130 | .data = (void *)ST_ASM330LHB_ID, | 130 | .data = (void *)ST_ASM330LHB_ID, |
| 131 | }, | 131 | }, |
| 132 | { | ||
| 133 | .compatible = "st,asm330lhhxg1", | ||
| 134 | .data = (void *)ST_ASM330LHHXG1_ID, | ||
| 135 | }, | ||
| 132 | {}, | 136 | {}, |
| 133 | }; | 137 | }; |
| 134 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); | 138 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); |
| @@ -157,6 +161,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { · 22 unmodified lines | |||
| 157 | { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, | 161 | { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, |
| 158 | { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, | 162 | { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, |
| 159 | { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, | 163 | { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, |
| 164 | { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, | ||
| 160 | {}, | 165 | {}, |
| 161 | }; | 166 | }; |
| 162 | MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); | 167 | MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); |
| @@ -4,9 +4,12 @@ · 3 unmodified lines | |||
| 4 | #ifndef ST_LSM9DS0_H | 4 | #ifndef ST_LSM9DS0_H |
| 5 | #define ST_LSM9DS0_H | 5 | #define ST_LSM9DS0_H |
| 6 | 6 | ||
| 7 | struct iio_dev; | 7 | struct device; |
| 8 | struct regmap; | ||
| 8 | struct regulator; | 9 | struct regulator; |
| 9 | 10 | ||
| 11 | struct iio_dev; | ||
| 12 | |||
| 10 | struct st_lsm9ds0 { | 13 | struct st_lsm9ds0 { |
| 11 | struct device *dev; | 14 | struct device *dev; |
| 12 | const char *name; | 15 | const char *name; |
| @@ -7,10 +7,10 @@ · 6 unmodified lines | |||
| 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/device.h> | 10 | #include <linux/array_size.h> |
| 11 | #include <linux/dev_printk.h> | ||
| 11 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 13 | #include <linux/regmap.h> | ||
| 14 | #include <linux/regulator/consumer.h> | 14 | #include <linux/regulator/consumer.h> |
| 15 | 15 | ||
| 16 | #include <linux/iio/common/st_sensors.h> | 16 | #include <linux/iio/common/st_sensors.h> |
| @@ -25,10 +25,9 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg · 8 unmodified lines | |||
| 25 | struct st_sensor_data *data; | 25 | struct st_sensor_data *data; |
| 26 | 26 | ||
| 27 | settings = st_accel_get_settings(lsm9ds0->name); | 27 | settings = st_accel_get_settings(lsm9ds0->name); |
| 28 | if (!settings) { | 28 | if (!settings) |
| 29 | dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); | 29 | return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n", |
| 30 | return -ENODEV; | 30 | lsm9ds0->name); |
| 31 | } | ||
| 32 | 31 | ||
| 33 | lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data)); | 32 | lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data)); |
| 34 | if (!lsm9ds0->accel) | 33 | if (!lsm9ds0->accel) |
| @@ -51,10 +50,9 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm · 16 unmodified lines | |||
| 51 | struct st_sensor_data *data; | 50 | struct st_sensor_data *data; |
| 52 | 51 | ||
| 53 | settings = st_magn_get_settings(lsm9ds0->name); | 52 | settings = st_magn_get_settings(lsm9ds0->name); |
| 54 | if (!settings) { | 53 | if (!settings) |
| 55 | dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); | 54 | return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n", |
| 56 | return -ENODEV; | 55 | lsm9ds0->name); |
| 57 | } | ||
| 58 | 56 | ||
| 59 | lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data)); | 57 | lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data)); |
| 60 | if (!lsm9ds0->magn) | 58 | if (!lsm9ds0->magn) |
| @@ -80,8 +78,7 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) · 19 unmodified lines | |||
| 80 | ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), | 78 | ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), |
| 81 | regulator_names); | 79 | regulator_names); |
| 82 | if (ret) | 80 | if (ret) |
| 83 | return dev_err_probe(dev, ret, | 81 | return dev_err_probe(dev, ret, "unable to enable Vdd supply\n"); |
| 84 | "unable to enable Vdd supply\n"); | ||
| 85 | 82 | ||
| 86 | /* Setup accelerometer device */ | 83 | /* Setup accelerometer device */ |
| 87 | ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap); | 84 | ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap); |
| @@ -7,8 +7,10 @@ · 6 unmodified lines | |||
| 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/err.h> | ||
| 12 | #include <linux/gfp_types.h> | ||
| 10 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | 15 | #include <linux/mod_devicetable.h> |
| 14 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
| @@ -39,7 +41,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); · 24 unmodified lines | |||
| 39 | 41 | ||
| 40 | static const struct acpi_device_id st_lsm9ds0_acpi_match[] = { | 42 | static const struct acpi_device_id st_lsm9ds0_acpi_match[] = { |
| 41 | {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME}, | 43 | {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME}, |
| 42 | { }, | 44 | {} |
| 43 | }; | 45 | }; |
| 44 | MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match); | 46 | MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match); |
| 45 | 47 | ||
| @@ -7,7 +7,9 @@ · 6 unmodified lines | |||
| 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 7 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/err.h> | ||
| 12 | #include <linux/gfp_types.h> | ||
| 11 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 12 | #include <linux/mod_devicetable.h> | 14 | #include <linux/mod_devicetable.h> |
| 13 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
| @@ -0,0 +1,418 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Framework to handle complex IIO aggregate devices. | ||
| 4 | * | ||
| 5 | * The typical architecture is to have one device as the frontend device which | ||
| 6 | * can be "linked" against one or multiple backend devices. All the IIO and | ||
| 7 | * userspace interface is expected to be registers/managed by the frontend | ||
| 8 | * device which will callback into the backends when needed (to get/set some | ||
| 9 | * configuration that it does not directly control). | ||
| 10 | * | ||
| 11 | * ------------------------------------------------------- | ||
| 12 | * ------------------ | ------------ ------------ ------- FPGA| | ||
| 13 | * | ADC |------------------------| | ADC CORE |---------| DMA CORE |------| RAM | | | ||
| 14 | * | (Frontend/IIO) | Serial Data (eg: LVDS) | |(backend) |---------| |------| | | | ||
| 15 | * | |------------------------| ------------ ------------ ------- | | ||
| 16 | * ------------------ ------------------------------------------------------- | ||
| 17 | * | ||
| 18 | * The framework interface is pretty simple: | ||
| 19 | * - Backends should register themselves with devm_iio_backend_register() | ||
| 20 | * - Frontend devices should get backends with devm_iio_backend_get() | ||
| 21 | * | ||
| 22 | * Also to note that the primary target for this framework are converters like | ||
| 23 | * ADC/DACs so iio_backend_ops will have some operations typical of converter | ||
| 24 | * devices. On top of that, this is "generic" for all IIO which means any kind | ||
| 25 | * of device can make use of the framework. That said, If the iio_backend_ops | ||
| 26 | * struct begins to grow out of control, we can always refactor things so that | ||
| 27 | * the industrialio-backend.c is only left with the really generic stuff. Then, | ||
| 28 | * we can build on top of it depending on the needs. | ||
| 29 | * | ||
| 30 | * Copyright (C) 2023-2024 Analog Devices Inc. | ||
| 31 | */ | ||
| 32 | #define dev_fmt(fmt) "iio-backend: " fmt | ||
| 33 | |||
| 34 | #include <linux/cleanup.h> | ||
| 35 | #include <linux/device.h> | ||
| 36 | #include <linux/err.h> | ||
| 37 | #include <linux/errno.h> | ||
| 38 | #include <linux/list.h> | ||
| 39 | #include <linux/module.h> | ||
| 40 | #include <linux/mutex.h> | ||
| 41 | #include <linux/property.h> | ||
| 42 | #include <linux/slab.h> | ||
| 43 | #include <linux/types.h> | ||
| 44 | |||
| 45 | #include <linux/iio/backend.h> | ||
| 46 | |||
| 47 | struct iio_backend { | ||
| 48 | struct list_head entry; | ||
| 49 | const struct iio_backend_ops *ops; | ||
| 50 | struct device *dev; | ||
| 51 | struct module *owner; | ||
| 52 | void *priv; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Helper struct for requesting buffers. This ensures that we have all data | ||
| 57 | * that we need to free the buffer in a device managed action. | ||
| 58 | */ | ||
| 59 | struct iio_backend_buffer_pair { | ||
| 60 | struct iio_backend *back; | ||
| 61 | struct iio_buffer *buffer; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static LIST_HEAD(iio_back_list); | ||
| 65 | static DEFINE_MUTEX(iio_back_lock); | ||
| 66 | |||
| 67 | /* | ||
| 68 | * Helper macros to call backend ops. Makes sure the option is supported. | ||
| 69 | */ | ||
| 70 | #define iio_backend_check_op(back, op) ({ \ | ||
| 71 | struct iio_backend *____back = back; \ | ||
| 72 | int ____ret = 0; \ | ||
| 73 | \ | ||
| 74 | if (!____back->ops->op) \ | ||
| 75 | ____ret = -EOPNOTSUPP; \ | ||
| 76 | \ | ||
| 77 | ____ret; \ | ||
| 78 | }) | ||
| 79 | |||
| 80 | #define iio_backend_op_call(back, op, args...) ({ \ | ||
| 81 | struct iio_backend *__back = back; \ | ||
| 82 | int __ret; \ | ||
| 83 | \ | ||
| 84 | __ret = iio_backend_check_op(__back, op); \ | ||
| 85 | if (!__ret) \ | ||
| 86 | __ret = __back->ops->op(__back, ##args); \ | ||
| 87 | \ | ||
| 88 | __ret; \ | ||
| 89 | }) | ||
| 90 | |||
| 91 | #define iio_backend_ptr_op_call(back, op, args...) ({ \ | ||
| 92 | struct iio_backend *__back = back; \ | ||
| 93 | void *ptr_err; \ | ||
| 94 | int __ret; \ | ||
| 95 | \ | ||
| 96 | __ret = iio_backend_check_op(__back, op); \ | ||
| 97 | if (__ret) \ | ||
| 98 | ptr_err = ERR_PTR(__ret); \ | ||
| 99 | else \ | ||
| 100 | ptr_err = __back->ops->op(__back, ##args); \ | ||
| 101 | \ | ||
| 102 | ptr_err; \ | ||
| 103 | }) | ||
| 104 | |||
| 105 | #define iio_backend_void_op_call(back, op, args...) { \ | ||
| 106 | struct iio_backend *__back = back; \ | ||
| 107 | int __ret; \ | ||
| 108 | \ | ||
| 109 | __ret = iio_backend_check_op(__back, op); \ | ||
| 110 | if (!__ret) \ | ||
| 111 | __back->ops->op(__back, ##args); \ | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * iio_backend_chan_enable - Enable a backend channel | ||
| 116 | * @back: Backend device | ||
| 117 | * @chan: Channel number | ||
| 118 | * | ||
| 119 | * RETURNS: | ||
| 120 | * 0 on success, negative error number on failure. | ||
| 121 | */ | ||
| 122 | int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan) | ||
| 123 | { | ||
| 124 | return iio_backend_op_call(back, chan_enable, chan); | ||
| 125 | } | ||
| 126 | EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND); | ||
| 127 | |||
| 128 | /** | ||
| 129 | * iio_backend_chan_disable - Disable a backend channel | ||
| 130 | * @back: Backend device | ||
| 131 | * @chan: Channel number | ||
| 132 | * | ||
| 133 | * RETURNS: | ||
| 134 | * 0 on success, negative error number on failure. | ||
| 135 | */ | ||
| 136 | int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan) | ||
| 137 | { | ||
| 138 | return iio_backend_op_call(back, chan_disable, chan); | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND); | ||
| 141 | |||
| 142 | static void __iio_backend_disable(void *back) | ||
| 143 | { | ||
| 144 | iio_backend_void_op_call(back, disable); | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * devm_iio_backend_enable - Device managed backend enable | ||
| 149 | * @dev: Consumer device for the backend | ||
| 150 | * @back: Backend device | ||
| 151 | * | ||
| 152 | * RETURNS: | ||
| 153 | * 0 on success, negative error number on failure. | ||
| 154 | */ | ||
| 155 | int devm_iio_backend_enable(struct device *dev, struct iio_backend *back) | ||
| 156 | { | ||
| 157 | int ret; | ||
| 158 | |||
| 159 | ret = iio_backend_op_call(back, enable); | ||
| 160 | if (ret) | ||
| 161 | return ret; | ||
| 162 | |||
| 163 | return devm_add_action_or_reset(dev, __iio_backend_disable, back); | ||
| 164 | } | ||
| 165 | EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * iio_backend_data_format_set - Configure the channel data format | ||
| 169 | * @back: Backend device | ||
| 170 | * @chan: Channel number | ||
| 171 | * @data: Data format | ||
| 172 | * | ||
| 173 | * Properly configure a channel with respect to the expected data format. A | ||
| 174 | * @struct iio_backend_data_fmt must be passed with the settings. | ||
| 175 | * | ||
| 176 | * RETURNS: | ||
| 177 | * 0 on success, negative error number on failure. | ||
| 178 | */ | ||
| 179 | int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, | ||
| 180 | const struct iio_backend_data_fmt *data) | ||
| 181 | { | ||
| 182 | if (!data || data->type >= IIO_BACKEND_DATA_TYPE_MAX) | ||
| 183 | return -EINVAL; | ||
| 184 | |||
| 185 | return iio_backend_op_call(back, data_format_set, chan, data); | ||
| 186 | } | ||
| 187 | EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); | ||
| 188 | |||
| 189 | static void iio_backend_free_buffer(void *arg) | ||
| 190 | { | ||
| 191 | struct iio_backend_buffer_pair *pair = arg; | ||
| 192 | |||
| 193 | iio_backend_void_op_call(pair->back, free_buffer, pair->buffer); | ||
| 194 | } | ||
| 195 | |||
| 196 | /** | ||
| 197 | * devm_iio_backend_request_buffer - Device managed buffer request | ||
| 198 | * @dev: Consumer device for the backend | ||
| 199 | * @back: Backend device | ||
| 200 | * @indio_dev: IIO device | ||
| 201 | * | ||
| 202 | * Request an IIO buffer from the backend. The type of the buffer (typically | ||
| 203 | * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because, | ||
| 204 | * normally, the backend dictates what kind of buffering we can get. | ||
| 205 | * | ||
| 206 | * The backend .free_buffer() hooks is automatically called on @dev detach. | ||
| 207 | * | ||
| 208 | * RETURNS: | ||
| 209 | * 0 on success, negative error number on failure. | ||
| 210 | */ | ||
| 211 | int devm_iio_backend_request_buffer(struct device *dev, | ||
| 212 | struct iio_backend *back, | ||
| 213 | struct iio_dev *indio_dev) | ||
| 214 | { | ||
| 215 | struct iio_backend_buffer_pair *pair; | ||
| 216 | struct iio_buffer *buffer; | ||
| 217 | |||
| 218 | pair = devm_kzalloc(dev, sizeof(*pair), GFP_KERNEL); | ||
| 219 | if (!pair) | ||
| 220 | return -ENOMEM; | ||
| 221 | |||
| 222 | buffer = iio_backend_ptr_op_call(back, request_buffer, indio_dev); | ||
| 223 | if (IS_ERR(buffer)) | ||
| 224 | return PTR_ERR(buffer); | ||
| 225 | |||
| 226 | /* weak reference should be all what we need */ | ||
| 227 | pair->back = back; | ||
| 228 | pair->buffer = buffer; | ||
| 229 | |||
| 230 | return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair); | ||
| 231 | } | ||
| 232 | EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); | ||
| 233 | |||
| 234 | static void iio_backend_release(void *arg) | ||
| 235 | { | ||
| 236 | struct iio_backend *back = arg; | ||
| 237 | |||
| 238 | module_put(back->owner); | ||
| 239 | } | ||
| 240 | |||
| 241 | static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) | ||
| 242 | { | ||
| 243 | struct device_link *link; | ||
| 244 | int ret; | ||
| 245 | |||
| 246 | /* | ||
| 247 | * Make sure the provider cannot be unloaded before the consumer module. | ||
| 248 | * Note that device_links would still guarantee that nothing is | ||
| 249 | * accessible (and breaks) but this makes it explicit that the consumer | ||
| 250 | * module must be also unloaded. | ||
| 251 | */ | ||
| 252 | if (!try_module_get(back->owner)) | ||
| 253 | return dev_err_probe(dev, -ENODEV, | ||
| 254 | "Cannot get module reference\n"); | ||
| 255 | |||
| 256 | ret = devm_add_action_or_reset(dev, iio_backend_release, back); | ||
| 257 | if (ret) | ||
| 258 | return ret; | ||
| 259 | |||
| 260 | link = device_link_add(dev, back->dev, DL_FLAG_AUTOREMOVE_CONSUMER); | ||
| 261 | if (!link) | ||
| 262 | return dev_err_probe(dev, -EINVAL, | ||
| 263 | "Could not link to supplier(%s)\n", | ||
| 264 | dev_name(back->dev)); | ||
| 265 | |||
| 266 | dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev)); | ||
| 267 | |||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | /** | ||
| 272 | * devm_iio_backend_get - Device managed backend device get | ||
| 273 | * @dev: Consumer device for the backend | ||
| 274 | * @name: Backend name | ||
| 275 | * | ||
| 276 | * Get's the backend associated with @dev. | ||
| 277 | * | ||
| 278 | * RETURNS: | ||
| 279 | * A backend pointer, negative error pointer otherwise. | ||
| 280 | */ | ||
| 281 | struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) | ||
| 282 | { | ||
| 283 | struct fwnode_handle *fwnode; | ||
| 284 | struct iio_backend *back; | ||
| 285 | unsigned int index; | ||
| 286 | int ret; | ||
| 287 | |||
| 288 | if (name) { | ||
| 289 | ret = device_property_match_string(dev, "io-backend-names", | ||
| 290 | name); | ||
| 291 | if (ret < 0) | ||
| 292 | return ERR_PTR(ret); | ||
| 293 | index = ret; | ||
| 294 | } else { | ||
| 295 | index = 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index); | ||
| 299 | if (IS_ERR(fwnode)) { | ||
| 300 | dev_err_probe(dev, PTR_ERR(fwnode), | ||
| 301 | "Cannot get Firmware reference\n"); | ||
| 302 | return ERR_CAST(fwnode); | ||
| 303 | } | ||
| 304 | |||
| 305 | guard(mutex)(&iio_back_lock); | ||
| 306 | list_for_each_entry(back, &iio_back_list, entry) { | ||
| 307 | if (!device_match_fwnode(back->dev, fwnode)) | ||
| 308 | continue; | ||
| 309 | |||
| 310 | fwnode_handle_put(fwnode); | ||
| 311 | ret = __devm_iio_backend_get(dev, back); | ||
| 312 | if (ret) | ||
| 313 | return ERR_PTR(ret); | ||
| 314 | |||
| 315 | return back; | ||
| 316 | } | ||
| 317 | |||
| 318 | fwnode_handle_put(fwnode); | ||
| 319 | return ERR_PTR(-EPROBE_DEFER); | ||
| 320 | } | ||
| 321 | EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND); | ||
| 322 | |||
| 323 | /** | ||
| 324 | * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get | ||
| 325 | * @dev: Consumer device for the backend | ||
| 326 | * @fwnode: Firmware node of the backend device | ||
| 327 | * | ||
| 328 | * Search the backend list for a device matching @fwnode. | ||
| 329 | * This API should not be used and it's only present for preventing the first | ||
| 330 | * user of this framework to break it's DT ABI. | ||
| 331 | * | ||
| 332 | * RETURNS: | ||
| 333 | * A backend pointer, negative error pointer otherwise. | ||
| 334 | */ | ||
| 335 | struct iio_backend * | ||
| 336 | __devm_iio_backend_get_from_fwnode_lookup(struct device *dev, | ||
| 337 | struct fwnode_handle *fwnode) | ||
| 338 | { | ||
| 339 | struct iio_backend *back; | ||
| 340 | int ret; | ||
| 341 | |||
| 342 | guard(mutex)(&iio_back_lock); | ||
| 343 | list_for_each_entry(back, &iio_back_list, entry) { | ||
| 344 | if (!device_match_fwnode(back->dev, fwnode)) | ||
| 345 | continue; | ||
| 346 | |||
| 347 | ret = __devm_iio_backend_get(dev, back); | ||
| 348 | if (ret) | ||
| 349 | return ERR_PTR(ret); | ||
| 350 | |||
| 351 | return back; | ||
| 352 | } | ||
| 353 | |||
| 354 | return ERR_PTR(-EPROBE_DEFER); | ||
| 355 | } | ||
| 356 | EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND); | ||
| 357 | |||
| 358 | /** | ||
| 359 | * iio_backend_get_priv - Get driver private data | ||
| 360 | * @back: Backend device | ||
| 361 | */ | ||
| 362 | void *iio_backend_get_priv(const struct iio_backend *back) | ||
| 363 | { | ||
| 364 | return back->priv; | ||
| 365 | } | ||
| 366 | EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND); | ||
| 367 | |||
| 368 | static void iio_backend_unregister(void *arg) | ||
| 369 | { | ||
| 370 | struct iio_backend *back = arg; | ||
| 371 | |||
| 372 | guard(mutex)(&iio_back_lock); | ||
| 373 | list_del(&back->entry); | ||
| 374 | } | ||
| 375 | |||
| 376 | /** | ||
| 377 | * devm_iio_backend_register - Device managed backend device register | ||
| 378 | * @dev: Backend device being registered | ||
| 379 | * @ops: Backend ops | ||
| 380 | * @priv: Device private data | ||
| 381 | * | ||
| 382 | * @ops is mandatory. Not providing it results in -EINVAL. | ||
| 383 | * | ||
| 384 | * RETURNS: | ||
| 385 | * 0 on success, negative error number on failure. | ||
| 386 | */ | ||
| 387 | int devm_iio_backend_register(struct device *dev, | ||
| 388 | const struct iio_backend_ops *ops, void *priv) | ||
| 389 | { | ||
| 390 | struct iio_backend *back; | ||
| 391 | |||
| 392 | if (!ops) | ||
| 393 | return dev_err_probe(dev, -EINVAL, "No backend ops given\n"); | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Through device_links, we guarantee that a frontend device cannot be | ||
| 397 | * bound/exist if the backend driver is not around. Hence, we can bind | ||
| 398 | * the backend object lifetime with the device being passed since | ||
| 399 | * removing it will tear the frontend/consumer down. | ||
| 400 | */ | ||
| 401 | back = devm_kzalloc(dev, sizeof(*back), GFP_KERNEL); | ||
| 402 | if (!back) | ||
| 403 | return -ENOMEM; | ||
| 404 | |||
| 405 | back->ops = ops; | ||
| 406 | back->owner = dev->driver->owner; | ||
| 407 | back->dev = dev; | ||
| 408 | back->priv = priv; | ||
| 409 | scoped_guard(mutex, &iio_back_lock) | ||
| 410 | list_add(&back->entry, &iio_back_list); | ||
| 411 | |||
| 412 | return devm_add_action_or_reset(dev, iio_backend_unregister, back); | ||
| 413 | } | ||
| 414 | EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND); | ||
| 415 | |||
| 416 | MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>"); | ||
| 417 | MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices"); | ||
| 418 | MODULE_LICENSE("GPL"); | ||
| @@ -42,7 +42,7 @@ static DEFINE_IDA(iio_ida); · 41 unmodified lines | |||
| 42 | static dev_t iio_devt; | 42 | static dev_t iio_devt; |
| 43 | 43 | ||
| 44 | #define IIO_DEV_MAX 256 | 44 | #define IIO_DEV_MAX 256 |
| 45 | struct bus_type iio_bus_type = { | 45 | const struct bus_type iio_bus_type = { |
| 46 | .name = "iio", | 46 | .name = "iio", |
| 47 | }; | 47 | }; |
| 48 | EXPORT_SYMBOL(iio_bus_type); | 48 | EXPORT_SYMBOL(iio_bus_type); |
| @@ -213,9 +213,7 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev) · 164 unmodified lines | |||
| 213 | { | 213 | { |
| 214 | struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); | 214 | struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
| 215 | 215 | ||
| 216 | return iio_dev_opaque->currentmode & | 216 | return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES; |
| 217 | (INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE | | ||
| 218 | INDIO_BUFFER_TRIGGERED); | ||
| 219 | } | 217 | } |
| 220 | EXPORT_SYMBOL_GPL(iio_buffer_enabled); | 218 | EXPORT_SYMBOL_GPL(iio_buffer_enabled); |
| 221 | 219 | ||
| @@ -34,24 +34,11 @@ · 33 unmodified lines | |||
| 34 | static int iio_gts_get_gain(const u64 max, const u64 scale) | 34 | static int iio_gts_get_gain(const u64 max, const u64 scale) |
| 35 | { | 35 | { |
| 36 | u64 full = max; | 36 | u64 full = max; |
| 37 | int tmp = 1; | ||
| 38 | 37 | ||
| 39 | if (scale > full || !scale) | 38 | if (scale > full || !scale) |
| 40 | return -EINVAL; | 39 | return -EINVAL; |
| 41 | 40 | ||
| 42 | if (U64_MAX - full < scale) { | 41 | return div64_u64(full, scale); |
| 43 | /* Risk of overflow */ | ||
| 44 | if (full - scale < scale) | ||
| 45 | return 1; | ||
| 46 | |||
| 47 | full -= scale; | ||
| 48 | tmp++; | ||
| 49 | } | ||
| 50 | |||
| 51 | while (full > scale * (u64)tmp) | ||
| 52 | tmp++; | ||
| 53 | |||
| 54 | return tmp; | ||
| 55 | } | 42 | } |
| 56 | 43 | ||
| 57 | /** | 44 | /** |
| @@ -87,13 +87,14 @@ config APDS9960 · 86 unmodified lines | |||
| 87 | module will be called apds9960 | 87 | module will be called apds9960 |
| 88 | 88 | ||
| 89 | config AS73211 | 89 | config AS73211 |
| 90 | tristate "AMS AS73211 XYZ color sensor" | 90 | tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor" |
| 91 | depends on I2C | 91 | depends on I2C |
| 92 | select IIO_BUFFER | 92 | select IIO_BUFFER |
| 93 | select IIO_TRIGGERED_BUFFER | 93 | select IIO_TRIGGERED_BUFFER |
| 94 | help | 94 | help |
| 95 | If you say yes here you get support for the AMS AS73211 | 95 | If you say yes here you get support for the AMS AS73211 |
| 96 | JENCOLOR(R) Digital XYZ Sensor. | 96 | JENCOLOR(R) Digital XYZ and the AMS AS7331 UVA, UVB and UVC |
| 97 | ultraviolet sensors. | ||
| 97 | 98 | ||
| 98 | For triggered measurements, you will need an additional trigger driver | 99 | For triggered measurements, you will need an additional trigger driver |
| 99 | like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER. | 100 | like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER. |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/bitfield.h> | 17 | #include <linux/bitfield.h> |
| 18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/of.h> | 20 | #include <linux/mod_devicetable.h> |
| 21 | 21 | ||
| 22 | #include <linux/iio/iio.h> | 22 | #include <linux/iio/iio.h> |
| 23 | #include <linux/iio/sysfs.h> | 23 | #include <linux/iio/sysfs.h> |
| @@ -15,7 +15,6 @@ · 14 unmodified lines | |||
| 15 | #include <linux/bitfield.h> | 15 | #include <linux/bitfield.h> |
| 16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/mod_devicetable.h> | 18 | #include <linux/mod_devicetable.h> |
| 20 | 19 | ||
| 21 | #include <linux/iio/iio.h> | 20 | #include <linux/iio/iio.h> |
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* | 2 | /* |
| 3 | * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor | 3 | * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 |
| 4 | * UVA, UVB and UVC (DUV) Ultraviolet Sensor | ||
| 4 | * | 5 | * |
| 5 | * Author: Christian Eggers <ceggers@arri.de> | 6 | * Author: Christian Eggers <ceggers@arri.de> |
| 6 | * | 7 | * |
| @@ -9,7 +10,9 @@ · 2 unmodified lines | |||
| 9 | * Color light sensor with 16-bit channels for x, y, z and temperature); | 10 | * Color light sensor with 16-bit channels for x, y, z and temperature); |
| 10 | * 7-bit I2C slave address 0x74 .. 0x77. | 11 | * 7-bit I2C slave address 0x74 .. 0x77. |
| 11 | * | 12 | * |
| 12 | * Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf | 13 | * Datasheets: |
| 14 | * AS73211: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf | ||
| 15 | * AS7331: https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf | ||
| 13 | */ | 16 | */ |
| 14 | 17 | ||
| 15 | #include <linux/bitfield.h> | 18 | #include <linux/bitfield.h> |
| @@ -84,6 +87,20 @@ static const int as73211_hardwaregain_avail[] = { · 68 unmodified lines | |||
| 84 | 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, | 87 | 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, |
| 85 | }; | 88 | }; |
| 86 | 89 | ||
| 90 | struct as73211_data; | ||
| 91 | |||
| 92 | /** | ||
| 93 | * struct as73211_spec_dev_data - device-specific data | ||
| 94 | * @intensity_scale: Function to retrieve intensity scale values. | ||
| 95 | * @channels: Device channels. | ||
| 96 | * @num_channels: Number of channels of the device. | ||
| 97 | */ | ||
| 98 | struct as73211_spec_dev_data { | ||
| 99 | int (*intensity_scale)(struct as73211_data *data, int chan, int *val, int *val2); | ||
| 100 | struct iio_chan_spec const *channels; | ||
| 101 | int num_channels; | ||
| 102 | }; | ||
| 103 | |||
| 87 | /** | 104 | /** |
| 88 | * struct as73211_data - Instance data for one AS73211 | 105 | * struct as73211_data - Instance data for one AS73211 |
| 89 | * @client: I2C client. | 106 | * @client: I2C client. |
| @@ -94,6 +111,7 @@ static const int as73211_hardwaregain_avail[] = { · 4 unmodified lines | |||
| 94 | * @mutex: Keeps cached registers in sync with the device. | 111 | * @mutex: Keeps cached registers in sync with the device. |
| 95 | * @completion: Completion to wait for interrupt. | 112 | * @completion: Completion to wait for interrupt. |
| 96 | * @int_time_avail: Available integration times (depend on sampling frequency). | 113 | * @int_time_avail: Available integration times (depend on sampling frequency). |
| 114 | * @spec_dev: device-specific configuration. | ||
| 97 | */ | 115 | */ |
| 98 | struct as73211_data { | 116 | struct as73211_data { |
| 99 | struct i2c_client *client; | 117 | struct i2c_client *client; |
| @@ -104,6 +122,7 @@ struct as73211_data { · 4 unmodified lines | |||
| 104 | struct mutex mutex; | 122 | struct mutex mutex; |
| 105 | struct completion completion; | 123 | struct completion completion; |
| 106 | int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2]; | 124 | int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2]; |
| 125 | const struct as73211_spec_dev_data *spec_dev; | ||
| 107 | }; | 126 | }; |
| 108 | 127 | ||
| 109 | #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \ | 128 | #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \ |
| @@ -138,6 +157,10 @@ struct as73211_data { · 28 unmodified lines | |||
| 138 | #define AS73211_SCALE_Y 298384270 /* nW/m^2 */ | 157 | #define AS73211_SCALE_Y 298384270 /* nW/m^2 */ |
| 139 | #define AS73211_SCALE_Z 160241927 /* nW/m^2 */ | 158 | #define AS73211_SCALE_Z 160241927 /* nW/m^2 */ |
| 140 | 159 | ||
| 160 | #define AS7331_SCALE_UVA 340000 /* nW/cm^2 */ | ||
| 161 | #define AS7331_SCALE_UVB 378000 /* nW/cm^2 */ | ||
| 162 | #define AS7331_SCALE_UVC 166000 /* nW/cm^2 */ | ||
| 163 | |||
| 141 | /* Channel order MUST match devices result register order */ | 164 | /* Channel order MUST match devices result register order */ |
| 142 | #define AS73211_SCAN_INDEX_TEMP 0 | 165 | #define AS73211_SCAN_INDEX_TEMP 0 |
| 143 | #define AS73211_SCAN_INDEX_X 1 | 166 | #define AS73211_SCAN_INDEX_X 1 |
| @@ -176,6 +199,28 @@ static const struct iio_chan_spec as73211_channels[] = { · 32 unmodified lines | |||
| 176 | IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), | 199 | IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), |
| 177 | }; | 200 | }; |
| 178 | 201 | ||
| 202 | static const struct iio_chan_spec as7331_channels[] = { | ||
| 203 | { | ||
| 204 | .type = IIO_TEMP, | ||
| 205 | .info_mask_separate = | ||
| 206 | BIT(IIO_CHAN_INFO_RAW) | | ||
| 207 | BIT(IIO_CHAN_INFO_OFFSET) | | ||
| 208 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 209 | .address = AS73211_OUT_TEMP, | ||
| 210 | .scan_index = AS73211_SCAN_INDEX_TEMP, | ||
| 211 | .scan_type = { | ||
| 212 | .sign = 'u', | ||
| 213 | .realbits = 16, | ||
| 214 | .storagebits = 16, | ||
| 215 | .endianness = IIO_LE, | ||
| 216 | } | ||
| 217 | }, | ||
| 218 | AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1), | ||
| 219 | AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2), | ||
| 220 | AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3), | ||
| 221 | IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), | ||
| 222 | }; | ||
| 223 | |||
| 179 | static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data) | 224 | static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data) |
| 180 | { | 225 | { |
| 181 | /* | 226 | /* |
| @@ -316,6 +361,48 @@ static int as73211_req_data(struct as73211_data *data) · 134 unmodified lines | |||
| 316 | return 0; | 361 | return 0; |
| 317 | } | 362 | } |
| 318 | 363 | ||
| 364 | static int as73211_intensity_scale(struct as73211_data *data, int chan, | ||
| 365 | int *val, int *val2) | ||
| 366 | { | ||
| 367 | switch (chan) { | ||
| 368 | case IIO_MOD_X: | ||
| 369 | *val = AS73211_SCALE_X; | ||
| 370 | break; | ||
| 371 | case IIO_MOD_Y: | ||
| 372 | *val = AS73211_SCALE_Y; | ||
| 373 | break; | ||
| 374 | case IIO_MOD_Z: | ||
| 375 | *val = AS73211_SCALE_Z; | ||
| 376 | break; | ||
| 377 | default: | ||
| 378 | return -EINVAL; | ||
| 379 | } | ||
| 380 | *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); | ||
| 381 | |||
| 382 | return IIO_VAL_FRACTIONAL; | ||
| 383 | } | ||
| 384 | |||
| 385 | static int as7331_intensity_scale(struct as73211_data *data, int chan, | ||
| 386 | int *val, int *val2) | ||
| 387 | { | ||
| 388 | switch (chan) { | ||
| 389 | case IIO_MOD_LIGHT_UVA: | ||
| 390 | *val = AS7331_SCALE_UVA; | ||
| 391 | break; | ||
| 392 | case IIO_MOD_LIGHT_UVB: | ||
| 393 | *val = AS7331_SCALE_UVB; | ||
| 394 | break; | ||
| 395 | case IIO_MOD_LIGHT_DUV: | ||
| 396 | *val = AS7331_SCALE_UVC; | ||
| 397 | break; | ||
| 398 | default: | ||
| 399 | return -EINVAL; | ||
| 400 | } | ||
| 401 | *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); | ||
| 402 | |||
| 403 | return IIO_VAL_FRACTIONAL; | ||
| 404 | } | ||
| 405 | |||
| 319 | static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, | 406 | static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
| 320 | int *val, int *val2, long mask) | 407 | int *val, int *val2, long mask) |
| 321 | { | 408 | { |
| @@ -355,30 +442,13 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons · 33 unmodified lines | |||
| 355 | *val2 = AS73211_SCALE_TEMP_MICRO; | 442 | *val2 = AS73211_SCALE_TEMP_MICRO; |
| 356 | return IIO_VAL_INT_PLUS_MICRO; | 443 | return IIO_VAL_INT_PLUS_MICRO; |
| 357 | 444 | ||
| 358 | case IIO_INTENSITY: { | 445 | case IIO_INTENSITY: |
| 359 | unsigned int scale; | 446 | return data->spec_dev->intensity_scale(data, chan->channel2, |
| 360 | 447 | val, val2); | |
| 361 | switch (chan->channel2) { | ||
| 362 | case IIO_MOD_X: | ||
| 363 | scale = AS73211_SCALE_X; | ||
| 364 | break; | ||
| 365 | case IIO_MOD_Y: | ||
| 366 | scale = AS73211_SCALE_Y; | ||
| 367 | break; | ||
| 368 | case IIO_MOD_Z: | ||
| 369 | scale = AS73211_SCALE_Z; | ||
| 370 | break; | ||
| 371 | default: | ||
| 372 | return -EINVAL; | ||
| 373 | } | ||
| 374 | scale /= as73211_gain(data); | ||
| 375 | scale /= as73211_integration_time_1024cyc(data); | ||
| 376 | *val = scale; | ||
| 377 | return IIO_VAL_INT; | ||
| 378 | 448 | ||
| 379 | default: | 449 | default: |
| 380 | return -EINVAL; | 450 | return -EINVAL; |
| 381 | }} | 451 | } |
| 382 | 452 | ||
| 383 | case IIO_CHAN_INFO_SAMP_FREQ: | 453 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 384 | /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ | 454 | /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ |
| @@ -676,13 +746,17 @@ static int as73211_probe(struct i2c_client *client) · 291 unmodified lines | |||
| 676 | i2c_set_clientdata(client, indio_dev); | 746 | i2c_set_clientdata(client, indio_dev); |
| 677 | data->client = client; | 747 | data->client = client; |
| 678 | 748 | ||
| 749 | data->spec_dev = i2c_get_match_data(client); | ||
| 750 | if (!data->spec_dev) | ||
| 751 | return -EINVAL; | ||
| 752 | |||
| 679 | mutex_init(&data->mutex); | 753 | mutex_init(&data->mutex); |
| 680 | init_completion(&data->completion); | 754 | init_completion(&data->completion); |
| 681 | 755 | ||
| 682 | indio_dev->info = &as73211_info; | 756 | indio_dev->info = &as73211_info; |
| 683 | indio_dev->name = AS73211_DRV_NAME; | 757 | indio_dev->name = AS73211_DRV_NAME; |
| 684 | indio_dev->channels = as73211_channels; | 758 | indio_dev->channels = data->spec_dev->channels; |
| 685 | indio_dev->num_channels = ARRAY_SIZE(as73211_channels); | 759 | indio_dev->num_channels = data->spec_dev->num_channels; |
| 686 | indio_dev->modes = INDIO_DIRECT_MODE; | 760 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 687 | 761 | ||
| 688 | ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR); | 762 | ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR); |
| @@ -772,14 +846,28 @@ static int as73211_resume(struct device *dev) · 83 unmodified lines | |||
| 772 | static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, | 846 | static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, |
| 773 | as73211_resume); | 847 | as73211_resume); |
| 774 | 848 | ||
| 849 | static const struct as73211_spec_dev_data as73211_spec = { | ||
| 850 | .intensity_scale = as73211_intensity_scale, | ||
| 851 | .channels = as73211_channels, | ||
| 852 | .num_channels = ARRAY_SIZE(as73211_channels), | ||
| 853 | }; | ||
| 854 | |||
| 855 | static const struct as73211_spec_dev_data as7331_spec = { | ||
| 856 | .intensity_scale = as7331_intensity_scale, | ||
| 857 | .channels = as7331_channels, | ||
| 858 | .num_channels = ARRAY_SIZE(as7331_channels), | ||
| 859 | }; | ||
| 860 | |||
| 775 | static const struct of_device_id as73211_of_match[] = { | 861 | static const struct of_device_id as73211_of_match[] = { |
| 776 | { .compatible = "ams,as73211" }, | 862 | { .compatible = "ams,as73211", &as73211_spec }, |
| 863 | { .compatible = "ams,as7331", &as7331_spec }, | ||
| 777 | { } | 864 | { } |
| 778 | }; | 865 | }; |
| 779 | MODULE_DEVICE_TABLE(of, as73211_of_match); | 866 | MODULE_DEVICE_TABLE(of, as73211_of_match); |
| 780 | 867 | ||
| 781 | static const struct i2c_device_id as73211_id[] = { | 868 | static const struct i2c_device_id as73211_id[] = { |
| 782 | { "as73211", 0 }, | 869 | { "as73211", (kernel_ulong_t)&as73211_spec }, |
| 870 | { "as7331", (kernel_ulong_t)&as7331_spec }, | ||
| 783 | { } | 871 | { } |
| 784 | }; | 872 | }; |
| 785 | MODULE_DEVICE_TABLE(i2c, as73211_id); | 873 | MODULE_DEVICE_TABLE(i2c, as73211_id); |
| @@ -14,8 +14,11 @@ · 13 unmodified lines | |||
| 14 | #include "../common/hid-sensors/hid-sensor-trigger.h" | 14 | #include "../common/hid-sensors/hid-sensor-trigger.h" |
| 15 | 15 | ||
| 16 | enum { | 16 | enum { |
| 17 | CHANNEL_SCAN_INDEX_INTENSITY = 0, | 17 | CHANNEL_SCAN_INDEX_INTENSITY, |
| 18 | CHANNEL_SCAN_INDEX_ILLUM = 1, | 18 | CHANNEL_SCAN_INDEX_ILLUM, |
| 19 | CHANNEL_SCAN_INDEX_COLOR_TEMP, | ||
| 20 | CHANNEL_SCAN_INDEX_CHROMATICITY_X, | ||
| 21 | CHANNEL_SCAN_INDEX_CHROMATICITY_Y, | ||
| 19 | CHANNEL_SCAN_INDEX_MAX | 22 | CHANNEL_SCAN_INDEX_MAX |
| 20 | }; | 23 | }; |
| 21 | 24 | ||
| @@ -25,6 +28,7 @@ struct als_state { · 3 unmodified lines | |||
| 25 | struct hid_sensor_hub_callbacks callbacks; | 28 | struct hid_sensor_hub_callbacks callbacks; |
| 26 | struct hid_sensor_common common_attributes; | 29 | struct hid_sensor_common common_attributes; |
| 27 | struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX]; | 30 | struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX]; |
| 31 | struct iio_chan_spec channels[CHANNEL_SCAN_INDEX_MAX + 1]; | ||
| 28 | struct { | 32 | struct { |
| 29 | u32 illum[CHANNEL_SCAN_INDEX_MAX]; | 33 | u32 illum[CHANNEL_SCAN_INDEX_MAX]; |
| 30 | u64 timestamp __aligned(8); | 34 | u64 timestamp __aligned(8); |
| @@ -33,7 +37,18 @@ struct als_state { · 2 unmodified lines | |||
| 33 | int scale_post_decml; | 37 | int scale_post_decml; |
| 34 | int scale_precision; | 38 | int scale_precision; |
| 35 | int value_offset; | 39 | int value_offset; |
| 40 | int num_channels; | ||
| 36 | s64 timestamp; | 41 | s64 timestamp; |
| 42 | unsigned long als_scan_mask[2]; | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* The order of usage ids must match scan index starting from CHANNEL_SCAN_INDEX_INTENSITY */ | ||
| 46 | static const u32 als_usage_ids[] = { | ||
| 47 | HID_USAGE_SENSOR_LIGHT_ILLUM, | ||
| 48 | HID_USAGE_SENSOR_LIGHT_ILLUM, | ||
| 49 | HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE, | ||
| 50 | HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X, | ||
| 51 | HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y, | ||
| 37 | }; | 52 | }; |
| 38 | 53 | ||
| 39 | static const u32 als_sensitivity_addresses[] = { | 54 | static const u32 als_sensitivity_addresses[] = { |
| @@ -65,6 +80,40 @@ static const struct iio_chan_spec als_channels[] = { · 25 unmodified lines | |||
| 65 | BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), | 80 | BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), |
| 66 | .scan_index = CHANNEL_SCAN_INDEX_ILLUM, | 81 | .scan_index = CHANNEL_SCAN_INDEX_ILLUM, |
| 67 | }, | 82 | }, |
| 83 | { | ||
| 84 | .type = IIO_COLORTEMP, | ||
| 85 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | ||
| 86 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | | ||
| 87 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 88 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | | ||
| 89 | BIT(IIO_CHAN_INFO_HYSTERESIS) | | ||
| 90 | BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), | ||
| 91 | .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP, | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | .type = IIO_CHROMATICITY, | ||
| 95 | .modified = 1, | ||
| 96 | .channel2 = IIO_MOD_X, | ||
| 97 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | ||
| 98 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | | ||
| 99 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 100 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | | ||
| 101 | BIT(IIO_CHAN_INFO_HYSTERESIS) | | ||
| 102 | BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), | ||
| 103 | .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X, | ||
| 104 | }, | ||
| 105 | { | ||
| 106 | .type = IIO_CHROMATICITY, | ||
| 107 | .modified = 1, | ||
| 108 | .channel2 = IIO_MOD_Y, | ||
| 109 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | ||
| 110 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | | ||
| 111 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 112 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | | ||
| 113 | BIT(IIO_CHAN_INFO_HYSTERESIS) | | ||
| 114 | BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), | ||
| 115 | .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y, | ||
| 116 | }, | ||
| 68 | IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) | 117 | IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) |
| 69 | }; | 118 | }; |
| 70 | 119 | ||
| @@ -103,6 +152,21 @@ static int als_read_raw(struct iio_dev *indio_dev, · 32 unmodified lines | |||
| 103 | min = als_state->als[chan->scan_index].logical_minimum; | 152 | min = als_state->als[chan->scan_index].logical_minimum; |
| 104 | address = HID_USAGE_SENSOR_LIGHT_ILLUM; | 153 | address = HID_USAGE_SENSOR_LIGHT_ILLUM; |
| 105 | break; | 154 | break; |
| 155 | case CHANNEL_SCAN_INDEX_COLOR_TEMP: | ||
| 156 | report_id = als_state->als[chan->scan_index].report_id; | ||
| 157 | min = als_state->als[chan->scan_index].logical_minimum; | ||
| 158 | address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE; | ||
| 159 | break; | ||
| 160 | case CHANNEL_SCAN_INDEX_CHROMATICITY_X: | ||
| 161 | report_id = als_state->als[chan->scan_index].report_id; | ||
| 162 | min = als_state->als[chan->scan_index].logical_minimum; | ||
| 163 | address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X; | ||
| 164 | break; | ||
| 165 | case CHANNEL_SCAN_INDEX_CHROMATICITY_Y: | ||
| 166 | report_id = als_state->als[chan->scan_index].report_id; | ||
| 167 | min = als_state->als[chan->scan_index].logical_minimum; | ||
| 168 | address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y; | ||
| 169 | break; | ||
| 106 | default: | 170 | default: |
| 107 | report_id = -1; | 171 | report_id = -1; |
| 108 | break; | 172 | break; |
| @@ -223,6 +287,18 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, · 114 unmodified lines | |||
| 223 | als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; | 287 | als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; |
| 224 | ret = 0; | 288 | ret = 0; |
| 225 | break; | 289 | break; |
| 290 | case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE: | ||
| 291 | als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data; | ||
| 292 | ret = 0; | ||
| 293 | break; | ||
| 294 | case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X: | ||
| 295 | als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data; | ||
| 296 | ret = 0; | ||
| 297 | break; | ||
| 298 | case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y: | ||
| 299 | als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data; | ||
| 300 | ret = 0; | ||
| 301 | break; | ||
| 226 | case HID_USAGE_SENSOR_TIME_TIMESTAMP: | 302 | case HID_USAGE_SENSOR_TIME_TIMESTAMP: |
| 227 | als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, | 303 | als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, |
| 228 | *(s64 *)raw_data); | 304 | *(s64 *)raw_data); |
| @@ -238,27 +314,38 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, · 9 unmodified lines | |||
| 238 | /* Parse report which is specific to an usage id*/ | 314 | /* Parse report which is specific to an usage id*/ |
| 239 | static int als_parse_report(struct platform_device *pdev, | 315 | static int als_parse_report(struct platform_device *pdev, |
| 240 | struct hid_sensor_hub_device *hsdev, | 316 | struct hid_sensor_hub_device *hsdev, |
| 241 | struct iio_chan_spec *channels, | ||
| 242 | unsigned usage_id, | 317 | unsigned usage_id, |
| 243 | struct als_state *st) | 318 | struct als_state *st) |
| 244 | { | 319 | { |
| 245 | int ret; | 320 | struct iio_chan_spec *channels; |
| 321 | int ret, index = 0; | ||
| 246 | int i; | 322 | int i; |
| 247 | 323 | ||
| 248 | for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) { | 324 | channels = st->channels; |
| 325 | |||
| 326 | for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) { | ||
| 249 | ret = sensor_hub_input_get_attribute_info(hsdev, | 327 | ret = sensor_hub_input_get_attribute_info(hsdev, |
| 250 | HID_INPUT_REPORT, | 328 | HID_INPUT_REPORT, |
| 251 | usage_id, | 329 | usage_id, |
| 252 | HID_USAGE_SENSOR_LIGHT_ILLUM, | 330 | als_usage_ids[i], |
| 253 | &st->als[i]); | 331 | &st->als[i]); |
| 254 | if (ret < 0) | 332 | if (ret < 0) |
| 255 | return ret; | 333 | continue; |
| 256 | als_adjust_channel_bit_mask(channels, i, st->als[i].size); | 334 | |
| 335 | channels[index] = als_channels[i]; | ||
| 336 | st->als_scan_mask[0] |= BIT(i); | ||
| 337 | als_adjust_channel_bit_mask(channels, index, st->als[i].size); | ||
| 338 | ++index; | ||
| 257 | 339 | ||
| 258 | dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, | 340 | dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, |
| 259 | st->als[i].report_id); | 341 | st->als[i].report_id); |
| 260 | } | 342 | } |
| 261 | 343 | ||
| 344 | st->num_channels = index; | ||
| 345 | /* Return success even if one usage id is present */ | ||
| 346 | if (index) | ||
| 347 | ret = 0; | ||
| 348 | |||
| 262 | st->scale_precision = hid_sensor_format_scale(usage_id, | 349 | st->scale_precision = hid_sensor_format_scale(usage_id, |
| 263 | &st->als[CHANNEL_SCAN_INDEX_INTENSITY], | 350 | &st->als[CHANNEL_SCAN_INDEX_INTENSITY], |
| 264 | &st->scale_pre_decml, &st->scale_post_decml); | 351 | &st->scale_pre_decml, &st->scale_post_decml); |
| @@ -294,15 +381,7 @@ static int hid_als_probe(struct platform_device *pdev) · 29 unmodified lines | |||
| 294 | return ret; | 381 | return ret; |
| 295 | } | 382 | } |
| 296 | 383 | ||
| 297 | indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels, | ||
| 298 | sizeof(als_channels), GFP_KERNEL); | ||
| 299 | if (!indio_dev->channels) { | ||
| 300 | dev_err(&pdev->dev, "failed to duplicate channels\n"); | ||
| 301 | return -ENOMEM; | ||
| 302 | } | ||
| 303 | |||
| 304 | ret = als_parse_report(pdev, hsdev, | 384 | ret = als_parse_report(pdev, hsdev, |
| 305 | (struct iio_chan_spec *)indio_dev->channels, | ||
| 306 | hsdev->usage, | 385 | hsdev->usage, |
| 307 | als_state); | 386 | als_state); |
| 308 | if (ret) { | 387 | if (ret) { |
| @@ -310,8 +389,15 @@ static int hid_als_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 310 | return ret; | 389 | return ret; |
| 311 | } | 390 | } |
| 312 | 391 | ||
| 313 | indio_dev->num_channels = | 392 | /* Add timestamp channel */ |
| 314 | ARRAY_SIZE(als_channels); | 393 | als_state->channels[als_state->num_channels] = als_channels[CHANNEL_SCAN_INDEX_TIMESTAMP]; |
| 394 | |||
| 395 | /* +1 for adding timestamp channel */ | ||
| 396 | indio_dev->num_channels = als_state->num_channels + 1; | ||
| 397 | |||
| 398 | indio_dev->channels = als_state->channels; | ||
| 399 | indio_dev->available_scan_masks = als_state->als_scan_mask; | ||
| 400 | |||
| 315 | indio_dev->info = &als_info; | 401 | indio_dev->info = &als_info; |
| 316 | indio_dev->name = name; | 402 | indio_dev->name = name; |
| 317 | indio_dev->modes = INDIO_DIRECT_MODE; | 403 | indio_dev->modes = INDIO_DIRECT_MODE; |
| @@ -12,10 +12,10 @@ · 11 unmodified lines | |||
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/mod_devicetable.h> | ||
| 15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 16 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
| 17 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 18 | #include <linux/acpi.h> | ||
| 19 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
| 20 | #include <linux/iio/iio.h> | 20 | #include <linux/iio/iio.h> |
| 21 | #include <linux/iio/sysfs.h> | 21 | #include <linux/iio/sysfs.h> |
| @@ -438,7 +438,7 @@ static struct i2c_driver jsa1212_driver = { · 416 unmodified lines | |||
| 438 | .driver = { | 438 | .driver = { |
| 439 | .name = JSA1212_DRIVER_NAME, | 439 | .name = JSA1212_DRIVER_NAME, |
| 440 | .pm = pm_sleep_ptr(&jsa1212_pm_ops), | 440 | .pm = pm_sleep_ptr(&jsa1212_pm_ops), |
| 441 | .acpi_match_table = ACPI_PTR(jsa1212_acpi_match), | 441 | .acpi_match_table = jsa1212_acpi_match, |
| 442 | }, | 442 | }, |
| 443 | .probe = jsa1212_probe, | 443 | .probe = jsa1212_probe, |
| 444 | .remove = jsa1212_remove, | 444 | .remove = jsa1212_remove, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 14 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| @@ -1639,7 +1640,7 @@ static struct i2c_driver ltr501_driver = { · 1623 unmodified lines | |||
| 1639 | .name = LTR501_DRV_NAME, | 1640 | .name = LTR501_DRV_NAME, |
| 1640 | .of_match_table = ltr501_of_match, | 1641 | .of_match_table = ltr501_of_match, |
| 1641 | .pm = pm_sleep_ptr(<r501_pm_ops), | 1642 | .pm = pm_sleep_ptr(<r501_pm_ops), |
| 1642 | .acpi_match_table = ACPI_PTR(ltr_acpi_match), | 1643 | .acpi_match_table = ltr_acpi_match, |
| 1643 | }, | 1644 | }, |
| 1644 | .probe = ltr501_probe, | 1645 | .probe = ltr501_probe, |
| 1645 | .remove = ltr501_remove, | 1646 | .remove = ltr501_remove, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 14 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 15 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
| @@ -19,7 +20,6 @@ · 3 unmodified lines | |||
| 19 | #include <linux/iio/buffer.h> | 20 | #include <linux/iio/buffer.h> |
| 20 | #include <linux/iio/trigger_consumer.h> | 21 | #include <linux/iio/trigger_consumer.h> |
| 21 | #include <linux/iio/triggered_buffer.h> | 22 | #include <linux/iio/triggered_buffer.h> |
| 22 | #include <linux/acpi.h> | ||
| 23 | 23 | ||
| 24 | #define MAX44000_DRV_NAME "max44000" | 24 | #define MAX44000_DRV_NAME "max44000" |
| 25 | 25 | ||
| @@ -603,18 +603,16 @@ static const struct i2c_device_id max44000_id[] = { · 577 unmodified lines | |||
| 603 | }; | 603 | }; |
| 604 | MODULE_DEVICE_TABLE(i2c, max44000_id); | 604 | MODULE_DEVICE_TABLE(i2c, max44000_id); |
| 605 | 605 | ||
| 606 | #ifdef CONFIG_ACPI | ||
| 607 | static const struct acpi_device_id max44000_acpi_match[] = { | 606 | static const struct acpi_device_id max44000_acpi_match[] = { |
| 608 | {"MAX44000", 0}, | 607 | {"MAX44000", 0}, |
| 609 | { } | 608 | { } |
| 610 | }; | 609 | }; |
| 611 | MODULE_DEVICE_TABLE(acpi, max44000_acpi_match); | 610 | MODULE_DEVICE_TABLE(acpi, max44000_acpi_match); |
| 612 | #endif | ||
| 613 | 611 | ||
| 614 | static struct i2c_driver max44000_driver = { | 612 | static struct i2c_driver max44000_driver = { |
| 615 | .driver = { | 613 | .driver = { |
| 616 | .name = MAX44000_DRV_NAME, | 614 | .name = MAX44000_DRV_NAME, |
| 617 | .acpi_match_table = ACPI_PTR(max44000_acpi_match), | 615 | .acpi_match_table = max44000_acpi_match, |
| 618 | }, | 616 | }, |
| 619 | .probe = max44000_probe, | 617 | .probe = max44000_probe, |
| 620 | .id_table = max44000_id, | 618 | .id_table = max44000_id, |
| @@ -10,11 +10,11 @@ · 9 unmodified lines | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 14 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 15 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
| 16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 17 | #include <linux/acpi.h> | ||
| 18 | 18 | ||
| 19 | #include <linux/iio/iio.h> | 19 | #include <linux/iio/iio.h> |
| 20 | #include <linux/iio/buffer.h> | 20 | #include <linux/iio/buffer.h> |
| @@ -1119,7 +1119,7 @@ static struct i2c_driver rpr0521_driver = { · 1098 unmodified lines | |||
| 1119 | .driver = { | 1119 | .driver = { |
| 1120 | .name = RPR0521_DRV_NAME, | 1120 | .name = RPR0521_DRV_NAME, |
| 1121 | .pm = pm_ptr(&rpr0521_pm_ops), | 1121 | .pm = pm_ptr(&rpr0521_pm_ops), |
| 1122 | .acpi_match_table = ACPI_PTR(rpr0521_acpi_match), | 1122 | .acpi_match_table = rpr0521_acpi_match, |
| 1123 | }, | 1123 | }, |
| 1124 | .probe = rpr0521_probe, | 1124 | .probe = rpr0521_probe, |
| 1125 | .remove = rpr0521_remove, | 1125 | .remove = rpr0521_remove, |
| @@ -7,11 +7,11 @@ · 6 unmodified lines | |||
| 7 | * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. | 7 | * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/acpi.h> | ||
| 11 | #include <linux/i2c.h> | 10 | #include <linux/i2c.h> |
| 12 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| 13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/mod_devicetable.h> | ||
| 15 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
| 16 | #include <linux/iio/events.h> | 16 | #include <linux/iio/events.h> |
| 17 | #include <linux/iio/iio.h> | 17 | #include <linux/iio/iio.h> |
| @@ -712,7 +712,7 @@ static struct i2c_driver stk3310_driver = { · 694 unmodified lines | |||
| 712 | .name = "stk3310", | 712 | .name = "stk3310", |
| 713 | .of_match_table = stk3310_of_match, | 713 | .of_match_table = stk3310_of_match, |
| 714 | .pm = pm_sleep_ptr(&stk3310_pm_ops), | 714 | .pm = pm_sleep_ptr(&stk3310_pm_ops), |
| 715 | .acpi_match_table = ACPI_PTR(stk3310_acpi_id), | 715 | .acpi_match_table = stk3310_acpi_id, |
| 716 | }, | 716 | }, |
| 717 | .probe = stk3310_probe, | 717 | .probe = stk3310_probe, |
| 718 | .remove = stk3310_remove, | 718 | .remove = stk3310_remove, |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/acpi.h> | 12 | #include <linux/mod_devicetable.h> |
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 15 | #include <linux/iio/events.h> | 15 | #include <linux/iio/events.h> |
| @@ -972,7 +972,7 @@ static struct i2c_driver us5182d_driver = { · 956 unmodified lines | |||
| 972 | .name = US5182D_DRV_NAME, | 972 | .name = US5182D_DRV_NAME, |
| 973 | .pm = pm_ptr(&us5182d_pm_ops), | 973 | .pm = pm_ptr(&us5182d_pm_ops), |
| 974 | .of_match_table = us5182d_of_match, | 974 | .of_match_table = us5182d_of_match, |
| 975 | .acpi_match_table = ACPI_PTR(us5182d_acpi_match), | 975 | .acpi_match_table = us5182d_acpi_match, |
| 976 | }, | 976 | }, |
| 977 | .probe = us5182d_probe, | 977 | .probe = us5182d_probe, |
| 978 | .remove = us5182d_remove, | 978 | .remove = us5182d_remove, |
| @@ -90,6 +90,7 @@ · 89 unmodified lines | |||
| 90 | #define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0) | 90 | #define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0) |
| 91 | #define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */ | 91 | #define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */ |
| 92 | #define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */ | 92 | #define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */ |
| 93 | #define VCNL4040_PS_CONF2_PS_HD BIT(11) /* Proximity high definition */ | ||
| 93 | #define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */ | 94 | #define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */ |
| 94 | #define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */ | 95 | #define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */ |
| 95 | #define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */ | 96 | #define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */ |
| @@ -114,6 +115,13 @@ · 18 unmodified lines | |||
| 114 | #define VCNL4010_INT_DRDY \ | 115 | #define VCNL4010_INT_DRDY \ |
| 115 | (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS)) | 116 | (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS)) |
| 116 | 117 | ||
| 118 | #define VCNL4040_CONF3_PS_MPS_16BITS 3 /* 8 multi pulses */ | ||
| 119 | #define VCNL4040_CONF3_PS_LED_I_16BITS 3 /* 120 mA */ | ||
| 120 | |||
| 121 | #define VCNL4040_CONF3_PS_SAMPLE_16BITS \ | ||
| 122 | (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \ | ||
| 123 | FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS)) | ||
| 124 | |||
| 117 | static const int vcnl4010_prox_sampling_frequency[][2] = { | 125 | static const int vcnl4010_prox_sampling_frequency[][2] = { |
| 118 | {1, 950000}, | 126 | {1, 950000}, |
| 119 | {3, 906250}, | 127 | {3, 906250}, |
| @@ -195,6 +203,7 @@ struct vcnl4000_data { · 75 unmodified lines | |||
| 195 | enum vcnl4000_device_ids id; | 203 | enum vcnl4000_device_ids id; |
| 196 | int rev; | 204 | int rev; |
| 197 | int al_scale; | 205 | int al_scale; |
| 206 | int ps_scale; | ||
| 198 | u8 ps_int; /* proximity interrupt mode */ | 207 | u8 ps_int; /* proximity interrupt mode */ |
| 199 | u8 als_int; /* ambient light interrupt mode*/ | 208 | u8 als_int; /* ambient light interrupt mode*/ |
| 200 | const struct vcnl4000_chip_spec *chip_spec; | 209 | const struct vcnl4000_chip_spec *chip_spec; |
| @@ -345,6 +354,7 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) · 144 unmodified lines | |||
| 345 | static int vcnl4200_init(struct vcnl4000_data *data) | 354 | static int vcnl4200_init(struct vcnl4000_data *data) |
| 346 | { | 355 | { |
| 347 | int ret, id; | 356 | int ret, id; |
| 357 | u16 regval; | ||
| 348 | 358 | ||
| 349 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); | 359 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); |
| 350 | if (ret < 0) | 360 | if (ret < 0) |
| @@ -386,9 +396,32 @@ static int vcnl4200_init(struct vcnl4000_data *data) · 35 unmodified lines | |||
| 386 | break; | 396 | break; |
| 387 | } | 397 | } |
| 388 | data->al_scale = data->chip_spec->ulux_step; | 398 | data->al_scale = data->chip_spec->ulux_step; |
| 399 | data->ps_scale = 16; | ||
| 389 | mutex_init(&data->vcnl4200_al.lock); | 400 | mutex_init(&data->vcnl4200_al.lock); |
| 390 | mutex_init(&data->vcnl4200_ps.lock); | 401 | mutex_init(&data->vcnl4200_ps.lock); |
| 391 | 402 | ||
| 403 | /* Use 16 bits proximity sensor readings */ | ||
| 404 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); | ||
| 405 | if (ret < 0) | ||
| 406 | return ret; | ||
| 407 | |||
| 408 | regval = ret | VCNL4040_PS_CONF2_PS_HD; | ||
| 409 | ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, | ||
| 410 | regval); | ||
| 411 | if (ret < 0) | ||
| 412 | return ret; | ||
| 413 | |||
| 414 | /* Align proximity sensor sample rate to 16 bits data width */ | ||
| 415 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); | ||
| 416 | if (ret < 0) | ||
| 417 | return ret; | ||
| 418 | |||
| 419 | regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS; | ||
| 420 | ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, | ||
| 421 | regval); | ||
| 422 | if (ret < 0) | ||
| 423 | return ret; | ||
| 424 | |||
| 392 | ret = data->chip_spec->set_power_state(data, true); | 425 | ret = data->chip_spec->set_power_state(data, true); |
| 393 | if (ret < 0) | 426 | if (ret < 0) |
| 394 | return ret; | 427 | return ret; |
| @@ -901,8 +934,9 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, · 506 unmodified lines | |||
| 901 | break; | 934 | break; |
| 902 | case IIO_PROXIMITY: | 935 | case IIO_PROXIMITY: |
| 903 | ret = data->chip_spec->measure_proximity(data, val); | 936 | ret = data->chip_spec->measure_proximity(data, val); |
| 937 | *val2 = data->ps_scale; | ||
| 904 | if (!ret) | 938 | if (!ret) |
| 905 | ret = IIO_VAL_INT; | 939 | ret = IIO_VAL_FRACTIONAL; |
| 906 | break; | 940 | break; |
| 907 | default: | 941 | default: |
| 908 | ret = -EINVAL; | 942 | ret = -EINVAL; |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
| 22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 25 | #include <linux/util_macros.h> | 24 | #include <linux/util_macros.h> |
| 26 | 25 | ||
| @@ -6,6 +6,18 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | menu "Magnetometer sensors" | 7 | menu "Magnetometer sensors" |
| 8 | 8 | ||
| 9 | config AF8133J | ||
| 10 | tristate "Voltafield AF8133J 3-Axis Magnetometer" | ||
| 11 | depends on I2C | ||
| 12 | depends on OF | ||
| 13 | select REGMAP_I2C | ||
| 14 | help | ||
| 15 | Say yes here to build support for Voltafield AF8133J I2C-based | ||
| 16 | 3-axis magnetometer chip. | ||
| 17 | |||
| 18 | To compile this driver as a module, choose M here: the module | ||
| 19 | will be called af8133j. | ||
| 20 | |||
| 9 | config AK8974 | 21 | config AK8974 |
| 10 | tristate "Asahi Kasei AK8974 3-Axis Magnetometer" | 22 | tristate "Asahi Kasei AK8974 3-Axis Magnetometer" |
| 11 | depends on I2C | 23 | depends on I2C |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | # When adding new entries keep the list in alphabetical order | 6 | # When adding new entries keep the list in alphabetical order |
| 7 | obj-$(CONFIG_AF8133J) += af8133j.o | ||
| 7 | obj-$(CONFIG_AK8974) += ak8974.o | 8 | obj-$(CONFIG_AK8974) += ak8974.o |
| 8 | obj-$(CONFIG_AK8975) += ak8975.o | 9 | obj-$(CONFIG_AK8975) += ak8975.o |
| 9 | obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o | 10 | obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o |
| @@ -0,0 +1,528 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * af8133j.c - Voltafield AF8133J magnetometer driver | ||
| 4 | * | ||
| 5 | * Copyright 2021 Icenowy Zheng <icenowy@aosc.io> | ||
| 6 | * Copyright 2024 Ondřej Jirman <megi@xff.cz> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/delay.h> | ||
| 10 | #include <linux/gpio/consumer.h> | ||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/pm_runtime.h> | ||
| 14 | #include <linux/regmap.h> | ||
| 15 | #include <linux/regulator/consumer.h> | ||
| 16 | |||
| 17 | #include <linux/iio/iio.h> | ||
| 18 | #include <linux/iio/trigger_consumer.h> | ||
| 19 | #include <linux/iio/triggered_buffer.h> | ||
| 20 | |||
| 21 | #define AF8133J_REG_OUT 0x03 | ||
| 22 | #define AF8133J_REG_PCODE 0x00 | ||
| 23 | #define AF8133J_REG_PCODE_VAL 0x5e | ||
| 24 | #define AF8133J_REG_STATUS 0x02 | ||
| 25 | #define AF8133J_REG_STATUS_ACQ BIT(0) | ||
| 26 | #define AF8133J_REG_STATE 0x0a | ||
| 27 | #define AF8133J_REG_STATE_STBY 0x00 | ||
| 28 | #define AF8133J_REG_STATE_WORK 0x01 | ||
| 29 | #define AF8133J_REG_RANGE 0x0b | ||
| 30 | #define AF8133J_REG_RANGE_22G 0x12 | ||
| 31 | #define AF8133J_REG_RANGE_12G 0x34 | ||
| 32 | #define AF8133J_REG_SWR 0x11 | ||
| 33 | #define AF8133J_REG_SWR_PERFORM 0x81 | ||
| 34 | |||
| 35 | static const char * const af8133j_supply_names[] = { | ||
| 36 | "avdd", | ||
| 37 | "dvdd", | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct af8133j_data { | ||
| 41 | struct i2c_client *client; | ||
| 42 | struct regmap *regmap; | ||
| 43 | /* | ||
| 44 | * Protect device internal state between starting a measurement | ||
| 45 | * and reading the result. | ||
| 46 | */ | ||
| 47 | struct mutex mutex; | ||
| 48 | struct iio_mount_matrix orientation; | ||
| 49 | |||
| 50 | struct gpio_desc *reset_gpiod; | ||
| 51 | struct regulator_bulk_data supplies[ARRAY_SIZE(af8133j_supply_names)]; | ||
| 52 | |||
| 53 | u8 range; | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum af8133j_axis { | ||
| 57 | AXIS_X = 0, | ||
| 58 | AXIS_Y, | ||
| 59 | AXIS_Z, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct iio_mount_matrix * | ||
| 63 | af8133j_get_mount_matrix(struct iio_dev *indio_dev, | ||
| 64 | const struct iio_chan_spec *chan) | ||
| 65 | { | ||
| 66 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 67 | |||
| 68 | return &data->orientation; | ||
| 69 | } | ||
| 70 | |||
| 71 | static const struct iio_chan_spec_ext_info af8133j_ext_info[] = { | ||
| 72 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, af8133j_get_mount_matrix), | ||
| 73 | { } | ||
| 74 | }; | ||
| 75 | |||
| 76 | #define AF8133J_CHANNEL(_si, _axis) { \ | ||
| 77 | .type = IIO_MAGN, \ | ||
| 78 | .modified = 1, \ | ||
| 79 | .channel2 = IIO_MOD_ ## _axis, \ | ||
| 80 | .address = AXIS_ ## _axis, \ | ||
| 81 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 82 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 83 | .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 84 | .ext_info = af8133j_ext_info, \ | ||
| 85 | .scan_index = _si, \ | ||
| 86 | .scan_type = { \ | ||
| 87 | .sign = 's', \ | ||
| 88 | .realbits = 16, \ | ||
| 89 | .storagebits = 16, \ | ||
| 90 | .endianness = IIO_LE, \ | ||
| 91 | }, \ | ||
| 92 | } | ||
| 93 | |||
| 94 | static const struct iio_chan_spec af8133j_channels[] = { | ||
| 95 | AF8133J_CHANNEL(0, X), | ||
| 96 | AF8133J_CHANNEL(1, Y), | ||
| 97 | AF8133J_CHANNEL(2, Z), | ||
| 98 | IIO_CHAN_SOFT_TIMESTAMP(3), | ||
| 99 | }; | ||
| 100 | |||
| 101 | static int af8133j_product_check(struct af8133j_data *data) | ||
| 102 | { | ||
| 103 | struct device *dev = &data->client->dev; | ||
| 104 | unsigned int val; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | ret = regmap_read(data->regmap, AF8133J_REG_PCODE, &val); | ||
| 108 | if (ret) { | ||
| 109 | dev_err(dev, "Error reading product code (%d)\n", ret); | ||
| 110 | return ret; | ||
| 111 | } | ||
| 112 | |||
| 113 | if (val != AF8133J_REG_PCODE_VAL) { | ||
| 114 | dev_warn(dev, "Invalid product code (0x%02x)\n", val); | ||
| 115 | return 0; /* Allow unknown ID so fallback compatibles work */ | ||
| 116 | } | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int af8133j_reset(struct af8133j_data *data) | ||
| 122 | { | ||
| 123 | struct device *dev = &data->client->dev; | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | if (data->reset_gpiod) { | ||
| 127 | /* If we have GPIO reset line, use it */ | ||
| 128 | gpiod_set_value_cansleep(data->reset_gpiod, 1); | ||
| 129 | udelay(10); | ||
| 130 | gpiod_set_value_cansleep(data->reset_gpiod, 0); | ||
| 131 | } else { | ||
| 132 | /* Otherwise use software reset */ | ||
| 133 | ret = regmap_write(data->regmap, AF8133J_REG_SWR, | ||
| 134 | AF8133J_REG_SWR_PERFORM); | ||
| 135 | if (ret) { | ||
| 136 | dev_err(dev, "Failed to reset the chip\n"); | ||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Wait for reset to finish */ | ||
| 142 | usleep_range(1000, 1100); | ||
| 143 | |||
| 144 | /* Restore range setting */ | ||
| 145 | if (data->range == AF8133J_REG_RANGE_22G) { | ||
| 146 | ret = regmap_write(data->regmap, AF8133J_REG_RANGE, data->range); | ||
| 147 | if (ret) | ||
| 148 | return ret; | ||
| 149 | } | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | static void af8133j_power_down(struct af8133j_data *data) | ||
| 155 | { | ||
| 156 | gpiod_set_value_cansleep(data->reset_gpiod, 1); | ||
| 157 | regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies); | ||
| 158 | } | ||
| 159 | |||
| 160 | static int af8133j_power_up(struct af8133j_data *data) | ||
| 161 | { | ||
| 162 | struct device *dev = &data->client->dev; | ||
| 163 | int ret; | ||
| 164 | |||
| 165 | ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies); | ||
| 166 | if (ret) { | ||
| 167 | dev_err(dev, "Could not enable regulators\n"); | ||
| 168 | return ret; | ||
| 169 | } | ||
| 170 | |||
| 171 | gpiod_set_value_cansleep(data->reset_gpiod, 0); | ||
| 172 | |||
| 173 | /* Wait for power on reset */ | ||
| 174 | usleep_range(15000, 16000); | ||
| 175 | |||
| 176 | ret = af8133j_reset(data); | ||
| 177 | if (ret) { | ||
| 178 | af8133j_power_down(data); | ||
| 179 | return ret; | ||
| 180 | } | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int af8133j_take_measurement(struct af8133j_data *data) | ||
| 186 | { | ||
| 187 | unsigned int val; | ||
| 188 | int ret; | ||
| 189 | |||
| 190 | ret = regmap_write(data->regmap, | ||
| 191 | AF8133J_REG_STATE, AF8133J_REG_STATE_WORK); | ||
| 192 | if (ret) | ||
| 193 | return ret; | ||
| 194 | |||
| 195 | /* The datasheet says "Mesaure Time <1.5ms" */ | ||
| 196 | ret = regmap_read_poll_timeout(data->regmap, AF8133J_REG_STATUS, val, | ||
| 197 | val & AF8133J_REG_STATUS_ACQ, | ||
| 198 | 500, 1500); | ||
| 199 | if (ret) | ||
| 200 | return ret; | ||
| 201 | |||
| 202 | ret = regmap_write(data->regmap, | ||
| 203 | AF8133J_REG_STATE, AF8133J_REG_STATE_STBY); | ||
| 204 | if (ret) | ||
| 205 | return ret; | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static int af8133j_read_measurement(struct af8133j_data *data, __le16 buf[3]) | ||
| 211 | { | ||
| 212 | struct device *dev = &data->client->dev; | ||
| 213 | int ret; | ||
| 214 | |||
| 215 | ret = pm_runtime_resume_and_get(dev); | ||
| 216 | if (ret) { | ||
| 217 | /* | ||
| 218 | * Ignore EACCES because that happens when RPM is disabled | ||
| 219 | * during system sleep, while userspace leave eg. hrtimer | ||
| 220 | * trigger attached and IIO core keeps trying to do measurements. | ||
| 221 | */ | ||
| 222 | if (ret != -EACCES) | ||
| 223 | dev_err(dev, "Failed to power on (%d)\n", ret); | ||
| 224 | return ret; | ||
| 225 | } | ||
| 226 | |||
| 227 | scoped_guard(mutex, &data->mutex) { | ||
| 228 | ret = af8133j_take_measurement(data); | ||
| 229 | if (ret) | ||
| 230 | goto out_rpm_put; | ||
| 231 | |||
| 232 | ret = regmap_bulk_read(data->regmap, AF8133J_REG_OUT, | ||
| 233 | buf, sizeof(__le16) * 3); | ||
| 234 | } | ||
| 235 | |||
| 236 | out_rpm_put: | ||
| 237 | pm_runtime_mark_last_busy(dev); | ||
| 238 | pm_runtime_put_autosuspend(dev); | ||
| 239 | |||
| 240 | return ret; | ||
| 241 | } | ||
| 242 | |||
| 243 | static const int af8133j_scales[][2] = { | ||
| 244 | [0] = { 0, 366210 }, /* 12 gauss */ | ||
| 245 | [1] = { 0, 671386 }, /* 22 gauss */ | ||
| 246 | }; | ||
| 247 | |||
| 248 | static int af8133j_read_raw(struct iio_dev *indio_dev, | ||
| 249 | struct iio_chan_spec const *chan, int *val, | ||
| 250 | int *val2, long mask) | ||
| 251 | { | ||
| 252 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 253 | __le16 buf[3]; | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | switch (mask) { | ||
| 257 | case IIO_CHAN_INFO_RAW: | ||
| 258 | ret = af8133j_read_measurement(data, buf); | ||
| 259 | if (ret) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | *val = sign_extend32(le16_to_cpu(buf[chan->address]), | ||
| 263 | chan->scan_type.realbits - 1); | ||
| 264 | return IIO_VAL_INT; | ||
| 265 | case IIO_CHAN_INFO_SCALE: | ||
| 266 | *val = 0; | ||
| 267 | |||
| 268 | if (data->range == AF8133J_REG_RANGE_12G) | ||
| 269 | *val2 = af8133j_scales[0][1]; | ||
| 270 | else | ||
| 271 | *val2 = af8133j_scales[1][1]; | ||
| 272 | |||
| 273 | return IIO_VAL_INT_PLUS_NANO; | ||
| 274 | default: | ||
| 275 | return -EINVAL; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | static int af8133j_read_avail(struct iio_dev *indio_dev, | ||
| 280 | struct iio_chan_spec const *chan, | ||
| 281 | const int **vals, int *type, int *length, | ||
| 282 | long mask) | ||
| 283 | { | ||
| 284 | switch (mask) { | ||
| 285 | case IIO_CHAN_INFO_SCALE: | ||
| 286 | *vals = (const int *)af8133j_scales; | ||
| 287 | *length = ARRAY_SIZE(af8133j_scales) * 2; | ||
| 288 | *type = IIO_VAL_INT_PLUS_NANO; | ||
| 289 | return IIO_AVAIL_LIST; | ||
| 290 | default: | ||
| 291 | return -EINVAL; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | static int af8133j_set_scale(struct af8133j_data *data, | ||
| 296 | unsigned int val, unsigned int val2) | ||
| 297 | { | ||
| 298 | struct device *dev = &data->client->dev; | ||
| 299 | u8 range; | ||
| 300 | int ret = 0; | ||
| 301 | |||
| 302 | if (af8133j_scales[0][0] == val && af8133j_scales[0][1] == val2) | ||
| 303 | range = AF8133J_REG_RANGE_12G; | ||
| 304 | else if (af8133j_scales[1][0] == val && af8133j_scales[1][1] == val2) | ||
| 305 | range = AF8133J_REG_RANGE_22G; | ||
| 306 | else | ||
| 307 | return -EINVAL; | ||
| 308 | |||
| 309 | pm_runtime_disable(dev); | ||
| 310 | |||
| 311 | /* | ||
| 312 | * When suspended, just store the new range to data->range to be | ||
| 313 | * applied later during power up. | ||
| 314 | */ | ||
| 315 | if (!pm_runtime_status_suspended(dev)) | ||
| 316 | scoped_guard(mutex, &data->mutex) | ||
| 317 | ret = regmap_write(data->regmap, | ||
| 318 | AF8133J_REG_RANGE, range); | ||
| 319 | |||
| 320 | pm_runtime_enable(dev); | ||
| 321 | |||
| 322 | data->range = range; | ||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int af8133j_write_raw(struct iio_dev *indio_dev, | ||
| 327 | struct iio_chan_spec const *chan, | ||
| 328 | int val, int val2, long mask) | ||
| 329 | { | ||
| 330 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 331 | |||
| 332 | switch (mask) { | ||
| 333 | case IIO_CHAN_INFO_SCALE: | ||
| 334 | return af8133j_set_scale(data, val, val2); | ||
| 335 | default: | ||
| 336 | return -EINVAL; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | static int af8133j_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 341 | struct iio_chan_spec const *chan, | ||
| 342 | long mask) | ||
| 343 | { | ||
| 344 | return IIO_VAL_INT_PLUS_NANO; | ||
| 345 | } | ||
| 346 | |||
| 347 | static const struct iio_info af8133j_info = { | ||
| 348 | .read_raw = af8133j_read_raw, | ||
| 349 | .read_avail = af8133j_read_avail, | ||
| 350 | .write_raw = af8133j_write_raw, | ||
| 351 | .write_raw_get_fmt = af8133j_write_raw_get_fmt, | ||
| 352 | }; | ||
| 353 | |||
| 354 | static irqreturn_t af8133j_trigger_handler(int irq, void *p) | ||
| 355 | { | ||
| 356 | struct iio_poll_func *pf = p; | ||
| 357 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 358 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 359 | s64 timestamp = iio_get_time_ns(indio_dev); | ||
| 360 | struct { | ||
| 361 | __le16 values[3]; | ||
| 362 | s64 timestamp __aligned(8); | ||
| 363 | } sample; | ||
| 364 | int ret; | ||
| 365 | |||
| 366 | memset(&sample, 0, sizeof(sample)); | ||
| 367 | |||
| 368 | ret = af8133j_read_measurement(data, sample.values); | ||
| 369 | if (ret) | ||
| 370 | goto out_done; | ||
| 371 | |||
| 372 | iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp); | ||
| 373 | |||
| 374 | out_done: | ||
| 375 | iio_trigger_notify_done(indio_dev->trig); | ||
| 376 | |||
| 377 | return IRQ_HANDLED; | ||
| 378 | } | ||
| 379 | |||
| 380 | static const struct regmap_config af8133j_regmap_config = { | ||
| 381 | .name = "af8133j_regmap", | ||
| 382 | .reg_bits = 8, | ||
| 383 | .val_bits = 8, | ||
| 384 | .max_register = AF8133J_REG_SWR, | ||
| 385 | .cache_type = REGCACHE_NONE, | ||
| 386 | }; | ||
| 387 | |||
| 388 | static void af8133j_power_down_action(void *ptr) | ||
| 389 | { | ||
| 390 | struct af8133j_data *data = ptr; | ||
| 391 | |||
| 392 | if (!pm_runtime_status_suspended(&data->client->dev)) | ||
| 393 | af8133j_power_down(data); | ||
| 394 | } | ||
| 395 | |||
| 396 | static int af8133j_probe(struct i2c_client *client) | ||
| 397 | { | ||
| 398 | struct device *dev = &client->dev; | ||
| 399 | struct af8133j_data *data; | ||
| 400 | struct iio_dev *indio_dev; | ||
| 401 | struct regmap *regmap; | ||
| 402 | int ret, i; | ||
| 403 | |||
| 404 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | ||
| 405 | if (!indio_dev) | ||
| 406 | return -ENOMEM; | ||
| 407 | |||
| 408 | regmap = devm_regmap_init_i2c(client, &af8133j_regmap_config); | ||
| 409 | if (IS_ERR(regmap)) | ||
| 410 | return dev_err_probe(dev, PTR_ERR(regmap), | ||
| 411 | "regmap initialization failed\n"); | ||
| 412 | |||
| 413 | data = iio_priv(indio_dev); | ||
| 414 | i2c_set_clientdata(client, indio_dev); | ||
| 415 | data->client = client; | ||
| 416 | data->regmap = regmap; | ||
| 417 | data->range = AF8133J_REG_RANGE_12G; | ||
| 418 | mutex_init(&data->mutex); | ||
| 419 | |||
| 420 | data->reset_gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); | ||
| 421 | if (IS_ERR(data->reset_gpiod)) | ||
| 422 | return dev_err_probe(dev, PTR_ERR(data->reset_gpiod), | ||
| 423 | "Failed to get reset gpio\n"); | ||
| 424 | |||
| 425 | for (i = 0; i < ARRAY_SIZE(af8133j_supply_names); i++) | ||
| 426 | data->supplies[i].supply = af8133j_supply_names[i]; | ||
| 427 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | ||
| 428 | data->supplies); | ||
| 429 | if (ret) | ||
| 430 | return ret; | ||
| 431 | |||
| 432 | ret = iio_read_mount_matrix(dev, &data->orientation); | ||
| 433 | if (ret) | ||
| 434 | return dev_err_probe(dev, ret, "Failed to read mount matrix\n"); | ||
| 435 | |||
| 436 | ret = af8133j_power_up(data); | ||
| 437 | if (ret) | ||
| 438 | return ret; | ||
| 439 | |||
| 440 | pm_runtime_set_active(dev); | ||
| 441 | |||
| 442 | ret = devm_add_action_or_reset(dev, af8133j_power_down_action, data); | ||
| 443 | if (ret) | ||
| 444 | return ret; | ||
| 445 | |||
| 446 | ret = af8133j_product_check(data); | ||
| 447 | if (ret) | ||
| 448 | return ret; | ||
| 449 | |||
| 450 | pm_runtime_get_noresume(dev); | ||
| 451 | pm_runtime_use_autosuspend(dev); | ||
| 452 | pm_runtime_set_autosuspend_delay(dev, 500); | ||
| 453 | ret = devm_pm_runtime_enable(dev); | ||
| 454 | if (ret) | ||
| 455 | return ret; | ||
| 456 | |||
| 457 | pm_runtime_put_autosuspend(dev); | ||
| 458 | |||
| 459 | indio_dev->info = &af8133j_info; | ||
| 460 | indio_dev->name = "af8133j"; | ||
| 461 | indio_dev->channels = af8133j_channels; | ||
| 462 | indio_dev->num_channels = ARRAY_SIZE(af8133j_channels); | ||
| 463 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 464 | |||
| 465 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, | ||
| 466 | &af8133j_trigger_handler, NULL); | ||
| 467 | if (ret) | ||
| 468 | return dev_err_probe(&client->dev, ret, | ||
| 469 | "Failed to setup iio triggered buffer\n"); | ||
| 470 | |||
| 471 | ret = devm_iio_device_register(dev, indio_dev); | ||
| 472 | if (ret) | ||
| 473 | return dev_err_probe(dev, ret, "Failed to register iio device"); | ||
| 474 | |||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | static int af8133j_runtime_suspend(struct device *dev) | ||
| 479 | { | ||
| 480 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 481 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 482 | |||
| 483 | af8133j_power_down(data); | ||
| 484 | |||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | static int af8133j_runtime_resume(struct device *dev) | ||
| 489 | { | ||
| 490 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 491 | struct af8133j_data *data = iio_priv(indio_dev); | ||
| 492 | |||
| 493 | return af8133j_power_up(data); | ||
| 494 | } | ||
| 495 | |||
| 496 | static const struct dev_pm_ops af8133j_pm_ops = { | ||
| 497 | SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) | ||
| 498 | RUNTIME_PM_OPS(af8133j_runtime_suspend, af8133j_runtime_resume, NULL) | ||
| 499 | }; | ||
| 500 | |||
| 501 | static const struct of_device_id af8133j_of_match[] = { | ||
| 502 | { .compatible = "voltafield,af8133j", }, | ||
| 503 | { } | ||
| 504 | }; | ||
| 505 | MODULE_DEVICE_TABLE(of, af8133j_of_match); | ||
| 506 | |||
| 507 | static const struct i2c_device_id af8133j_id[] = { | ||
| 508 | { "af8133j", 0 }, | ||
| 509 | { } | ||
| 510 | }; | ||
| 511 | MODULE_DEVICE_TABLE(i2c, af8133j_id); | ||
| 512 | |||
| 513 | static struct i2c_driver af8133j_driver = { | ||
| 514 | .driver = { | ||
| 515 | .name = "af8133j", | ||
| 516 | .of_match_table = af8133j_of_match, | ||
| 517 | .pm = pm_ptr(&af8133j_pm_ops), | ||
| 518 | }, | ||
| 519 | .probe = af8133j_probe, | ||
| 520 | .id_table = af8133j_id, | ||
| 521 | }; | ||
| 522 | |||
| 523 | module_i2c_driver(af8133j_driver); | ||
| 524 | |||
| 525 | MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>"); | ||
| 526 | MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>"); | ||
| 527 | MODULE_DESCRIPTION("Voltafield AF8133J magnetic sensor driver"); | ||
| 528 | MODULE_LICENSE("GPL"); | ||
| @@ -11,7 +11,6 @@ · 10 unmodified lines | |||
| 11 | #include <linux/mod_devicetable.h> | 11 | #include <linux/mod_devicetable.h> |
| 12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/acpi.h> | ||
| 15 | #include <linux/regmap.h> | 14 | #include <linux/regmap.h> |
| 16 | 15 | ||
| 17 | #include "bmc150_magn.h" | 16 | #include "bmc150_magn.h" |
| @@ -68,7 +67,7 @@ static struct i2c_driver bmc150_magn_driver = { · 50 unmodified lines | |||
| 68 | .driver = { | 67 | .driver = { |
| 69 | .name = "bmc150_magn_i2c", | 68 | .name = "bmc150_magn_i2c", |
| 70 | .of_match_table = bmc150_magn_of_match, | 69 | .of_match_table = bmc150_magn_of_match, |
| 71 | .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match), | 70 | .acpi_match_table = bmc150_magn_acpi_match, |
| 72 | .pm = &bmc150_magn_pm_ops, | 71 | .pm = &bmc150_magn_pm_ops, |
| 73 | }, | 72 | }, |
| 74 | .probe = bmc150_magn_i2c_probe, | 73 | .probe = bmc150_magn_i2c_probe, |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | |||
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/mod_devicetable.h> | 11 | #include <linux/mod_devicetable.h> |
| 12 | #include <linux/spi/spi.h> | 12 | #include <linux/spi/spi.h> |
| 13 | #include <linux/acpi.h> | ||
| 14 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
| 15 | 14 | ||
| 16 | #include "bmc150_magn.h" | 15 | #include "bmc150_magn.h" |
| @@ -55,7 +54,7 @@ static struct spi_driver bmc150_magn_spi_driver = { · 38 unmodified lines | |||
| 55 | .remove = bmc150_magn_spi_remove, | 54 | .remove = bmc150_magn_spi_remove, |
| 56 | .id_table = bmc150_magn_spi_id, | 55 | .id_table = bmc150_magn_spi_id, |
| 57 | .driver = { | 56 | .driver = { |
| 58 | .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match), | 57 | .acpi_match_table = bmc150_magn_acpi_match, |
| 59 | .name = "bmc150_magn_spi", | 58 | .name = "bmc150_magn_spi", |
| 60 | }, | 59 | }, |
| 61 | }; | 60 | }; |
| @@ -10,11 +10,11 @@ · 9 unmodified lines | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | ||
| 13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 14 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 16 | #include <linux/regmap.h> | 17 | #include <linux/regmap.h> |
| 17 | #include <linux/acpi.h> | ||
| 18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
| 19 | 19 | ||
| 20 | #include <linux/iio/iio.h> | 20 | #include <linux/iio/iio.h> |
| @@ -573,7 +573,7 @@ static struct i2c_driver mmc35240_driver = { · 552 unmodified lines | |||
| 573 | .name = MMC35240_DRV_NAME, | 573 | .name = MMC35240_DRV_NAME, |
| 574 | .of_match_table = mmc35240_of_match, | 574 | .of_match_table = mmc35240_of_match, |
| 575 | .pm = pm_sleep_ptr(&mmc35240_pm_ops), | 575 | .pm = pm_sleep_ptr(&mmc35240_pm_ops), |
| 576 | .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), | 576 | .acpi_match_table = mmc35240_acpi_match, |
| 577 | }, | 577 | }, |
| 578 | .probe = mmc35240_probe, | 578 | .probe = mmc35240_probe, |
| 579 | .id_table = mmc35240_id, | 579 | .id_table = mmc35240_id, |
| @@ -5,8 +5,8 @@ · 4 unmodified lines | |||
| 5 | * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com> | 5 | * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com> |
| 6 | */ | 6 | */ |
| 7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 8 | #include <linux/mod_devicetable.h> | ||
| 8 | #include <linux/spi/spi.h> | 9 | #include <linux/spi/spi.h> |
| 9 | #include <linux/acpi.h> | ||
| 10 | 10 | ||
| 11 | #include <linux/iio/sysfs.h> | 11 | #include <linux/iio/sysfs.h> |
| 12 | #include <linux/iio/iio.h> | 12 | #include <linux/iio/iio.h> |
| @@ -144,7 +144,7 @@ MODULE_DEVICE_TABLE(acpi, max5487_acpi_match); · 131 unmodified lines | |||
| 144 | static struct spi_driver max5487_driver = { | 144 | static struct spi_driver max5487_driver = { |
| 145 | .driver = { | 145 | .driver = { |
| 146 | .name = "max5487", | 146 | .name = "max5487", |
| 147 | .acpi_match_table = ACPI_PTR(max5487_acpi_match), | 147 | .acpi_match_table = max5487_acpi_match, |
| 148 | }, | 148 | }, |
| 149 | .id_table = max5487_id, | 149 | .id_table = max5487_id, |
| 150 | .probe = max5487_spi_probe, | 150 | .probe = max5487_spi_probe, |
| @@ -114,6 +114,8 @@ config HSC030PA · 113 unmodified lines | |||
| 114 | depends on (I2C || SPI_MASTER) | 114 | depends on (I2C || SPI_MASTER) |
| 115 | select HSC030PA_I2C if I2C | 115 | select HSC030PA_I2C if I2C |
| 116 | select HSC030PA_SPI if SPI_MASTER | 116 | select HSC030PA_SPI if SPI_MASTER |
| 117 | select IIO_BUFFER | ||
| 118 | select IIO_TRIGGERED_BUFFER | ||
| 117 | help | 119 | help |
| 118 | Say Y here to build support for the Honeywell TruStability | 120 | Say Y here to build support for the Honeywell TruStability |
| 119 | HSC and SSC pressure and temperature sensor series. | 121 | HSC and SSC pressure and temperature sensor series. |
| @@ -181,7 +183,9 @@ config MPL3115 · 61 unmodified lines | |||
| 181 | 183 | ||
| 182 | config MPRLS0025PA | 184 | config MPRLS0025PA |
| 183 | tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)" | 185 | tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)" |
| 184 | depends on I2C | 186 | depends on (I2C || SPI_MASTER) |
| 187 | select MPRLS0025PA_I2C if I2C | ||
| 188 | select MPRLS0025PA_SPI if SPI_MASTER | ||
| 185 | select IIO_BUFFER | 189 | select IIO_BUFFER |
| 186 | select IIO_TRIGGERED_BUFFER | 190 | select IIO_TRIGGERED_BUFFER |
| 187 | help | 191 | help |
| @@ -192,6 +196,16 @@ config MPRLS0025PA · 4 unmodified lines | |||
| 192 | To compile this driver as a module, choose M here: the module will be | 196 | To compile this driver as a module, choose M here: the module will be |
| 193 | called mprls0025pa. | 197 | called mprls0025pa. |
| 194 | 198 | ||
| 199 | config MPRLS0025PA_I2C | ||
| 200 | tristate | ||
| 201 | depends on MPRLS0025PA | ||
| 202 | depends on I2C | ||
| 203 | |||
| 204 | config MPRLS0025PA_SPI | ||
| 205 | tristate | ||
| 206 | depends on MPRLS0025PA | ||
| 207 | depends on SPI_MASTER | ||
| 208 | |||
| 195 | config MS5611 | 209 | config MS5611 |
| 196 | tristate "Measurement Specialties MS5611 pressure sensor driver" | 210 | tristate "Measurement Specialties MS5611 pressure sensor driver" |
| 197 | select IIO_BUFFER | 211 | select IIO_BUFFER |
| @@ -24,6 +24,8 @@ obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o · 23 unmodified lines | |||
| 24 | obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o | 24 | obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o |
| 25 | obj-$(CONFIG_MPL3115) += mpl3115.o | 25 | obj-$(CONFIG_MPL3115) += mpl3115.o |
| 26 | obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o | 26 | obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o |
| 27 | obj-$(CONFIG_MPRLS0025PA_I2C) += mprls0025pa_i2c.o | ||
| 28 | obj-$(CONFIG_MPRLS0025PA_SPI) += mprls0025pa_spi.o | ||
| 27 | obj-$(CONFIG_MS5611) += ms5611_core.o | 29 | obj-$(CONFIG_MS5611) += ms5611_core.o |
| 28 | obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o | 30 | obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o |
| 29 | obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o | 31 | obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o |
| @@ -11,12 +11,12 @@ · 10 unmodified lines | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/mod_devicetable.h> | ||
| 14 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 15 | #include <linux/iio/iio.h> | 16 | #include <linux/iio/iio.h> |
| 16 | #include <linux/iio/sysfs.h> | 17 | #include <linux/iio/sysfs.h> |
| 17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 18 | #include <linux/util_macros.h> | 19 | #include <linux/util_macros.h> |
| 19 | #include <linux/acpi.h> | ||
| 20 | 20 | ||
| 21 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
| 22 | 22 | ||
| @@ -400,20 +400,18 @@ static const struct i2c_device_id hp206c_id[] = { · 377 unmodified lines | |||
| 400 | }; | 400 | }; |
| 401 | MODULE_DEVICE_TABLE(i2c, hp206c_id); | 401 | MODULE_DEVICE_TABLE(i2c, hp206c_id); |
| 402 | 402 | ||
| 403 | #ifdef CONFIG_ACPI | ||
| 404 | static const struct acpi_device_id hp206c_acpi_match[] = { | 403 | static const struct acpi_device_id hp206c_acpi_match[] = { |
| 405 | {"HOP206C", 0}, | 404 | {"HOP206C", 0}, |
| 406 | { }, | 405 | { }, |
| 407 | }; | 406 | }; |
| 408 | MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match); | 407 | MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match); |
| 409 | #endif | ||
| 410 | 408 | ||
| 411 | static struct i2c_driver hp206c_driver = { | 409 | static struct i2c_driver hp206c_driver = { |
| 412 | .probe = hp206c_probe, | 410 | .probe = hp206c_probe, |
| 413 | .id_table = hp206c_id, | 411 | .id_table = hp206c_id, |
| 414 | .driver = { | 412 | .driver = { |
| 415 | .name = "hp206c", | 413 | .name = "hp206c", |
| 416 | .acpi_match_table = ACPI_PTR(hp206c_acpi_match), | 414 | .acpi_match_table = hp206c_acpi_match, |
| 417 | }, | 415 | }, |
| 418 | }; | 416 | }; |
| 419 | 417 | ||
| @@ -22,8 +22,11 @@ · 21 unmodified lines | |||
| 22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 23 | #include <linux/units.h> | 23 | #include <linux/units.h> |
| 24 | 24 | ||
| 25 | #include <linux/iio/buffer.h> | ||
| 25 | #include <linux/iio/iio.h> | 26 | #include <linux/iio/iio.h> |
| 26 | #include <linux/iio/sysfs.h> | 27 | #include <linux/iio/sysfs.h> |
| 28 | #include <linux/iio/trigger_consumer.h> | ||
| 29 | #include <linux/iio/triggered_buffer.h> | ||
| 27 | 30 | ||
| 28 | #include <asm/unaligned.h> | 31 | #include <asm/unaligned.h> |
| 29 | 32 | ||
| @@ -297,6 +300,29 @@ static int hsc_get_measurement(struct hsc_data *data) · 267 unmodified lines | |||
| 297 | return 0; | 300 | return 0; |
| 298 | } | 301 | } |
| 299 | 302 | ||
| 303 | static irqreturn_t hsc_trigger_handler(int irq, void *private) | ||
| 304 | { | ||
| 305 | struct iio_poll_func *pf = private; | ||
| 306 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 307 | struct hsc_data *data = iio_priv(indio_dev); | ||
| 308 | int ret; | ||
| 309 | |||
| 310 | ret = hsc_get_measurement(data); | ||
| 311 | if (ret) | ||
| 312 | goto error; | ||
| 313 | |||
| 314 | memcpy(&data->scan.chan[0], &data->buffer[0], 2); | ||
| 315 | memcpy(&data->scan.chan[1], &data->buffer[2], 2); | ||
| 316 | |||
| 317 | iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, | ||
| 318 | iio_get_time_ns(indio_dev)); | ||
| 319 | |||
| 320 | error: | ||
| 321 | iio_trigger_notify_done(indio_dev->trig); | ||
| 322 | |||
| 323 | return IRQ_HANDLED; | ||
| 324 | } | ||
| 325 | |||
| 300 | /* | 326 | /* |
| 301 | * IIO ABI expects | 327 | * IIO ABI expects |
| 302 | * value = (conv + offset) * scale | 328 | * value = (conv + offset) * scale |
| @@ -382,13 +408,29 @@ static const struct iio_chan_spec hsc_channels[] = { · 79 unmodified lines | |||
| 382 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | 408 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 383 | BIT(IIO_CHAN_INFO_SCALE) | | 409 | BIT(IIO_CHAN_INFO_SCALE) | |
| 384 | BIT(IIO_CHAN_INFO_OFFSET), | 410 | BIT(IIO_CHAN_INFO_OFFSET), |
| 411 | .scan_index = 0, | ||
| 412 | .scan_type = { | ||
| 413 | .sign = 'u', | ||
| 414 | .realbits = 14, | ||
| 415 | .storagebits = 16, | ||
| 416 | .endianness = IIO_BE, | ||
| 417 | }, | ||
| 385 | }, | 418 | }, |
| 386 | { | 419 | { |
| 387 | .type = IIO_TEMP, | 420 | .type = IIO_TEMP, |
| 388 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | 421 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 389 | BIT(IIO_CHAN_INFO_SCALE) | | 422 | BIT(IIO_CHAN_INFO_SCALE) | |
| 390 | BIT(IIO_CHAN_INFO_OFFSET), | 423 | BIT(IIO_CHAN_INFO_OFFSET), |
| 424 | .scan_index = 1, | ||
| 425 | .scan_type = { | ||
| 426 | .sign = 'u', | ||
| 427 | .realbits = 11, | ||
| 428 | .storagebits = 16, | ||
| 429 | .shift = 5, | ||
| 430 | .endianness = IIO_BE, | ||
| 431 | }, | ||
| 391 | }, | 432 | }, |
| 433 | IIO_CHAN_SOFT_TIMESTAMP(2), | ||
| 392 | }; | 434 | }; |
| 393 | 435 | ||
| 394 | static const struct iio_info hsc_info = { | 436 | static const struct iio_info hsc_info = { |
| @@ -406,7 +448,7 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv) · 11 unmodified lines | |||
| 406 | struct hsc_data *hsc; | 448 | struct hsc_data *hsc; |
| 407 | struct iio_dev *indio_dev; | 449 | struct iio_dev *indio_dev; |
| 408 | const char *triplet; | 450 | const char *triplet; |
| 409 | u64 tmp; | 451 | s64 tmp; |
| 410 | int ret; | 452 | int ret; |
| 411 | 453 | ||
| 412 | indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc)); | 454 | indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc)); |
| @@ -485,6 +527,11 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv) · 72 unmodified lines | |||
| 485 | indio_dev->channels = hsc->chip->channels; | 527 | indio_dev->channels = hsc->chip->channels; |
| 486 | indio_dev->num_channels = hsc->chip->num_channels; | 528 | indio_dev->num_channels = hsc->chip->num_channels; |
| 487 | 529 | ||
| 530 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, | ||
| 531 | hsc_trigger_handler, NULL); | ||
| 532 | if (ret) | ||
| 533 | return ret; | ||
| 534 | |||
| 488 | return devm_iio_device_register(dev, indio_dev); | 535 | return devm_iio_device_register(dev, indio_dev); |
| 489 | } | 536 | } |
| 490 | EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA); | 537 | EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA); |
| @@ -10,7 +10,10 @@ · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | 12 | ||
| 13 | #include <linux/iio/iio.h> | ||
| 14 | |||
| 13 | #define HSC_REG_MEASUREMENT_RD_SIZE 4 | 15 | #define HSC_REG_MEASUREMENT_RD_SIZE 4 |
| 16 | #define HSC_RESP_TIME_MS 2 | ||
| 14 | 17 | ||
| 15 | struct device; | 18 | struct device; |
| 16 | 19 | ||
| @@ -53,6 +56,10 @@ struct hsc_data { · 36 unmodified lines | |||
| 53 | s32 p_scale_dec; | 56 | s32 p_scale_dec; |
| 54 | s64 p_offset; | 57 | s64 p_offset; |
| 55 | s32 p_offset_dec; | 58 | s32 p_offset_dec; |
| 59 | struct { | ||
| 60 | __be16 chan[2]; | ||
| 61 | s64 timestamp __aligned(8); | ||
| 62 | } scan; | ||
| 56 | u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); | 63 | u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); |
| 57 | }; | 64 | }; |
| 58 | 65 | ||
| @@ -4,14 +4,17 @@ · 3 unmodified lines | |||
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> | 5 | * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> |
| 6 | * | 6 | * |
| 7 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf [hsc] | 7 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf |
| 8 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf [i2c related] | 8 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/device.h> | ||
| 11 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 12 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 13 | #include <linux/mod_devicetable.h> | 15 | #include <linux/mod_devicetable.h> |
| 14 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/types.h> | ||
| 15 | 18 | ||
| 16 | #include <linux/iio/iio.h> | 19 | #include <linux/iio/iio.h> |
| 17 | 20 | ||
| @@ -23,6 +26,8 @@ static int hsc_i2c_recv(struct hsc_data *data) · 5 unmodified lines | |||
| 23 | struct i2c_msg msg; | 26 | struct i2c_msg msg; |
| 24 | int ret; | 27 | int ret; |
| 25 | 28 | ||
| 29 | msleep_interruptible(HSC_RESP_TIME_MS); | ||
| 30 | |||
| 26 | msg.addr = client->addr; | 31 | msg.addr = client->addr; |
| 27 | msg.flags = client->flags | I2C_M_RD; | 32 | msg.flags = client->flags | I2C_M_RD; |
| 28 | msg.len = HSC_REG_MEASUREMENT_RD_SIZE; | 33 | msg.len = HSC_REG_MEASUREMENT_RD_SIZE; |
| @@ -4,13 +4,17 @@ · 3 unmodified lines | |||
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> | 5 | * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro> |
| 6 | * | 6 | * |
| 7 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf | 7 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-spi-comms-digital-ouptu-pressure-sensors-tn-008202-3-en-ciid-45843.pdf |
| 8 | * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf | ||
| 8 | */ | 9 | */ |
| 9 | 10 | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/device.h> | ||
| 10 | #include <linux/mod_devicetable.h> | 13 | #include <linux/mod_devicetable.h> |
| 11 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 12 | #include <linux/spi/spi.h> | 15 | #include <linux/spi/spi.h> |
| 13 | #include <linux/stddef.h> | 16 | #include <linux/stddef.h> |
| 17 | #include <linux/types.h> | ||
| 14 | 18 | ||
| 15 | #include <linux/iio/iio.h> | 19 | #include <linux/iio/iio.h> |
| 16 | 20 | ||
| @@ -25,6 +29,7 @@ static int hsc_spi_recv(struct hsc_data *data) · 8 unmodified lines | |||
| 25 | .len = HSC_REG_MEASUREMENT_RD_SIZE, | 29 | .len = HSC_REG_MEASUREMENT_RD_SIZE, |
| 26 | }; | 30 | }; |
| 27 | 31 | ||
| 32 | msleep_interruptible(HSC_RESP_TIME_MS); | ||
| 28 | return spi_sync_transfer(spi, &xfer, 1); | 33 | return spi_sync_transfer(spi, &xfer, 1); |
| 29 | } | 34 | } |
| 30 | 35 | ||
| @@ -5,17 +5,13 @@ · 4 unmodified lines | |||
| 5 | * Copyright (c) Andreas Klinger <ak@it-klinger.de> | 5 | * Copyright (c) Andreas Klinger <ak@it-klinger.de> |
| 6 | * | 6 | * |
| 7 | * Data sheet: | 7 | * Data sheet: |
| 8 | * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ | 8 | * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf |
| 9 | * products/sensors/pressure-sensors/board-mount-pressure-sensors/ | ||
| 10 | * micropressure-mpr-series/documents/ | ||
| 11 | * sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf | ||
| 12 | * | 9 | * |
| 13 | * 7-bit I2C default slave address: 0x18 | ||
| 14 | */ | 10 | */ |
| 15 | 11 | ||
| 16 | #include <linux/delay.h> | 12 | #include <linux/array_size.h> |
| 17 | #include <linux/device.h> | 13 | #include <linux/bitfield.h> |
| 18 | #include <linux/i2c.h> | 14 | #include <linux/bits.h> |
| 19 | #include <linux/math64.h> | 15 | #include <linux/math64.h> |
| 20 | #include <linux/mod_devicetable.h> | 16 | #include <linux/mod_devicetable.h> |
| 21 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| @@ -25,7 +21,6 @@ · 3 unmodified lines | |||
| 25 | #include <linux/gpio/consumer.h> | 21 | #include <linux/gpio/consumer.h> |
| 26 | 22 | ||
| 27 | #include <linux/iio/buffer.h> | 23 | #include <linux/iio/buffer.h> |
| 28 | #include <linux/iio/iio.h> | ||
| 29 | #include <linux/iio/trigger_consumer.h> | 24 | #include <linux/iio/trigger_consumer.h> |
| 30 | #include <linux/iio/triggered_buffer.h> | 25 | #include <linux/iio/triggered_buffer.h> |
| 31 | 26 | ||
| @@ -33,11 +28,15 @@ · 1 unmodified line | |||
| 33 | 28 | ||
| 34 | #include <asm/unaligned.h> | 29 | #include <asm/unaligned.h> |
| 35 | 30 | ||
| 36 | /* bits in i2c status byte */ | 31 | #include "mprls0025pa.h" |
| 37 | #define MPR_I2C_POWER BIT(6) /* device is powered */ | 32 | |
| 38 | #define MPR_I2C_BUSY BIT(5) /* device is busy */ | 33 | /* bits in status byte */ |
| 39 | #define MPR_I2C_MEMORY BIT(2) /* integrity test passed */ | 34 | #define MPR_ST_POWER BIT(6) /* device is powered */ |
| 40 | #define MPR_I2C_MATH BIT(0) /* internal math saturation */ | 35 | #define MPR_ST_BUSY BIT(5) /* device is busy */ |
| 36 | #define MPR_ST_MEMORY BIT(2) /* integrity test passed */ | ||
| 37 | #define MPR_ST_MATH BIT(0) /* internal math saturation */ | ||
| 38 | |||
| 39 | #define MPR_ST_ERR_FLAG (MPR_ST_BUSY | MPR_ST_MEMORY | MPR_ST_MATH) | ||
| 41 | 40 | ||
| 42 | /* | 41 | /* |
| 43 | * support _RAW sysfs interface: | 42 | * support _RAW sysfs interface: |
| @@ -70,60 +69,87 @@ · 26 unmodified lines | |||
| 70 | * transfer function B: 2.5% to 22.5% of 2^24 | 69 | * transfer function B: 2.5% to 22.5% of 2^24 |
| 71 | * transfer function C: 20% to 80% of 2^24 | 70 | * transfer function C: 20% to 80% of 2^24 |
| 72 | */ | 71 | */ |
| 73 | enum mpr_func_id { | ||
| 74 | MPR_FUNCTION_A, | ||
| 75 | MPR_FUNCTION_B, | ||
| 76 | MPR_FUNCTION_C, | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct mpr_func_spec { | 72 | struct mpr_func_spec { |
| 80 | u32 output_min; | 73 | u32 output_min; |
| 81 | u32 output_max; | 74 | u32 output_max; |
| 82 | }; | 75 | }; |
| 83 | 76 | ||
| 84 | static const struct mpr_func_spec mpr_func_spec[] = { | 77 | static const struct mpr_func_spec mpr_func_spec[] = { |
| 85 | [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494}, | 78 | [MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 }, |
| 86 | [MPR_FUNCTION_B] = {.output_min = 419430, .output_max = 3774874}, | 79 | [MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 }, |
| 87 | [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773}, | 80 | [MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 }, |
| 88 | }; | 81 | }; |
| 89 | 82 | ||
| 90 | struct mpr_chan { | 83 | enum mpr_variants { |
| 91 | s32 pres; /* pressure value */ | 84 | MPR0001BA = 0x00, MPR01_6BA = 0x01, MPR02_5BA = 0x02, MPR0060MG = 0x03, |
| 92 | s64 ts; /* timestamp */ | 85 | MPR0100MG = 0x04, MPR0160MG = 0x05, MPR0250MG = 0x06, MPR0400MG = 0x07, |
| 86 | MPR0600MG = 0x08, MPR0001BG = 0x09, MPR01_6BG = 0x0a, MPR02_5BG = 0x0b, | ||
| 87 | MPR0100KA = 0x0c, MPR0160KA = 0x0d, MPR0250KA = 0x0e, MPR0006KG = 0x0f, | ||
| 88 | MPR0010KG = 0x10, MPR0016KG = 0x11, MPR0025KG = 0x12, MPR0040KG = 0x13, | ||
| 89 | MPR0060KG = 0x14, MPR0100KG = 0x15, MPR0160KG = 0x16, MPR0250KG = 0x17, | ||
| 90 | MPR0015PA = 0x18, MPR0025PA = 0x19, MPR0030PA = 0x1a, MPR0001PG = 0x1b, | ||
| 91 | MPR0005PG = 0x1c, MPR0015PG = 0x1d, MPR0030PG = 0x1e, MPR0300YG = 0x1f, | ||
| 92 | MPR_VARIANTS_MAX | ||
| 93 | }; | ||
| 94 | |||
| 95 | static const char * const mpr_triplet_variants[MPR_VARIANTS_MAX] = { | ||
| 96 | [MPR0001BA] = "0001BA", [MPR01_6BA] = "01.6BA", [MPR02_5BA] = "02.5BA", | ||
| 97 | [MPR0060MG] = "0060MG", [MPR0100MG] = "0100MG", [MPR0160MG] = "0160MG", | ||
| 98 | [MPR0250MG] = "0250MG", [MPR0400MG] = "0400MG", [MPR0600MG] = "0600MG", | ||
| 99 | [MPR0001BG] = "0001BG", [MPR01_6BG] = "01.6BG", [MPR02_5BG] = "02.5BG", | ||
| 100 | [MPR0100KA] = "0100KA", [MPR0160KA] = "0160KA", [MPR0250KA] = "0250KA", | ||
| 101 | [MPR0006KG] = "0006KG", [MPR0010KG] = "0010KG", [MPR0016KG] = "0016KG", | ||
| 102 | [MPR0025KG] = "0025KG", [MPR0040KG] = "0040KG", [MPR0060KG] = "0060KG", | ||
| 103 | [MPR0100KG] = "0100KG", [MPR0160KG] = "0160KG", [MPR0250KG] = "0250KG", | ||
| 104 | [MPR0015PA] = "0015PA", [MPR0025PA] = "0025PA", [MPR0030PA] = "0030PA", | ||
| 105 | [MPR0001PG] = "0001PG", [MPR0005PG] = "0005PG", [MPR0015PG] = "0015PG", | ||
| 106 | [MPR0030PG] = "0030PG", [MPR0300YG] = "0300YG" | ||
| 107 | }; | ||
| 108 | |||
| 109 | /** | ||
| 110 | * struct mpr_range_config - list of pressure ranges based on nomenclature | ||
| 111 | * @pmin: lowest pressure that can be measured | ||
| 112 | * @pmax: highest pressure that can be measured | ||
| 113 | */ | ||
| 114 | struct mpr_range_config { | ||
| 115 | const s32 pmin; | ||
| 116 | const s32 pmax; | ||
| 93 | }; | 117 | }; |
| 94 | 118 | ||
| 95 | struct mpr_data { | 119 | /* All min max limits have been converted to pascals */ |
| 96 | struct i2c_client *client; | 120 | static const struct mpr_range_config mpr_range_config[MPR_VARIANTS_MAX] = { |
| 97 | struct mutex lock; /* | 121 | [MPR0001BA] = { .pmin = 0, .pmax = 100000 }, |
| 98 | * access to device during read | 122 | [MPR01_6BA] = { .pmin = 0, .pmax = 160000 }, |
| 99 | */ | 123 | [MPR02_5BA] = { .pmin = 0, .pmax = 250000 }, |
| 100 | u32 pmin; /* minimal pressure in pascal */ | 124 | [MPR0060MG] = { .pmin = 0, .pmax = 6000 }, |
| 101 | u32 pmax; /* maximal pressure in pascal */ | 125 | [MPR0100MG] = { .pmin = 0, .pmax = 10000 }, |
| 102 | enum mpr_func_id function; /* transfer function */ | 126 | [MPR0160MG] = { .pmin = 0, .pmax = 16000 }, |
| 103 | u32 outmin; /* | 127 | [MPR0250MG] = { .pmin = 0, .pmax = 25000 }, |
| 104 | * minimal numerical range raw | 128 | [MPR0400MG] = { .pmin = 0, .pmax = 40000 }, |
| 105 | * value from sensor | 129 | [MPR0600MG] = { .pmin = 0, .pmax = 60000 }, |
| 106 | */ | 130 | [MPR0001BG] = { .pmin = 0, .pmax = 100000 }, |
| 107 | u32 outmax; /* | 131 | [MPR01_6BG] = { .pmin = 0, .pmax = 160000 }, |
| 108 | * maximal numerical range raw | 132 | [MPR02_5BG] = { .pmin = 0, .pmax = 250000 }, |
| 109 | * value from sensor | 133 | [MPR0100KA] = { .pmin = 0, .pmax = 100000 }, |
| 110 | */ | 134 | [MPR0160KA] = { .pmin = 0, .pmax = 160000 }, |
| 111 | int scale; /* int part of scale */ | 135 | [MPR0250KA] = { .pmin = 0, .pmax = 250000 }, |
| 112 | int scale2; /* nano part of scale */ | 136 | [MPR0006KG] = { .pmin = 0, .pmax = 6000 }, |
| 113 | int offset; /* int part of offset */ | 137 | [MPR0010KG] = { .pmin = 0, .pmax = 10000 }, |
| 114 | int offset2; /* nano part of offset */ | 138 | [MPR0016KG] = { .pmin = 0, .pmax = 16000 }, |
| 115 | struct gpio_desc *gpiod_reset; /* reset */ | 139 | [MPR0025KG] = { .pmin = 0, .pmax = 25000 }, |
| 116 | int irq; /* | 140 | [MPR0040KG] = { .pmin = 0, .pmax = 40000 }, |
| 117 | * end of conversion irq; | 141 | [MPR0060KG] = { .pmin = 0, .pmax = 60000 }, |
| 118 | * used to distinguish between | 142 | [MPR0100KG] = { .pmin = 0, .pmax = 100000 }, |
| 119 | * irq mode and reading in a | 143 | [MPR0160KG] = { .pmin = 0, .pmax = 160000 }, |
| 120 | * loop until data is ready | 144 | [MPR0250KG] = { .pmin = 0, .pmax = 250000 }, |
| 121 | */ | 145 | [MPR0015PA] = { .pmin = 0, .pmax = 103421 }, |
| 122 | struct completion completion; /* handshake from irq to read */ | 146 | [MPR0025PA] = { .pmin = 0, .pmax = 172369 }, |
| 123 | struct mpr_chan chan; /* | 147 | [MPR0030PA] = { .pmin = 0, .pmax = 206843 }, |
| 124 | * channel values for buffered | 148 | [MPR0001PG] = { .pmin = 0, .pmax = 6895 }, |
| 125 | * mode | 149 | [MPR0005PG] = { .pmin = 0, .pmax = 34474 }, |
| 126 | */ | 150 | [MPR0015PG] = { .pmin = 0, .pmax = 103421 }, |
| 151 | [MPR0030PG] = { .pmin = 0, .pmax = 206843 }, | ||
| 152 | [MPR0300YG] = { .pmin = 0, .pmax = 39997 } | ||
| 127 | }; | 153 | }; |
| 128 | 154 | ||
| 129 | static const struct iio_chan_spec mpr_channels[] = { | 155 | static const struct iio_chan_spec mpr_channels[] = { |
| @@ -153,11 +179,11 @@ static void mpr_reset(struct mpr_data *data) · 23 unmodified lines | |||
| 153 | } | 179 | } |
| 154 | 180 | ||
| 155 | /** | 181 | /** |
| 156 | * mpr_read_pressure() - Read pressure value from sensor via I2C | 182 | * mpr_read_pressure() - Read pressure value from sensor |
| 157 | * @data: Pointer to private data struct. | 183 | * @data: Pointer to private data struct. |
| 158 | * @press: Output value read from sensor. | 184 | * @press: Output value read from sensor. |
| 159 | * | 185 | * |
| 160 | * Reading from the sensor by sending and receiving I2C telegrams. | 186 | * Reading from the sensor by sending and receiving telegrams. |
| 161 | * | 187 | * |
| 162 | * If there is an end of conversion (EOC) interrupt registered the function | 188 | * If there is an end of conversion (EOC) interrupt registered the function |
| 163 | * waits for a maximum of one second for the interrupt. | 189 | * waits for a maximum of one second for the interrupt. |
| @@ -170,25 +196,17 @@ static void mpr_reset(struct mpr_data *data) · 6 unmodified lines | |||
| 170 | */ | 196 | */ |
| 171 | static int mpr_read_pressure(struct mpr_data *data, s32 *press) | 197 | static int mpr_read_pressure(struct mpr_data *data, s32 *press) |
| 172 | { | 198 | { |
| 173 | struct device *dev = &data->client->dev; | 199 | struct device *dev = data->dev; |
| 174 | int ret, i; | 200 | int ret, i; |
| 175 | u8 wdata[] = {0xAA, 0x00, 0x00}; | ||
| 176 | s32 status; | ||
| 177 | int nloops = 10; | 201 | int nloops = 10; |
| 178 | u8 buf[4]; | ||
| 179 | 202 | ||
| 180 | reinit_completion(&data->completion); | 203 | reinit_completion(&data->completion); |
| 181 | 204 | ||
| 182 | ret = i2c_master_send(data->client, wdata, sizeof(wdata)); | 205 | ret = data->ops->write(data, MPR_CMD_SYNC, MPR_PKT_SYNC_LEN); |
| 183 | if (ret < 0) { | 206 | if (ret < 0) { |
| 184 | dev_err(dev, "error while writing ret: %d\n", ret); | 207 | dev_err(dev, "error while writing ret: %d\n", ret); |
| 185 | return ret; | 208 | return ret; |
| 186 | } | 209 | } |
| 187 | if (ret != sizeof(wdata)) { | ||
| 188 | dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, | ||
| 189 | (u32)sizeof(wdata)); | ||
| 190 | return -EIO; | ||
| 191 | } | ||
| 192 | 210 | ||
| 193 | if (data->irq > 0) { | 211 | if (data->irq > 0) { |
| 194 | ret = wait_for_completion_timeout(&data->completion, HZ); | 212 | ret = wait_for_completion_timeout(&data->completion, HZ); |
| @@ -206,14 +224,14 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press) · 11 unmodified lines | |||
| 206 | * quite long | 224 | * quite long |
| 207 | */ | 225 | */ |
| 208 | usleep_range(5000, 10000); | 226 | usleep_range(5000, 10000); |
| 209 | status = i2c_smbus_read_byte(data->client); | 227 | ret = data->ops->read(data, MPR_CMD_NOP, 1); |
| 210 | if (status < 0) { | 228 | if (ret < 0) { |
| 211 | dev_err(dev, | 229 | dev_err(dev, |
| 212 | "error while reading, status: %d\n", | 230 | "error while reading, status: %d\n", |
| 213 | status); | 231 | ret); |
| 214 | return status; | 232 | return ret; |
| 215 | } | 233 | } |
| 216 | if (!(status & MPR_I2C_BUSY)) | 234 | if (!(data->buffer[0] & MPR_ST_ERR_FLAG)) |
| 217 | break; | 235 | break; |
| 218 | } | 236 | } |
| 219 | if (i == nloops) { | 237 | if (i == nloops) { |
| @@ -222,29 +240,19 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press) · 2 unmodified lines | |||
| 222 | } | 240 | } |
| 223 | } | 241 | } |
| 224 | 242 | ||
| 225 | ret = i2c_master_recv(data->client, buf, sizeof(buf)); | 243 | ret = data->ops->read(data, MPR_CMD_NOP, MPR_PKT_NOP_LEN); |
| 226 | if (ret < 0) { | 244 | if (ret < 0) |
| 227 | dev_err(dev, "error in i2c_master_recv ret: %d\n", ret); | ||
| 228 | return ret; | 245 | return ret; |
| 229 | } | ||
| 230 | if (ret != sizeof(buf)) { | ||
| 231 | dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, | ||
| 232 | (u32)sizeof(buf)); | ||
| 233 | return -EIO; | ||
| 234 | } | ||
| 235 | 246 | ||
| 236 | if (buf[0] & MPR_I2C_BUSY) { | 247 | if (data->buffer[0] & MPR_ST_ERR_FLAG) { |
| 237 | /* | 248 | dev_err(data->dev, |
| 238 | * it should never be the case that status still indicates | 249 | "unexpected status byte %02x\n", data->buffer[0]); |
| 239 | * business | ||
| 240 | */ | ||
| 241 | dev_err(dev, "data still not ready: %08x\n", buf[0]); | ||
| 242 | return -ETIMEDOUT; | 250 | return -ETIMEDOUT; |
| 243 | } | 251 | } |
| 244 | 252 | ||
| 245 | *press = get_unaligned_be24(&buf[1]); | 253 | *press = get_unaligned_be24(&data->buffer[1]); |
| 246 | 254 | ||
| 247 | dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press); | 255 | dev_dbg(dev, "received: %*ph cnt: %d\n", ret, data->buffer, *press); |
| 248 | 256 | ||
| 249 | return 0; | 257 | return 0; |
| 250 | } | 258 | } |
| @@ -271,7 +279,7 @@ static irqreturn_t mpr_trigger_handler(int irq, void *p) · 20 unmodified lines | |||
| 271 | goto err; | 279 | goto err; |
| 272 | 280 | ||
| 273 | iio_push_to_buffers_with_timestamp(indio_dev, &data->chan, | 281 | iio_push_to_buffers_with_timestamp(indio_dev, &data->chan, |
| 274 | iio_get_time_ns(indio_dev)); | 282 | iio_get_time_ns(indio_dev)); |
| 275 | 283 | ||
| 276 | err: | 284 | err: |
| 277 | mutex_unlock(&data->lock); | 285 | mutex_unlock(&data->lock); |
| @@ -316,25 +324,23 @@ static const struct iio_info mpr_info = { · 38 unmodified lines | |||
| 316 | .read_raw = &mpr_read_raw, | 324 | .read_raw = &mpr_read_raw, |
| 317 | }; | 325 | }; |
| 318 | 326 | ||
| 319 | static int mpr_probe(struct i2c_client *client) | 327 | int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) |
| 320 | { | 328 | { |
| 321 | int ret; | 329 | int ret; |
| 322 | struct mpr_data *data; | 330 | struct mpr_data *data; |
| 323 | struct iio_dev *indio_dev; | 331 | struct iio_dev *indio_dev; |
| 324 | struct device *dev = &client->dev; | 332 | const char *triplet; |
| 325 | s64 scale, offset; | 333 | s64 scale, offset; |
| 326 | 334 | u32 func; | |
| 327 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) | ||
| 328 | return dev_err_probe(dev, -EOPNOTSUPP, | ||
| 329 | "I2C functionality not supported\n"); | ||
| 330 | 335 | ||
| 331 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | 336 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); |
| 332 | if (!indio_dev) | 337 | if (!indio_dev) |
| 333 | return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n"); | 338 | return -ENOMEM; |
| 334 | 339 | ||
| 335 | data = iio_priv(indio_dev); | 340 | data = iio_priv(indio_dev); |
| 336 | data->client = client; | 341 | data->dev = dev; |
| 337 | data->irq = client->irq; | 342 | data->ops = ops; |
| 343 | data->irq = irq; | ||
| 338 | 344 | ||
| 339 | mutex_init(&data->lock); | 345 | mutex_init(&data->lock); |
| 340 | init_completion(&data->completion); | 346 | init_completion(&data->completion); |
| @@ -348,103 +354,102 @@ static int mpr_probe(struct i2c_client *client) · 7 unmodified lines | |||
| 348 | ret = devm_regulator_get_enable(dev, "vdd"); | 354 | ret = devm_regulator_get_enable(dev, "vdd"); |
| 349 | if (ret) | 355 | if (ret) |
| 350 | return dev_err_probe(dev, ret, | 356 | return dev_err_probe(dev, ret, |
| 351 | "can't get and enable vdd supply\n"); | 357 | "can't get and enable vdd supply\n"); |
| 352 | 358 | ||
| 353 | if (dev_fwnode(dev)) { | 359 | ret = data->ops->init(data->dev); |
| 360 | if (ret) | ||
| 361 | return ret; | ||
| 362 | |||
| 363 | ret = device_property_read_u32(dev, | ||
| 364 | "honeywell,transfer-function", &func); | ||
| 365 | if (ret) | ||
| 366 | return dev_err_probe(dev, ret, | ||
| 367 | "honeywell,transfer-function could not be read\n"); | ||
| 368 | data->function = func - 1; | ||
| 369 | if (data->function > MPR_FUNCTION_C) | ||
| 370 | return dev_err_probe(dev, -EINVAL, | ||
| 371 | "honeywell,transfer-function %d invalid\n", | ||
| 372 | data->function); | ||
| 373 | |||
| 374 | ret = device_property_read_string(dev, "honeywell,pressure-triplet", | ||
| 375 | &triplet); | ||
| 376 | if (ret) { | ||
| 354 | ret = device_property_read_u32(dev, "honeywell,pmin-pascal", | 377 | ret = device_property_read_u32(dev, "honeywell,pmin-pascal", |
| 355 | &data->pmin); | 378 | &data->pmin); |
| 356 | if (ret) | 379 | if (ret) |
| 357 | return dev_err_probe(dev, ret, | 380 | return dev_err_probe(dev, ret, |
| 358 | "honeywell,pmin-pascal could not be read\n"); | 381 | "honeywell,pmin-pascal could not be read\n"); |
| 382 | |||
| 359 | ret = device_property_read_u32(dev, "honeywell,pmax-pascal", | 383 | ret = device_property_read_u32(dev, "honeywell,pmax-pascal", |
| 360 | &data->pmax); | 384 | &data->pmax); |
| 361 | if (ret) | 385 | if (ret) |
| 362 | return dev_err_probe(dev, ret, | 386 | return dev_err_probe(dev, ret, |
| 363 | "honeywell,pmax-pascal could not be read\n"); | 387 | "honeywell,pmax-pascal could not be read\n"); |
| 364 | ret = device_property_read_u32(dev, | ||
| 365 | "honeywell,transfer-function", &data->function); | ||
| 366 | if (ret) | ||
| 367 | return dev_err_probe(dev, ret, | ||
| 368 | "honeywell,transfer-function could not be read\n"); | ||
| 369 | if (data->function > MPR_FUNCTION_C) | ||
| 370 | return dev_err_probe(dev, -EINVAL, | ||
| 371 | "honeywell,transfer-function %d invalid\n", | ||
| 372 | data->function); | ||
| 373 | } else { | 388 | } else { |
| 374 | /* when loaded as i2c device we need to use default values */ | 389 | ret = device_property_match_property_string(dev, |
| 375 | dev_notice(dev, "firmware node not found; using defaults\n"); | 390 | "honeywell,pressure-triplet", |
| 376 | data->pmin = 0; | 391 | mpr_triplet_variants, |
| 377 | data->pmax = 172369; /* 25 psi */ | 392 | MPR_VARIANTS_MAX); |
| 378 | data->function = MPR_FUNCTION_A; | 393 | if (ret < 0) |
| 394 | return dev_err_probe(dev, -EINVAL, | ||
| 395 | "honeywell,pressure-triplet is invalid\n"); | ||
| 396 | |||
| 397 | data->pmin = mpr_range_config[ret].pmin; | ||
| 398 | data->pmax = mpr_range_config[ret].pmax; | ||
| 379 | } | 399 | } |
| 380 | 400 | ||
| 401 | if (data->pmin >= data->pmax) | ||
| 402 | return dev_err_probe(dev, -EINVAL, | ||
| 403 | "pressure limits are invalid\n"); | ||
| 404 | |||
| 381 | data->outmin = mpr_func_spec[data->function].output_min; | 405 | data->outmin = mpr_func_spec[data->function].output_min; |
| 382 | data->outmax = mpr_func_spec[data->function].output_max; | 406 | data->outmax = mpr_func_spec[data->function].output_max; |
| 383 | 407 | ||
| 384 | /* use 64 bit calculation for preserving a reasonable precision */ | 408 | /* use 64 bit calculation for preserving a reasonable precision */ |
| 385 | scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, | 409 | scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, |
| 386 | data->outmax - data->outmin); | 410 | data->outmax - data->outmin); |
| 387 | data->scale = div_s64_rem(scale, NANO, &data->scale2); | 411 | data->scale = div_s64_rem(scale, NANO, &data->scale2); |
| 388 | /* | 412 | /* |
| 389 | * multiply with NANO before dividing by scale and later divide by NANO | 413 | * multiply with NANO before dividing by scale and later divide by NANO |
| 390 | * again. | 414 | * again. |
| 391 | */ | 415 | */ |
| 392 | offset = ((-1LL) * (s64)data->outmin) * NANO - | 416 | offset = ((-1LL) * (s64)data->outmin) * NANO - |
| 393 | div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); | 417 | div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); |
| 394 | data->offset = div_s64_rem(offset, NANO, &data->offset2); | 418 | data->offset = div_s64_rem(offset, NANO, &data->offset2); |
| 395 | 419 | ||
| 396 | if (data->irq > 0) { | 420 | if (data->irq > 0) { |
| 397 | ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, | 421 | ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, |
| 398 | IRQF_TRIGGER_RISING, client->name, data); | 422 | IRQF_TRIGGER_RISING, |
| 423 | dev_name(dev), | ||
| 424 | data); | ||
| 399 | if (ret) | 425 | if (ret) |
| 400 | return dev_err_probe(dev, ret, | 426 | return dev_err_probe(dev, ret, |
| 401 | "request irq %d failed\n", data->irq); | 427 | "request irq %d failed\n", data->irq); |
| 402 | } | 428 | } |
| 403 | 429 | ||
| 404 | data->gpiod_reset = devm_gpiod_get_optional(dev, "reset", | 430 | data->gpiod_reset = devm_gpiod_get_optional(dev, "reset", |
| 405 | GPIOD_OUT_HIGH); | 431 | GPIOD_OUT_HIGH); |
| 406 | if (IS_ERR(data->gpiod_reset)) | 432 | if (IS_ERR(data->gpiod_reset)) |
| 407 | return dev_err_probe(dev, PTR_ERR(data->gpiod_reset), | 433 | return dev_err_probe(dev, PTR_ERR(data->gpiod_reset), |
| 408 | "request reset-gpio failed\n"); | 434 | "request reset-gpio failed\n"); |
| 409 | 435 | ||
| 410 | mpr_reset(data); | 436 | mpr_reset(data); |
| 411 | 437 | ||
| 412 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, | 438 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, |
| 413 | mpr_trigger_handler, NULL); | 439 | mpr_trigger_handler, NULL); |
| 414 | if (ret) | 440 | if (ret) |
| 415 | return dev_err_probe(dev, ret, | 441 | return dev_err_probe(dev, ret, |
| 416 | "iio triggered buffer setup failed\n"); | 442 | "iio triggered buffer setup failed\n"); |
| 417 | 443 | ||
| 418 | ret = devm_iio_device_register(dev, indio_dev); | 444 | ret = devm_iio_device_register(dev, indio_dev); |
| 419 | if (ret) | 445 | if (ret) |
| 420 | return dev_err_probe(dev, ret, | 446 | return dev_err_probe(dev, ret, |
| 421 | "unable to register iio device\n"); | 447 | "unable to register iio device\n"); |
| 422 | 448 | ||
| 423 | return 0; | 449 | return 0; |
| 424 | } | 450 | } |
| 425 | 451 | EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA); | |
| 426 | static const struct of_device_id mpr_matches[] = { | ||
| 427 | { .compatible = "honeywell,mprls0025pa" }, | ||
| 428 | { } | ||
| 429 | }; | ||
| 430 | MODULE_DEVICE_TABLE(of, mpr_matches); | ||
| 431 | |||
| 432 | static const struct i2c_device_id mpr_id[] = { | ||
| 433 | { "mprls0025pa" }, | ||
| 434 | { } | ||
| 435 | }; | ||
| 436 | MODULE_DEVICE_TABLE(i2c, mpr_id); | ||
| 437 | |||
| 438 | static struct i2c_driver mpr_driver = { | ||
| 439 | .probe = mpr_probe, | ||
| 440 | .id_table = mpr_id, | ||
| 441 | .driver = { | ||
| 442 | .name = "mprls0025pa", | ||
| 443 | .of_match_table = mpr_matches, | ||
| 444 | }, | ||
| 445 | }; | ||
| 446 | module_i2c_driver(mpr_driver); | ||
| 447 | 452 | ||
| 448 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); | 453 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); |
| 449 | MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver"); | 454 | MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver"); |
| 450 | MODULE_LICENSE("GPL"); | 455 | MODULE_LICENSE("GPL"); |
| @@ -0,0 +1,102 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver | ||
| 4 | * | ||
| 5 | * Copyright (c) Andreas Klinger <ak@it-klinger.de> | ||
| 6 | * | ||
| 7 | * Data sheet: | ||
| 8 | * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _MPRLS0025PA_H | ||
| 12 | #define _MPRLS0025PA_H | ||
| 13 | |||
| 14 | #include <linux/completion.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | #include <linux/stddef.h> | ||
| 19 | #include <linux/types.h> | ||
| 20 | |||
| 21 | #include <linux/iio/iio.h> | ||
| 22 | |||
| 23 | #define MPR_MEASUREMENT_RD_SIZE 4 | ||
| 24 | #define MPR_CMD_NOP 0xf0 | ||
| 25 | #define MPR_CMD_SYNC 0xaa | ||
| 26 | #define MPR_PKT_NOP_LEN MPR_MEASUREMENT_RD_SIZE | ||
| 27 | #define MPR_PKT_SYNC_LEN 3 | ||
| 28 | |||
| 29 | struct device; | ||
| 30 | |||
| 31 | struct iio_chan_spec; | ||
| 32 | struct iio_dev; | ||
| 33 | |||
| 34 | struct mpr_data; | ||
| 35 | struct mpr_ops; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * struct mpr_chan | ||
| 39 | * @pres: pressure value | ||
| 40 | * @ts: timestamp | ||
| 41 | */ | ||
| 42 | struct mpr_chan { | ||
| 43 | s32 pres; | ||
| 44 | s64 ts; | ||
| 45 | }; | ||
| 46 | |||
| 47 | enum mpr_func_id { | ||
| 48 | MPR_FUNCTION_A, | ||
| 49 | MPR_FUNCTION_B, | ||
| 50 | MPR_FUNCTION_C, | ||
| 51 | }; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * struct mpr_data | ||
| 55 | * @dev: current device structure | ||
| 56 | * @ops: functions that implement the sensor reads/writes, bus init | ||
| 57 | * @lock: access to device during read | ||
| 58 | * @pmin: minimal pressure in pascal | ||
| 59 | * @pmax: maximal pressure in pascal | ||
| 60 | * @function: transfer function | ||
| 61 | * @outmin: minimum raw pressure in counts (based on transfer function) | ||
| 62 | * @outmax: maximum raw pressure in counts (based on transfer function) | ||
| 63 | * @scale: pressure scale | ||
| 64 | * @scale2: pressure scale, decimal number | ||
| 65 | * @offset: pressure offset | ||
| 66 | * @offset2: pressure offset, decimal number | ||
| 67 | * @gpiod_reset: reset | ||
| 68 | * @irq: end of conversion irq. used to distinguish between irq mode and | ||
| 69 | * reading in a loop until data is ready | ||
| 70 | * @completion: handshake from irq to read | ||
| 71 | * @chan: channel values for buffered mode | ||
| 72 | * @buffer: raw conversion data | ||
| 73 | */ | ||
| 74 | struct mpr_data { | ||
| 75 | struct device *dev; | ||
| 76 | const struct mpr_ops *ops; | ||
| 77 | struct mutex lock; | ||
| 78 | u32 pmin; | ||
| 79 | u32 pmax; | ||
| 80 | enum mpr_func_id function; | ||
| 81 | u32 outmin; | ||
| 82 | u32 outmax; | ||
| 83 | int scale; | ||
| 84 | int scale2; | ||
| 85 | int offset; | ||
| 86 | int offset2; | ||
| 87 | struct gpio_desc *gpiod_reset; | ||
| 88 | int irq; | ||
| 89 | struct completion completion; | ||
| 90 | struct mpr_chan chan; | ||
| 91 | u8 buffer[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct mpr_ops { | ||
| 95 | int (*init)(struct device *dev); | ||
| 96 | int (*read)(struct mpr_data *data, const u8 cmd, const u8 cnt); | ||
| 97 | int (*write)(struct mpr_data *data, const u8 cmd, const u8 cnt); | ||
| 98 | }; | ||
| 99 | |||
| 100 | int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq); | ||
| 101 | |||
| 102 | #endif | ||
| @@ -0,0 +1,100 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver | ||
| 4 | * | ||
| 5 | * Copyright (c) Andreas Klinger <ak@it-klinger.de> | ||
| 6 | * | ||
| 7 | * Data sheet: | ||
| 8 | * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/mod_devicetable.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/types.h> | ||
| 17 | |||
| 18 | #include "mprls0025pa.h" | ||
| 19 | |||
| 20 | static int mpr_i2c_init(struct device *unused) | ||
| 21 | { | ||
| 22 | return 0; | ||
| 23 | } | ||
| 24 | |||
| 25 | static int mpr_i2c_read(struct mpr_data *data, const u8 unused, const u8 cnt) | ||
| 26 | { | ||
| 27 | int ret; | ||
| 28 | struct i2c_client *client = to_i2c_client(data->dev); | ||
| 29 | |||
| 30 | if (cnt > MPR_MEASUREMENT_RD_SIZE) | ||
| 31 | return -EOVERFLOW; | ||
| 32 | |||
| 33 | memset(data->buffer, 0, MPR_MEASUREMENT_RD_SIZE); | ||
| 34 | ret = i2c_master_recv(client, data->buffer, cnt); | ||
| 35 | if (ret < 0) | ||
| 36 | return ret; | ||
| 37 | else if (ret != cnt) | ||
| 38 | return -EIO; | ||
| 39 | |||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | static int mpr_i2c_write(struct mpr_data *data, const u8 cmd, const u8 unused) | ||
| 44 | { | ||
| 45 | int ret; | ||
| 46 | struct i2c_client *client = to_i2c_client(data->dev); | ||
| 47 | u8 wdata[MPR_PKT_SYNC_LEN]; | ||
| 48 | |||
| 49 | memset(wdata, 0, sizeof(wdata)); | ||
| 50 | wdata[0] = cmd; | ||
| 51 | |||
| 52 | ret = i2c_master_send(client, wdata, MPR_PKT_SYNC_LEN); | ||
| 53 | if (ret < 0) | ||
| 54 | return ret; | ||
| 55 | else if (ret != MPR_PKT_SYNC_LEN) | ||
| 56 | return -EIO; | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static const struct mpr_ops mpr_i2c_ops = { | ||
| 62 | .init = mpr_i2c_init, | ||
| 63 | .read = mpr_i2c_read, | ||
| 64 | .write = mpr_i2c_write, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static int mpr_i2c_probe(struct i2c_client *client) | ||
| 68 | { | ||
| 69 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) | ||
| 70 | return -EOPNOTSUPP; | ||
| 71 | |||
| 72 | return mpr_common_probe(&client->dev, &mpr_i2c_ops, client->irq); | ||
| 73 | } | ||
| 74 | |||
| 75 | static const struct of_device_id mpr_i2c_match[] = { | ||
| 76 | { .compatible = "honeywell,mprls0025pa" }, | ||
| 77 | {} | ||
| 78 | }; | ||
| 79 | MODULE_DEVICE_TABLE(of, mpr_i2c_match); | ||
| 80 | |||
| 81 | static const struct i2c_device_id mpr_i2c_id[] = { | ||
| 82 | { "mprls0025pa" }, | ||
| 83 | {} | ||
| 84 | }; | ||
| 85 | MODULE_DEVICE_TABLE(i2c, mpr_i2c_id); | ||
| 86 | |||
| 87 | static struct i2c_driver mpr_i2c_driver = { | ||
| 88 | .probe = mpr_i2c_probe, | ||
| 89 | .id_table = mpr_i2c_id, | ||
| 90 | .driver = { | ||
| 91 | .name = "mprls0025pa", | ||
| 92 | .of_match_table = mpr_i2c_match, | ||
| 93 | }, | ||
| 94 | }; | ||
| 95 | module_i2c_driver(mpr_i2c_driver); | ||
| 96 | |||
| 97 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); | ||
| 98 | MODULE_DESCRIPTION("Honeywell MPR pressure sensor i2c driver"); | ||
| 99 | MODULE_LICENSE("GPL"); | ||
| 100 | MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); | ||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * MPRLS0025PA - Honeywell MicroPressure MPR series SPI sensor driver | ||
| 4 | * | ||
| 5 | * Copyright (c) 2024 Petre Rodan <petre.rodan@subdimension.ro> | ||
| 6 | * | ||
| 7 | * Data sheet: | ||
| 8 | * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/mod_devicetable.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | #include <linux/stddef.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | |||
| 19 | #include "mprls0025pa.h" | ||
| 20 | |||
| 21 | struct mpr_spi_buf { | ||
| 22 | u8 tx[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); | ||
| 23 | }; | ||
| 24 | |||
| 25 | static int mpr_spi_init(struct device *dev) | ||
| 26 | { | ||
| 27 | struct spi_device *spi = to_spi_device(dev); | ||
| 28 | struct mpr_spi_buf *buf; | ||
| 29 | |||
| 30 | buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL); | ||
| 31 | if (!buf) | ||
| 32 | return -ENOMEM; | ||
| 33 | |||
| 34 | spi_set_drvdata(spi, buf); | ||
| 35 | |||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len) | ||
| 40 | { | ||
| 41 | struct spi_device *spi = to_spi_device(data->dev); | ||
| 42 | struct mpr_spi_buf *buf = spi_get_drvdata(spi); | ||
| 43 | struct spi_transfer xfer; | ||
| 44 | |||
| 45 | if (pkt_len > MPR_MEASUREMENT_RD_SIZE) | ||
| 46 | return -EOVERFLOW; | ||
| 47 | |||
| 48 | buf->tx[0] = cmd; | ||
| 49 | xfer.tx_buf = buf->tx; | ||
| 50 | xfer.rx_buf = data->buffer; | ||
| 51 | xfer.len = pkt_len; | ||
| 52 | |||
| 53 | return spi_sync_transfer(spi, &xfer, 1); | ||
| 54 | } | ||
| 55 | |||
| 56 | static const struct mpr_ops mpr_spi_ops = { | ||
| 57 | .init = mpr_spi_init, | ||
| 58 | .read = mpr_spi_xfer, | ||
| 59 | .write = mpr_spi_xfer, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static int mpr_spi_probe(struct spi_device *spi) | ||
| 63 | { | ||
| 64 | return mpr_common_probe(&spi->dev, &mpr_spi_ops, spi->irq); | ||
| 65 | } | ||
| 66 | |||
| 67 | static const struct of_device_id mpr_spi_match[] = { | ||
| 68 | { .compatible = "honeywell,mprls0025pa" }, | ||
| 69 | {} | ||
| 70 | }; | ||
| 71 | MODULE_DEVICE_TABLE(of, mpr_spi_match); | ||
| 72 | |||
| 73 | static const struct spi_device_id mpr_spi_id[] = { | ||
| 74 | { "mprls0025pa" }, | ||
| 75 | {} | ||
| 76 | }; | ||
| 77 | MODULE_DEVICE_TABLE(spi, mpr_spi_id); | ||
| 78 | |||
| 79 | static struct spi_driver mpr_spi_driver = { | ||
| 80 | .driver = { | ||
| 81 | .name = "mprls0025pa", | ||
| 82 | .of_match_table = mpr_spi_match, | ||
| 83 | }, | ||
| 84 | .probe = mpr_spi_probe, | ||
| 85 | .id_table = mpr_spi_id, | ||
| 86 | }; | ||
| 87 | module_spi_driver(mpr_spi_driver); | ||
| 88 | |||
| 89 | MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); | ||
| 90 | MODULE_DESCRIPTION("Honeywell MPR pressure sensor spi driver"); | ||
| 91 | MODULE_LICENSE("GPL"); | ||
| 92 | MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); | ||
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | * Denis Ciocca <denis.ciocca@st.com> | 7 | * Denis Ciocca <denis.ciocca@st.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/acpi.h> | ||
| 11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | 12 | #include <linux/mod_devicetable.h> |
| @@ -55,13 +54,11 @@ static const struct of_device_id st_press_of_match[] = { · 41 unmodified lines | |||
| 55 | }; | 54 | }; |
| 56 | MODULE_DEVICE_TABLE(of, st_press_of_match); | 55 | MODULE_DEVICE_TABLE(of, st_press_of_match); |
| 57 | 56 | ||
| 58 | #ifdef CONFIG_ACPI | ||
| 59 | static const struct acpi_device_id st_press_acpi_match[] = { | 57 | static const struct acpi_device_id st_press_acpi_match[] = { |
| 60 | {"SNO9210", LPS22HB}, | 58 | {"SNO9210", LPS22HB}, |
| 61 | { }, | 59 | { }, |
| 62 | }; | 60 | }; |
| 63 | MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); | 61 | MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); |
| 64 | #endif | ||
| 65 | 62 | ||
| 66 | static const struct i2c_device_id st_press_id_table[] = { | 63 | static const struct i2c_device_id st_press_id_table[] = { |
| 67 | { LPS001WP_PRESS_DEV_NAME, LPS001WP }, | 64 | { LPS001WP_PRESS_DEV_NAME, LPS001WP }, |
| @@ -114,7 +111,7 @@ static struct i2c_driver st_press_driver = { · 46 unmodified lines | |||
| 114 | .driver = { | 111 | .driver = { |
| 115 | .name = "st-press-i2c", | 112 | .name = "st-press-i2c", |
| 116 | .of_match_table = st_press_of_match, | 113 | .of_match_table = st_press_of_match, |
| 117 | .acpi_match_table = ACPI_PTR(st_press_acpi_match), | 114 | .acpi_match_table = st_press_acpi_match, |
| 118 | }, | 115 | }, |
| 119 | .probe = st_press_i2c_probe, | 116 | .probe = st_press_i2c_probe, |
| 120 | .id_table = st_press_id_table, | 117 | .id_table = st_press_id_table, |
| @@ -995,17 +995,16 @@ static const struct i2c_device_id isl29501_id[] = { · 994 unmodified lines | |||
| 995 | 995 | ||
| 996 | MODULE_DEVICE_TABLE(i2c, isl29501_id); | 996 | MODULE_DEVICE_TABLE(i2c, isl29501_id); |
| 997 | 997 | ||
| 998 | #if defined(CONFIG_OF) | ||
| 999 | static const struct of_device_id isl29501_i2c_matches[] = { | 998 | static const struct of_device_id isl29501_i2c_matches[] = { |
| 1000 | { .compatible = "renesas,isl29501" }, | 999 | { .compatible = "renesas,isl29501" }, |
| 1001 | { } | 1000 | { } |
| 1002 | }; | 1001 | }; |
| 1003 | MODULE_DEVICE_TABLE(of, isl29501_i2c_matches); | 1002 | MODULE_DEVICE_TABLE(of, isl29501_i2c_matches); |
| 1004 | #endif | ||
| 1005 | 1003 | ||
| 1006 | static struct i2c_driver isl29501_driver = { | 1004 | static struct i2c_driver isl29501_driver = { |
| 1007 | .driver = { | 1005 | .driver = { |
| 1008 | .name = "isl29501", | 1006 | .name = "isl29501", |
| 1007 | .of_match_table = isl29501_i2c_matches, | ||
| 1009 | }, | 1008 | }, |
| 1010 | .id_table = isl29501_id, | 1009 | .id_table = isl29501_id, |
| 1011 | .probe = isl29501_probe, | 1010 | .probe = isl29501_probe, |
| @@ -337,28 +337,19 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, · 336 unmodified lines | |||
| 337 | int *val2, long mask) | 337 | int *val2, long mask) |
| 338 | { | 338 | { |
| 339 | struct sx_common_data *data = iio_priv(indio_dev); | 339 | struct sx_common_data *data = iio_priv(indio_dev); |
| 340 | int ret; | ||
| 341 | 340 | ||
| 342 | if (chan->type != IIO_PROXIMITY) | 341 | if (chan->type != IIO_PROXIMITY) |
| 343 | return -EINVAL; | 342 | return -EINVAL; |
| 344 | 343 | ||
| 345 | switch (mask) { | 344 | switch (mask) { |
| 346 | case IIO_CHAN_INFO_RAW: | 345 | case IIO_CHAN_INFO_RAW: |
| 347 | ret = iio_device_claim_direct_mode(indio_dev); | 346 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 348 | if (ret) | 347 | return sx_common_read_proximity(data, chan, val); |
| 349 | return ret; | 348 | unreachable(); |
| 350 | |||
| 351 | ret = sx_common_read_proximity(data, chan, val); | ||
| 352 | iio_device_release_direct_mode(indio_dev); | ||
| 353 | return ret; | ||
| 354 | case IIO_CHAN_INFO_HARDWAREGAIN: | 349 | case IIO_CHAN_INFO_HARDWAREGAIN: |
| 355 | ret = iio_device_claim_direct_mode(indio_dev); | 350 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 356 | if (ret) | 351 | return sx9310_read_gain(data, chan, val); |
| 357 | return ret; | 352 | unreachable(); |
| 358 | |||
| 359 | ret = sx9310_read_gain(data, chan, val); | ||
| 360 | iio_device_release_direct_mode(indio_dev); | ||
| 361 | return ret; | ||
| 362 | case IIO_CHAN_INFO_SAMP_FREQ: | 353 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 363 | return sx9310_read_samp_freq(data, val, val2); | 354 | return sx9310_read_samp_freq(data, val, val2); |
| 364 | default: | 355 | default: |
| @@ -546,12 +537,10 @@ static int sx9310_write_thresh(struct sx_common_data *data, · 181 unmodified lines | |||
| 546 | return -EINVAL; | 537 | return -EINVAL; |
| 547 | 538 | ||
| 548 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); | 539 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); |
| 549 | mutex_lock(&data->mutex); | ||
| 550 | ret = regmap_update_bits(data->regmap, reg, | ||
| 551 | SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); | ||
| 552 | mutex_unlock(&data->mutex); | ||
| 553 | 540 | ||
| 554 | return ret; | 541 | guard(mutex)(&data->mutex); |
| 542 | return regmap_update_bits(data->regmap, reg, | ||
| 543 | SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); | ||
| 555 | } | 544 | } |
| 556 | 545 | ||
| 557 | static int sx9310_write_hysteresis(struct sx_common_data *data, | 546 | static int sx9310_write_hysteresis(struct sx_common_data *data, |
| @@ -576,17 +565,14 @@ static int sx9310_write_hysteresis(struct sx_common_data *data, · 18 unmodified lines | |||
| 576 | return -EINVAL; | 565 | return -EINVAL; |
| 577 | 566 | ||
| 578 | hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); | 567 | hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); |
| 579 | mutex_lock(&data->mutex); | ||
| 580 | ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, | ||
| 581 | SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); | ||
| 582 | mutex_unlock(&data->mutex); | ||
| 583 | 568 | ||
| 584 | return ret; | 569 | guard(mutex)(&data->mutex); |
| 570 | return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, | ||
| 571 | SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); | ||
| 585 | } | 572 | } |
| 586 | 573 | ||
| 587 | static int sx9310_write_far_debounce(struct sx_common_data *data, int val) | 574 | static int sx9310_write_far_debounce(struct sx_common_data *data, int val) |
| 588 | { | 575 | { |
| 589 | int ret; | ||
| 590 | unsigned int regval; | 576 | unsigned int regval; |
| 591 | 577 | ||
| 592 | if (val > 0) | 578 | if (val > 0) |
| @@ -596,18 +582,14 @@ static int sx9310_write_far_debounce(struct sx_common_data *data, int val) · 3 unmodified lines | |||
| 596 | 582 | ||
| 597 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); | 583 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); |
| 598 | 584 | ||
| 599 | mutex_lock(&data->mutex); | 585 | guard(mutex)(&data->mutex); |
| 600 | ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, | 586 | return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, |
| 601 | SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, | 587 | SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, |
| 602 | regval); | 588 | regval); |
| 603 | mutex_unlock(&data->mutex); | ||
| 604 | |||
| 605 | return ret; | ||
| 606 | } | 589 | } |
| 607 | 590 | ||
| 608 | static int sx9310_write_close_debounce(struct sx_common_data *data, int val) | 591 | static int sx9310_write_close_debounce(struct sx_common_data *data, int val) |
| 609 | { | 592 | { |
| 610 | int ret; | ||
| 611 | unsigned int regval; | 593 | unsigned int regval; |
| 612 | 594 | ||
| 613 | if (val > 0) | 595 | if (val > 0) |
| @@ -617,13 +599,10 @@ static int sx9310_write_close_debounce(struct sx_common_data *data, int val) · 3 unmodified lines | |||
| 617 | 599 | ||
| 618 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); | 600 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); |
| 619 | 601 | ||
| 620 | mutex_lock(&data->mutex); | 602 | guard(mutex)(&data->mutex); |
| 621 | ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, | 603 | return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, |
| 622 | SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, | 604 | SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, |
| 623 | regval); | 605 | regval); |
| 624 | mutex_unlock(&data->mutex); | ||
| 625 | |||
| 626 | return ret; | ||
| 627 | } | 606 | } |
| 628 | 607 | ||
| 629 | static int sx9310_write_event_val(struct iio_dev *indio_dev, | 608 | static int sx9310_write_event_val(struct iio_dev *indio_dev, |
| @@ -658,7 +637,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev, · 28 unmodified lines | |||
| 658 | 637 | ||
| 659 | static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) | 638 | static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) |
| 660 | { | 639 | { |
| 661 | int i, ret; | 640 | int i; |
| 662 | 641 | ||
| 663 | for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) | 642 | for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) |
| 664 | if (val == sx9310_samp_freq_table[i].val && | 643 | if (val == sx9310_samp_freq_table[i].val && |
| @@ -668,23 +647,17 @@ static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) · 3 unmodified lines | |||
| 668 | if (i == ARRAY_SIZE(sx9310_samp_freq_table)) | 647 | if (i == ARRAY_SIZE(sx9310_samp_freq_table)) |
| 669 | return -EINVAL; | 648 | return -EINVAL; |
| 670 | 649 | ||
| 671 | mutex_lock(&data->mutex); | 650 | guard(mutex)(&data->mutex); |
| 672 | 651 | return regmap_update_bits( | |
| 673 | ret = regmap_update_bits( | ||
| 674 | data->regmap, SX9310_REG_PROX_CTRL0, | 652 | data->regmap, SX9310_REG_PROX_CTRL0, |
| 675 | SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, | 653 | SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, |
| 676 | FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i)); | 654 | FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i)); |
| 677 | |||
| 678 | mutex_unlock(&data->mutex); | ||
| 679 | |||
| 680 | return ret; | ||
| 681 | } | 655 | } |
| 682 | 656 | ||
| 683 | static int sx9310_write_gain(struct sx_common_data *data, | 657 | static int sx9310_write_gain(struct sx_common_data *data, |
| 684 | const struct iio_chan_spec *chan, int val) | 658 | const struct iio_chan_spec *chan, int val) |
| 685 | { | 659 | { |
| 686 | unsigned int gain, mask; | 660 | unsigned int gain, mask; |
| 687 | int ret; | ||
| 688 | 661 | ||
| 689 | gain = ilog2(val); | 662 | gain = ilog2(val); |
| 690 | 663 | ||
| @@ -703,12 +676,9 @@ static int sx9310_write_gain(struct sx_common_data *data, · 12 unmodified lines | |||
| 703 | return -EINVAL; | 676 | return -EINVAL; |
| 704 | } | 677 | } |
| 705 | 678 | ||
| 706 | mutex_lock(&data->mutex); | 679 | guard(mutex)(&data->mutex); |
| 707 | ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask, | 680 | return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask, |
| 708 | gain); | 681 | gain); |
| 709 | mutex_unlock(&data->mutex); | ||
| 710 | |||
| 711 | return ret; | ||
| 712 | } | 682 | } |
| 713 | 683 | ||
| 714 | static int sx9310_write_raw(struct iio_dev *indio_dev, | 684 | static int sx9310_write_raw(struct iio_dev *indio_dev, |
| @@ -969,22 +939,18 @@ static int sx9310_suspend(struct device *dev) · 254 unmodified lines | |||
| 969 | 939 | ||
| 970 | disable_irq_nosync(data->client->irq); | 940 | disable_irq_nosync(data->client->irq); |
| 971 | 941 | ||
| 972 | mutex_lock(&data->mutex); | 942 | guard(mutex)(&data->mutex); |
| 973 | ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, | 943 | ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, |
| 974 | &data->suspend_ctrl); | 944 | &data->suspend_ctrl); |
| 975 | if (ret) | 945 | if (ret) |
| 976 | goto out; | 946 | return ret; |
| 977 | 947 | ||
| 978 | ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; | 948 | ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; |
| 979 | ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); | 949 | ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); |
| 980 | if (ret) | 950 | if (ret) |
| 981 | goto out; | 951 | return ret; |
| 982 | |||
| 983 | ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0); | ||
| 984 | 952 | ||
| 985 | out: | 953 | return regmap_write(data->regmap, SX9310_REG_PAUSE, 0); |
| 986 | mutex_unlock(&data->mutex); | ||
| 987 | return ret; | ||
| 988 | } | 954 | } |
| 989 | 955 | ||
| 990 | static int sx9310_resume(struct device *dev) | 956 | static int sx9310_resume(struct device *dev) |
| @@ -992,18 +958,16 @@ static int sx9310_resume(struct device *dev) · 1 unmodified line | |||
| 992 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); | 958 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); |
| 993 | int ret; | 959 | int ret; |
| 994 | 960 | ||
| 995 | mutex_lock(&data->mutex); | 961 | scoped_guard(mutex, &data->mutex) { |
| 996 | ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1); | 962 | ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1); |
| 997 | if (ret) | 963 | if (ret) |
| 998 | goto out; | 964 | return ret; |
| 999 | |||
| 1000 | ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, | ||
| 1001 | data->suspend_ctrl); | ||
| 1002 | 965 | ||
| 1003 | out: | 966 | ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, |
| 1004 | mutex_unlock(&data->mutex); | 967 | data->suspend_ctrl); |
| 1005 | if (ret) | 968 | if (ret) |
| 1006 | return ret; | 969 | return ret; |
| 970 | } | ||
| 1007 | 971 | ||
| 1008 | enable_irq(data->client->irq); | 972 | enable_irq(data->client->irq); |
| 1009 | return 0; | 973 | return 0; |
| @@ -429,25 +429,16 @@ static int sx9324_read_raw(struct iio_dev *indio_dev, · 428 unmodified lines | |||
| 429 | int *val, int *val2, long mask) | 429 | int *val, int *val2, long mask) |
| 430 | { | 430 | { |
| 431 | struct sx_common_data *data = iio_priv(indio_dev); | 431 | struct sx_common_data *data = iio_priv(indio_dev); |
| 432 | int ret; | ||
| 433 | 432 | ||
| 434 | switch (mask) { | 433 | switch (mask) { |
| 435 | case IIO_CHAN_INFO_RAW: | 434 | case IIO_CHAN_INFO_RAW: |
| 436 | ret = iio_device_claim_direct_mode(indio_dev); | 435 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 437 | if (ret) | 436 | return sx_common_read_proximity(data, chan, val); |
| 438 | return ret; | 437 | unreachable(); |
| 439 | |||
| 440 | ret = sx_common_read_proximity(data, chan, val); | ||
| 441 | iio_device_release_direct_mode(indio_dev); | ||
| 442 | return ret; | ||
| 443 | case IIO_CHAN_INFO_HARDWAREGAIN: | 438 | case IIO_CHAN_INFO_HARDWAREGAIN: |
| 444 | ret = iio_device_claim_direct_mode(indio_dev); | 439 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 445 | if (ret) | 440 | return sx9324_read_gain(data, chan, val); |
| 446 | return ret; | 441 | unreachable(); |
| 447 | |||
| 448 | ret = sx9324_read_gain(data, chan, val); | ||
| 449 | iio_device_release_direct_mode(indio_dev); | ||
| 450 | return ret; | ||
| 451 | case IIO_CHAN_INFO_SAMP_FREQ: | 442 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 452 | return sx9324_read_samp_freq(data, val, val2); | 443 | return sx9324_read_samp_freq(data, val, val2); |
| 453 | default: | 444 | default: |
| @@ -484,7 +475,7 @@ static int sx9324_read_avail(struct iio_dev *indio_dev, · 30 unmodified lines | |||
| 484 | static int sx9324_set_samp_freq(struct sx_common_data *data, | 475 | static int sx9324_set_samp_freq(struct sx_common_data *data, |
| 485 | int val, int val2) | 476 | int val, int val2) |
| 486 | { | 477 | { |
| 487 | int i, ret; | 478 | int i; |
| 488 | 479 | ||
| 489 | for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++) | 480 | for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++) |
| 490 | if (val == sx9324_samp_freq_table[i].val && | 481 | if (val == sx9324_samp_freq_table[i].val && |
| @@ -494,15 +485,11 @@ static int sx9324_set_samp_freq(struct sx_common_data *data, · 3 unmodified lines | |||
| 494 | if (i == ARRAY_SIZE(sx9324_samp_freq_table)) | 485 | if (i == ARRAY_SIZE(sx9324_samp_freq_table)) |
| 495 | return -EINVAL; | 486 | return -EINVAL; |
| 496 | 487 | ||
| 497 | mutex_lock(&data->mutex); | 488 | guard(mutex)(&data->mutex); |
| 498 | |||
| 499 | ret = regmap_update_bits(data->regmap, | ||
| 500 | SX9324_REG_GNRL_CTRL0, | ||
| 501 | SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); | ||
| 502 | |||
| 503 | mutex_unlock(&data->mutex); | ||
| 504 | 489 | ||
| 505 | return ret; | 490 | return regmap_update_bits(data->regmap, |
| 491 | SX9324_REG_GNRL_CTRL0, | ||
| 492 | SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); | ||
| 506 | } | 493 | } |
| 507 | 494 | ||
| 508 | static int sx9324_read_thresh(struct sx_common_data *data, | 495 | static int sx9324_read_thresh(struct sx_common_data *data, |
| @@ -623,7 +610,6 @@ static int sx9324_write_thresh(struct sx_common_data *data, · 114 unmodified lines | |||
| 623 | const struct iio_chan_spec *chan, int _val) | 610 | const struct iio_chan_spec *chan, int _val) |
| 624 | { | 611 | { |
| 625 | unsigned int reg, val = _val; | 612 | unsigned int reg, val = _val; |
| 626 | int ret; | ||
| 627 | 613 | ||
| 628 | reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; | 614 | reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; |
| 629 | 615 | ||
| @@ -633,11 +619,9 @@ static int sx9324_write_thresh(struct sx_common_data *data, · 3 unmodified lines | |||
| 633 | if (val > 0xff) | 619 | if (val > 0xff) |
| 634 | return -EINVAL; | 620 | return -EINVAL; |
| 635 | 621 | ||
| 636 | mutex_lock(&data->mutex); | 622 | guard(mutex)(&data->mutex); |
| 637 | ret = regmap_write(data->regmap, reg, val); | ||
| 638 | mutex_unlock(&data->mutex); | ||
| 639 | 623 | ||
| 640 | return ret; | 624 | return regmap_write(data->regmap, reg, val); |
| 641 | } | 625 | } |
| 642 | 626 | ||
| 643 | static int sx9324_write_hysteresis(struct sx_common_data *data, | 627 | static int sx9324_write_hysteresis(struct sx_common_data *data, |
| @@ -662,18 +646,15 @@ static int sx9324_write_hysteresis(struct sx_common_data *data, · 18 unmodified lines | |||
| 662 | return -EINVAL; | 646 | return -EINVAL; |
| 663 | 647 | ||
| 664 | hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); | 648 | hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); |
| 665 | mutex_lock(&data->mutex); | 649 | guard(mutex)(&data->mutex); |
| 666 | ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, | ||
| 667 | SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); | ||
| 668 | mutex_unlock(&data->mutex); | ||
| 669 | 650 | ||
| 670 | return ret; | 651 | return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, |
| 652 | SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); | ||
| 671 | } | 653 | } |
| 672 | 654 | ||
| 673 | static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) | 655 | static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) |
| 674 | { | 656 | { |
| 675 | unsigned int regval, val = _val; | 657 | unsigned int regval, val = _val; |
| 676 | int ret; | ||
| 677 | 658 | ||
| 678 | if (val > 0) | 659 | if (val > 0) |
| 679 | val = ilog2(val); | 660 | val = ilog2(val); |
| @@ -682,19 +663,16 @@ static int sx9324_write_far_debounce(struct sx_common_data *data, int _val) · 2 unmodified lines | |||
| 682 | 663 | ||
| 683 | regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val); | 664 | regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val); |
| 684 | 665 | ||
| 685 | mutex_lock(&data->mutex); | 666 | guard(mutex)(&data->mutex); |
| 686 | ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, | ||
| 687 | SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, | ||
| 688 | regval); | ||
| 689 | mutex_unlock(&data->mutex); | ||
| 690 | 667 | ||
| 691 | return ret; | 668 | return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, |
| 669 | SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, | ||
| 670 | regval); | ||
| 692 | } | 671 | } |
| 693 | 672 | ||
| 694 | static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) | 673 | static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) |
| 695 | { | 674 | { |
| 696 | unsigned int regval, val = _val; | 675 | unsigned int regval, val = _val; |
| 697 | int ret; | ||
| 698 | 676 | ||
| 699 | if (val > 0) | 677 | if (val > 0) |
| 700 | val = ilog2(val); | 678 | val = ilog2(val); |
| @@ -703,13 +681,11 @@ static int sx9324_write_close_debounce(struct sx_common_data *data, int _val) · 2 unmodified lines | |||
| 703 | 681 | ||
| 704 | regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val); | 682 | regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val); |
| 705 | 683 | ||
| 706 | mutex_lock(&data->mutex); | 684 | guard(mutex)(&data->mutex); |
| 707 | ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, | ||
| 708 | SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, | ||
| 709 | regval); | ||
| 710 | mutex_unlock(&data->mutex); | ||
| 711 | 685 | ||
| 712 | return ret; | 686 | return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, |
| 687 | SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, | ||
| 688 | regval); | ||
| 713 | } | 689 | } |
| 714 | 690 | ||
| 715 | static int sx9324_write_event_val(struct iio_dev *indio_dev, | 691 | static int sx9324_write_event_val(struct iio_dev *indio_dev, |
| @@ -746,7 +722,6 @@ static int sx9324_write_gain(struct sx_common_data *data, · 30 unmodified lines | |||
| 746 | const struct iio_chan_spec *chan, int val) | 722 | const struct iio_chan_spec *chan, int val) |
| 747 | { | 723 | { |
| 748 | unsigned int gain, reg; | 724 | unsigned int gain, reg; |
| 749 | int ret; | ||
| 750 | 725 | ||
| 751 | reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; | 726 | reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; |
| 752 | 727 | ||
| @@ -756,13 +731,11 @@ static int sx9324_write_gain(struct sx_common_data *data, · 3 unmodified lines | |||
| 756 | 731 | ||
| 757 | gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain); | 732 | gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain); |
| 758 | 733 | ||
| 759 | mutex_lock(&data->mutex); | 734 | guard(mutex)(&data->mutex); |
| 760 | ret = regmap_update_bits(data->regmap, reg, | ||
| 761 | SX9324_REG_PROX_CTRL0_GAIN_MASK, | ||
| 762 | gain); | ||
| 763 | mutex_unlock(&data->mutex); | ||
| 764 | 735 | ||
| 765 | return ret; | 736 | return regmap_update_bits(data->regmap, reg, |
| 737 | SX9324_REG_PROX_CTRL0_GAIN_MASK, | ||
| 738 | gain); | ||
| 766 | } | 739 | } |
| 767 | 740 | ||
| 768 | static int sx9324_write_raw(struct iio_dev *indio_dev, | 741 | static int sx9324_write_raw(struct iio_dev *indio_dev, |
| @@ -873,6 +846,29 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev) · 104 unmodified lines | |||
| 873 | 20000, 2000000); | 846 | 20000, 2000000); |
| 874 | } | 847 | } |
| 875 | 848 | ||
| 849 | static u8 sx9324_parse_phase_prop(struct device *dev, | ||
| 850 | struct sx_common_reg_default *reg_def, | ||
| 851 | const char *prop) | ||
| 852 | { | ||
| 853 | unsigned int pin_defs[SX9324_NUM_PINS]; | ||
| 854 | int count, ret, pin; | ||
| 855 | u32 raw = 0; | ||
| 856 | |||
| 857 | count = device_property_count_u32(dev, prop); | ||
| 858 | if (count != ARRAY_SIZE(pin_defs)) | ||
| 859 | return reg_def->def; | ||
| 860 | ret = device_property_read_u32_array(dev, prop, pin_defs, | ||
| 861 | ARRAY_SIZE(pin_defs)); | ||
| 862 | if (ret) | ||
| 863 | return reg_def->def; | ||
| 864 | |||
| 865 | for (pin = 0; pin < SX9324_NUM_PINS; pin++) | ||
| 866 | raw |= (pin_defs[pin] << (2 * pin)) & | ||
| 867 | SX9324_REG_AFE_PH0_PIN_MASK(pin); | ||
| 868 | |||
| 869 | return raw; | ||
| 870 | } | ||
| 871 | |||
| 876 | static const struct sx_common_reg_default * | 872 | static const struct sx_common_reg_default * |
| 877 | sx9324_get_default_reg(struct device *dev, int idx, | 873 | sx9324_get_default_reg(struct device *dev, int idx, |
| 878 | struct sx_common_reg_default *reg_def) | 874 | struct sx_common_reg_default *reg_def) |
| @@ -881,37 +877,29 @@ sx9324_get_default_reg(struct device *dev, int idx, · 2 unmodified lines | |||
| 881 | "highest" }; | 877 | "highest" }; |
| 882 | static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd", | 878 | static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd", |
| 883 | "vdd" }; | 879 | "vdd" }; |
| 884 | #define SX9324_PIN_DEF "semtech,ph0-pin" | ||
| 885 | #define SX9324_RESOLUTION_DEF "semtech,ph01-resolution" | ||
| 886 | #define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength" | ||
| 887 | unsigned int pin_defs[SX9324_NUM_PINS]; | ||
| 888 | char prop[] = SX9324_PROXRAW_DEF; | ||
| 889 | u32 start = 0, raw = 0, pos = 0; | 880 | u32 start = 0, raw = 0, pos = 0; |
| 890 | int ret, count, ph, pin; | 881 | const char *prop; |
| 882 | int ret; | ||
| 891 | 883 | ||
| 892 | memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); | 884 | memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); |
| 893 | 885 | ||
| 894 | sx_common_get_raw_register_config(dev, reg_def); | 886 | sx_common_get_raw_register_config(dev, reg_def); |
| 895 | switch (reg_def->reg) { | 887 | switch (reg_def->reg) { |
| 896 | case SX9324_REG_AFE_PH0: | 888 | case SX9324_REG_AFE_PH0: |
| 889 | reg_def->def = sx9324_parse_phase_prop(dev, reg_def, | ||
| 890 | "semtech,ph0-pin"); | ||
| 891 | break; | ||
| 897 | case SX9324_REG_AFE_PH1: | 892 | case SX9324_REG_AFE_PH1: |
| 893 | reg_def->def = sx9324_parse_phase_prop(dev, reg_def, | ||
| 894 | "semtech,ph1-pin"); | ||
| 895 | break; | ||
| 898 | case SX9324_REG_AFE_PH2: | 896 | case SX9324_REG_AFE_PH2: |
| 897 | reg_def->def = sx9324_parse_phase_prop(dev, reg_def, | ||
| 898 | "semtech,ph2-pin"); | ||
| 899 | break; | ||
| 899 | case SX9324_REG_AFE_PH3: | 900 | case SX9324_REG_AFE_PH3: |
| 900 | ph = reg_def->reg - SX9324_REG_AFE_PH0; | 901 | reg_def->def = sx9324_parse_phase_prop(dev, reg_def, |
| 901 | snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); | 902 | "semtech,ph3-pin"); |
| 902 | |||
| 903 | count = device_property_count_u32(dev, prop); | ||
| 904 | if (count != ARRAY_SIZE(pin_defs)) | ||
| 905 | break; | ||
| 906 | ret = device_property_read_u32_array(dev, prop, pin_defs, | ||
| 907 | ARRAY_SIZE(pin_defs)); | ||
| 908 | if (ret) | ||
| 909 | break; | ||
| 910 | |||
| 911 | for (pin = 0; pin < SX9324_NUM_PINS; pin++) | ||
| 912 | raw |= (pin_defs[pin] << (2 * pin)) & | ||
| 913 | SX9324_REG_AFE_PH0_PIN_MASK(pin); | ||
| 914 | reg_def->def = raw; | ||
| 915 | break; | 903 | break; |
| 916 | case SX9324_REG_AFE_CTRL0: | 904 | case SX9324_REG_AFE_CTRL0: |
| 917 | ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep", | 905 | ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep", |
| @@ -933,11 +921,9 @@ sx9324_get_default_reg(struct device *dev, int idx, · 15 unmodified lines | |||
| 933 | case SX9324_REG_AFE_CTRL4: | 921 | case SX9324_REG_AFE_CTRL4: |
| 934 | case SX9324_REG_AFE_CTRL7: | 922 | case SX9324_REG_AFE_CTRL7: |
| 935 | if (reg_def->reg == SX9324_REG_AFE_CTRL4) | 923 | if (reg_def->reg == SX9324_REG_AFE_CTRL4) |
| 936 | strncpy(prop, "semtech,ph01-resolution", | 924 | prop = "semtech,ph01-resolution"; |
| 937 | ARRAY_SIZE(prop)); | ||
| 938 | else | 925 | else |
| 939 | strncpy(prop, "semtech,ph23-resolution", | 926 | prop = "semtech,ph23-resolution"; |
| 940 | ARRAY_SIZE(prop)); | ||
| 941 | 927 | ||
| 942 | ret = device_property_read_u32(dev, prop, &raw); | 928 | ret = device_property_read_u32(dev, prop, &raw); |
| 943 | if (ret) | 929 | if (ret) |
| @@ -1008,11 +994,9 @@ sx9324_get_default_reg(struct device *dev, int idx, · 64 unmodified lines | |||
| 1008 | case SX9324_REG_PROX_CTRL0: | 994 | case SX9324_REG_PROX_CTRL0: |
| 1009 | case SX9324_REG_PROX_CTRL1: | 995 | case SX9324_REG_PROX_CTRL1: |
| 1010 | if (reg_def->reg == SX9324_REG_PROX_CTRL0) | 996 | if (reg_def->reg == SX9324_REG_PROX_CTRL0) |
| 1011 | strncpy(prop, "semtech,ph01-proxraw-strength", | 997 | prop = "semtech,ph01-proxraw-strength"; |
| 1012 | ARRAY_SIZE(prop)); | ||
| 1013 | else | 998 | else |
| 1014 | strncpy(prop, "semtech,ph23-proxraw-strength", | 999 | prop = "semtech,ph23-proxraw-strength"; |
| 1015 | ARRAY_SIZE(prop)); | ||
| 1016 | ret = device_property_read_u32(dev, prop, &raw); | 1000 | ret = device_property_read_u32(dev, prop, &raw); |
| 1017 | if (ret) | 1001 | if (ret) |
| 1018 | break; | 1002 | break; |
| @@ -1081,34 +1065,30 @@ static int sx9324_suspend(struct device *dev) · 62 unmodified lines | |||
| 1081 | 1065 | ||
| 1082 | disable_irq_nosync(data->client->irq); | 1066 | disable_irq_nosync(data->client->irq); |
| 1083 | 1067 | ||
| 1084 | mutex_lock(&data->mutex); | 1068 | guard(mutex)(&data->mutex); |
| 1085 | ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, ®val); | 1069 | ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, ®val); |
| 1070 | if (ret < 0) | ||
| 1071 | return ret; | ||
| 1086 | 1072 | ||
| 1087 | data->suspend_ctrl = | 1073 | data->suspend_ctrl = |
| 1088 | FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval); | 1074 | FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval); |
| 1089 | 1075 | ||
| 1090 | if (ret < 0) | ||
| 1091 | goto out; | ||
| 1092 | 1076 | ||
| 1093 | /* Disable all phases, send the device to sleep. */ | 1077 | /* Disable all phases, send the device to sleep. */ |
| 1094 | ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); | 1078 | return regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); |
| 1095 | |||
| 1096 | out: | ||
| 1097 | mutex_unlock(&data->mutex); | ||
| 1098 | return ret; | ||
| 1099 | } | 1079 | } |
| 1100 | 1080 | ||
| 1101 | static int sx9324_resume(struct device *dev) | 1081 | static int sx9324_resume(struct device *dev) |
| 1102 | { | 1082 | { |
| 1103 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); | 1083 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); |
| 1104 | int ret; | ||
| 1105 | 1084 | ||
| 1106 | mutex_lock(&data->mutex); | 1085 | scoped_guard(mutex, &data->mutex) { |
| 1107 | ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, | 1086 | int ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, |
| 1108 | data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL); | 1087 | data->suspend_ctrl | |
| 1109 | mutex_unlock(&data->mutex); | 1088 | SX9324_REG_GNRL_CTRL1_PAUSECTRL); |
| 1110 | if (ret) | 1089 | if (ret) |
| 1111 | return ret; | 1090 | return ret; |
| 1091 | } | ||
| 1112 | 1092 | ||
| 1113 | enable_irq(data->client->irq); | 1093 | enable_irq(data->client->irq); |
| 1114 | return 0; | 1094 | return 0; |
| @@ -322,25 +322,16 @@ static int sx9360_read_raw(struct iio_dev *indio_dev, · 321 unmodified lines | |||
| 322 | int *val, int *val2, long mask) | 322 | int *val, int *val2, long mask) |
| 323 | { | 323 | { |
| 324 | struct sx_common_data *data = iio_priv(indio_dev); | 324 | struct sx_common_data *data = iio_priv(indio_dev); |
| 325 | int ret; | ||
| 326 | 325 | ||
| 327 | switch (mask) { | 326 | switch (mask) { |
| 328 | case IIO_CHAN_INFO_RAW: | 327 | case IIO_CHAN_INFO_RAW: |
| 329 | ret = iio_device_claim_direct_mode(indio_dev); | 328 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 330 | if (ret) | 329 | return sx_common_read_proximity(data, chan, val); |
| 331 | return ret; | 330 | unreachable(); |
| 332 | |||
| 333 | ret = sx_common_read_proximity(data, chan, val); | ||
| 334 | iio_device_release_direct_mode(indio_dev); | ||
| 335 | return ret; | ||
| 336 | case IIO_CHAN_INFO_HARDWAREGAIN: | 331 | case IIO_CHAN_INFO_HARDWAREGAIN: |
| 337 | ret = iio_device_claim_direct_mode(indio_dev); | 332 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
| 338 | if (ret) | 333 | return sx9360_read_gain(data, chan, val); |
| 339 | return ret; | 334 | unreachable(); |
| 340 | |||
| 341 | ret = sx9360_read_gain(data, chan, val); | ||
| 342 | iio_device_release_direct_mode(indio_dev); | ||
| 343 | return ret; | ||
| 344 | case IIO_CHAN_INFO_SAMP_FREQ: | 335 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 345 | return sx9360_read_samp_freq(data, val, val2); | 336 | return sx9360_read_samp_freq(data, val, val2); |
| 346 | default: | 337 | default: |
| @@ -387,19 +378,15 @@ static int sx9360_read_avail(struct iio_dev *indio_dev, · 40 unmodified lines | |||
| 387 | static int sx9360_set_samp_freq(struct sx_common_data *data, | 378 | static int sx9360_set_samp_freq(struct sx_common_data *data, |
| 388 | int val, int val2) | 379 | int val, int val2) |
| 389 | { | 380 | { |
| 390 | int ret, reg; | 381 | int reg; |
| 391 | __be16 buf; | 382 | __be16 buf; |
| 392 | 383 | ||
| 393 | reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ); | 384 | reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ); |
| 394 | buf = cpu_to_be16(reg); | 385 | buf = cpu_to_be16(reg); |
| 395 | mutex_lock(&data->mutex); | 386 | guard(mutex)(&data->mutex); |
| 396 | |||
| 397 | ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf, | ||
| 398 | sizeof(buf)); | ||
| 399 | 387 | ||
| 400 | mutex_unlock(&data->mutex); | 388 | return regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf, |
| 401 | 389 | sizeof(buf)); | |
| 402 | return ret; | ||
| 403 | } | 390 | } |
| 404 | 391 | ||
| 405 | static int sx9360_read_thresh(struct sx_common_data *data, int *val) | 392 | static int sx9360_read_thresh(struct sx_common_data *data, int *val) |
| @@ -510,7 +497,6 @@ static int sx9360_read_event_val(struct iio_dev *indio_dev, · 104 unmodified lines | |||
| 510 | static int sx9360_write_thresh(struct sx_common_data *data, int _val) | 497 | static int sx9360_write_thresh(struct sx_common_data *data, int _val) |
| 511 | { | 498 | { |
| 512 | unsigned int val = _val; | 499 | unsigned int val = _val; |
| 513 | int ret; | ||
| 514 | 500 | ||
| 515 | if (val >= 1) | 501 | if (val >= 1) |
| 516 | val = int_sqrt(2 * val); | 502 | val = int_sqrt(2 * val); |
| @@ -518,11 +504,8 @@ static int sx9360_write_thresh(struct sx_common_data *data, int _val) · 1 unmodified line | |||
| 518 | if (val > 0xff) | 504 | if (val > 0xff) |
| 519 | return -EINVAL; | 505 | return -EINVAL; |
| 520 | 506 | ||
| 521 | mutex_lock(&data->mutex); | 507 | guard(mutex)(&data->mutex); |
| 522 | ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val); | 508 | return regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val); |
| 523 | mutex_unlock(&data->mutex); | ||
| 524 | |||
| 525 | return ret; | ||
| 526 | } | 509 | } |
| 527 | 510 | ||
| 528 | static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) | 511 | static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) |
| @@ -546,18 +529,14 @@ static int sx9360_write_hysteresis(struct sx_common_data *data, int _val) · 17 unmodified lines | |||
| 546 | return -EINVAL; | 529 | return -EINVAL; |
| 547 | 530 | ||
| 548 | hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); | 531 | hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); |
| 549 | mutex_lock(&data->mutex); | 532 | guard(mutex)(&data->mutex); |
| 550 | ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, | 533 | return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, |
| 551 | SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); | 534 | SX9360_REG_PROX_CTRL4_HYST_MASK, hyst); |
| 552 | mutex_unlock(&data->mutex); | ||
| 553 | |||
| 554 | return ret; | ||
| 555 | } | 535 | } |
| 556 | 536 | ||
| 557 | static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) | 537 | static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) |
| 558 | { | 538 | { |
| 559 | unsigned int regval, val = _val; | 539 | unsigned int regval, val = _val; |
| 560 | int ret; | ||
| 561 | 540 | ||
| 562 | if (val > 0) | 541 | if (val > 0) |
| 563 | val = ilog2(val); | 542 | val = ilog2(val); |
| @@ -566,19 +545,15 @@ static int sx9360_write_far_debounce(struct sx_common_data *data, int _val) · 2 unmodified lines | |||
| 566 | 545 | ||
| 567 | regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val); | 546 | regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val); |
| 568 | 547 | ||
| 569 | mutex_lock(&data->mutex); | 548 | guard(mutex)(&data->mutex); |
| 570 | ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, | 549 | return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, |
| 571 | SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, | 550 | SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, |
| 572 | regval); | 551 | regval); |
| 573 | mutex_unlock(&data->mutex); | ||
| 574 | |||
| 575 | return ret; | ||
| 576 | } | 552 | } |
| 577 | 553 | ||
| 578 | static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) | 554 | static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) |
| 579 | { | 555 | { |
| 580 | unsigned int regval, val = _val; | 556 | unsigned int regval, val = _val; |
| 581 | int ret; | ||
| 582 | 557 | ||
| 583 | if (val > 0) | 558 | if (val > 0) |
| 584 | val = ilog2(val); | 559 | val = ilog2(val); |
| @@ -587,13 +562,10 @@ static int sx9360_write_close_debounce(struct sx_common_data *data, int _val) · 2 unmodified lines | |||
| 587 | 562 | ||
| 588 | regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val); | 563 | regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val); |
| 589 | 564 | ||
| 590 | mutex_lock(&data->mutex); | 565 | guard(mutex)(&data->mutex); |
| 591 | ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, | 566 | return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4, |
| 592 | SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, | 567 | SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, |
| 593 | regval); | 568 | regval); |
| 594 | mutex_unlock(&data->mutex); | ||
| 595 | |||
| 596 | return ret; | ||
| 597 | } | 569 | } |
| 598 | 570 | ||
| 599 | static int sx9360_write_event_val(struct iio_dev *indio_dev, | 571 | static int sx9360_write_event_val(struct iio_dev *indio_dev, |
| @@ -630,19 +602,15 @@ static int sx9360_write_gain(struct sx_common_data *data, · 30 unmodified lines | |||
| 630 | const struct iio_chan_spec *chan, int val) | 602 | const struct iio_chan_spec *chan, int val) |
| 631 | { | 603 | { |
| 632 | unsigned int gain, reg; | 604 | unsigned int gain, reg; |
| 633 | int ret; | ||
| 634 | 605 | ||
| 635 | gain = ilog2(val); | 606 | gain = ilog2(val); |
| 636 | reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel; | 607 | reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel; |
| 637 | gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain); | 608 | gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain); |
| 638 | 609 | ||
| 639 | mutex_lock(&data->mutex); | 610 | guard(mutex)(&data->mutex); |
| 640 | ret = regmap_update_bits(data->regmap, reg, | 611 | return regmap_update_bits(data->regmap, reg, |
| 641 | SX9360_REG_PROX_CTRL0_GAIN_MASK, | 612 | SX9360_REG_PROX_CTRL0_GAIN_MASK, |
| 642 | gain); | 613 | gain); |
| 643 | mutex_unlock(&data->mutex); | ||
| 644 | |||
| 645 | return ret; | ||
| 646 | } | 614 | } |
| 647 | 615 | ||
| 648 | static int sx9360_write_raw(struct iio_dev *indio_dev, | 616 | static int sx9360_write_raw(struct iio_dev *indio_dev, |
| @@ -827,36 +795,31 @@ static int sx9360_suspend(struct device *dev) · 178 unmodified lines | |||
| 827 | 795 | ||
| 828 | disable_irq_nosync(data->client->irq); | 796 | disable_irq_nosync(data->client->irq); |
| 829 | 797 | ||
| 830 | mutex_lock(&data->mutex); | 798 | guard(mutex)(&data->mutex); |
| 831 | ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, ®val); | 799 | ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, ®val); |
| 800 | if (ret < 0) | ||
| 801 | return ret; | ||
| 832 | 802 | ||
| 833 | data->suspend_ctrl = | 803 | data->suspend_ctrl = |
| 834 | FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval); | 804 | FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval); |
| 835 | 805 | ||
| 836 | if (ret < 0) | ||
| 837 | goto out; | ||
| 838 | 806 | ||
| 839 | /* Disable all phases, send the device to sleep. */ | 807 | /* Disable all phases, send the device to sleep. */ |
| 840 | ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0); | 808 | return regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0); |
| 841 | |||
| 842 | out: | ||
| 843 | mutex_unlock(&data->mutex); | ||
| 844 | return ret; | ||
| 845 | } | 809 | } |
| 846 | 810 | ||
| 847 | static int sx9360_resume(struct device *dev) | 811 | static int sx9360_resume(struct device *dev) |
| 848 | { | 812 | { |
| 849 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); | 813 | struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); |
| 850 | int ret; | ||
| 851 | |||
| 852 | mutex_lock(&data->mutex); | ||
| 853 | ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0, | ||
| 854 | SX9360_REG_GNRL_CTRL0_PHEN_MASK, | ||
| 855 | data->suspend_ctrl); | ||
| 856 | mutex_unlock(&data->mutex); | ||
| 857 | if (ret) | ||
| 858 | return ret; | ||
| 859 | 814 | ||
| 815 | scoped_guard(mutex, &data->mutex) { | ||
| 816 | int ret = regmap_update_bits(data->regmap, | ||
| 817 | SX9360_REG_GNRL_CTRL0, | ||
| 818 | SX9360_REG_GNRL_CTRL0_PHEN_MASK, | ||
| 819 | data->suspend_ctrl); | ||
| 820 | if (ret) | ||
| 821 | return ret; | ||
| 822 | } | ||
| 860 | enable_irq(data->client->irq); | 823 | enable_irq(data->client->irq); |
| 861 | return 0; | 824 | return 0; |
| 862 | } | 825 | } |
| @@ -207,6 +207,7 @@ enum { · 206 unmodified lines | |||
| 207 | container_of(_sensor, struct ltc2983_temp, sensor) | 207 | container_of(_sensor, struct ltc2983_temp, sensor) |
| 208 | 208 | ||
| 209 | struct ltc2983_chip_info { | 209 | struct ltc2983_chip_info { |
| 210 | const char *name; | ||
| 210 | unsigned int max_channels_nr; | 211 | unsigned int max_channels_nr; |
| 211 | bool has_temp; | 212 | bool has_temp; |
| 212 | bool has_eeprom; | 213 | bool has_eeprom; |
| @@ -1346,7 +1347,7 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data) · 1133 unmodified lines | |||
| 1346 | __chan; \ | 1347 | __chan; \ |
| 1347 | }) | 1348 | }) |
| 1348 | 1349 | ||
| 1349 | static int ltc2983_parse_dt(struct ltc2983_data *st) | 1350 | static int ltc2983_parse_fw(struct ltc2983_data *st) |
| 1350 | { | 1351 | { |
| 1351 | struct device *dev = &st->spi->dev; | 1352 | struct device *dev = &st->spi->dev; |
| 1352 | struct fwnode_handle *child; | 1353 | struct fwnode_handle *child; |
| @@ -1605,7 +1606,6 @@ static int ltc2983_probe(struct spi_device *spi) · 252 unmodified lines | |||
| 1605 | struct ltc2983_data *st; | 1606 | struct ltc2983_data *st; |
| 1606 | struct iio_dev *indio_dev; | 1607 | struct iio_dev *indio_dev; |
| 1607 | struct gpio_desc *gpio; | 1608 | struct gpio_desc *gpio; |
| 1608 | const char *name = spi_get_device_id(spi)->name; | ||
| 1609 | int ret; | 1609 | int ret; |
| 1610 | 1610 | ||
| 1611 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | 1611 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
| @@ -1614,9 +1614,7 @@ static int ltc2983_probe(struct spi_device *spi) · 2 unmodified lines | |||
| 1614 | 1614 | ||
| 1615 | st = iio_priv(indio_dev); | 1615 | st = iio_priv(indio_dev); |
| 1616 | 1616 | ||
| 1617 | st->info = device_get_match_data(&spi->dev); | 1617 | st->info = spi_get_device_match_data(spi); |
| 1618 | if (!st->info) | ||
| 1619 | st->info = (void *)spi_get_device_id(spi)->driver_data; | ||
| 1620 | if (!st->info) | 1618 | if (!st->info) |
| 1621 | return -ENODEV; | 1619 | return -ENODEV; |
| 1622 | 1620 | ||
| @@ -1632,7 +1630,7 @@ static int ltc2983_probe(struct spi_device *spi) · 9 unmodified lines | |||
| 1632 | st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY); | 1630 | st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY); |
| 1633 | spi_set_drvdata(spi, st); | 1631 | spi_set_drvdata(spi, st); |
| 1634 | 1632 | ||
| 1635 | ret = ltc2983_parse_dt(st); | 1633 | ret = ltc2983_parse_fw(st); |
| 1636 | if (ret) | 1634 | if (ret) |
| 1637 | return ret; | 1635 | return ret; |
| 1638 | 1636 | ||
| @@ -1657,7 +1655,7 @@ static int ltc2983_probe(struct spi_device *spi) · 18 unmodified lines | |||
| 1657 | return ret; | 1655 | return ret; |
| 1658 | 1656 | ||
| 1659 | ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, | 1657 | ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, |
| 1660 | IRQF_TRIGGER_RISING, name, st); | 1658 | IRQF_TRIGGER_RISING, st->info->name, st); |
| 1661 | if (ret) { | 1659 | if (ret) { |
| 1662 | dev_err(&spi->dev, "failed to request an irq, %d", ret); | 1660 | dev_err(&spi->dev, "failed to request an irq, %d", ret); |
| 1663 | return ret; | 1661 | return ret; |
| @@ -1672,7 +1670,7 @@ static int ltc2983_probe(struct spi_device *spi) · 8 unmodified lines | |||
| 1672 | return ret; | 1670 | return ret; |
| 1673 | } | 1671 | } |
| 1674 | 1672 | ||
| 1675 | indio_dev->name = name; | 1673 | indio_dev->name = st->info->name; |
| 1676 | indio_dev->num_channels = st->iio_channels; | 1674 | indio_dev->num_channels = st->iio_channels; |
| 1677 | indio_dev->channels = st->iio_chan; | 1675 | indio_dev->channels = st->iio_chan; |
| 1678 | indio_dev->modes = INDIO_DIRECT_MODE; | 1676 | indio_dev->modes = INDIO_DIRECT_MODE; |
| @@ -1703,15 +1701,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend, · 24 unmodified lines | |||
| 1703 | ltc2983_resume); | 1701 | ltc2983_resume); |
| 1704 | 1702 | ||
| 1705 | static const struct ltc2983_chip_info ltc2983_chip_info_data = { | 1703 | static const struct ltc2983_chip_info ltc2983_chip_info_data = { |
| 1704 | .name = "ltc2983", | ||
| 1706 | .max_channels_nr = 20, | 1705 | .max_channels_nr = 20, |
| 1707 | }; | 1706 | }; |
| 1708 | 1707 | ||
| 1709 | static const struct ltc2983_chip_info ltc2984_chip_info_data = { | 1708 | static const struct ltc2983_chip_info ltc2984_chip_info_data = { |
| 1709 | .name = "ltc2984", | ||
| 1710 | .max_channels_nr = 20, | 1710 | .max_channels_nr = 20, |
| 1711 | .has_eeprom = true, | 1711 | .has_eeprom = true, |
| 1712 | }; | 1712 | }; |
| 1713 | 1713 | ||
| 1714 | static const struct ltc2983_chip_info ltc2986_chip_info_data = { | 1714 | static const struct ltc2983_chip_info ltc2986_chip_info_data = { |
| 1715 | .name = "ltc2986", | ||
| 1716 | .max_channels_nr = 10, | ||
| 1717 | .has_temp = true, | ||
| 1718 | .has_eeprom = true, | ||
| 1719 | }; | ||
| 1720 | |||
| 1721 | static const struct ltc2983_chip_info ltm2985_chip_info_data = { | ||
| 1722 | .name = "ltm2985", | ||
| 1715 | .max_channels_nr = 10, | 1723 | .max_channels_nr = 10, |
| 1716 | .has_temp = true, | 1724 | .has_temp = true, |
| 1717 | .has_eeprom = true, | 1725 | .has_eeprom = true, |
| @@ -1721,7 +1729,7 @@ static const struct spi_device_id ltc2983_id_table[] = { · 3 unmodified lines | |||
| 1721 | { "ltc2983", (kernel_ulong_t)<c2983_chip_info_data }, | 1729 | { "ltc2983", (kernel_ulong_t)<c2983_chip_info_data }, |
| 1722 | { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, | 1730 | { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, |
| 1723 | { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, | 1731 | { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, |
| 1724 | { "ltm2985", (kernel_ulong_t)<c2986_chip_info_data }, | 1732 | { "ltm2985", (kernel_ulong_t)<m2985_chip_info_data }, |
| 1725 | {}, | 1733 | {}, |
| 1726 | }; | 1734 | }; |
| 1727 | MODULE_DEVICE_TABLE(spi, ltc2983_id_table); | 1735 | MODULE_DEVICE_TABLE(spi, ltc2983_id_table); |
| @@ -1730,7 +1738,7 @@ static const struct of_device_id ltc2983_of_match[] = { · 2 unmodified lines | |||
| 1730 | { .compatible = "adi,ltc2983", .data = <c2983_chip_info_data }, | 1738 | { .compatible = "adi,ltc2983", .data = <c2983_chip_info_data }, |
| 1731 | { .compatible = "adi,ltc2984", .data = <c2984_chip_info_data }, | 1739 | { .compatible = "adi,ltc2984", .data = <c2984_chip_info_data }, |
| 1732 | { .compatible = "adi,ltc2986", .data = <c2986_chip_info_data }, | 1740 | { .compatible = "adi,ltc2986", .data = <c2986_chip_info_data }, |
| 1733 | { .compatible = "adi,ltm2985", .data = <c2986_chip_info_data }, | 1741 | { .compatible = "adi,ltm2985", .data = <m2985_chip_info_data }, |
| 1734 | {}, | 1742 | {}, |
| 1735 | }; | 1743 | }; |
| 1736 | MODULE_DEVICE_TABLE(of, ltc2983_of_match); | 1744 | MODULE_DEVICE_TABLE(of, ltc2983_of_match); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | * Note: This driver assumes that the sensor has been calibrated beforehand. | 9 | * Note: This driver assumes that the sensor has been calibrated beforehand. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/delay.h> | ||
| 12 | #include <linux/err.h> | 13 | #include <linux/err.h> |
| 13 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| @@ -17,6 +18,7 @@ · 2 unmodified lines | |||
| 17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 18 | #include <linux/limits.h> | 19 | #include <linux/limits.h> |
| 19 | #include <linux/property.h> | 20 | #include <linux/property.h> |
| 21 | #include <linux/regulator/consumer.h> | ||
| 20 | 22 | ||
| 21 | #include <linux/iio/iio.h> | 23 | #include <linux/iio/iio.h> |
| 22 | 24 | ||
| @@ -148,10 +150,17 @@ static int tmp117_probe(struct i2c_client *client) · 125 unmodified lines | |||
| 148 | struct tmp117_data *data; | 150 | struct tmp117_data *data; |
| 149 | struct iio_dev *indio_dev; | 151 | struct iio_dev *indio_dev; |
| 150 | int dev_id; | 152 | int dev_id; |
| 153 | int ret; | ||
| 151 | 154 | ||
| 152 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) | 155 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) |
| 153 | return -EOPNOTSUPP; | 156 | return -EOPNOTSUPP; |
| 154 | 157 | ||
| 158 | ret = devm_regulator_get_enable(&client->dev, "vcc"); | ||
| 159 | if (ret) | ||
| 160 | return ret; | ||
| 161 | |||
| 162 | fsleep(1500); | ||
| 163 | |||
| 155 | dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); | 164 | dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); |
| 156 | if (dev_id < 0) | 165 | if (dev_id < 0) |
| 157 | return dev_id; | 166 | return dev_id; |
| @@ -4,6 +4,20 @@ · 3 unmodified lines | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | # Keep in alphabetical order | 6 | # Keep in alphabetical order |
| 7 | config IIO_GTS_KUNIT_TEST | ||
| 8 | tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS | ||
| 9 | depends on KUNIT | ||
| 10 | select IIO_GTS_HELPER | ||
| 11 | select TEST_KUNIT_DEVICE_HELPERS | ||
| 12 | default KUNIT_ALL_TESTS | ||
| 13 | help | ||
| 14 | build unit tests for the IIO light sensor gain-time-scale helpers. | ||
| 15 | |||
| 16 | For more information on KUnit and unit tests in general, please refer | ||
| 17 | to the KUnit documentation in Documentation/dev-tools/kunit/. | ||
| 18 | |||
| 19 | If unsure, say N. Keep in alphabetical order | ||
| 20 | |||
| 7 | config IIO_RESCALE_KUNIT_TEST | 21 | config IIO_RESCALE_KUNIT_TEST |
| 8 | tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS | 22 | tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS |
| 9 | depends on KUNIT && IIO_RESCALE | 23 | depends on KUNIT && IIO_RESCALE |
| @@ -6,4 +6,5 @@ · 5 unmodified lines | |||
| 6 | # Keep in alphabetical order | 6 | # Keep in alphabetical order |
| 7 | obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o | 7 | obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o |
| 8 | obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o | 8 | obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o |
| 9 | obj-$(CONFIG_IIO_GTS_KUNIT_TEST) += iio-test-gts.o | ||
| 9 | CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN) | 10 | CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN) |
| @@ -0,0 +1,513 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* Unit tests for IIO light sensor gain-time-scale helpers | ||
| 3 | * | ||
| 4 | * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <kunit/device.h> | ||
| 8 | #include <kunit/test.h> | ||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/iio/iio-gts-helper.h> | ||
| 11 | #include <linux/iio/types.h> | ||
| 12 | |||
| 13 | /* | ||
| 14 | * Please, read the "rant" from the top of the lib/test_linear_ranges.c if | ||
| 15 | * you see a line of helper code which is not being tested. | ||
| 16 | * | ||
| 17 | * Then, please look at the line which is not being tested. Is this line | ||
| 18 | * somehow unusually complex? If answer is "no", then chances are that the | ||
| 19 | * "development inertia" caused by adding a test exceeds the benefits. | ||
| 20 | * | ||
| 21 | * If yes, then adding a test is probably a good idea but please stop for a | ||
| 22 | * moment and consider the effort of changing all the tests when code gets | ||
| 23 | * refactored. Eventually it neeeds to be. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #define TEST_TSEL_50 1 | ||
| 27 | #define TEST_TSEL_X_MIN TEST_TSEL_50 | ||
| 28 | #define TEST_TSEL_100 0 | ||
| 29 | #define TEST_TSEL_200 2 | ||
| 30 | #define TEST_TSEL_400 4 | ||
| 31 | #define TEST_TSEL_X_MAX TEST_TSEL_400 | ||
| 32 | |||
| 33 | #define TEST_GSEL_1 0x00 | ||
| 34 | #define TEST_GSEL_X_MIN TEST_GSEL_1 | ||
| 35 | #define TEST_GSEL_4 0x08 | ||
| 36 | #define TEST_GSEL_16 0x0a | ||
| 37 | #define TEST_GSEL_32 0x0b | ||
| 38 | #define TEST_GSEL_64 0x0c | ||
| 39 | #define TEST_GSEL_256 0x18 | ||
| 40 | #define TEST_GSEL_512 0x19 | ||
| 41 | #define TEST_GSEL_1024 0x1a | ||
| 42 | #define TEST_GSEL_2048 0x1b | ||
| 43 | #define TEST_GSEL_4096 0x1c | ||
| 44 | #define TEST_GSEL_X_MAX TEST_GSEL_4096 | ||
| 45 | |||
| 46 | #define TEST_SCALE_1X 64 | ||
| 47 | #define TEST_SCALE_MIN_X TEST_SCALE_1X | ||
| 48 | #define TEST_SCALE_2X 32 | ||
| 49 | #define TEST_SCALE_4X 16 | ||
| 50 | #define TEST_SCALE_8X 8 | ||
| 51 | #define TEST_SCALE_16X 4 | ||
| 52 | #define TEST_SCALE_32X 2 | ||
| 53 | #define TEST_SCALE_64X 1 | ||
| 54 | |||
| 55 | #define TEST_SCALE_NANO_128X 500000000 | ||
| 56 | #define TEST_SCALE_NANO_256X 250000000 | ||
| 57 | #define TEST_SCALE_NANO_512X 125000000 | ||
| 58 | #define TEST_SCALE_NANO_1024X 62500000 | ||
| 59 | #define TEST_SCALE_NANO_2048X 31250000 | ||
| 60 | #define TEST_SCALE_NANO_4096X 15625000 | ||
| 61 | #define TEST_SCALE_NANO_4096X2 7812500 | ||
| 62 | #define TEST_SCALE_NANO_4096X4 3906250 | ||
| 63 | #define TEST_SCALE_NANO_4096X8 1953125 | ||
| 64 | |||
| 65 | #define TEST_SCALE_NANO_MAX_X TEST_SCALE_NANO_4096X8 | ||
| 66 | |||
| 67 | /* | ||
| 68 | * Can't have this allocated from stack because the kunit clean-up will | ||
| 69 | * happen only after the test function has already gone | ||
| 70 | */ | ||
| 71 | static struct iio_gts gts; | ||
| 72 | |||
| 73 | static const struct iio_gain_sel_pair gts_test_gains[] = { | ||
| 74 | GAIN_SCALE_GAIN(1, TEST_GSEL_1), | ||
| 75 | GAIN_SCALE_GAIN(4, TEST_GSEL_4), | ||
| 76 | GAIN_SCALE_GAIN(16, TEST_GSEL_16), | ||
| 77 | GAIN_SCALE_GAIN(32, TEST_GSEL_32), | ||
| 78 | GAIN_SCALE_GAIN(64, TEST_GSEL_64), | ||
| 79 | GAIN_SCALE_GAIN(256, TEST_GSEL_256), | ||
| 80 | GAIN_SCALE_GAIN(512, TEST_GSEL_512), | ||
| 81 | GAIN_SCALE_GAIN(1024, TEST_GSEL_1024), | ||
| 82 | GAIN_SCALE_GAIN(2048, TEST_GSEL_2048), | ||
| 83 | GAIN_SCALE_GAIN(4096, TEST_GSEL_4096), | ||
| 84 | #define HWGAIN_MAX 4096 | ||
| 85 | }; | ||
| 86 | |||
| 87 | static const struct iio_itime_sel_mul gts_test_itimes[] = { | ||
| 88 | GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), | ||
| 89 | GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), | ||
| 90 | GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2), | ||
| 91 | GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1), | ||
| 92 | #define TIMEGAIN_MAX 8 | ||
| 93 | }; | ||
| 94 | #define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX) | ||
| 95 | #define IIO_GTS_TEST_DEV "iio-gts-test-dev" | ||
| 96 | |||
| 97 | static struct device *__test_init_iio_gain_scale(struct kunit *test, | ||
| 98 | struct iio_gts *gts, const struct iio_gain_sel_pair *g_table, | ||
| 99 | int num_g, const struct iio_itime_sel_mul *i_table, int num_i) | ||
| 100 | { | ||
| 101 | struct device *dev; | ||
| 102 | int ret; | ||
| 103 | |||
| 104 | dev = kunit_device_register(test, IIO_GTS_TEST_DEV); | ||
| 105 | |||
| 106 | KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); | ||
| 107 | if (IS_ERR_OR_NULL(dev)) | ||
| 108 | return NULL; | ||
| 109 | |||
| 110 | ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g, | ||
| 111 | i_table, num_i, gts); | ||
| 112 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 113 | if (ret) | ||
| 114 | return NULL; | ||
| 115 | |||
| 116 | return dev; | ||
| 117 | } | ||
| 118 | |||
| 119 | #define test_init_iio_gain_scale(test, gts) \ | ||
| 120 | __test_init_iio_gain_scale(test, gts, gts_test_gains, \ | ||
| 121 | ARRAY_SIZE(gts_test_gains), gts_test_itimes, \ | ||
| 122 | ARRAY_SIZE(gts_test_itimes)) | ||
| 123 | |||
| 124 | static void test_init_iio_gts_invalid(struct kunit *test) | ||
| 125 | { | ||
| 126 | struct device *dev; | ||
| 127 | int ret; | ||
| 128 | const struct iio_itime_sel_mul itimes_neg[] = { | ||
| 129 | GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8), | ||
| 130 | GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), | ||
| 131 | }; | ||
| 132 | const struct iio_gain_sel_pair gains_neg[] = { | ||
| 133 | GAIN_SCALE_GAIN(1, TEST_GSEL_1), | ||
| 134 | GAIN_SCALE_GAIN(2, TEST_GSEL_4), | ||
| 135 | GAIN_SCALE_GAIN(-2, TEST_GSEL_16), | ||
| 136 | }; | ||
| 137 | /* 55555 * 38656 = 2147534080 => overflows 32bit int */ | ||
| 138 | const struct iio_itime_sel_mul itimes_overflow[] = { | ||
| 139 | GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555), | ||
| 140 | GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), | ||
| 141 | }; | ||
| 142 | const struct iio_gain_sel_pair gains_overflow[] = { | ||
| 143 | GAIN_SCALE_GAIN(1, TEST_GSEL_1), | ||
| 144 | GAIN_SCALE_GAIN(2, TEST_GSEL_4), | ||
| 145 | GAIN_SCALE_GAIN(38656, TEST_GSEL_16), | ||
| 146 | }; | ||
| 147 | |||
| 148 | dev = kunit_device_register(test, IIO_GTS_TEST_DEV); | ||
| 149 | KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); | ||
| 150 | if (!dev) | ||
| 151 | return; | ||
| 152 | |||
| 153 | /* Ok gains, negative time */ | ||
| 154 | ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains, | ||
| 155 | ARRAY_SIZE(gts_test_gains), itimes_neg, | ||
| 156 | ARRAY_SIZE(itimes_neg), >s); | ||
| 157 | KUNIT_EXPECT_EQ(test, -EINVAL, ret); | ||
| 158 | |||
| 159 | /* Ok times, negative gain */ | ||
| 160 | ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg, | ||
| 161 | ARRAY_SIZE(gains_neg), gts_test_itimes, | ||
| 162 | ARRAY_SIZE(gts_test_itimes), >s); | ||
| 163 | KUNIT_EXPECT_EQ(test, -EINVAL, ret); | ||
| 164 | |||
| 165 | /* gain * time overflow int */ | ||
| 166 | ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow, | ||
| 167 | ARRAY_SIZE(gains_overflow), itimes_overflow, | ||
| 168 | ARRAY_SIZE(itimes_overflow), >s); | ||
| 169 | KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test) | ||
| 173 | { | ||
| 174 | struct device *dev; | ||
| 175 | int ret, gain_sel; | ||
| 176 | |||
| 177 | dev = test_init_iio_gain_scale(test, >s); | ||
| 178 | if (!dev) | ||
| 179 | return; | ||
| 180 | |||
| 181 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, | ||
| 182 | TEST_SCALE_8X, 0, &gain_sel); | ||
| 183 | /* | ||
| 184 | * Meas time 100 => gain by time 2x | ||
| 185 | * TEST_SCALE_8X matches total gain 8x | ||
| 186 | * => required HWGAIN 4x | ||
| 187 | */ | ||
| 188 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 189 | KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel); | ||
| 190 | |||
| 191 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, | ||
| 192 | TEST_SCALE_NANO_256X, &gain_sel); | ||
| 193 | /* | ||
| 194 | * Meas time 200 => gain by time 4x | ||
| 195 | * TEST_SCALE_256X matches total gain 256x | ||
| 196 | * => required HWGAIN 256/4 => 64x | ||
| 197 | */ | ||
| 198 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 199 | KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel); | ||
| 200 | |||
| 201 | /* Min time, Min gain */ | ||
| 202 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MIN, | ||
| 203 | TEST_SCALE_MIN_X, 0, &gain_sel); | ||
| 204 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 205 | KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel); | ||
| 206 | |||
| 207 | /* Max time, Max gain */ | ||
| 208 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MAX, | ||
| 209 | 0, TEST_SCALE_NANO_MAX_X, &gain_sel); | ||
| 210 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 211 | KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel); | ||
| 212 | |||
| 213 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, 0, | ||
| 214 | TEST_SCALE_NANO_256X, &gain_sel); | ||
| 215 | /* | ||
| 216 | * Meas time 100 => gain by time 2x | ||
| 217 | * TEST_SCALE_256X matches total gain 256x | ||
| 218 | * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported) | ||
| 219 | */ | ||
| 220 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 221 | |||
| 222 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, | ||
| 223 | TEST_SCALE_NANO_MAX_X, &gain_sel); | ||
| 224 | /* We can't reach the max gain with integration time smaller than MAX */ | ||
| 225 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 226 | |||
| 227 | ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_50, 0, | ||
| 228 | TEST_SCALE_NANO_MAX_X, &gain_sel); | ||
| 229 | /* We can't reach the max gain with integration time smaller than MAX */ | ||
| 230 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 231 | } | ||
| 232 | |||
| 233 | static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test) | ||
| 234 | { | ||
| 235 | struct device *dev; | ||
| 236 | int ret, old_gain, new_gain, old_time_sel, new_time_sel; | ||
| 237 | |||
| 238 | dev = test_init_iio_gain_scale(test, >s); | ||
| 239 | if (!dev) | ||
| 240 | return; | ||
| 241 | |||
| 242 | old_gain = 32; | ||
| 243 | old_time_sel = TEST_TSEL_200; | ||
| 244 | new_time_sel = TEST_TSEL_400; | ||
| 245 | |||
| 246 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 247 | old_time_sel, new_time_sel, &new_gain); | ||
| 248 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 249 | /* | ||
| 250 | * Doubling the integration time doubles the total gain - so old | ||
| 251 | * (hw)gain must be divided by two to compensate. => 32 / 2 => 16 | ||
| 252 | */ | ||
| 253 | KUNIT_EXPECT_EQ(test, 16, new_gain); | ||
| 254 | |||
| 255 | old_gain = 4; | ||
| 256 | old_time_sel = TEST_TSEL_50; | ||
| 257 | new_time_sel = TEST_TSEL_200; | ||
| 258 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 259 | old_time_sel, new_time_sel, &new_gain); | ||
| 260 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 261 | /* | ||
| 262 | * gain by time 1x => 4x - (hw)gain 4x => 1x | ||
| 263 | */ | ||
| 264 | KUNIT_EXPECT_EQ(test, 1, new_gain); | ||
| 265 | |||
| 266 | old_gain = 512; | ||
| 267 | old_time_sel = TEST_TSEL_400; | ||
| 268 | new_time_sel = TEST_TSEL_50; | ||
| 269 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 270 | old_time_sel, new_time_sel, &new_gain); | ||
| 271 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 272 | /* | ||
| 273 | * gain by time 8x => 1x - (hw)gain 512x => 4096x) | ||
| 274 | */ | ||
| 275 | KUNIT_EXPECT_EQ(test, 4096, new_gain); | ||
| 276 | |||
| 277 | /* Unsupported gain 2x */ | ||
| 278 | old_gain = 4; | ||
| 279 | old_time_sel = TEST_TSEL_200; | ||
| 280 | new_time_sel = TEST_TSEL_400; | ||
| 281 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 282 | old_time_sel, new_time_sel, &new_gain); | ||
| 283 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 284 | |||
| 285 | /* Too small gain */ | ||
| 286 | old_gain = 4; | ||
| 287 | old_time_sel = TEST_TSEL_50; | ||
| 288 | new_time_sel = TEST_TSEL_400; | ||
| 289 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 290 | old_time_sel, new_time_sel, &new_gain); | ||
| 291 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 292 | |||
| 293 | /* Too big gain */ | ||
| 294 | old_gain = 1024; | ||
| 295 | old_time_sel = TEST_TSEL_400; | ||
| 296 | new_time_sel = TEST_TSEL_50; | ||
| 297 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, | ||
| 298 | old_time_sel, new_time_sel, &new_gain); | ||
| 299 | KUNIT_EXPECT_NE(test, 0, ret); | ||
| 300 | |||
| 301 | } | ||
| 302 | |||
| 303 | static void test_iio_find_closest_gain_low(struct kunit *test) | ||
| 304 | { | ||
| 305 | struct device *dev; | ||
| 306 | bool in_range; | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | const struct iio_gain_sel_pair gts_test_gains_gain_low[] = { | ||
| 310 | GAIN_SCALE_GAIN(4, TEST_GSEL_4), | ||
| 311 | GAIN_SCALE_GAIN(16, TEST_GSEL_16), | ||
| 312 | GAIN_SCALE_GAIN(32, TEST_GSEL_32), | ||
| 313 | }; | ||
| 314 | |||
| 315 | dev = test_init_iio_gain_scale(test, >s); | ||
| 316 | if (!dev) | ||
| 317 | return; | ||
| 318 | |||
| 319 | ret = iio_find_closest_gain_low(>s, 2, &in_range); | ||
| 320 | KUNIT_EXPECT_EQ(test, 1, ret); | ||
| 321 | KUNIT_EXPECT_EQ(test, true, in_range); | ||
| 322 | |||
| 323 | ret = iio_find_closest_gain_low(>s, 1, &in_range); | ||
| 324 | KUNIT_EXPECT_EQ(test, 1, ret); | ||
| 325 | KUNIT_EXPECT_EQ(test, true, in_range); | ||
| 326 | |||
| 327 | ret = iio_find_closest_gain_low(>s, 4095, &in_range); | ||
| 328 | KUNIT_EXPECT_EQ(test, 2048, ret); | ||
| 329 | KUNIT_EXPECT_EQ(test, true, in_range); | ||
| 330 | |||
| 331 | ret = iio_find_closest_gain_low(>s, 4097, &in_range); | ||
| 332 | KUNIT_EXPECT_EQ(test, 4096, ret); | ||
| 333 | KUNIT_EXPECT_EQ(test, false, in_range); | ||
| 334 | |||
| 335 | kunit_device_unregister(test, dev); | ||
| 336 | |||
| 337 | dev = __test_init_iio_gain_scale(test, >s, gts_test_gains_gain_low, | ||
| 338 | ARRAY_SIZE(gts_test_gains_gain_low), | ||
| 339 | gts_test_itimes, ARRAY_SIZE(gts_test_itimes)); | ||
| 340 | if (!dev) | ||
| 341 | return; | ||
| 342 | |||
| 343 | ret = iio_find_closest_gain_low(>s, 3, &in_range); | ||
| 344 | KUNIT_EXPECT_EQ(test, -EINVAL, ret); | ||
| 345 | KUNIT_EXPECT_EQ(test, false, in_range); | ||
| 346 | } | ||
| 347 | |||
| 348 | static void test_iio_gts_total_gain_to_scale(struct kunit *test) | ||
| 349 | { | ||
| 350 | struct device *dev; | ||
| 351 | int ret, scale_int, scale_nano; | ||
| 352 | |||
| 353 | dev = test_init_iio_gain_scale(test, >s); | ||
| 354 | if (!dev) | ||
| 355 | return; | ||
| 356 | |||
| 357 | ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); | ||
| 358 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 359 | KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); | ||
| 360 | KUNIT_EXPECT_EQ(test, 0, scale_nano); | ||
| 361 | |||
| 362 | ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); | ||
| 363 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 364 | KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); | ||
| 365 | KUNIT_EXPECT_EQ(test, 0, scale_nano); | ||
| 366 | |||
| 367 | ret = iio_gts_total_gain_to_scale(>s, 4096 * 8, &scale_int, | ||
| 368 | &scale_nano); | ||
| 369 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 370 | KUNIT_EXPECT_EQ(test, 0, scale_int); | ||
| 371 | KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano); | ||
| 372 | } | ||
| 373 | |||
| 374 | static void test_iio_gts_chk_times(struct kunit *test, const int *vals) | ||
| 375 | { | ||
| 376 | static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000}; | ||
| 377 | int i; | ||
| 378 | |||
| 379 | for (i = 0; i < ARRAY_SIZE(expected); i++) | ||
| 380 | KUNIT_EXPECT_EQ(test, expected[i], vals[i]); | ||
| 381 | } | ||
| 382 | |||
| 383 | static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts, | ||
| 384 | const int *vals, int len) | ||
| 385 | { | ||
| 386 | static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, | ||
| 387 | 1024, 2048, 4096, 4096 * 2, 4096 * 4, | ||
| 388 | 4096 * 8}; | ||
| 389 | int expected[ARRAY_SIZE(gains) * 2]; | ||
| 390 | int i, ret; | ||
| 391 | int exp_len = ARRAY_SIZE(gains) * 2; | ||
| 392 | |||
| 393 | KUNIT_EXPECT_EQ(test, exp_len, len); | ||
| 394 | if (len != exp_len) | ||
| 395 | return; | ||
| 396 | |||
| 397 | for (i = 0; i < ARRAY_SIZE(gains); i++) { | ||
| 398 | ret = iio_gts_total_gain_to_scale(gts, gains[i], | ||
| 399 | &expected[2 * i], | ||
| 400 | &expected[2 * i + 1]); | ||
| 401 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 402 | if (ret) | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | |||
| 406 | for (i = 0; i < ARRAY_SIZE(expected); i++) | ||
| 407 | KUNIT_EXPECT_EQ(test, expected[i], vals[i]); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts, | ||
| 411 | const int *vals, int len) | ||
| 412 | { | ||
| 413 | /* The gain caused by time 200 is 4x */ | ||
| 414 | static const int gains[] = { | ||
| 415 | 1 * 4, | ||
| 416 | 4 * 4, | ||
| 417 | 16 * 4, | ||
| 418 | 32 * 4, | ||
| 419 | 64 * 4, | ||
| 420 | 256 * 4, | ||
| 421 | 512 * 4, | ||
| 422 | 1024 * 4, | ||
| 423 | 2048 * 4, | ||
| 424 | 4096 * 4 | ||
| 425 | }; | ||
| 426 | int expected[ARRAY_SIZE(gains) * 2]; | ||
| 427 | int i, ret; | ||
| 428 | |||
| 429 | KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len); | ||
| 430 | if (len < 2 * ARRAY_SIZE(gains)) | ||
| 431 | return; | ||
| 432 | |||
| 433 | for (i = 0; i < ARRAY_SIZE(gains); i++) { | ||
| 434 | ret = iio_gts_total_gain_to_scale(gts, gains[i], | ||
| 435 | &expected[2 * i], | ||
| 436 | &expected[2 * i + 1]); | ||
| 437 | KUNIT_EXPECT_EQ(test, 0, ret); | ||
| 438 | if (ret) | ||
| 439 | return; | ||
| 440 | } | ||
| 441 | |||
| 442 | for (i = 0; i < ARRAY_SIZE(expected); i++) | ||
| 443 | KUNIT_EXPECT_EQ(test, expected[i], vals[i]); | ||
| 444 | } | ||
| 445 | |||
| 446 | static void test_iio_gts_avail_test(struct kunit *test) | ||
| 447 | { | ||
| 448 | struct device *dev; | ||
| 449 | int ret; | ||
| 450 | int type, len; | ||
| 451 | const int *vals; | ||
| 452 | |||
| 453 | dev = test_init_iio_gain_scale(test, >s); | ||
| 454 | if (!dev) | ||
| 455 | return; | ||
| 456 | |||
| 457 | /* test table building for times and iio_gts_avail_times() */ | ||
| 458 | ret = iio_gts_avail_times(>s, &vals, &type, &len); | ||
| 459 | KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); | ||
| 460 | if (ret) | ||
| 461 | return; | ||
| 462 | |||
| 463 | KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type); | ||
| 464 | KUNIT_EXPECT_EQ(test, 8, len); | ||
| 465 | if (len < 8) | ||
| 466 | return; | ||
| 467 | |||
| 468 | test_iio_gts_chk_times(test, vals); | ||
| 469 | |||
| 470 | /* Test table building for all scales and iio_gts_all_avail_scales() */ | ||
| 471 | ret = iio_gts_all_avail_scales(>s, &vals, &type, &len); | ||
| 472 | KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); | ||
| 473 | if (ret) | ||
| 474 | return; | ||
| 475 | |||
| 476 | KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); | ||
| 477 | |||
| 478 | test_iio_gts_chk_scales_all(test, >s, vals, len); | ||
| 479 | |||
| 480 | /* | ||
| 481 | * Test table building for scales/time and | ||
| 482 | * iio_gts_avail_scales_for_time() | ||
| 483 | */ | ||
| 484 | ret = iio_gts_avail_scales_for_time(>s, 200000, &vals, &type, &len); | ||
| 485 | KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); | ||
| 486 | if (ret) | ||
| 487 | return; | ||
| 488 | |||
| 489 | KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); | ||
| 490 | test_iio_gts_chk_scales_t200(test, >s, vals, len); | ||
| 491 | } | ||
| 492 | |||
| 493 | static struct kunit_case iio_gts_test_cases[] = { | ||
| 494 | KUNIT_CASE(test_init_iio_gts_invalid), | ||
| 495 | KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time), | ||
| 496 | KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time), | ||
| 497 | KUNIT_CASE(test_iio_find_closest_gain_low), | ||
| 498 | KUNIT_CASE(test_iio_gts_total_gain_to_scale), | ||
| 499 | KUNIT_CASE(test_iio_gts_avail_test), | ||
| 500 | {} | ||
| 501 | }; | ||
| 502 | |||
| 503 | static struct kunit_suite iio_gts_test_suite = { | ||
| 504 | .name = "iio-gain-time-scale", | ||
| 505 | .test_cases = iio_gts_test_cases, | ||
| 506 | }; | ||
| 507 | |||
| 508 | kunit_test_suite(iio_gts_test_suite); | ||
| 509 | |||
| 510 | MODULE_LICENSE("GPL"); | ||
| 511 | MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); | ||
| 512 | MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers"); | ||
| 513 | MODULE_IMPORT_NS(IIO_GTS_HELPER); | ||
| @@ -343,7 +343,7 @@ EXPORT_SYMBOL_GPL(icc_std_aggregate); · 342 unmodified lines | |||
| 343 | * an array of icc nodes specified in the icc_onecell_data struct when | 343 | * an array of icc nodes specified in the icc_onecell_data struct when |
| 344 | * registering the provider. | 344 | * registering the provider. |
| 345 | */ | 345 | */ |
| 346 | struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec, | 346 | struct icc_node *of_icc_xlate_onecell(const struct of_phandle_args *spec, |
| 347 | void *data) | 347 | void *data) |
| 348 | { | 348 | { |
| 349 | struct icc_onecell_data *icc_data = data; | 349 | struct icc_onecell_data *icc_data = data; |
| @@ -368,7 +368,7 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell); · 18 unmodified lines | |||
| 368 | * Returns a valid pointer to struct icc_node_data on success or ERR_PTR() | 368 | * Returns a valid pointer to struct icc_node_data on success or ERR_PTR() |
| 369 | * on failure. | 369 | * on failure. |
| 370 | */ | 370 | */ |
| 371 | struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec) | 371 | struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spec) |
| 372 | { | 372 | { |
| 373 | struct icc_node *node = ERR_PTR(-EPROBE_DEFER); | 373 | struct icc_node *node = ERR_PTR(-EPROBE_DEFER); |
| 374 | struct icc_node_data *data = NULL; | 374 | struct icc_node_data *data = NULL; |
| @@ -8,6 +8,15 @@ config INTERCONNECT_QCOM · 7 unmodified lines | |||
| 8 | config INTERCONNECT_QCOM_BCM_VOTER | 8 | config INTERCONNECT_QCOM_BCM_VOTER |
| 9 | tristate | 9 | tristate |
| 10 | 10 | ||
| 11 | config INTERCONNECT_QCOM_MSM8909 | ||
| 12 | tristate "Qualcomm MSM8909 interconnect driver" | ||
| 13 | depends on INTERCONNECT_QCOM | ||
| 14 | depends on QCOM_SMD_RPM | ||
| 15 | select INTERCONNECT_QCOM_SMD_RPM | ||
| 16 | help | ||
| 17 | This is a driver for the Qualcomm Network-on-Chip on msm8909-based | ||
| 18 | platforms. | ||
| 19 | |||
| 11 | config INTERCONNECT_QCOM_MSM8916 | 20 | config INTERCONNECT_QCOM_MSM8916 |
| 12 | tristate "Qualcomm MSM8916 interconnect driver" | 21 | tristate "Qualcomm MSM8916 interconnect driver" |
| 13 | depends on INTERCONNECT_QCOM | 22 | depends on INTERCONNECT_QCOM |
| @@ -209,6 +218,15 @@ config INTERCONNECT_QCOM_SM6350 · 195 unmodified lines | |||
| 209 | This is a driver for the Qualcomm Network-on-Chip on sm6350-based | 218 | This is a driver for the Qualcomm Network-on-Chip on sm6350-based |
| 210 | platforms. | 219 | platforms. |
| 211 | 220 | ||
| 221 | config INTERCONNECT_QCOM_SM7150 | ||
| 222 | tristate "Qualcomm SM7150 interconnect driver" | ||
| 223 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE | ||
| 224 | select INTERCONNECT_QCOM_RPMH | ||
| 225 | select INTERCONNECT_QCOM_BCM_VOTER | ||
| 226 | help | ||
| 227 | This is a driver for the Qualcomm Network-on-Chip on sm7150-based | ||
| 228 | platforms. | ||
| 229 | |||
| 212 | config INTERCONNECT_QCOM_SM8150 | 230 | config INTERCONNECT_QCOM_SM8150 |
| 213 | tristate "Qualcomm SM8150 interconnect driver" | 231 | tristate "Qualcomm SM8150 interconnect driver" |
| 214 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE | 232 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE |
| @@ -4,6 +4,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | interconnect_qcom-y := icc-common.o | 5 | interconnect_qcom-y := icc-common.o |
| 6 | icc-bcm-voter-objs := bcm-voter.o | 6 | icc-bcm-voter-objs := bcm-voter.o |
| 7 | qnoc-msm8909-objs := msm8909.o | ||
| 7 | qnoc-msm8916-objs := msm8916.o | 8 | qnoc-msm8916-objs := msm8916.o |
| 8 | qnoc-msm8939-objs := msm8939.o | 9 | qnoc-msm8939-objs := msm8939.o |
| 9 | qnoc-msm8974-objs := msm8974.o | 10 | qnoc-msm8974-objs := msm8974.o |
| @@ -26,6 +27,7 @@ qnoc-sdx65-objs := sdx65.o · 16 unmodified lines | |||
| 26 | qnoc-sdx75-objs := sdx75.o | 27 | qnoc-sdx75-objs := sdx75.o |
| 27 | qnoc-sm6115-objs := sm6115.o | 28 | qnoc-sm6115-objs := sm6115.o |
| 28 | qnoc-sm6350-objs := sm6350.o | 29 | qnoc-sm6350-objs := sm6350.o |
| 30 | qnoc-sm7150-objs := sm7150.o | ||
| 29 | qnoc-sm8150-objs := sm8150.o | 31 | qnoc-sm8150-objs := sm8150.o |
| 30 | qnoc-sm8250-objs := sm8250.o | 32 | qnoc-sm8250-objs := sm8250.o |
| 31 | qnoc-sm8350-objs := sm8350.o | 33 | qnoc-sm8350-objs := sm8350.o |
| @@ -36,6 +38,7 @@ qnoc-x1e80100-objs := x1e80100.o · 4 unmodified lines | |||
| 36 | icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o | 38 | icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o |
| 37 | 39 | ||
| 38 | obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o | 40 | obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o |
| 41 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o | ||
| 39 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o | 42 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o |
| 40 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o | 43 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o |
| 41 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o | 44 | obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o |
| @@ -58,6 +61,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o · 16 unmodified lines | |||
| 58 | obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o | 61 | obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o |
| 59 | obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o | 62 | obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o |
| 60 | obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o | 63 | obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o |
| 64 | obj-$(CONFIG_INTERCONNECT_QCOM_SM7150) += qnoc-sm7150.o | ||
| 61 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o | 65 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o |
| 62 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o | 66 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o |
| 63 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o | 67 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o |
| @@ -9,7 +9,8 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include "icc-common.h" | 10 | #include "icc-common.h" |
| 11 | 11 | ||
| 12 | struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data) | 12 | struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec, |
| 13 | void *data) | ||
| 13 | { | 14 | { |
| 14 | struct icc_node_data *ndata; | 15 | struct icc_node_data *ndata; |
| 15 | struct icc_node *node; | 16 | struct icc_node *node; |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/interconnect-provider.h> | 9 | #include <linux/interconnect-provider.h> |
| 10 | 10 | ||
| 11 | struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data); | 11 | struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec, |
| 12 | void *data); | ||
| 12 | 13 | ||
| 13 | #endif | 14 | #endif |
| @@ -0,0 +1,1329 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Based on data from msm8909-bus.dtsi in Qualcomm's msm-3.18 release: | ||
| 4 | * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/device.h> | ||
| 8 | #include <linux/interconnect-provider.h> | ||
| 9 | #include <linux/mod_devicetable.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | |||
| 14 | #include <dt-bindings/interconnect/qcom,msm8909.h> | ||
| 15 | |||
| 16 | #include "icc-rpm.h" | ||
| 17 | |||
| 18 | enum { | ||
| 19 | QNOC_MASTER_AMPSS_M0 = 1, | ||
| 20 | QNOC_MASTER_GRAPHICS_3D, | ||
| 21 | QNOC_SNOC_BIMC_0_MAS, | ||
| 22 | QNOC_SNOC_BIMC_1_MAS, | ||
| 23 | QNOC_MASTER_TCU_0, | ||
| 24 | QNOC_MASTER_TCU_1, | ||
| 25 | QNOC_MASTER_AUDIO, | ||
| 26 | QNOC_MASTER_SPDM, | ||
| 27 | QNOC_MASTER_DEHR, | ||
| 28 | QNOC_MASTER_QPIC, | ||
| 29 | QNOC_MASTER_BLSP_1, | ||
| 30 | QNOC_MASTER_USB_HS, | ||
| 31 | QNOC_MASTER_CRYPTO_CORE0, | ||
| 32 | QNOC_MASTER_SDCC_1, | ||
| 33 | QNOC_MASTER_SDCC_2, | ||
| 34 | QNOC_SNOC_PNOC_MAS, | ||
| 35 | QNOC_MASTER_QDSS_BAM, | ||
| 36 | QNOC_BIMC_SNOC_MAS, | ||
| 37 | QNOC_MASTER_MDP_PORT0, | ||
| 38 | QNOC_PNOC_SNOC_MAS, | ||
| 39 | QNOC_MASTER_VIDEO_P0, | ||
| 40 | QNOC_MASTER_VFE, | ||
| 41 | QNOC_MASTER_QDSS_ETR, | ||
| 42 | QNOC_PNOC_M_0, | ||
| 43 | QNOC_PNOC_M_1, | ||
| 44 | QNOC_PNOC_INT_0, | ||
| 45 | QNOC_PNOC_INT_1, | ||
| 46 | QNOC_PNOC_SLV_0, | ||
| 47 | QNOC_PNOC_SLV_1, | ||
| 48 | QNOC_PNOC_SLV_2, | ||
| 49 | QNOC_PNOC_SLV_3, | ||
| 50 | QNOC_PNOC_SLV_4, | ||
| 51 | QNOC_PNOC_SLV_5, | ||
| 52 | QNOC_PNOC_SLV_7, | ||
| 53 | QNOC_SNOC_MM_INT_0, | ||
| 54 | QNOC_SNOC_MM_INT_1, | ||
| 55 | QNOC_SNOC_MM_INT_2, | ||
| 56 | QNOC_SNOC_MM_INT_BIMC, | ||
| 57 | QNOC_SNOC_QDSS_INT, | ||
| 58 | QNOC_SNOC_INT_0, | ||
| 59 | QNOC_SNOC_INT_1, | ||
| 60 | QNOC_SNOC_INT_BIMC, | ||
| 61 | QNOC_SLAVE_EBI_CH0, | ||
| 62 | QNOC_BIMC_SNOC_SLV, | ||
| 63 | QNOC_SLAVE_TCSR, | ||
| 64 | QNOC_SLAVE_SDCC_1, | ||
| 65 | QNOC_SLAVE_BLSP_1, | ||
| 66 | QNOC_SLAVE_CRYPTO_0_CFG, | ||
| 67 | QNOC_SLAVE_MESSAGE_RAM, | ||
| 68 | QNOC_SLAVE_PDM, | ||
| 69 | QNOC_SLAVE_PRNG, | ||
| 70 | QNOC_SLAVE_USB_HS, | ||
| 71 | QNOC_SLAVE_QPIC, | ||
| 72 | QNOC_SLAVE_SPDM, | ||
| 73 | QNOC_SLAVE_SDCC_2, | ||
| 74 | QNOC_SLAVE_AUDIO, | ||
| 75 | QNOC_SLAVE_DEHR_CFG, | ||
| 76 | QNOC_SLAVE_SNOC_CFG, | ||
| 77 | QNOC_SLAVE_QDSS_CFG, | ||
| 78 | QNOC_SLAVE_USB_PHYS_CFG, | ||
| 79 | QNOC_SLAVE_CAMERA_CFG, | ||
1250 more lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 1755 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 635 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 450 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.