Pull staging / IIO driver updates from Greg KH: "Here is the big staging and iio driver update for 5.2-rc1. Lots of tiny fixes all over the staging and IIO driver trees here, along with some new IIO drivers. The "counter" subsystem was added in here as well, as it is needed by the IIO drivers and subsystem. Also we ended up deleting two drivers, making this pull request remove a few hundred thousand lines of code, always a nice thing to see. Both of the drivers removed have been replaced with "real" drivers in their various subsystem directories, and they will be coming to you from those locations during this merge window. There are some core vt/selection changes in here, that was due to some cleanups needed for the speakup fixes. Those have all been acked by the various subsystem maintainers (i.e. me), so those are ok. We also added a few new drivers, for some odd hardware, giving new developers plenty to work on with basic coding style cleanups to come in the near future. Other than that, nothing unusual here. All of these have been in linux-next for a while with no reported issues, other than an odd gcc warning for one of the new drivers that should be fixed up soon" [ I fixed up the warning myself - Linus ] * tag 'staging-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (663 commits) staging: kpc2000: kpc_spi: Fix build error for {read,write}q Staging: rtl8192e: Remove extra space before break statement Staging: rtl8192u: ieee80211: Fix if-else indentation warning Staging: rtl8192u: ieee80211: Fix indentation errors by removing extra spaces staging: most: cdev: fix chrdev_region leak in mod_exit staging: wlan-ng: Fix improper SPDX comment style staging: rtl8192u: ieee80211: Resolve ERROR reported by checkpatch staging: vc04_services: bcm2835-camera: Compress two lines into one line staging: rtl8723bs: core: Use !x in place of NULL comparison. staging: rtl8723bs: core: Prefer using the BIT Macro. staging: fieldbus: anybus-s: fix wait_for_completion_timeout return handling staging: kpc2000: fix up build problems with readq() staging: rtlwifi: move remaining phydm .h files staging: rtlwifi: strip down phydm .h files staging: rtlwifi: delete the staging driver staging: fieldbus: anybus-s: rename bus id field to avoid confusion staging: fieldbus: anybus-s: keep device bus id in bus endianness Staging: sm750fb: Change *array into *const array staging: rtl8192u: ieee80211: Fix spelling mistake staging: rtl8192u: ieee80211: Replace bit shifting with BIT macro ...
Unified · Split
| @@ -189,6 +189,7 @@ Santosh Shilimkar <ssantosh@kernel.org> · 188 unmodified lines | |||
| 189 | Santosh Shilimkar <santosh.shilimkar@oracle.org> | 189 | Santosh Shilimkar <santosh.shilimkar@oracle.org> |
| 190 | Sascha Hauer <s.hauer@pengutronix.de> | 190 | Sascha Hauer <s.hauer@pengutronix.de> |
| 191 | S.Çağlar Onur <caglar@pardus.org.tr> | 191 | S.Çağlar Onur <caglar@pardus.org.tr> |
| 192 | Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> | ||
| 192 | Sebastian Reichel <sre@kernel.org> <sre@debian.org> | 193 | Sebastian Reichel <sre@kernel.org> <sre@debian.org> |
| 193 | Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> | 194 | Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> |
| 194 | Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> | 195 | Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> |
| @@ -0,0 +1,230 @@ | |||
| 1 | What: /sys/bus/counter/devices/counterX/countY/count | ||
| 2 | KernelVersion: 5.2 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Count data of Count Y represented as a string. | ||
| 6 | |||
| 7 | What: /sys/bus/counter/devices/counterX/countY/ceiling | ||
| 8 | KernelVersion: 5.2 | ||
| 9 | Contact: linux-iio@vger.kernel.org | ||
| 10 | Description: | ||
| 11 | Count value ceiling for Count Y. This is the upper limit for the | ||
| 12 | respective counter. | ||
| 13 | |||
| 14 | What: /sys/bus/counter/devices/counterX/countY/floor | ||
| 15 | KernelVersion: 5.2 | ||
| 16 | Contact: linux-iio@vger.kernel.org | ||
| 17 | Description: | ||
| 18 | Count value floor for Count Y. This is the lower limit for the | ||
| 19 | respective counter. | ||
| 20 | |||
| 21 | What: /sys/bus/counter/devices/counterX/countY/count_mode | ||
| 22 | KernelVersion: 5.2 | ||
| 23 | Contact: linux-iio@vger.kernel.org | ||
| 24 | Description: | ||
| 25 | Count mode for channel Y. The ceiling and floor values for | ||
| 26 | Count Y are used by the count mode where required. The following | ||
| 27 | count modes are available: | ||
| 28 | |||
| 29 | normal: | ||
| 30 | Counting is continuous in either direction. | ||
| 31 | |||
| 32 | range limit: | ||
| 33 | An upper or lower limit is set, mimicking limit switches | ||
| 34 | in the mechanical counterpart. The upper limit is set to | ||
| 35 | the Count Y ceiling value, while the lower limit is set | ||
| 36 | to the Count Y floor value. The counter freezes at | ||
| 37 | count = ceiling when counting up, and at count = floor | ||
| 38 | when counting down. At either of these limits, the | ||
| 39 | counting is resumed only when the count direction is | ||
| 40 | reversed. | ||
| 41 | |||
| 42 | non-recycle: | ||
| 43 | The counter is disabled whenever a counter overflow or | ||
| 44 | underflow takes place. The counter is re-enabled when a | ||
| 45 | new count value is loaded to the counter via a preset | ||
| 46 | operation or direct write. | ||
| 47 | |||
| 48 | modulo-n: | ||
| 49 | A count value boundary is set between the Count Y floor | ||
| 50 | value and the Count Y ceiling value. The counter is | ||
| 51 | reset to the Count Y floor value at count = ceiling when | ||
| 52 | counting up, while the counter is set to the Count Y | ||
| 53 | ceiling value at count = floor when counting down; the | ||
| 54 | counter does not freeze at the boundary points, but | ||
| 55 | counts continuously throughout. | ||
| 56 | |||
| 57 | What: /sys/bus/counter/devices/counterX/countY/count_mode_available | ||
| 58 | What: /sys/bus/counter/devices/counterX/countY/error_noise_available | ||
| 59 | What: /sys/bus/counter/devices/counterX/countY/function_available | ||
| 60 | What: /sys/bus/counter/devices/counterX/countY/signalZ_action_available | ||
| 61 | KernelVersion: 5.2 | ||
| 62 | Contact: linux-iio@vger.kernel.org | ||
| 63 | Description: | ||
| 64 | Discrete set of available values for the respective Count Y | ||
| 65 | configuration are listed in this file. Values are delimited by | ||
| 66 | newline characters. | ||
| 67 | |||
| 68 | What: /sys/bus/counter/devices/counterX/countY/direction | ||
| 69 | KernelVersion: 5.2 | ||
| 70 | Contact: linux-iio@vger.kernel.org | ||
| 71 | Description: | ||
| 72 | Read-only attribute that indicates the count direction of Count | ||
| 73 | Y. Two count directions are available: forward and backward. | ||
| 74 | |||
| 75 | Some counter devices are able to determine the direction of | ||
| 76 | their counting. For example, quadrature encoding counters can | ||
| 77 | determine the direction of movement by evaluating the leading | ||
| 78 | phase of the respective A and B quadrature encoding signals. | ||
| 79 | This attribute exposes such count directions. | ||
| 80 | |||
| 81 | What: /sys/bus/counter/devices/counterX/countY/enable | ||
| 82 | KernelVersion: 5.2 | ||
| 83 | Contact: linux-iio@vger.kernel.org | ||
| 84 | Description: | ||
| 85 | Whether channel Y counter is enabled. Valid attribute values are | ||
| 86 | boolean. | ||
| 87 | |||
| 88 | This attribute is intended to serve as a pause/unpause mechanism | ||
| 89 | for Count Y. Suppose a counter device is used to count the total | ||
| 90 | movement of a conveyor belt: this attribute allows an operator | ||
| 91 | to temporarily pause the counter, service the conveyor belt, | ||
| 92 | and then finally unpause the counter to continue where it had | ||
| 93 | left off. | ||
| 94 | |||
| 95 | What: /sys/bus/counter/devices/counterX/countY/error_noise | ||
| 96 | KernelVersion: 5.2 | ||
| 97 | Contact: linux-iio@vger.kernel.org | ||
| 98 | Description: | ||
| 99 | Read-only attribute that indicates whether excessive noise is | ||
| 100 | present at the channel Y counter inputs. | ||
| 101 | |||
| 102 | What: /sys/bus/counter/devices/counterX/countY/function | ||
| 103 | KernelVersion: 5.2 | ||
| 104 | Contact: linux-iio@vger.kernel.org | ||
| 105 | Description: | ||
| 106 | Count function mode of Count Y; count function evaluation is | ||
| 107 | triggered by conditions specified by the Count Y signalZ_action | ||
| 108 | attributes. The following count functions are available: | ||
| 109 | |||
| 110 | increase: | ||
| 111 | Accumulated count is incremented. | ||
| 112 | |||
| 113 | decrease: | ||
| 114 | Accumulated count is decremented. | ||
| 115 | |||
| 116 | pulse-direction: | ||
| 117 | Rising edges on signal A updates the respective count. | ||
| 118 | The input level of signal B determines direction. | ||
| 119 | |||
| 120 | quadrature x1 a: | ||
| 121 | If direction is forward, rising edges on quadrature pair | ||
| 122 | signal A updates the respective count; if the direction | ||
| 123 | is backward, falling edges on quadrature pair signal A | ||
| 124 | updates the respective count. Quadrature encoding | ||
| 125 | determines the direction. | ||
| 126 | |||
| 127 | quadrature x1 b: | ||
| 128 | If direction is forward, rising edges on quadrature pair | ||
| 129 | signal B updates the respective count; if the direction | ||
| 130 | is backward, falling edges on quadrature pair signal B | ||
| 131 | updates the respective count. Quadrature encoding | ||
| 132 | determines the direction. | ||
| 133 | |||
| 134 | quadrature x2 a: | ||
| 135 | Any state transition on quadrature pair signal A updates | ||
| 136 | the respective count. Quadrature encoding determines the | ||
| 137 | direction. | ||
| 138 | |||
| 139 | quadrature x2 b: | ||
| 140 | Any state transition on quadrature pair signal B updates | ||
| 141 | the respective count. Quadrature encoding determines the | ||
| 142 | direction. | ||
| 143 | |||
| 144 | quadrature x4: | ||
| 145 | Any state transition on either quadrature pair signals | ||
| 146 | updates the respective count. Quadrature encoding | ||
| 147 | determines the direction. | ||
| 148 | |||
| 149 | What: /sys/bus/counter/devices/counterX/countY/name | ||
| 150 | KernelVersion: 5.2 | ||
| 151 | Contact: linux-iio@vger.kernel.org | ||
| 152 | Description: | ||
| 153 | Read-only attribute that indicates the device-specific name of | ||
| 154 | Count Y. If possible, this should match the name of the | ||
| 155 | respective channel as it appears in the device datasheet. | ||
| 156 | |||
| 157 | What: /sys/bus/counter/devices/counterX/countY/preset | ||
| 158 | KernelVersion: 5.2 | ||
| 159 | Contact: linux-iio@vger.kernel.org | ||
| 160 | Description: | ||
| 161 | If the counter device supports preset registers -- registers | ||
| 162 | used to load counter channels to a set count upon device-defined | ||
| 163 | preset operation trigger events -- the preset count for channel | ||
| 164 | Y is provided by this attribute. | ||
| 165 | |||
| 166 | What: /sys/bus/counter/devices/counterX/countY/preset_enable | ||
| 167 | KernelVersion: 5.2 | ||
| 168 | Contact: linux-iio@vger.kernel.org | ||
| 169 | Description: | ||
| 170 | Whether channel Y counter preset operation is enabled. Valid | ||
| 171 | attribute values are boolean. | ||
| 172 | |||
| 173 | What: /sys/bus/counter/devices/counterX/countY/signalZ_action | ||
| 174 | KernelVersion: 5.2 | ||
| 175 | Contact: linux-iio@vger.kernel.org | ||
| 176 | Description: | ||
| 177 | Action mode of Count Y for Signal Z. This attribute indicates | ||
| 178 | the condition of Signal Z that triggers the count function | ||
| 179 | evaluation for Count Y. The following action modes are | ||
| 180 | available: | ||
| 181 | |||
| 182 | none: | ||
| 183 | Signal does not trigger the count function. In | ||
| 184 | Pulse-Direction count function mode, this Signal is | ||
| 185 | evaluated as Direction. | ||
| 186 | |||
| 187 | rising edge: | ||
| 188 | Low state transitions to high state. | ||
| 189 | |||
| 190 | falling edge: | ||
| 191 | High state transitions to low state. | ||
| 192 | |||
| 193 | both edges: | ||
| 194 | Any state transition. | ||
| 195 | |||
| 196 | What: /sys/bus/counter/devices/counterX/name | ||
| 197 | KernelVersion: 5.2 | ||
| 198 | Contact: linux-iio@vger.kernel.org | ||
| 199 | Description: | ||
| 200 | Read-only attribute that indicates the device-specific name of | ||
| 201 | the Counter. This should match the name of the device as it | ||
| 202 | appears in its respective datasheet. | ||
| 203 | |||
| 204 | What: /sys/bus/counter/devices/counterX/num_counts | ||
| 205 | KernelVersion: 5.2 | ||
| 206 | Contact: linux-iio@vger.kernel.org | ||
| 207 | Description: | ||
| 208 | Read-only attribute that indicates the total number of Counts | ||
| 209 | belonging to the Counter. | ||
| 210 | |||
| 211 | What: /sys/bus/counter/devices/counterX/num_signals | ||
| 212 | KernelVersion: 5.2 | ||
| 213 | Contact: linux-iio@vger.kernel.org | ||
| 214 | Description: | ||
| 215 | Read-only attribute that indicates the total number of Signals | ||
| 216 | belonging to the Counter. | ||
| 217 | |||
| 218 | What: /sys/bus/counter/devices/counterX/signalY/signal | ||
| 219 | KernelVersion: 5.2 | ||
| 220 | Contact: linux-iio@vger.kernel.org | ||
| 221 | Description: | ||
| 222 | Signal data of Signal Y represented as a string. | ||
| 223 | |||
| 224 | What: /sys/bus/counter/devices/counterX/signalY/name | ||
| 225 | KernelVersion: 5.2 | ||
| 226 | Contact: linux-iio@vger.kernel.org | ||
| 227 | Description: | ||
| 228 | Read-only attribute that indicates the device-specific name of | ||
| 229 | Signal Y. If possible, this should match the name of the | ||
| 230 | respective signal as it appears in the device datasheet. | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | What: /sys/bus/counter/devices/counterX/signalY/index_polarity | ||
| 2 | KernelVersion: 5.2 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Active level of index input Signal Y; irrelevant in | ||
| 6 | non-synchronous load mode. | ||
| 7 | |||
| 8 | What: /sys/bus/counter/devices/counterX/signalY/index_polarity_available | ||
| 9 | What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_available | ||
| 10 | KernelVersion: 5.2 | ||
| 11 | Contact: linux-iio@vger.kernel.org | ||
| 12 | Description: | ||
| 13 | Discrete set of available values for the respective Signal Y | ||
| 14 | configuration are listed in this file. | ||
| 15 | |||
| 16 | What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode | ||
| 17 | KernelVersion: 5.2 | ||
| 18 | Contact: linux-iio@vger.kernel.org | ||
| 19 | Description: | ||
| 20 | Configure the counter associated with Signal Y for | ||
| 21 | non-synchronous or synchronous load mode. Synchronous load mode | ||
| 22 | cannot be selected in non-quadrature (Pulse-Direction) clock | ||
| 23 | mode. | ||
| 24 | |||
| 25 | non-synchronous: | ||
| 26 | A logic low level is the active level at this index | ||
| 27 | input. The index function (as enabled via preset_enable) | ||
| 28 | is performed directly on the active level of the index | ||
| 29 | input. | ||
| 30 | |||
| 31 | synchronous: | ||
| 32 | Intended for interfacing with encoder Index output in | ||
| 33 | quadrature clock mode. The active level is configured | ||
| 34 | via index_polarity. The index function (as enabled via | ||
| 35 | preset_enable) is performed synchronously with the | ||
| 36 | quadrature clock on the active level of the index input. | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | What: /sys/bus/counter/devices/counterX/countY/prescaler_available | ||
| 2 | KernelVersion: 5.2 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Discrete set of available values for the respective Count Y | ||
| 6 | configuration are listed in this file. Values are delimited by | ||
| 7 | newline characters. | ||
| 8 | |||
| 9 | What: /sys/bus/counter/devices/counterX/countY/prescaler | ||
| 10 | KernelVersion: 5.2 | ||
| 11 | Contact: linux-iio@vger.kernel.org | ||
| 12 | Description: | ||
| 13 | Configure the prescaler value associated with Count Y. | ||
| 14 | On the FlexTimer, the counter clock source passes through a | ||
| 15 | prescaler (i.e. a counter). This acts like a clock | ||
| 16 | divider. | ||
| @@ -1656,6 +1656,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_raw · 1655 unmodified lines | |||
| 1656 | KernelVersion: 4.10 | 1656 | KernelVersion: 4.10 |
| 1657 | Contact: linux-iio@vger.kernel.org | 1657 | Contact: linux-iio@vger.kernel.org |
| 1658 | Description: | 1658 | Description: |
| 1659 | This interface is deprecated; please use the Counter subsystem. | ||
| 1660 | |||
| 1659 | Raw counter device counts from channel Y. For quadrature | 1661 | Raw counter device counts from channel Y. For quadrature |
| 1660 | counters, multiplication by an available [Y]_scale results in | 1662 | counters, multiplication by an available [Y]_scale results in |
| 1661 | the counts of a single quadrature signal phase from channel Y. | 1663 | the counts of a single quadrature signal phase from channel Y. |
| @@ -1664,6 +1666,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_indexY_raw · 2 unmodified lines | |||
| 1664 | KernelVersion: 4.10 | 1666 | KernelVersion: 4.10 |
| 1665 | Contact: linux-iio@vger.kernel.org | 1667 | Contact: linux-iio@vger.kernel.org |
| 1666 | Description: | 1668 | Description: |
| 1669 | This interface is deprecated; please use the Counter subsystem. | ||
| 1670 | |||
| 1667 | Raw counter device index value from channel Y. This attribute | 1671 | Raw counter device index value from channel Y. This attribute |
| 1668 | provides an absolute positional reference (e.g. a pulse once per | 1672 | provides an absolute positional reference (e.g. a pulse once per |
| 1669 | revolution) which may be used to home positional systems as | 1673 | revolution) which may be used to home positional systems as |
| @@ -1673,6 +1677,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_count_count_direction_available · 3 unmodified lines | |||
| 1673 | KernelVersion: 4.12 | 1677 | KernelVersion: 4.12 |
| 1674 | Contact: linux-iio@vger.kernel.org | 1678 | Contact: linux-iio@vger.kernel.org |
| 1675 | Description: | 1679 | Description: |
| 1680 | This interface is deprecated; please use the Counter subsystem. | ||
| 1681 | |||
| 1676 | A list of possible counting directions which are: | 1682 | A list of possible counting directions which are: |
| 1677 | - "up" : counter device is increasing. | 1683 | - "up" : counter device is increasing. |
| 1678 | - "down": counter device is decreasing. | 1684 | - "down": counter device is decreasing. |
| @@ -1681,6 +1687,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_direction · 2 unmodified lines | |||
| 1681 | KernelVersion: 4.12 | 1687 | KernelVersion: 4.12 |
| 1682 | Contact: linux-iio@vger.kernel.org | 1688 | Contact: linux-iio@vger.kernel.org |
| 1683 | Description: | 1689 | Description: |
| 1690 | This interface is deprecated; please use the Counter subsystem. | ||
| 1691 | |||
| 1684 | Raw counter device counters direction for channel Y. | 1692 | Raw counter device counters direction for channel Y. |
| 1685 | 1693 | ||
| 1686 | What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw | 1694 | What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw |
| @@ -6,6 +6,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_index_synchronous_mode_available · 5 unmodified lines | |||
| 6 | KernelVersion: 4.10 | 6 | KernelVersion: 4.10 |
| 7 | Contact: linux-iio@vger.kernel.org | 7 | Contact: linux-iio@vger.kernel.org |
| 8 | Description: | 8 | Description: |
| 9 | This interface is deprecated; please use the Counter subsystem. | ||
| 10 | |||
| 9 | Discrete set of available values for the respective counter | 11 | Discrete set of available values for the respective counter |
| 10 | configuration are listed in this file. | 12 | configuration are listed in this file. |
| 11 | 13 | ||
| @@ -13,6 +15,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode · 1 unmodified line | |||
| 13 | KernelVersion: 4.10 | 15 | KernelVersion: 4.10 |
| 14 | Contact: linux-iio@vger.kernel.org | 16 | Contact: linux-iio@vger.kernel.org |
| 15 | Description: | 17 | Description: |
| 18 | This interface is deprecated; please use the Counter subsystem. | ||
| 19 | |||
| 16 | Count mode for channel Y. Four count modes are available: | 20 | Count mode for channel Y. Four count modes are available: |
| 17 | normal, range limit, non-recycle, and modulo-n. The preset value | 21 | normal, range limit, non-recycle, and modulo-n. The preset value |
| 18 | for channel Y is used by the count mode where required. | 22 | for channel Y is used by the count mode where required. |
| @@ -47,6 +51,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_noise_error · 28 unmodified lines | |||
| 47 | KernelVersion: 4.10 | 51 | KernelVersion: 4.10 |
| 48 | Contact: linux-iio@vger.kernel.org | 52 | Contact: linux-iio@vger.kernel.org |
| 49 | Description: | 53 | Description: |
| 54 | This interface is deprecated; please use the Counter subsystem. | ||
| 55 | |||
| 50 | Read-only attribute that indicates whether excessive noise is | 56 | Read-only attribute that indicates whether excessive noise is |
| 51 | present at the channel Y count inputs in quadrature clock mode; | 57 | present at the channel Y count inputs in quadrature clock mode; |
| 52 | irrelevant in non-quadrature clock mode. | 58 | irrelevant in non-quadrature clock mode. |
| @@ -55,6 +61,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_preset · 2 unmodified lines | |||
| 55 | KernelVersion: 4.10 | 61 | KernelVersion: 4.10 |
| 56 | Contact: linux-iio@vger.kernel.org | 62 | Contact: linux-iio@vger.kernel.org |
| 57 | Description: | 63 | Description: |
| 64 | This interface is deprecated; please use the Counter subsystem. | ||
| 65 | |||
| 58 | If the counter device supports preset registers, the preset | 66 | If the counter device supports preset registers, the preset |
| 59 | count for channel Y is provided by this attribute. | 67 | count for channel Y is provided by this attribute. |
| 60 | 68 | ||
| @@ -62,6 +70,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_quadrature_mode · 1 unmodified line | |||
| 62 | KernelVersion: 4.10 | 70 | KernelVersion: 4.10 |
| 63 | Contact: linux-iio@vger.kernel.org | 71 | Contact: linux-iio@vger.kernel.org |
| 64 | Description: | 72 | Description: |
| 73 | This interface is deprecated; please use the Counter subsystem. | ||
| 74 | |||
| 65 | Configure channel Y counter for non-quadrature or quadrature | 75 | Configure channel Y counter for non-quadrature or quadrature |
| 66 | clock mode. Selecting non-quadrature clock mode will disable | 76 | clock mode. Selecting non-quadrature clock mode will disable |
| 67 | synchronous load mode. In quadrature clock mode, the channel Y | 77 | synchronous load mode. In quadrature clock mode, the channel Y |
| @@ -83,6 +93,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_countY_set_to_preset_on_index · 15 unmodified lines | |||
| 83 | KernelVersion: 4.10 | 93 | KernelVersion: 4.10 |
| 84 | Contact: linux-iio@vger.kernel.org | 94 | Contact: linux-iio@vger.kernel.org |
| 85 | Description: | 95 | Description: |
| 96 | This interface is deprecated; please use the Counter subsystem. | ||
| 97 | |||
| 86 | Whether to set channel Y counter with channel Y preset value | 98 | Whether to set channel Y counter with channel Y preset value |
| 87 | when channel Y index input is active, or continuously count. | 99 | when channel Y index input is active, or continuously count. |
| 88 | Valid attribute values are boolean. | 100 | Valid attribute values are boolean. |
| @@ -91,6 +103,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_indexY_index_polarity · 2 unmodified lines | |||
| 91 | KernelVersion: 4.10 | 103 | KernelVersion: 4.10 |
| 92 | Contact: linux-iio@vger.kernel.org | 104 | Contact: linux-iio@vger.kernel.org |
| 93 | Description: | 105 | Description: |
| 106 | This interface is deprecated; please use the Counter subsystem. | ||
| 107 | |||
| 94 | Active level of channel Y index input; irrelevant in | 108 | Active level of channel Y index input; irrelevant in |
| 95 | non-synchronous load mode. | 109 | non-synchronous load mode. |
| 96 | 110 | ||
| @@ -98,6 +112,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_indexY_synchronous_mode · 1 unmodified line | |||
| 98 | KernelVersion: 4.10 | 112 | KernelVersion: 4.10 |
| 99 | Contact: linux-iio@vger.kernel.org | 113 | Contact: linux-iio@vger.kernel.org |
| 100 | Description: | 114 | Description: |
| 115 | This interface is deprecated; please use the Counter subsystem. | ||
| 116 | |||
| 101 | Configure channel Y counter for non-synchronous or synchronous | 117 | Configure channel Y counter for non-synchronous or synchronous |
| 102 | load mode. Synchronous load mode cannot be selected in | 118 | load mode. Synchronous load mode cannot be selected in |
| 103 | non-quadrature clock mode. | 119 | non-quadrature clock mode. |
| @@ -1,26 +1,31 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/outY_freq_start | 1 | What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_start |
| 2 | Date: March 2019 | ||
| 2 | KernelVersion: 3.1.0 | 3 | KernelVersion: 3.1.0 |
| 3 | Contact: linux-iio@vger.kernel.org | 4 | Contact: linux-iio@vger.kernel.org |
| 4 | Description: | 5 | Description: |
| 5 | Frequency sweep start frequency in Hz. | 6 | Frequency sweep start frequency in Hz. |
| 6 | 7 | ||
| 7 | What: /sys/bus/iio/devices/iio:deviceX/outY_freq_increment | 8 | What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_increment |
| 9 | Date: March 2019 | ||
| 8 | KernelVersion: 3.1.0 | 10 | KernelVersion: 3.1.0 |
| 9 | Contact: linux-iio@vger.kernel.org | 11 | Contact: linux-iio@vger.kernel.org |
| 10 | Description: | 12 | Description: |
| 11 | Frequency increment in Hz (step size) between consecutive | 13 | Frequency increment in Hz (step size) between consecutive |
| 12 | frequency points along the sweep. | 14 | frequency points along the sweep. |
| 13 | 15 | ||
| 14 | What: /sys/bus/iio/devices/iio:deviceX/outY_freq_points | 16 | What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_points |
| 17 | Date: March 2019 | ||
| 15 | KernelVersion: 3.1.0 | 18 | KernelVersion: 3.1.0 |
| 16 | Contact: linux-iio@vger.kernel.org | 19 | Contact: linux-iio@vger.kernel.org |
| 17 | Description: | 20 | Description: |
| 18 | Number of frequency points (steps) in the frequency sweep. | 21 | Number of frequency points (steps) in the frequency sweep. |
| 19 | This value, in conjunction with the outY_freq_start and the | 22 | This value, in conjunction with the |
| 20 | outY_freq_increment, determines the frequency sweep range | 23 | out_altvoltageY_frequency_start and the |
| 21 | for the sweep operation. | 24 | out_altvoltageY_frequency_increment, determines the frequency |
| 25 | sweep range for the sweep operation. | ||
| 22 | 26 | ||
| 23 | What: /sys/bus/iio/devices/iio:deviceX/outY_settling_cycles | 27 | What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_settling_cycles |
| 28 | Date: March 2019 | ||
| 24 | KernelVersion: 3.1.0 | 29 | KernelVersion: 3.1.0 |
| 25 | Contact: linux-iio@vger.kernel.org | 30 | Contact: linux-iio@vger.kernel.org |
| 26 | Description: | 31 | Description: |
| @@ -1,6 +1,6 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/start_cleaning | 1 | What: /sys/bus/iio/devices/iio:deviceX/start_cleaning |
| 2 | Date: December 2018 | 2 | Date: December 2018 |
| 3 | KernelVersion: 4.22 | 3 | KernelVersion: 5.0 |
| 4 | Contact: linux-iio@vger.kernel.org | 4 | Contact: linux-iio@vger.kernel.org |
| 5 | Description: | 5 | Description: |
| 6 | Writing 1 starts sensor self cleaning. Internal fan accelerates | 6 | Writing 1 starts sensor self cleaning. Internal fan accelerates |
| @@ -0,0 +1,24 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/fault_oc | ||
| 2 | KernelVersion: 5.1 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Open-circuit fault. The detection of open-circuit faults, | ||
| 6 | such as those caused by broken thermocouple wires. | ||
| 7 | Reading returns either '1' or '0'. | ||
| 8 | '1' = An open circuit such as broken thermocouple wires | ||
| 9 | has been detected. | ||
| 10 | '0' = No open circuit or broken thermocouple wires are detected | ||
| 11 | |||
| 12 | What: /sys/bus/iio/devices/iio:deviceX/fault_ovuv | ||
| 13 | KernelVersion: 5.1 | ||
| 14 | Contact: linux-iio@vger.kernel.org | ||
| 15 | Description: | ||
| 16 | Overvoltage or Undervoltage Input Fault. The internal circuitry | ||
| 17 | is protected from excessive voltages applied to the thermocouple | ||
| 18 | cables by integrated MOSFETs at the T+ and T- inputs, and the | ||
| 19 | BIAS output. These MOSFETs turn off when the input voltage is | ||
| 20 | negative or greater than VDD. | ||
| 21 | Reading returns either '1' or '0'. | ||
| 22 | '1' = The input voltage is negative or greater than VDD. | ||
| 23 | '0' = The input voltage is positive and less than VDD (normal | ||
| 24 | state). | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | FlexTimer Quadrature decoder counter | ||
| 2 | |||
| 3 | This driver exposes a simple counter for the quadrature decoder mode. | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: Must be "fsl,ftm-quaddec". | ||
| 7 | - reg: Must be set to the memory region of the flextimer. | ||
| 8 | |||
| 9 | Optional property: | ||
| 10 | - big-endian: Access the device registers in big-endian mode. | ||
| 11 | |||
| 12 | Example: | ||
| 13 | counter0: counter@29d0000 { | ||
| 14 | compatible = "fsl,ftm-quaddec"; | ||
| 15 | reg = <0x0 0x29d0000 0x0 0x10000>; | ||
| 16 | big-endian; | ||
| 17 | status = "disabled"; | ||
| 18 | }; | ||
| @@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node. · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | Required properties: | 11 | Required properties: |
| 12 | - compatible: Must be "st,stm32-lptimer-counter". | 12 | - compatible: Must be "st,stm32-lptimer-counter". |
| 13 | - pinctrl-names: Set to "default". | 13 | - pinctrl-names: Set to "default". An additional "sleep" state can be |
| 14 | - pinctrl-0: List of phandles pointing to pin configuration nodes, | 14 | defined to set pins in sleep state. |
| 15 | - pinctrl-n: List of phandles pointing to pin configuration nodes, | ||
| 15 | to set IN1/IN2 pins in mode of operation for Low-Power | 16 | to set IN1/IN2 pins in mode of operation for Low-Power |
| 16 | Timer input on external pin. | 17 | Timer input on external pin. |
| 17 | 18 | ||
| @@ -21,7 +22,8 @@ Example: · 3 unmodified lines | |||
| 21 | ... | 22 | ... |
| 22 | counter { | 23 | counter { |
| 23 | compatible = "st,stm32-lptimer-counter"; | 24 | compatible = "st,stm32-lptimer-counter"; |
| 24 | pinctrl-names = "default"; | 25 | pinctrl-names = "default", "sleep"; |
| 25 | pinctrl-0 = <&lptim1_in_pins>; | 26 | pinctrl-0 = <&lptim1_in_pins>; |
| 27 | pinctrl-1 = <&lptim1_sleep_in_pins>; | ||
| 26 | }; | 28 | }; |
| 27 | }; | 29 | }; |
| @@ -0,0 +1,31 @@ | |||
| 1 | STMicroelectronics STM32 Timer quadrature encoder | ||
| 2 | |||
| 3 | STM32 Timer provides quadrature encoder to detect | ||
| 4 | angular position and direction of rotary elements, | ||
| 5 | from IN1 and IN2 input signals. | ||
| 6 | |||
| 7 | Must be a sub-node of an STM32 Timer device tree node. | ||
| 8 | See ../mfd/stm32-timers.txt for details about the parent node. | ||
| 9 | |||
| 10 | Required properties: | ||
| 11 | - compatible: Must be "st,stm32-timer-counter". | ||
| 12 | - pinctrl-names: Set to "default". | ||
| 13 | - pinctrl-0: List of phandles pointing to pin configuration nodes, | ||
| 14 | to set CH1/CH2 pins in mode of operation for STM32 | ||
| 15 | Timer input on external pin. | ||
| 16 | |||
| 17 | Example: | ||
| 18 | timers@40010000 { | ||
| 19 | #address-cells = <1>; | ||
| 20 | #size-cells = <0>; | ||
| 21 | compatible = "st,stm32-timers"; | ||
| 22 | reg = <0x40010000 0x400>; | ||
| 23 | clocks = <&rcc 0 160>; | ||
| 24 | clock-names = "int"; | ||
| 25 | |||
| 26 | counter { | ||
| 27 | compatible = "st,stm32-timer-counter"; | ||
| 28 | pinctrl-names = "default"; | ||
| 29 | pinctrl-0 = <&tim1_in_pins>; | ||
| 30 | }; | ||
| 31 | }; | ||
| @@ -0,0 +1,71 @@ | |||
| 1 | * Arcx Anybus-S controller | ||
| 2 | |||
| 3 | This chip communicates with the SoC over a parallel bus. It is | ||
| 4 | expected that its Device Tree node is specified as the child of a node | ||
| 5 | corresponding to the parallel bus used for communication. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | -------------------- | ||
| 9 | |||
| 10 | - compatible : The following chip-specific string: | ||
| 11 | "arcx,anybus-controller" | ||
| 12 | |||
| 13 | - reg : three areas: | ||
| 14 | index 0: bus memory area where the cpld registers are located. | ||
| 15 | index 1: bus memory area of the first host's dual-port ram. | ||
| 16 | index 2: bus memory area of the second host's dual-port ram. | ||
| 17 | |||
| 18 | - reset-gpios : the GPIO pin connected to the reset line of the controller. | ||
| 19 | |||
| 20 | - interrupts : two interrupts: | ||
| 21 | index 0: interrupt connected to the first host | ||
| 22 | index 1: interrupt connected to the second host | ||
| 23 | Generic interrupt client node bindings are described in | ||
| 24 | interrupt-controller/interrupts.txt | ||
| 25 | |||
| 26 | Optional: use of subnodes | ||
| 27 | ------------------------- | ||
| 28 | |||
| 29 | The card connected to a host may need additional properties. These can be | ||
| 30 | specified in subnodes to the controller node. | ||
| 31 | |||
| 32 | The subnodes are identified by the standard 'reg' property. Which information | ||
| 33 | exactly can be specified depends on the bindings for the function driver | ||
| 34 | for the subnode. | ||
| 35 | |||
| 36 | Required controller node properties when using subnodes: | ||
| 37 | - #address-cells: should be one. | ||
| 38 | - #size-cells: should be zero. | ||
| 39 | |||
| 40 | Required subnode properties: | ||
| 41 | - reg: Must contain the host index of the card this subnode describes: | ||
| 42 | <0> for the first host on the controller | ||
| 43 | <1> for the second host on the controller | ||
| 44 | Note that only a single card can be plugged into a host, so the host | ||
| 45 | index uniquely describes the card location. | ||
| 46 | |||
| 47 | Example of usage: | ||
| 48 | ----------------- | ||
| 49 | |||
| 50 | This example places the bridge on top of the i.MX WEIM parallel bus, see: | ||
| 51 | Documentation/devicetree/bindings/bus/imx-weim.txt | ||
| 52 | |||
| 53 | &weim { | ||
| 54 | controller@0,0 { | ||
| 55 | compatible = "arcx,anybus-controller"; | ||
| 56 | reg = <0 0 0x100>, <0 0x400000 0x800>, <1 0x400000 0x800>; | ||
| 57 | reset-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; | ||
| 58 | interrupt-parent = <&gpio1>; | ||
| 59 | interrupts = <1 IRQ_TYPE_LEVEL_LOW>, <5 IRQ_TYPE_LEVEL_LOW>; | ||
| 60 | /* fsl,weim-cs-timing is a i.MX WEIM bus specific property */ | ||
| 61 | fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100 | ||
| 62 | 0x00000000 0xa0000240 0x00000000>; | ||
| 63 | /* optional subnode for a card plugged into the first host */ | ||
| 64 | #address-cells = <1>; | ||
| 65 | #size-cells = <0>; | ||
| 66 | card@0 { | ||
| 67 | reg = <0>; | ||
| 68 | /* card specific properties go here */ | ||
| 69 | }; | ||
| 70 | }; | ||
| 71 | }; | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | Kionix KXCJK-1013 Accelerometer device tree bindings | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible: Must be one of: | ||
| 6 | "kionix,kxcjk1013" | ||
| 7 | "kionix,kxcj91008" | ||
| 8 | "kionix,kxtj21009" | ||
| 9 | "kionix,kxtf9" | ||
| 10 | - reg: i2c slave address | ||
| 11 | |||
| 12 | Example: | ||
| 13 | |||
| 14 | kxtf9@f { | ||
| 15 | compatible = "kionix,kxtf9"; | ||
| 16 | reg = <0x0F>; | ||
| 17 | }; | ||
| @@ -7,6 +7,7 @@ Required properties for the AD7606: · 6 unmodified lines | |||
| 7 | * "adi,ad7606-8" | 7 | * "adi,ad7606-8" |
| 8 | * "adi,ad7606-6" | 8 | * "adi,ad7606-6" |
| 9 | * "adi,ad7606-4" | 9 | * "adi,ad7606-4" |
| 10 | * "adi,ad7616" | ||
| 10 | - reg: SPI chip select number for the device | 11 | - reg: SPI chip select number for the device |
| 11 | - spi-max-frequency: Max SPI frequency to use | 12 | - spi-max-frequency: Max SPI frequency to use |
| 12 | see: Documentation/devicetree/bindings/spi/spi-bus.txt | 13 | see: Documentation/devicetree/bindings/spi/spi-bus.txt |
| @@ -0,0 +1,48 @@ | |||
| 1 | * Analog Devices AD7170/AD7171/AD7780/AD7781 | ||
| 2 | |||
| 3 | Data sheets: | ||
| 4 | |||
| 5 | - AD7170: | ||
| 6 | * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf | ||
| 7 | - AD7171: | ||
| 8 | * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf | ||
| 9 | - AD7780: | ||
| 10 | * https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf | ||
| 11 | - AD7781: | ||
| 12 | * https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf | ||
| 13 | |||
| 14 | Required properties: | ||
| 15 | |||
| 16 | - compatible: should be one of | ||
| 17 | * "adi,ad7170" | ||
| 18 | * "adi,ad7171" | ||
| 19 | * "adi,ad7780" | ||
| 20 | * "adi,ad7781" | ||
| 21 | - reg: spi chip select number for the device | ||
| 22 | - vref-supply: the regulator supply for the ADC reference voltage | ||
| 23 | |||
| 24 | Optional properties: | ||
| 25 | |||
| 26 | - powerdown-gpios: must be the device tree identifier of the PDRST pin. If | ||
| 27 | specified, it will be asserted during driver probe. As the | ||
| 28 | line is active high, it should be marked GPIO_ACTIVE_HIGH. | ||
| 29 | - adi,gain-gpios: must be the device tree identifier of the GAIN pin. Only for | ||
| 30 | the ad778x chips. If specified, it will be asserted during | ||
| 31 | driver probe. As the line is active low, it should be marked | ||
| 32 | GPIO_ACTIVE_LOW. | ||
| 33 | - adi,filter-gpios: must be the device tree identifier of the FILTER pin. Only | ||
| 34 | for the ad778x chips. If specified, it will be asserted | ||
| 35 | during driver probe. As the line is active low, it should be | ||
| 36 | marked GPIO_ACTIVE_LOW. | ||
| 37 | |||
| 38 | Example: | ||
| 39 | |||
| 40 | adc@0 { | ||
| 41 | compatible = "adi,ad7780"; | ||
| 42 | reg = <0>; | ||
| 43 | vref-supply = <&vdd_supply> | ||
| 44 | |||
| 45 | powerdown-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; | ||
| 46 | adi,gain-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; | ||
| 47 | adi,filter-gpios = <&gpio 15 GPIO_ACTIVE_LOW>; | ||
| 48 | }; | ||
| @@ -9,6 +9,7 @@ Required properties: · 8 unmodified lines | |||
| 9 | - "amlogic,meson-gxl-saradc" for GXL | 9 | - "amlogic,meson-gxl-saradc" for GXL |
| 10 | - "amlogic,meson-gxm-saradc" for GXM | 10 | - "amlogic,meson-gxm-saradc" for GXM |
| 11 | - "amlogic,meson-axg-saradc" for AXG | 11 | - "amlogic,meson-axg-saradc" for AXG |
| 12 | - "amlogic,meson-g12a-saradc" for AXG | ||
| 12 | along with the generic "amlogic,meson-saradc" | 13 | along with the generic "amlogic,meson-saradc" |
| 13 | - reg: the physical base address and length of the registers | 14 | - reg: the physical base address and length of the registers |
| 14 | - interrupts: the interrupt indicating end of sampling | 15 | - interrupts: the interrupt indicating end of sampling |
| @@ -1,24 +0,0 @@ | |||
| 1 | * AVIA HX711 ADC chip for weight cells | ||
| 2 | Bit-banging driver | ||
| 3 | |||
| 4 | Required properties: | ||
| 5 | - compatible: Should be "avia,hx711" | ||
| 6 | - sck-gpios: Definition of the GPIO for the clock | ||
| 7 | - dout-gpios: Definition of the GPIO for data-out | ||
| 8 | See Documentation/devicetree/bindings/gpio/gpio.txt | ||
| 9 | - avdd-supply: Definition of the regulator used as analog supply | ||
| 10 | |||
| 11 | Optional properties: | ||
| 12 | - clock-frequency: Frequency of PD_SCK in Hz | ||
| 13 | Minimum value allowed is 10 kHz because of maximum | ||
| 14 | high time of 50 microseconds. | ||
| 15 | |||
| 16 | Example: | ||
| 17 | weight { | ||
| 18 | compatible = "avia,hx711"; | ||
| 19 | sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; | ||
| 20 | dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; | ||
| 21 | avdd-suppy = <&avdd>; | ||
| 22 | clock-frequency = <100000>; | ||
| 23 | }; | ||
| 24 | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: "http://devicetree.org/schemas/iio/adc/avia-hx711.yaml#" | ||
| 5 | $schema: "http://devicetree.org/meta-schemas/core.yaml#" | ||
| 6 | |||
| 7 | title: AVIA HX711 ADC chip for weight cells | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Andreas Klinger <ak@it-klinger.de> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | Bit-banging driver using two GPIOs: | ||
| 14 | - sck-gpio gives a clock to the sensor with 24 cycles for data retrieval | ||
| 15 | and up to 3 cycles for selection of the input channel and gain for the | ||
| 16 | next measurement | ||
| 17 | - dout-gpio is the sensor data the sensor responds to the clock | ||
| 18 | |||
| 19 | Specifications about the driver can be found at: | ||
| 20 | http://www.aviaic.com/ENProducts.aspx | ||
| 21 | |||
| 22 | properties: | ||
| 23 | compatible: | ||
| 24 | enum: | ||
| 25 | - avia,hx711 | ||
| 26 | |||
| 27 | sck-gpios: | ||
| 28 | description: | ||
| 29 | Definition of the GPIO for the clock (output). In the datasheet it is | ||
| 30 | named PD_SCK | ||
| 31 | maxItems: 1 | ||
| 32 | |||
| 33 | dout-gpios: | ||
| 34 | description: | ||
| 35 | Definition of the GPIO for the data-out sent by the sensor in | ||
| 36 | response to the clock (input). | ||
| 37 | See Documentation/devicetree/bindings/gpio/gpio.txt for information | ||
| 38 | on how to specify a consumer gpio. | ||
| 39 | maxItems: 1 | ||
| 40 | |||
| 41 | avdd-supply: | ||
| 42 | description: | ||
| 43 | Definition of the regulator used as analog supply | ||
| 44 | maxItems: 1 | ||
| 45 | |||
| 46 | clock-frequency: | ||
| 47 | minimum: 20000 | ||
| 48 | maximum: 2500000 | ||
| 49 | default: 400000 | ||
| 50 | |||
| 51 | required: | ||
| 52 | - compatible | ||
| 53 | - sck-gpios | ||
| 54 | - dout-gpios | ||
| 55 | - avdd-supply | ||
| 56 | |||
| 57 | examples: | ||
| 58 | - | | ||
| 59 | #include <dt-bindings/gpio/gpio.h> | ||
| 60 | weight { | ||
| 61 | compatible = "avia,hx711"; | ||
| 62 | sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; | ||
| 63 | dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; | ||
| 64 | avdd-suppy = <&avdd>; | ||
| 65 | clock-frequency = <100000>; | ||
| 66 | }; | ||
| @@ -6,6 +6,10 @@ Required properties: · 5 unmodified lines | |||
| 6 | region. | 6 | region. |
| 7 | - interrupts: The ADC interrupt | 7 | - interrupts: The ADC interrupt |
| 8 | 8 | ||
| 9 | Optional: | ||
| 10 | - vref-supply: The regulator supply ADC reference voltage, optional | ||
| 11 | for legacy reason, but highly encouraging to us in new device tree | ||
| 12 | |||
| 9 | Example: | 13 | Example: |
| 10 | 14 | ||
| 11 | adc@40048000 { | 15 | adc@40048000 { |
| @@ -13,4 +17,5 @@ Example: · 1 unmodified line | |||
| 13 | reg = <0x40048000 0x1000>; | 17 | reg = <0x40048000 0x1000>; |
| 14 | interrupt-parent = <&mic>; | 18 | interrupt-parent = <&mic>; |
| 15 | interrupts = <39 0>; | 19 | interrupts = <39 0>; |
| 20 | vref-supply = <&vcc>; | ||
| 16 | }; | 21 | }; |
| @@ -0,0 +1,19 @@ | |||
| 1 | * Texas Instruments ADS8344 A/DC chip | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Must be "ti,ads8344" | ||
| 5 | - reg: SPI chip select number for the device | ||
| 6 | - vref-supply: phandle to a regulator node that supplies the | ||
| 7 | reference voltage | ||
| 8 | |||
| 9 | Recommended properties: | ||
| 10 | - spi-max-frequency: Definition as per | ||
| 11 | Documentation/devicetree/bindings/spi/spi-bus.txt | ||
| 12 | |||
| 13 | Example: | ||
| 14 | adc@0 { | ||
| 15 | compatible = "ti,ads8344"; | ||
| 16 | reg = <0>; | ||
| 17 | vref-supply = <&refin_supply>; | ||
| 18 | spi-max-frequency = <10000000>; | ||
| 19 | }; | ||
| @@ -1,7 +1,13 @@ | |||
| 1 | * Plantower PMS7003 particulate matter sensor | 1 | * Plantower PMS7003 particulate matter sensor |
| 2 | 2 | ||
| 3 | Required properties: | 3 | Required properties: |
| 4 | - compatible: must be "plantower,pms7003" | 4 | - compatible: must one of: |
| 5 | "plantower,pms1003" | ||
| 6 | "plantower,pms3003" | ||
| 7 | "plantower,pms5003" | ||
| 8 | "plantower,pms6003" | ||
| 9 | "plantower,pms7003" | ||
| 10 | "plantower,pmsa003" | ||
| 5 | - vcc-supply: phandle to the regulator that provides power to the sensor | 11 | - vcc-supply: phandle to the regulator that provides power to the sensor |
| 6 | 12 | ||
| 7 | Optional properties: | 13 | Optional properties: |
| @@ -0,0 +1,20 @@ | |||
| 1 | * Bosch BMG160 triaxial rotation sensor (gyroscope) | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : should be "bosch,bmg160" or "bosch,bmi055_gyro" | ||
| 6 | - reg : the I2C address of the sensor (0x69) | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | |||
| 10 | - interrupts : interrupt mapping for GPIO IRQ, it should by configured with | ||
| 11 | flags IRQ_TYPE_EDGE_RISING | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | bmg160@69 { | ||
| 16 | compatible = "bosch,bmg160"; | ||
| 17 | reg = <0x69>; | ||
| 18 | interrupt-parent = <&gpio6>; | ||
| 19 | interrupts = <18 (IRQ_TYPE_EDGE_RISING)>; | ||
| 20 | }; | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | * NXP FXAS21002C Gyroscope device tree bindings | ||
| 2 | |||
| 3 | http://www.nxp.com/products/sensors/gyroscopes/3-axis-digital-gyroscope:FXAS21002C | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible : should be "nxp,fxas21002c" | ||
| 7 | - reg : the I2C address of the sensor or SPI chip select number for the | ||
| 8 | device. | ||
| 9 | - vdd-supply: phandle to the regulator that provides power to the sensor. | ||
| 10 | - vddio-supply: phandle to the regulator that provides power to the bus. | ||
| 11 | |||
| 12 | Optional properties: | ||
| 13 | - reset-gpios : gpio used to reset the device, see gpio/gpio.txt | ||
| 14 | - interrupts : device support 2 interrupts, INT1 and INT2, | ||
| 15 | the interrupts can be triggered on rising or falling edges. | ||
| 16 | See interrupt-controller/interrupts.txt | ||
| 17 | - interrupt-names: should contain "INT1" or "INT2", the gyroscope interrupt | ||
| 18 | line in use. | ||
| 19 | - drive-open-drain: the interrupt/data ready line will be configured | ||
| 20 | as open drain, which is useful if several sensors share | ||
| 21 | the same interrupt line. This is a boolean property. | ||
| 22 | (This binding is taken from pinctrl/pinctrl-bindings.txt) | ||
| 23 | |||
| 24 | Example: | ||
| 25 | |||
| 26 | gyroscope@20 { | ||
| 27 | compatible = "nxp,fxas21002c"; | ||
| 28 | reg = <0x20>; | ||
| 29 | vdd-supply = <®_peri_3p15v>; | ||
| 30 | vddio-supply = <®_peri_3p15v>; | ||
| 31 | }; | ||
| @@ -0,0 +1,85 @@ | |||
| 1 | |||
| 2 | Analog Devices ADIS16480 and similar IMUs | ||
| 3 | |||
| 4 | Required properties for the ADIS16480: | ||
| 5 | |||
| 6 | - compatible: Must be one of | ||
| 7 | * "adi,adis16375" | ||
| 8 | * "adi,adis16480" | ||
| 9 | * "adi,adis16485" | ||
| 10 | * "adi,adis16488" | ||
| 11 | * "adi,adis16495-1" | ||
| 12 | * "adi,adis16495-2" | ||
| 13 | * "adi,adis16495-3" | ||
| 14 | * "adi,adis16497-1" | ||
| 15 | * "adi,adis16497-2" | ||
| 16 | * "adi,adis16497-3" | ||
| 17 | - reg: SPI chip select number for the device | ||
| 18 | - spi-max-frequency: Max SPI frequency to use | ||
| 19 | see: Documentation/devicetree/bindings/spi/spi-bus.txt | ||
| 20 | - spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt | ||
| 21 | - spi-cpol: See Documentation/devicetree/bindings/spi/spi-bus.txt | ||
| 22 | - interrupts: interrupt mapping for IRQ, accepted values are: | ||
| 23 | * IRQF_TRIGGER_RISING | ||
| 24 | * IRQF_TRIGGER_FALLING | ||
| 25 | |||
| 26 | Optional properties: | ||
| 27 | |||
| 28 | - interrupt-names: Data ready line selection. Valid values are: | ||
| 29 | * DIO1 | ||
| 30 | * DIO2 | ||
| 31 | * DIO3 | ||
| 32 | * DIO4 | ||
| 33 | If this field is left empty, DIO1 is assigned as default data ready | ||
| 34 | signal. | ||
| 35 | - reset-gpios: must be the device tree identifier of the RESET pin. As the line | ||
| 36 | is active low, it should be marked GPIO_ACTIVE_LOW. | ||
| 37 | - clocks: phandle to the external clock. Should be set according to | ||
| 38 | "clock-names". | ||
| 39 | If this field is left empty together with the "clock-names" field, then | ||
| 40 | the internal clock is used. | ||
| 41 | - clock-names: The name of the external clock to be used. Valid values are: | ||
| 42 | * sync: In sync mode, the internal clock is disabled and the frequency | ||
| 43 | of the external clock signal establishes therate of data | ||
| 44 | collection and processing. See Fig 14 and 15 in the datasheet. | ||
| 45 | The clock-frequency must be: | ||
| 46 | * 3000 to 4500 Hz for adis1649x devices. | ||
| 47 | * 700 to 2400 Hz for adis1648x devices. | ||
| 48 | * pps: In Pulse Per Second (PPS) Mode, the rate of data collection and | ||
| 49 | production is equal to the product of the external clock | ||
| 50 | frequency and the scale factor in the SYNC_SCALE register, see | ||
| 51 | Table 154 in the datasheet. | ||
| 52 | The clock-frequency must be: | ||
| 53 | * 1 to 128 Hz for adis1649x devices. | ||
| 54 | * This mode is not supported by adis1648x devices. | ||
| 55 | If this field is left empty together with the "clocks" field, then the | ||
| 56 | internal clock is used. | ||
| 57 | - adi,ext-clk-pin: The DIOx line to be used as an external clock input. | ||
| 58 | Valid values are: | ||
| 59 | * DIO1 | ||
| 60 | * DIO2 | ||
| 61 | * DIO3 | ||
| 62 | * DIO4 | ||
| 63 | Each DIOx pin supports only one function at a time (data ready line | ||
| 64 | selection or external clock input). When a single pin has two | ||
| 65 | two assignments, the enable bit for the lower priority function | ||
| 66 | automatically resets to zero (disabling the lower priority function). | ||
| 67 | Data ready has highest priority. | ||
| 68 | If this field is left empty, DIO2 is assigned as default external clock | ||
| 69 | input pin. | ||
| 70 | |||
| 71 | Example: | ||
| 72 | |||
| 73 | imu@0 { | ||
| 74 | compatible = "adi,adis16495-1"; | ||
| 75 | reg = <0>; | ||
| 76 | spi-max-frequency = <3200000>; | ||
| 77 | spi-cpol; | ||
| 78 | spi-cpha; | ||
| 79 | interrupts = <25 IRQF_TRIGGER_FALLING>; | ||
| 80 | interrupt-parent = <&gpio>; | ||
| 81 | interrupt-names = "DIO2"; | ||
| 82 | clocks = <&adis16495_sync>; | ||
| 83 | clock-names = "sync"; | ||
| 84 | adi,ext-clk-pin = "DIO1"; | ||
| 85 | }; | ||
| @@ -8,6 +8,9 @@ Required properties: · 7 unmodified lines | |||
| 8 | "st,lsm6dsm" | 8 | "st,lsm6dsm" |
| 9 | "st,ism330dlc" | 9 | "st,ism330dlc" |
| 10 | "st,lsm6dso" | 10 | "st,lsm6dso" |
| 11 | "st,asm330lhh" | ||
| 12 | "st,lsm6dsox" | ||
| 13 | "st,lsm6dsr" | ||
| 11 | - reg: i2c address of the sensor / spi cs line | 14 | - reg: i2c address of the sensor / spi cs line |
| 12 | 15 | ||
| 13 | Optional properties: | 16 | Optional properties: |
| @@ -0,0 +1,24 @@ | |||
| 1 | VISHAY VCNL4000 - Ambient Light and proximity sensor | ||
| 2 | |||
| 3 | This driver supports the VCNL4000/10/20/40 and VCNL4200 chips | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | |||
| 7 | -compatible: must be one of : | ||
| 8 | vishay,vcnl4000 | ||
| 9 | vishay,vcnl4010 | ||
| 10 | vishay,vcnl4020 | ||
| 11 | vishay,vcnl4040 | ||
| 12 | vishay,vcnl4200 | ||
| 13 | |||
| 14 | -reg: I2C address of the sensor, should be one from below based on the model: | ||
| 15 | 0x13 | ||
| 16 | 0x51 | ||
| 17 | 0x60 | ||
| 18 | |||
| 19 | Example: | ||
| 20 | |||
| 21 | light-sensor@51 { | ||
| 22 | compatible = "vishay,vcnl4200"; | ||
| 23 | reg = <0x51>; | ||
| 24 | }; | ||
| @@ -1,27 +0,0 @@ | |||
| 1 | BMP085/BMP18x/BMP28x digital pressure sensors | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: must be one of: | ||
| 5 | "bosch,bmp085" | ||
| 6 | "bosch,bmp180" | ||
| 7 | "bosch,bmp280" | ||
| 8 | "bosch,bme280" | ||
| 9 | |||
| 10 | Optional properties: | ||
| 11 | - interrupts: interrupt mapping for IRQ | ||
| 12 | - reset-gpios: a GPIO line handling reset of the sensor: as the line is | ||
| 13 | active low, it should be marked GPIO_ACTIVE_LOW (see gpio/gpio.txt) | ||
| 14 | - vddd-supply: digital voltage regulator (see regulator/regulator.txt) | ||
| 15 | - vdda-supply: analog voltage regulator (see regulator/regulator.txt) | ||
| 16 | |||
| 17 | Example: | ||
| 18 | |||
| 19 | pressure@77 { | ||
| 20 | compatible = "bosch,bmp085"; | ||
| 21 | reg = <0x77>; | ||
| 22 | interrupt-parent = <&gpio0>; | ||
| 23 | interrupts = <25 IRQ_TYPE_EDGE_RISING>; | ||
| 24 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; | ||
| 25 | vddd-supply = <&foo>; | ||
| 26 | vdda-supply = <&bar>; | ||
| 27 | }; | ||
| @@ -0,0 +1,70 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/pressure/bmp085.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: BMP085/BMP180/BMP280/BME280 pressure iio sensors | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Andreas Klinger <ak@it-klinger.de> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | Pressure, temperature and humidity iio sensors with i2c and spi interfaces | ||
| 14 | |||
| 15 | Specifications about the sensor can be found at: | ||
| 16 | https://www.bosch-sensortec.com/bst/products/all_products/bmp180 | ||
| 17 | https://www.bosch-sensortec.com/bst/products/all_products/bmp280 | ||
| 18 | https://www.bosch-sensortec.com/bst/products/all_products/bme280 | ||
| 19 | |||
| 20 | properties: | ||
| 21 | compatible: | ||
| 22 | enum: | ||
| 23 | - bosch,bmp085 | ||
| 24 | - bosch,bmp180 | ||
| 25 | - bosch,bmp280 | ||
| 26 | - bosch,bme280 | ||
| 27 | |||
| 28 | vddd-supply: | ||
| 29 | description: | ||
| 30 | digital voltage regulator (see regulator/regulator.txt) | ||
| 31 | maxItems: 1 | ||
| 32 | |||
| 33 | vdda-supply: | ||
| 34 | description: | ||
| 35 | analog voltage regulator (see regulator/regulator.txt) | ||
| 36 | maxItems: 1 | ||
| 37 | |||
| 38 | reset-gpios: | ||
| 39 | description: | ||
| 40 | A GPIO line handling reset of the sensor. As the line is active low, | ||
| 41 | it should be marked GPIO_ACTIVE_LOW (see gpio/gpio.txt) | ||
| 42 | maxItems: 1 | ||
| 43 | |||
| 44 | interrupts: | ||
| 45 | description: | ||
| 46 | interrupt mapping for IRQ (BMP085 only) | ||
| 47 | maxItems: 1 | ||
| 48 | |||
| 49 | required: | ||
| 50 | - compatible | ||
| 51 | - vddd-supply | ||
| 52 | - vdda-supply | ||
| 53 | |||
| 54 | examples: | ||
| 55 | - | | ||
| 56 | #include <dt-bindings/gpio/gpio.h> | ||
| 57 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 58 | i2c0 { | ||
| 59 | #address-cells = <1>; | ||
| 60 | #size-cells = <0>; | ||
| 61 | pressure@77 { | ||
| 62 | compatible = "bosch,bmp085"; | ||
| 63 | reg = <0x77>; | ||
| 64 | interrupt-parent = <&gpio0>; | ||
| 65 | interrupts = <25 IRQ_TYPE_EDGE_RISING>; | ||
| 66 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; | ||
| 67 | vddd-supply = <&foo>; | ||
| 68 | vdda-supply = <&bar>; | ||
| 69 | }; | ||
| 70 | }; | ||
| @@ -1,28 +0,0 @@ | |||
| 1 | * Devantech SRF04 ultrasonic range finder | ||
| 2 | Bit-banging driver using two GPIOs | ||
| 3 | |||
| 4 | Required properties: | ||
| 5 | - compatible: Should be "devantech,srf04" | ||
| 6 | |||
| 7 | - trig-gpios: Definition of the GPIO for the triggering (output) | ||
| 8 | This GPIO is set for about 10 us by the driver to tell the | ||
| 9 | device it should initiate the measurement cycle. | ||
| 10 | |||
| 11 | - echo-gpios: Definition of the GPIO for the echo (input) | ||
| 12 | This GPIO is set by the device as soon as an ultrasonic | ||
| 13 | burst is sent out and reset when the first echo is | ||
| 14 | received. | ||
| 15 | Thus this GPIO is set while the ultrasonic waves are doing | ||
| 16 | one round trip. | ||
| 17 | It needs to be an GPIO which is able to deliver an | ||
| 18 | interrupt because the time between two interrupts is | ||
| 19 | measured in the driver. | ||
| 20 | See Documentation/devicetree/bindings/gpio/gpio.txt for | ||
| 21 | information on how to specify a consumer gpio. | ||
| 22 | |||
| 23 | Example: | ||
| 24 | srf04@0 { | ||
| 25 | compatible = "devantech,srf04"; | ||
| 26 | trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; | ||
| 27 | echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; | ||
| 28 | }; | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/proximity/devantech-srf04.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Devantech SRF04 and Maxbotix mb1000 ultrasonic range finder | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Andreas Klinger <ak@it-klinger.de> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | Bit-banging driver using two GPIOs: | ||
| 14 | - trigger-gpio is raised by the driver to start sending out an ultrasonic | ||
| 15 | burst | ||
| 16 | - echo-gpio is held high by the sensor after sending ultrasonic burst | ||
| 17 | until it is received once again | ||
| 18 | |||
| 19 | Specifications about the devices can be found at: | ||
| 20 | http://www.robot-electronics.co.uk/htm/srf04tech.htm | ||
| 21 | |||
| 22 | http://www.maxbotix.com/documents/LV-MaxSonar-EZ_Datasheet.pdf | ||
| 23 | |||
| 24 | properties: | ||
| 25 | compatible: | ||
| 26 | enum: | ||
| 27 | - devantech,srf04 | ||
| 28 | - maxbotix,mb1000 | ||
| 29 | - maxbotix,mb1010 | ||
| 30 | - maxbotix,mb1020 | ||
| 31 | - maxbotix,mb1030 | ||
| 32 | - maxbotix,mb1040 | ||
| 33 | |||
| 34 | trig-gpios: | ||
| 35 | description: | ||
| 36 | Definition of the GPIO for the triggering (output) | ||
| 37 | This GPIO is set for about 10 us by the driver to tell the device it | ||
| 38 | should initiate the measurement cycle. | ||
| 39 | See Documentation/devicetree/bindings/gpio/gpio.txt for information | ||
| 40 | on how to specify a consumer gpio. | ||
| 41 | maxItems: 1 | ||
| 42 | |||
| 43 | echo-gpios: | ||
| 44 | description: | ||
| 45 | Definition of the GPIO for the echo (input) | ||
| 46 | This GPIO is set by the device as soon as an ultrasonic burst is sent | ||
| 47 | out and reset when the first echo is received. | ||
| 48 | Thus this GPIO is set while the ultrasonic waves are doing one round | ||
| 49 | trip. | ||
| 50 | It needs to be an GPIO which is able to deliver an interrupt because | ||
| 51 | the time between two interrupts is measured in the driver. | ||
| 52 | maxItems: 1 | ||
| 53 | |||
| 54 | required: | ||
| 55 | - compatible | ||
| 56 | - trig-gpios | ||
| 57 | - echo-gpios | ||
| 58 | |||
| 59 | examples: | ||
| 60 | - | | ||
| 61 | #include <dt-bindings/gpio/gpio.h> | ||
| 62 | proximity { | ||
| 63 | compatible = "devantech,srf04"; | ||
| 64 | trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; | ||
| 65 | echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; | ||
| 66 | }; | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | * MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202, | ||
| 2 | mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface | ||
| 3 | for ranging | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: "maxbotix,mb1202", | ||
| 7 | "maxbotix,mb1212", | ||
| 8 | "maxbotix,mb1222", | ||
| 9 | "maxbotix,mb1232", | ||
| 10 | "maxbotix,mb1242", | ||
| 11 | "maxbotix,mb7040" or | ||
| 12 | "maxbotix,mb7137" | ||
| 13 | |||
| 14 | - reg: i2c address of the device, see also i2c/i2c.txt | ||
| 15 | |||
| 16 | Optional properties: | ||
| 17 | - interrupts: Interrupt used to announce the preceding reading | ||
| 18 | request has finished and that data is available. | ||
| 19 | If no interrupt is specified the device driver | ||
| 20 | falls back to wait a fixed amount of time until | ||
| 21 | data can be retrieved. | ||
| 22 | |||
| 23 | Example: | ||
| 24 | proximity@70 { | ||
| 25 | compatible = "maxbotix,mb1232"; | ||
| 26 | reg = <0x70>; | ||
| 27 | interrupt-parent = <&gpio2>; | ||
| 28 | interrupts = <2 IRQ_TYPE_EDGE_FALLING>; | ||
| 29 | }; | ||
| @@ -49,6 +49,7 @@ Accelerometers: · 48 unmodified lines | |||
| 49 | - st,lis2dw12 | 49 | - st,lis2dw12 |
| 50 | - st,lis3dhh | 50 | - st,lis3dhh |
| 51 | - st,lis3de | 51 | - st,lis3de |
| 52 | - st,lis2de12 | ||
| 52 | 53 | ||
| 53 | Gyroscopes: | 54 | Gyroscopes: |
| 54 | - st,l3g4200d-gyro | 55 | - st,l3g4200d-gyro |
| @@ -0,0 +1,24 @@ | |||
| 1 | Maxim MAX31856 thermocouple support | ||
| 2 | |||
| 3 | https://datasheets.maximintegrated.com/en/ds/MAX31856.pdf | ||
| 4 | |||
| 5 | Optional property: | ||
| 6 | - thermocouple-type: Type of thermocouple (THERMOCOUPLE_TYPE_K if | ||
| 7 | omitted). Supported types are B, E, J, K, N, R, S, T. | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | - compatible: must be "maxim,max31856" | ||
| 11 | - reg: SPI chip select number for the device | ||
| 12 | - spi-max-frequency: As per datasheet max. supported freq is 5000000 | ||
| 13 | - spi-cpha: must be defined for max31856 to enable SPI mode 1 | ||
| 14 | |||
| 15 | Refer to spi/spi-bus.txt for generic SPI slave bindings. | ||
| 16 | |||
| 17 | Example: | ||
| 18 | temp-sensor@0 { | ||
| 19 | compatible = "maxim,max31856"; | ||
| 20 | reg = <0>; | ||
| 21 | spi-max-frequency = <5000000>; | ||
| 22 | spi-cpha; | ||
| 23 | thermocouple-type = <THERMOCOUPLE_TYPE_K>; | ||
| 24 | }; | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | If the temperature sensor device can be configured to use some specific | ||
| 2 | thermocouple type, you can use the defined types provided in the file | ||
| 3 | "include/dt-bindings/iio/temperature/thermocouple.h". | ||
| 4 | |||
| 5 | Property: | ||
| 6 | thermocouple-type: A single cell representing the type of the thermocouple | ||
| 7 | used by the device. | ||
| @@ -16,7 +16,7 @@ Required properties: · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | Optional subnodes: | 17 | Optional subnodes: |
| 18 | - pwm: See ../pwm/pwm-stm32-lp.txt | 18 | - pwm: See ../pwm/pwm-stm32-lp.txt |
| 19 | - counter: See ../iio/timer/stm32-lptimer-cnt.txt | 19 | - counter: See ../counter/stm32-lptimer-cnt.txt |
| 20 | - trigger: See ../iio/timer/stm32-lptimer-trigger.txt | 20 | - trigger: See ../iio/timer/stm32-lptimer-trigger.txt |
| 21 | 21 | ||
| 22 | Example: | 22 | Example: |
| @@ -28,6 +28,7 @@ Optional parameters: · 27 unmodified lines | |||
| 28 | Optional subnodes: | 28 | Optional subnodes: |
| 29 | - pwm: See ../pwm/pwm-stm32.txt | 29 | - pwm: See ../pwm/pwm-stm32.txt |
| 30 | - timer: See ../iio/timer/stm32-timer-trigger.txt | 30 | - timer: See ../iio/timer/stm32-timer-trigger.txt |
| 31 | - counter: See ../counter/stm32-timer-cnt.txt | ||
| 31 | 32 | ||
| 32 | Example: | 33 | Example: |
| 33 | timers@40010000 { | 34 | timers@40010000 { |
| @@ -48,6 +49,12 @@ Example: · 14 unmodified lines | |||
| 48 | compatible = "st,stm32-timer-trigger"; | 49 | compatible = "st,stm32-timer-trigger"; |
| 49 | reg = <0>; | 50 | reg = <0>; |
| 50 | }; | 51 | }; |
| 52 | |||
| 53 | counter { | ||
| 54 | compatible = "st,stm32-timer-counter"; | ||
| 55 | pinctrl-names = "default"; | ||
| 56 | pinctrl-0 = <&tim1_in_pins>; | ||
| 57 | }; | ||
| 51 | }; | 58 | }; |
| 52 | 59 | ||
| 53 | Example with all dmas: | 60 | Example with all dmas: |
| @@ -36,6 +36,7 @@ aptina Aptina Imaging · 35 unmodified lines | |||
| 36 | arasan Arasan Chip Systems | 36 | arasan Arasan Chip Systems |
| 37 | archermind ArcherMind Technology (Nanjing) Co., Ltd. | 37 | archermind ArcherMind Technology (Nanjing) Co., Ltd. |
| 38 | arctic Arctic Sand | 38 | arctic Arctic Sand |
| 39 | arcx arcx Inc. / Archronix Inc. | ||
| 39 | aries Aries Embedded GmbH | 40 | aries Aries Embedded GmbH |
| 40 | arm ARM Ltd. | 41 | arm ARM Ltd. |
| 41 | armadeus ARMadeus Systems SARL | 42 | armadeus ARMadeus Systems SARL |
| @@ -210,6 +211,7 @@ kiebackpeter Kieback & Peter GmbH · 168 unmodified lines | |||
| 210 | kinetic Kinetic Technologies | 211 | kinetic Kinetic Technologies |
| 211 | kingdisplay King & Display Technology Co., Ltd. | 212 | kingdisplay King & Display Technology Co., Ltd. |
| 212 | kingnovel Kingnovel Technology Co., Ltd. | 213 | kingnovel Kingnovel Technology Co., Ltd. |
| 214 | kionix Kionix, Inc. | ||
| 213 | koe Kaohsiung Opto-Electronics Inc. | 215 | koe Kaohsiung Opto-Electronics Inc. |
| 214 | kosagi Sutajio Ko-Usagi PTE Ltd. | 216 | kosagi Sutajio Ko-Usagi PTE Ltd. |
| 215 | kyo Kyocera Corporation | 217 | kyo Kyocera Corporation |
| @@ -233,6 +235,7 @@ lsi LSI Corp. (LSI Logic) · 17 unmodified lines | |||
| 233 | lwn Liebherr-Werk Nenzing GmbH | 235 | lwn Liebherr-Werk Nenzing GmbH |
| 234 | macnica Macnica Americas | 236 | macnica Macnica Americas |
| 235 | marvell Marvell Technology Group Ltd. | 237 | marvell Marvell Technology Group Ltd. |
| 238 | maxbotix MaxBotix Inc. | ||
| 236 | maxim Maxim Integrated Products | 239 | maxim Maxim Integrated Products |
| 237 | mbvl Mobiveil Inc. | 240 | mbvl Mobiveil Inc. |
| 238 | mcube mCube | 241 | mcube mCube |
| @@ -0,0 +1,342 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | ========================= | ||
| 4 | Generic Counter Interface | ||
| 5 | ========================= | ||
| 6 | |||
| 7 | Introduction | ||
| 8 | ============ | ||
| 9 | |||
| 10 | Counter devices are prevalent within a diverse spectrum of industries. | ||
| 11 | The ubiquitous presence of these devices necessitates a common interface | ||
| 12 | and standard of interaction and exposure. This driver API attempts to | ||
| 13 | resolve the issue of duplicate code found among existing counter device | ||
| 14 | drivers by introducing a generic counter interface for consumption. The | ||
| 15 | Generic Counter interface enables drivers to support and expose a common | ||
| 16 | set of components and functionality present in counter devices. | ||
| 17 | |||
| 18 | Theory | ||
| 19 | ====== | ||
| 20 | |||
| 21 | Counter devices can vary greatly in design, but regardless of whether | ||
| 22 | some devices are quadrature encoder counters or tally counters, all | ||
| 23 | counter devices consist of a core set of components. This core set of | ||
| 24 | components, shared by all counter devices, is what forms the essence of | ||
| 25 | the Generic Counter interface. | ||
| 26 | |||
| 27 | There are three core components to a counter: | ||
| 28 | |||
| 29 | * Count: | ||
| 30 | Count data for a set of Signals. | ||
| 31 | |||
| 32 | * Signal: | ||
| 33 | Input data that is evaluated by the counter to determine the count | ||
| 34 | data. | ||
| 35 | |||
| 36 | * Synapse: | ||
| 37 | The association of a Signal with a respective Count. | ||
| 38 | |||
| 39 | COUNT | ||
| 40 | ----- | ||
| 41 | A Count represents the count data for a set of Signals. The Generic | ||
| 42 | Counter interface provides the following available count data types: | ||
| 43 | |||
| 44 | * COUNT_POSITION: | ||
| 45 | Unsigned integer value representing position. | ||
| 46 | |||
| 47 | A Count has a count function mode which represents the update behavior | ||
| 48 | for the count data. The Generic Counter interface provides the following | ||
| 49 | available count function modes: | ||
| 50 | |||
| 51 | * Increase: | ||
| 52 | Accumulated count is incremented. | ||
| 53 | |||
| 54 | * Decrease: | ||
| 55 | Accumulated count is decremented. | ||
| 56 | |||
| 57 | * Pulse-Direction: | ||
| 58 | Rising edges on signal A updates the respective count. The input level | ||
| 59 | of signal B determines direction. | ||
| 60 | |||
| 61 | * Quadrature: | ||
| 62 | A pair of quadrature encoding signals are evaluated to determine | ||
| 63 | position and direction. The following Quadrature modes are available: | ||
| 64 | |||
| 65 | - x1 A: | ||
| 66 | If direction is forward, rising edges on quadrature pair signal A | ||
| 67 | updates the respective count; if the direction is backward, falling | ||
| 68 | edges on quadrature pair signal A updates the respective count. | ||
| 69 | Quadrature encoding determines the direction. | ||
| 70 | |||
| 71 | - x1 B: | ||
| 72 | If direction is forward, rising edges on quadrature pair signal B | ||
| 73 | updates the respective count; if the direction is backward, falling | ||
| 74 | edges on quadrature pair signal B updates the respective count. | ||
| 75 | Quadrature encoding determines the direction. | ||
| 76 | |||
| 77 | - x2 A: | ||
| 78 | Any state transition on quadrature pair signal A updates the | ||
| 79 | respective count. Quadrature encoding determines the direction. | ||
| 80 | |||
| 81 | - x2 B: | ||
| 82 | Any state transition on quadrature pair signal B updates the | ||
| 83 | respective count. Quadrature encoding determines the direction. | ||
| 84 | |||
| 85 | - x4: | ||
| 86 | Any state transition on either quadrature pair signals updates the | ||
| 87 | respective count. Quadrature encoding determines the direction. | ||
| 88 | |||
| 89 | A Count has a set of one or more associated Signals. | ||
| 90 | |||
| 91 | SIGNAL | ||
| 92 | ------ | ||
| 93 | A Signal represents a counter input data; this is the input data that is | ||
| 94 | evaluated by the counter to determine the count data; e.g. a quadrature | ||
| 95 | signal output line of a rotary encoder. Not all counter devices provide | ||
| 96 | user access to the Signal data. | ||
| 97 | |||
| 98 | The Generic Counter interface provides the following available signal | ||
| 99 | data types for when the Signal data is available for user access: | ||
| 100 | |||
| 101 | * SIGNAL_LEVEL: | ||
| 102 | Signal line state level. The following states are possible: | ||
| 103 | |||
| 104 | - SIGNAL_LEVEL_LOW: | ||
| 105 | Signal line is in a low state. | ||
| 106 | |||
| 107 | - SIGNAL_LEVEL_HIGH: | ||
| 108 | Signal line is in a high state. | ||
| 109 | |||
| 110 | A Signal may be associated with one or more Counts. | ||
| 111 | |||
| 112 | SYNAPSE | ||
| 113 | ------- | ||
| 114 | A Synapse represents the association of a Signal with a respective | ||
| 115 | Count. Signal data affects respective Count data, and the Synapse | ||
| 116 | represents this relationship. | ||
| 117 | |||
| 118 | The Synapse action mode specifies the Signal data condition which | ||
| 119 | triggers the respective Count's count function evaluation to update the | ||
| 120 | count data. The Generic Counter interface provides the following | ||
| 121 | available action modes: | ||
| 122 | |||
| 123 | * None: | ||
| 124 | Signal does not trigger the count function. In Pulse-Direction count | ||
| 125 | function mode, this Signal is evaluated as Direction. | ||
| 126 | |||
| 127 | * Rising Edge: | ||
| 128 | Low state transitions to high state. | ||
| 129 | |||
| 130 | * Falling Edge: | ||
| 131 | High state transitions to low state. | ||
| 132 | |||
| 133 | * Both Edges: | ||
| 134 | Any state transition. | ||
| 135 | |||
| 136 | A counter is defined as a set of input signals associated with count | ||
| 137 | data that are generated by the evaluation of the state of the associated | ||
| 138 | input signals as defined by the respective count functions. Within the | ||
| 139 | context of the Generic Counter interface, a counter consists of Counts | ||
| 140 | each associated with a set of Signals, whose respective Synapse | ||
| 141 | instances represent the count function update conditions for the | ||
| 142 | associated Counts. | ||
| 143 | |||
| 144 | Paradigm | ||
| 145 | ======== | ||
| 146 | |||
| 147 | The most basic counter device may be expressed as a single Count | ||
| 148 | associated with a single Signal via a single Synapse. Take for example | ||
| 149 | a counter device which simply accumulates a count of rising edges on a | ||
| 150 | source input line:: | ||
| 151 | |||
| 152 | Count Synapse Signal | ||
| 153 | ----- ------- ------ | ||
| 154 | +---------------------+ | ||
| 155 | | Data: Count | Rising Edge ________ | ||
| 156 | | Function: Increase | <------------- / Source \ | ||
| 157 | | | ____________ | ||
| 158 | +---------------------+ | ||
| 159 | |||
| 160 | In this example, the Signal is a source input line with a pulsing | ||
| 161 | voltage, while the Count is a persistent count value which is repeatedly | ||
| 162 | incremented. The Signal is associated with the respective Count via a | ||
| 163 | Synapse. The increase function is triggered by the Signal data condition | ||
| 164 | specified by the Synapse -- in this case a rising edge condition on the | ||
| 165 | voltage input line. In summary, the counter device existence and | ||
| 166 | behavior is aptly represented by respective Count, Signal, and Synapse | ||
| 167 | components: a rising edge condition triggers an increase function on an | ||
| 168 | accumulating count datum. | ||
| 169 | |||
| 170 | A counter device is not limited to a single Signal; in fact, in theory | ||
| 171 | many Signals may be associated with even a single Count. For example, a | ||
| 172 | quadrature encoder counter device can keep track of position based on | ||
| 173 | the states of two input lines:: | ||
| 174 | |||
| 175 | Count Synapse Signal | ||
| 176 | ----- ------- ------ | ||
| 177 | +-------------------------+ | ||
| 178 | | Data: Position | Both Edges ___ | ||
| 179 | | Function: Quadrature x4 | <------------ / A \ | ||
| 180 | | | _______ | ||
| 181 | | | | ||
| 182 | | | Both Edges ___ | ||
| 183 | | | <------------ / B \ | ||
| 184 | | | _______ | ||
| 185 | +-------------------------+ | ||
| 186 | |||
| 187 | In this example, two Signals (quadrature encoder lines A and B) are | ||
| 188 | associated with a single Count: a rising or falling edge on either A or | ||
| 189 | B triggers the "Quadrature x4" function which determines the direction | ||
| 190 | of movement and updates the respective position data. The "Quadrature | ||
| 191 | x4" function is likely implemented in the hardware of the quadrature | ||
| 192 | encoder counter device; the Count, Signals, and Synapses simply | ||
| 193 | represent this hardware behavior and functionality. | ||
| 194 | |||
| 195 | Signals associated with the same Count can have differing Synapse action | ||
| 196 | mode conditions. For example, a quadrature encoder counter device | ||
| 197 | operating in a non-quadrature Pulse-Direction mode could have one input | ||
| 198 | line dedicated for movement and a second input line dedicated for | ||
| 199 | direction:: | ||
| 200 | |||
| 201 | Count Synapse Signal | ||
| 202 | ----- ------- ------ | ||
| 203 | +---------------------------+ | ||
| 204 | | Data: Position | Rising Edge ___ | ||
| 205 | | Function: Pulse-Direction | <------------- / A \ (Movement) | ||
| 206 | | | _______ | ||
| 207 | | | | ||
| 208 | | | None ___ | ||
| 209 | | | <------------- / B \ (Direction) | ||
| 210 | | | _______ | ||
| 211 | +---------------------------+ | ||
| 212 | |||
| 213 | Only Signal A triggers the "Pulse-Direction" update function, but the | ||
| 214 | instantaneous state of Signal B is still required in order to know the | ||
| 215 | direction so that the position data may be properly updated. Ultimately, | ||
| 216 | both Signals are associated with the same Count via two respective | ||
| 217 | Synapses, but only one Synapse has an active action mode condition which | ||
| 218 | triggers the respective count function while the other is left with a | ||
| 219 | "None" condition action mode to indicate its respective Signal's | ||
| 220 | availability for state evaluation despite its non-triggering mode. | ||
| 221 | |||
| 222 | Keep in mind that the Signal, Synapse, and Count are abstract | ||
| 223 | representations which do not need to be closely married to their | ||
| 224 | respective physical sources. This allows the user of a counter to | ||
| 225 | divorce themselves from the nuances of physical components (such as | ||
| 226 | whether an input line is differential or single-ended) and instead focus | ||
| 227 | on the core idea of what the data and process represent (e.g. position | ||
| 228 | as interpreted from quadrature encoding data). | ||
| 229 | |||
| 230 | Userspace Interface | ||
| 231 | =================== | ||
| 232 | |||
| 233 | Several sysfs attributes are generated by the Generic Counter interface, | ||
| 234 | and reside under the /sys/bus/counter/devices/counterX directory, where | ||
| 235 | counterX refers to the respective counter device. Please see | ||
| 236 | Documentation/ABI/testing/sys-bus-counter-generic-sysfs for detailed | ||
| 237 | information on each Generic Counter interface sysfs attribute. | ||
| 238 | |||
| 239 | Through these sysfs attributes, programs and scripts may interact with | ||
| 240 | the Generic Counter paradigm Counts, Signals, and Synapses of respective | ||
| 241 | counter devices. | ||
| 242 | |||
| 243 | Driver API | ||
| 244 | ========== | ||
| 245 | |||
| 246 | Driver authors may utilize the Generic Counter interface in their code | ||
| 247 | by including the include/linux/counter.h header file. This header file | ||
| 248 | provides several core data structures, function prototypes, and macros | ||
| 249 | for defining a counter device. | ||
| 250 | |||
| 251 | .. kernel-doc:: include/linux/counter.h | ||
| 252 | :internal: | ||
| 253 | |||
| 254 | .. kernel-doc:: drivers/counter/generic-counter.c | ||
| 255 | :export: | ||
| 256 | |||
| 257 | Implementation | ||
| 258 | ============== | ||
| 259 | |||
| 260 | To support a counter device, a driver must first allocate the available | ||
| 261 | Counter Signals via counter_signal structures. These Signals should | ||
| 262 | be stored as an array and set to the signals array member of an | ||
| 263 | allocated counter_device structure before the Counter is registered to | ||
| 264 | the system. | ||
| 265 | |||
| 266 | Counter Counts may be allocated via counter_count structures, and | ||
| 267 | respective Counter Signal associations (Synapses) made via | ||
| 268 | counter_synapse structures. Associated counter_synapse structures are | ||
| 269 | stored as an array and set to the the synapses array member of the | ||
| 270 | respective counter_count structure. These counter_count structures are | ||
| 271 | set to the counts array member of an allocated counter_device structure | ||
| 272 | before the Counter is registered to the system. | ||
| 273 | |||
| 274 | Driver callbacks should be provided to the counter_device structure via | ||
| 275 | a constant counter_ops structure in order to communicate with the | ||
| 276 | device: to read and write various Signals and Counts, and to set and get | ||
| 277 | the "action mode" and "function mode" for various Synapses and Counts | ||
| 278 | respectively. | ||
| 279 | |||
| 280 | A defined counter_device structure may be registered to the system by | ||
| 281 | passing it to the counter_register function, and unregistered by passing | ||
| 282 | it to the counter_unregister function. Similarly, the | ||
| 283 | devm_counter_register and devm_counter_unregister functions may be used | ||
| 284 | if device memory-managed registration is desired. | ||
| 285 | |||
| 286 | Extension sysfs attributes can be created for auxiliary functionality | ||
| 287 | and data by passing in defined counter_device_ext, counter_count_ext, | ||
| 288 | and counter_signal_ext structures. In these cases, the | ||
| 289 | counter_device_ext structure is used for global configuration of the | ||
| 290 | respective Counter device, while the counter_count_ext and | ||
| 291 | counter_signal_ext structures allow for auxiliary exposure and | ||
| 292 | configuration of a specific Count or Signal respectively. | ||
| 293 | |||
| 294 | Architecture | ||
| 295 | ============ | ||
| 296 | |||
| 297 | When the Generic Counter interface counter module is loaded, the | ||
| 298 | counter_init function is called which registers a bus_type named | ||
| 299 | "counter" to the system. Subsequently, when the module is unloaded, the | ||
| 300 | counter_exit function is called which unregisters the bus_type named | ||
| 301 | "counter" from the system. | ||
| 302 | |||
| 303 | Counter devices are registered to the system via the counter_register | ||
| 304 | function, and later removed via the counter_unregister function. The | ||
| 305 | counter_register function establishes a unique ID for the Counter | ||
| 306 | device and creates a respective sysfs directory, where X is the | ||
| 307 | mentioned unique ID: | ||
| 308 | |||
| 309 | /sys/bus/counter/devices/counterX | ||
| 310 | |||
| 311 | Sysfs attributes are created within the counterX directory to expose | ||
| 312 | functionality, configurations, and data relating to the Counts, Signals, | ||
| 313 | and Synapses of the Counter device, as well as options and information | ||
| 314 | for the Counter device itself. | ||
| 315 | |||
| 316 | Each Signal has a directory created to house its relevant sysfs | ||
| 317 | attributes, where Y is the unique ID of the respective Signal: | ||
| 318 | |||
| 319 | /sys/bus/counter/devices/counterX/signalY | ||
| 320 | |||
| 321 | Similarly, each Count has a directory created to house its relevant | ||
| 322 | sysfs attributes, where Y is the unique ID of the respective Count: | ||
| 323 | |||
| 324 | /sys/bus/counter/devices/counterX/countY | ||
| 325 | |||
| 326 | For a more detailed breakdown of the available Generic Counter interface | ||
| 327 | sysfs attributes, please refer to the | ||
| 328 | Documentation/ABI/testing/sys-bus-counter file. | ||
| 329 | |||
| 330 | The Signals and Counts associated with the Counter device are registered | ||
| 331 | to the system as well by the counter_register function. The | ||
| 332 | signal_read/signal_write driver callbacks are associated with their | ||
| 333 | respective Signal attributes, while the count_read/count_write and | ||
| 334 | function_get/function_set driver callbacks are associated with their | ||
| 335 | respective Count attributes; similarly, the same is true for the | ||
| 336 | action_get/action_set driver callbacks and their respective Synapse | ||
| 337 | attributes. If a driver callback is left undefined, then the respective | ||
| 338 | read/write permission is left disabled for the relevant attributes. | ||
| 339 | |||
| 340 | Similarly, extension sysfs attributes are created for the defined | ||
| 341 | counter_device_ext, counter_count_ext, and counter_signal_ext | ||
| 342 | structures that are passed in. | ||
| @@ -57,6 +57,7 @@ available subsections can be seen below. · 56 unmodified lines | |||
| 57 | soundwire/index | 57 | soundwire/index |
| 58 | fpga/index | 58 | fpga/index |
| 59 | acpi/index | 59 | acpi/index |
| 60 | generic-counter | ||
| 60 | 61 | ||
| 61 | .. only:: subproject and html | 62 | .. only:: subproject and html |
| 62 | 63 | ||
| @@ -268,12 +268,13 @@ L: linux-gpio@vger.kernel.org · 267 unmodified lines | |||
| 268 | S: Maintained | 268 | S: Maintained |
| 269 | F: drivers/gpio/gpio-104-idio-16.c | 269 | F: drivers/gpio/gpio-104-idio-16.c |
| 270 | 270 | ||
| 271 | ACCES 104-QUAD-8 IIO DRIVER | 271 | ACCES 104-QUAD-8 DRIVER |
| 272 | M: William Breathitt Gray <vilhelm.gray@gmail.com> | 272 | M: William Breathitt Gray <vilhelm.gray@gmail.com> |
| 273 | L: linux-iio@vger.kernel.org | 273 | L: linux-iio@vger.kernel.org |
| 274 | S: Maintained | 274 | S: Maintained |
| 275 | F: Documentation/ABI/testing/sysfs-bus-counter-104-quad-8 | ||
| 275 | F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 | 276 | F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 |
| 276 | F: drivers/iio/counter/104-quad-8.c | 277 | F: drivers/counter/104-quad-8.c |
| 277 | 278 | ||
| 278 | ACCES PCI-IDIO-16 GPIO DRIVER | 279 | ACCES PCI-IDIO-16 GPIO DRIVER |
| 279 | M: William Breathitt Gray <vilhelm.gray@gmail.com> | 280 | M: William Breathitt Gray <vilhelm.gray@gmail.com> |
| @@ -868,7 +869,7 @@ L: linux-iio@vger.kernel.org · 588 unmodified lines | |||
| 868 | W: http://ez.analog.com/community/linux-device-drivers | 869 | W: http://ez.analog.com/community/linux-device-drivers |
| 869 | S: Supported | 870 | S: Supported |
| 870 | F: drivers/iio/adc/ad7606.c | 871 | F: drivers/iio/adc/ad7606.c |
| 871 | F: Documentation/devicetree/bindings/iio/adc/ad7606.txt | 872 | F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt |
| 872 | 873 | ||
| 873 | ANALOG DEVICES INC AD7768-1 DRIVER | 874 | ANALOG DEVICES INC AD7768-1 DRIVER |
| 874 | M: Stefan Popa <stefan.popa@analog.com> | 875 | M: Stefan Popa <stefan.popa@analog.com> |
| @@ -950,6 +951,7 @@ F: drivers/dma/dma-axi-dmac.c · 75 unmodified lines | |||
| 950 | ANALOG DEVICES INC IIO DRIVERS | 951 | ANALOG DEVICES INC IIO DRIVERS |
| 951 | M: Lars-Peter Clausen <lars@metafoo.de> | 952 | M: Lars-Peter Clausen <lars@metafoo.de> |
| 952 | M: Michael Hennerich <Michael.Hennerich@analog.com> | 953 | M: Michael Hennerich <Michael.Hennerich@analog.com> |
| 954 | M: Stefan Popa <stefan.popa@analog.com> | ||
| 953 | W: http://wiki.analog.com/ | 955 | W: http://wiki.analog.com/ |
| 954 | W: http://ez.analog.com/community/linux-device-drivers | 956 | W: http://ez.analog.com/community/linux-device-drivers |
| 955 | S: Supported | 957 | S: Supported |
| @@ -4057,6 +4059,16 @@ W: http://www.fi.muni.cz/~kas/cosa/ · 3101 unmodified lines | |||
| 4057 | S: Maintained | 4059 | S: Maintained |
| 4058 | F: drivers/net/wan/cosa* | 4060 | F: drivers/net/wan/cosa* |
| 4059 | 4061 | ||
| 4062 | COUNTER SUBSYSTEM | ||
| 4063 | M: William Breathitt Gray <vilhelm.gray@gmail.com> | ||
| 4064 | L: linux-iio@vger.kernel.org | ||
| 4065 | S: Maintained | ||
| 4066 | F: Documentation/ABI/testing/sysfs-bus-counter* | ||
| 4067 | F: Documentation/driver-api/generic-counter.rst | ||
| 4068 | F: drivers/counter/ | ||
| 4069 | F: include/linux/counter.h | ||
| 4070 | F: include/linux/counter_enum.h | ||
| 4071 | |||
| 4060 | CPMAC ETHERNET DRIVER | 4072 | CPMAC ETHERNET DRIVER |
| 4061 | M: Florian Fainelli <f.fainelli@gmail.com> | 4073 | M: Florian Fainelli <f.fainelli@gmail.com> |
| 4062 | L: netdev@vger.kernel.org | 4074 | L: netdev@vger.kernel.org |
| @@ -9417,6 +9429,13 @@ S: Maintained · 5354 unmodified lines | |||
| 9417 | F: Documentation/devicetree/bindings/sound/max9860.txt | 9429 | F: Documentation/devicetree/bindings/sound/max9860.txt |
| 9418 | F: sound/soc/codecs/max9860.* | 9430 | F: sound/soc/codecs/max9860.* |
| 9419 | 9431 | ||
| 9432 | MAXBOTIX ULTRASONIC RANGER IIO DRIVER | ||
| 9433 | M: Andreas Klinger <ak@it-klinger.de> | ||
| 9434 | L: linux-iio@vger.kernel.org | ||
| 9435 | S: Maintained | ||
| 9436 | F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt | ||
| 9437 | F: drivers/iio/proximity/mb1232.c | ||
| 9438 | |||
| 9420 | MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER | 9439 | MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER |
| 9421 | M: Javier Martinez Canillas <javier@dowhile0.org> | 9440 | M: Javier Martinez Canillas <javier@dowhile0.org> |
| 9422 | L: linux-kernel@vger.kernel.org | 9441 | L: linux-kernel@vger.kernel.org |
| @@ -11133,6 +11152,16 @@ F: Documentation/ABI/stable/sysfs-bus-nvmem · 1710 unmodified lines | |||
| 11133 | F: include/linux/nvmem-consumer.h | 11152 | F: include/linux/nvmem-consumer.h |
| 11134 | F: include/linux/nvmem-provider.h | 11153 | F: include/linux/nvmem-provider.h |
| 11135 | 11154 | ||
| 11155 | NXP FXAS21002C DRIVER | ||
| 11156 | M: Rui Miguel Silva <rmfrfs@gmail.com> | ||
| 11157 | L: linux-iio@vger.kernel.org | ||
| 11158 | S: Maintained | ||
| 11159 | F: Documentation/devicetree/bindings/iio/gyroscope/fxas21002c.txt | ||
| 11160 | F: drivers/iio/gyro/fxas21002c_core.c | ||
| 11161 | F: drivers/iio/gyro/fxas21002c.h | ||
| 11162 | F: drivers/iio/gyro/fxas21002c_i2c.c | ||
| 11163 | F: drivers/iio/gyro/fxas21002c_spi.c | ||
| 11164 | |||
| 11136 | NXP SGTL5000 DRIVER | 11165 | NXP SGTL5000 DRIVER |
| 11137 | M: Fabio Estevam <festevam@gmail.com> | 11166 | M: Fabio Estevam <festevam@gmail.com> |
| 11138 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 11167 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
| @@ -446,6 +446,34 @@ · 445 unmodified lines | |||
| 446 | status = "disabled"; | 446 | status = "disabled"; |
| 447 | }; | 447 | }; |
| 448 | 448 | ||
| 449 | counter0: counter@29d0000 { | ||
| 450 | compatible = "fsl,ftm-quaddec"; | ||
| 451 | reg = <0x0 0x29d0000 0x0 0x10000>; | ||
| 452 | big-endian; | ||
| 453 | status = "disabled"; | ||
| 454 | }; | ||
| 455 | |||
| 456 | counter1: counter@29e0000 { | ||
| 457 | compatible = "fsl,ftm-quaddec"; | ||
| 458 | reg = <0x0 0x29e0000 0x0 0x10000>; | ||
| 459 | big-endian; | ||
| 460 | status = "disabled"; | ||
| 461 | }; | ||
| 462 | |||
| 463 | counter2: counter@29f0000 { | ||
| 464 | compatible = "fsl,ftm-quaddec"; | ||
| 465 | reg = <0x0 0x29f0000 0x0 0x10000>; | ||
| 466 | big-endian; | ||
| 467 | status = "disabled"; | ||
| 468 | }; | ||
| 469 | |||
| 470 | counter3: counter@2a00000 { | ||
| 471 | compatible = "fsl,ftm-quaddec"; | ||
| 472 | reg = <0x0 0x2a00000 0x0 0x10000>; | ||
| 473 | big-endian; | ||
| 474 | status = "disabled"; | ||
| 475 | }; | ||
| 476 | |||
| 449 | gpio0: gpio@2300000 { | 477 | gpio0: gpio@2300000 { |
| 450 | compatible = "fsl,ls1021a-gpio", "fsl,qoriq-gpio"; | 478 | compatible = "fsl,ls1021a-gpio", "fsl,qoriq-gpio"; |
| 451 | reg = <0x0 0x2300000 0x0 0x10000>; | 479 | reg = <0x0 0x2300000 0x0 0x10000>; |
| @@ -230,4 +230,6 @@ source "drivers/slimbus/Kconfig" · 229 unmodified lines | |||
| 230 | 230 | ||
| 231 | source "drivers/interconnect/Kconfig" | 231 | source "drivers/interconnect/Kconfig" |
| 232 | 232 | ||
| 233 | source "drivers/counter/Kconfig" | ||
| 234 | |||
| 233 | endmenu | 235 | endmenu |
| @@ -187,3 +187,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ · 186 unmodified lines | |||
| 187 | obj-$(CONFIG_SIOX) += siox/ | 187 | obj-$(CONFIG_SIOX) += siox/ |
| 188 | obj-$(CONFIG_GNSS) += gnss/ | 188 | obj-$(CONFIG_GNSS) += gnss/ |
| 189 | obj-$(CONFIG_INTERCONNECT) += interconnect/ | 189 | obj-$(CONFIG_INTERCONNECT) += interconnect/ |
| 190 | obj-$(CONFIG_COUNTER) += counter/ | ||
| @@ -19,20 +19,9 @@ · 18 unmodified lines | |||
| 19 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
| 20 | #include <linux/sched_clock.h> | 20 | #include <linux/sched_clock.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <linux/fsl/ftm.h> | ||
| 22 | 23 | ||
| 23 | #define FTM_SC 0x00 | 24 | #define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT) |
| 24 | #define FTM_SC_CLK_SHIFT 3 | ||
| 25 | #define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT) | ||
| 26 | #define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT) | ||
| 27 | #define FTM_SC_PS_MASK 0x7 | ||
| 28 | #define FTM_SC_TOIE BIT(6) | ||
| 29 | #define FTM_SC_TOF BIT(7) | ||
| 30 | |||
| 31 | #define FTM_CNT 0x04 | ||
| 32 | #define FTM_MOD 0x08 | ||
| 33 | #define FTM_CNTIN 0x4C | ||
| 34 | |||
| 35 | #define FTM_PS_MAX 7 | ||
| 36 | 25 | ||
| 37 | struct ftm_clock_device { | 26 | struct ftm_clock_device { |
| 38 | void __iomem *clksrc_base; | 27 | void __iomem *clksrc_base; |
| @@ -0,0 +1,1367 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Counter driver for the ACCES 104-QUAD-8 | ||
| 4 | * Copyright (C) 2016 William Breathitt Gray | ||
| 5 | * | ||
| 6 | * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. | ||
| 7 | */ | ||
| 8 | #include <linux/bitops.h> | ||
| 9 | #include <linux/counter.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/iio/iio.h> | ||
| 13 | #include <linux/iio/types.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/ioport.h> | ||
| 16 | #include <linux/isa.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/moduleparam.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | |||
| 22 | #define QUAD8_EXTENT 32 | ||
| 23 | |||
| 24 | static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; | ||
| 25 | static unsigned int num_quad8; | ||
| 26 | module_param_array(base, uint, &num_quad8, 0); | ||
| 27 | MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); | ||
| 28 | |||
| 29 | #define QUAD8_NUM_COUNTERS 8 | ||
| 30 | |||
| 31 | /** | ||
| 32 | * struct quad8_iio - IIO device private data structure | ||
| 33 | * @counter: instance of the counter_device | ||
| 34 | * @preset: array of preset values | ||
| 35 | * @count_mode: array of count mode configurations | ||
| 36 | * @quadrature_mode: array of quadrature mode configurations | ||
| 37 | * @quadrature_scale: array of quadrature mode scale configurations | ||
| 38 | * @ab_enable: array of A and B inputs enable configurations | ||
| 39 | * @preset_enable: array of set_to_preset_on_index attribute configurations | ||
| 40 | * @synchronous_mode: array of index function synchronous mode configurations | ||
| 41 | * @index_polarity: array of index function polarity configurations | ||
| 42 | * @base: base port address of the IIO device | ||
| 43 | */ | ||
| 44 | struct quad8_iio { | ||
| 45 | struct counter_device counter; | ||
| 46 | unsigned int preset[QUAD8_NUM_COUNTERS]; | ||
| 47 | unsigned int count_mode[QUAD8_NUM_COUNTERS]; | ||
| 48 | unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; | ||
| 49 | unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; | ||
| 50 | unsigned int ab_enable[QUAD8_NUM_COUNTERS]; | ||
| 51 | unsigned int preset_enable[QUAD8_NUM_COUNTERS]; | ||
| 52 | unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; | ||
| 53 | unsigned int index_polarity[QUAD8_NUM_COUNTERS]; | ||
| 54 | unsigned int base; | ||
| 55 | }; | ||
| 56 | |||
| 57 | #define QUAD8_REG_CHAN_OP 0x11 | ||
| 58 | #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 | ||
| 59 | /* Borrow Toggle flip-flop */ | ||
| 60 | #define QUAD8_FLAG_BT BIT(0) | ||
| 61 | /* Carry Toggle flip-flop */ | ||
| 62 | #define QUAD8_FLAG_CT BIT(1) | ||
| 63 | /* Error flag */ | ||
| 64 | #define QUAD8_FLAG_E BIT(4) | ||
| 65 | /* Up/Down flag */ | ||
| 66 | #define QUAD8_FLAG_UD BIT(5) | ||
| 67 | /* Reset and Load Signal Decoders */ | ||
| 68 | #define QUAD8_CTR_RLD 0x00 | ||
| 69 | /* Counter Mode Register */ | ||
| 70 | #define QUAD8_CTR_CMR 0x20 | ||
| 71 | /* Input / Output Control Register */ | ||
| 72 | #define QUAD8_CTR_IOR 0x40 | ||
| 73 | /* Index Control Register */ | ||
| 74 | #define QUAD8_CTR_IDR 0x60 | ||
| 75 | /* Reset Byte Pointer (three byte data pointer) */ | ||
| 76 | #define QUAD8_RLD_RESET_BP 0x01 | ||
| 77 | /* Reset Counter */ | ||
| 78 | #define QUAD8_RLD_RESET_CNTR 0x02 | ||
| 79 | /* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */ | ||
| 80 | #define QUAD8_RLD_RESET_FLAGS 0x04 | ||
| 81 | /* Reset Error flag */ | ||
| 82 | #define QUAD8_RLD_RESET_E 0x06 | ||
| 83 | /* Preset Register to Counter */ | ||
| 84 | #define QUAD8_RLD_PRESET_CNTR 0x08 | ||
| 85 | /* Transfer Counter to Output Latch */ | ||
| 86 | #define QUAD8_RLD_CNTR_OUT 0x10 | ||
| 87 | #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00 | ||
| 88 | #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 | ||
| 89 | #define QUAD8_CMR_QUADRATURE_X1 0x08 | ||
| 90 | #define QUAD8_CMR_QUADRATURE_X2 0x10 | ||
| 91 | #define QUAD8_CMR_QUADRATURE_X4 0x18 | ||
| 92 | |||
| 93 | |||
| 94 | static int quad8_read_raw(struct iio_dev *indio_dev, | ||
| 95 | struct iio_chan_spec const *chan, int *val, int *val2, long mask) | ||
| 96 | { | ||
| 97 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 98 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 99 | unsigned int flags; | ||
| 100 | unsigned int borrow; | ||
| 101 | unsigned int carry; | ||
| 102 | int i; | ||
| 103 | |||
| 104 | switch (mask) { | ||
| 105 | case IIO_CHAN_INFO_RAW: | ||
| 106 | if (chan->type == IIO_INDEX) { | ||
| 107 | *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) | ||
| 108 | & BIT(chan->channel)); | ||
| 109 | return IIO_VAL_INT; | ||
| 110 | } | ||
| 111 | |||
| 112 | flags = inb(base_offset + 1); | ||
| 113 | borrow = flags & QUAD8_FLAG_BT; | ||
| 114 | carry = !!(flags & QUAD8_FLAG_CT); | ||
| 115 | |||
| 116 | /* Borrow XOR Carry effectively doubles count range */ | ||
| 117 | *val = (borrow ^ carry) << 24; | ||
| 118 | |||
| 119 | /* Reset Byte Pointer; transfer Counter to Output Latch */ | ||
| 120 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, | ||
| 121 | base_offset + 1); | ||
| 122 | |||
| 123 | for (i = 0; i < 3; i++) | ||
| 124 | *val |= (unsigned int)inb(base_offset) << (8 * i); | ||
| 125 | |||
| 126 | return IIO_VAL_INT; | ||
| 127 | case IIO_CHAN_INFO_ENABLE: | ||
| 128 | *val = priv->ab_enable[chan->channel]; | ||
| 129 | return IIO_VAL_INT; | ||
| 130 | case IIO_CHAN_INFO_SCALE: | ||
| 131 | *val = 1; | ||
| 132 | *val2 = priv->quadrature_scale[chan->channel]; | ||
| 133 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 134 | } | ||
| 135 | |||
| 136 | return -EINVAL; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int quad8_write_raw(struct iio_dev *indio_dev, | ||
| 140 | struct iio_chan_spec const *chan, int val, int val2, long mask) | ||
| 141 | { | ||
| 142 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 143 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 144 | int i; | ||
| 145 | unsigned int ior_cfg; | ||
| 146 | |||
| 147 | switch (mask) { | ||
| 148 | case IIO_CHAN_INFO_RAW: | ||
| 149 | if (chan->type == IIO_INDEX) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | /* Only 24-bit values are supported */ | ||
| 153 | if ((unsigned int)val > 0xFFFFFF) | ||
| 154 | return -EINVAL; | ||
| 155 | |||
| 156 | /* Reset Byte Pointer */ | ||
| 157 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 158 | |||
| 159 | /* Counter can only be set via Preset Register */ | ||
| 160 | for (i = 0; i < 3; i++) | ||
| 161 | outb(val >> (8 * i), base_offset); | ||
| 162 | |||
| 163 | /* Transfer Preset Register to Counter */ | ||
| 164 | outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); | ||
| 165 | |||
| 166 | /* Reset Byte Pointer */ | ||
| 167 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 168 | |||
| 169 | /* Set Preset Register back to original value */ | ||
| 170 | val = priv->preset[chan->channel]; | ||
| 171 | for (i = 0; i < 3; i++) | ||
| 172 | outb(val >> (8 * i), base_offset); | ||
| 173 | |||
| 174 | /* Reset Borrow, Carry, Compare, and Sign flags */ | ||
| 175 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); | ||
| 176 | /* Reset Error flag */ | ||
| 177 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | case IIO_CHAN_INFO_ENABLE: | ||
| 181 | /* only boolean values accepted */ | ||
| 182 | if (val < 0 || val > 1) | ||
| 183 | return -EINVAL; | ||
| 184 | |||
| 185 | priv->ab_enable[chan->channel] = val; | ||
| 186 | |||
| 187 | ior_cfg = val | priv->preset_enable[chan->channel] << 1; | ||
| 188 | |||
| 189 | /* Load I/O control configuration */ | ||
| 190 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | case IIO_CHAN_INFO_SCALE: | ||
| 194 | /* Quadrature scaling only available in quadrature mode */ | ||
| 195 | if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) | ||
| 196 | return -EINVAL; | ||
| 197 | |||
| 198 | /* Only three gain states (1, 0.5, 0.25) */ | ||
| 199 | if (val == 1 && !val2) | ||
| 200 | priv->quadrature_scale[chan->channel] = 0; | ||
| 201 | else if (!val) | ||
| 202 | switch (val2) { | ||
| 203 | case 500000: | ||
| 204 | priv->quadrature_scale[chan->channel] = 1; | ||
| 205 | break; | ||
| 206 | case 250000: | ||
| 207 | priv->quadrature_scale[chan->channel] = 2; | ||
| 208 | break; | ||
| 209 | default: | ||
| 210 | return -EINVAL; | ||
| 211 | } | ||
| 212 | else | ||
| 213 | return -EINVAL; | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | return -EINVAL; | ||
| 219 | } | ||
| 220 | |||
| 221 | static const struct iio_info quad8_info = { | ||
| 222 | .read_raw = quad8_read_raw, | ||
| 223 | .write_raw = quad8_write_raw | ||
| 224 | }; | ||
| 225 | |||
| 226 | static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, | ||
| 227 | const struct iio_chan_spec *chan, char *buf) | ||
| 228 | { | ||
| 229 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 230 | |||
| 231 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); | ||
| 232 | } | ||
| 233 | |||
| 234 | static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, | ||
| 235 | const struct iio_chan_spec *chan, const char *buf, size_t len) | ||
| 236 | { | ||
| 237 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 238 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 239 | unsigned int preset; | ||
| 240 | int ret; | ||
| 241 | int i; | ||
| 242 | |||
| 243 | ret = kstrtouint(buf, 0, &preset); | ||
| 244 | if (ret) | ||
| 245 | return ret; | ||
| 246 | |||
| 247 | /* Only 24-bit values are supported */ | ||
| 248 | if (preset > 0xFFFFFF) | ||
| 249 | return -EINVAL; | ||
| 250 | |||
| 251 | priv->preset[chan->channel] = preset; | ||
| 252 | |||
| 253 | /* Reset Byte Pointer */ | ||
| 254 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 255 | |||
| 256 | /* Set Preset Register */ | ||
| 257 | for (i = 0; i < 3; i++) | ||
| 258 | outb(preset >> (8 * i), base_offset); | ||
| 259 | |||
| 260 | return len; | ||
| 261 | } | ||
| 262 | |||
| 263 | static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, | ||
| 264 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) | ||
| 265 | { | ||
| 266 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 267 | |||
| 268 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
| 269 | !priv->preset_enable[chan->channel]); | ||
| 270 | } | ||
| 271 | |||
| 272 | static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, | ||
| 273 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, | ||
| 274 | size_t len) | ||
| 275 | { | ||
| 276 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 277 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 278 | bool preset_enable; | ||
| 279 | int ret; | ||
| 280 | unsigned int ior_cfg; | ||
| 281 | |||
| 282 | ret = kstrtobool(buf, &preset_enable); | ||
| 283 | if (ret) | ||
| 284 | return ret; | ||
| 285 | |||
| 286 | /* Preset enable is active low in Input/Output Control register */ | ||
| 287 | preset_enable = !preset_enable; | ||
| 288 | |||
| 289 | priv->preset_enable[chan->channel] = preset_enable; | ||
| 290 | |||
| 291 | ior_cfg = priv->ab_enable[chan->channel] | | ||
| 292 | (unsigned int)preset_enable << 1; | ||
| 293 | |||
| 294 | /* Load I/O control configuration to Input / Output Control Register */ | ||
| 295 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset); | ||
| 296 | |||
| 297 | return len; | ||
| 298 | } | ||
| 299 | |||
| 300 | static const char *const quad8_noise_error_states[] = { | ||
| 301 | "No excessive noise is present at the count inputs", | ||
| 302 | "Excessive noise is present at the count inputs" | ||
| 303 | }; | ||
| 304 | |||
| 305 | static int quad8_get_noise_error(struct iio_dev *indio_dev, | ||
| 306 | const struct iio_chan_spec *chan) | ||
| 307 | { | ||
| 308 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 309 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 310 | |||
| 311 | return !!(inb(base_offset) & QUAD8_FLAG_E); | ||
| 312 | } | ||
| 313 | |||
| 314 | static const struct iio_enum quad8_noise_error_enum = { | ||
| 315 | .items = quad8_noise_error_states, | ||
| 316 | .num_items = ARRAY_SIZE(quad8_noise_error_states), | ||
| 317 | .get = quad8_get_noise_error | ||
| 318 | }; | ||
| 319 | |||
| 320 | static const char *const quad8_count_direction_states[] = { | ||
| 321 | "down", | ||
| 322 | "up" | ||
| 323 | }; | ||
| 324 | |||
| 325 | static int quad8_get_count_direction(struct iio_dev *indio_dev, | ||
| 326 | const struct iio_chan_spec *chan) | ||
| 327 | { | ||
| 328 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 329 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 330 | |||
| 331 | return !!(inb(base_offset) & QUAD8_FLAG_UD); | ||
| 332 | } | ||
| 333 | |||
| 334 | static const struct iio_enum quad8_count_direction_enum = { | ||
| 335 | .items = quad8_count_direction_states, | ||
| 336 | .num_items = ARRAY_SIZE(quad8_count_direction_states), | ||
| 337 | .get = quad8_get_count_direction | ||
| 338 | }; | ||
| 339 | |||
| 340 | static const char *const quad8_count_modes[] = { | ||
| 341 | "normal", | ||
| 342 | "range limit", | ||
| 343 | "non-recycle", | ||
| 344 | "modulo-n" | ||
| 345 | }; | ||
| 346 | |||
| 347 | static int quad8_set_count_mode(struct iio_dev *indio_dev, | ||
| 348 | const struct iio_chan_spec *chan, unsigned int cnt_mode) | ||
| 349 | { | ||
| 350 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 351 | unsigned int mode_cfg = cnt_mode << 1; | ||
| 352 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 353 | |||
| 354 | priv->count_mode[chan->channel] = cnt_mode; | ||
| 355 | |||
| 356 | /* Add quadrature mode configuration */ | ||
| 357 | if (priv->quadrature_mode[chan->channel]) | ||
| 358 | mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; | ||
| 359 | |||
| 360 | /* Load mode configuration to Counter Mode Register */ | ||
| 361 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 362 | |||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | static int quad8_get_count_mode(struct iio_dev *indio_dev, | ||
| 367 | const struct iio_chan_spec *chan) | ||
| 368 | { | ||
| 369 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 370 | |||
| 371 | return priv->count_mode[chan->channel]; | ||
| 372 | } | ||
| 373 | |||
| 374 | static const struct iio_enum quad8_count_mode_enum = { | ||
| 375 | .items = quad8_count_modes, | ||
| 376 | .num_items = ARRAY_SIZE(quad8_count_modes), | ||
| 377 | .set = quad8_set_count_mode, | ||
| 378 | .get = quad8_get_count_mode | ||
| 379 | }; | ||
| 380 | |||
| 381 | static const char *const quad8_synchronous_modes[] = { | ||
| 382 | "non-synchronous", | ||
| 383 | "synchronous" | ||
| 384 | }; | ||
| 385 | |||
| 386 | static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, | ||
| 387 | const struct iio_chan_spec *chan, unsigned int synchronous_mode) | ||
| 388 | { | ||
| 389 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 390 | const unsigned int idr_cfg = synchronous_mode | | ||
| 391 | priv->index_polarity[chan->channel] << 1; | ||
| 392 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 393 | |||
| 394 | /* Index function must be non-synchronous in non-quadrature mode */ | ||
| 395 | if (synchronous_mode && !priv->quadrature_mode[chan->channel]) | ||
| 396 | return -EINVAL; | ||
| 397 | |||
| 398 | priv->synchronous_mode[chan->channel] = synchronous_mode; | ||
| 399 | |||
| 400 | /* Load Index Control configuration to Index Control Register */ | ||
| 401 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, | ||
| 407 | const struct iio_chan_spec *chan) | ||
| 408 | { | ||
| 409 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 410 | |||
| 411 | return priv->synchronous_mode[chan->channel]; | ||
| 412 | } | ||
| 413 | |||
| 414 | static const struct iio_enum quad8_synchronous_mode_enum = { | ||
| 415 | .items = quad8_synchronous_modes, | ||
| 416 | .num_items = ARRAY_SIZE(quad8_synchronous_modes), | ||
| 417 | .set = quad8_set_synchronous_mode, | ||
| 418 | .get = quad8_get_synchronous_mode | ||
| 419 | }; | ||
| 420 | |||
| 421 | static const char *const quad8_quadrature_modes[] = { | ||
| 422 | "non-quadrature", | ||
| 423 | "quadrature" | ||
| 424 | }; | ||
| 425 | |||
| 426 | static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, | ||
| 427 | const struct iio_chan_spec *chan, unsigned int quadrature_mode) | ||
| 428 | { | ||
| 429 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 430 | unsigned int mode_cfg = priv->count_mode[chan->channel] << 1; | ||
| 431 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 432 | |||
| 433 | if (quadrature_mode) | ||
| 434 | mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; | ||
| 435 | else { | ||
| 436 | /* Quadrature scaling only available in quadrature mode */ | ||
| 437 | priv->quadrature_scale[chan->channel] = 0; | ||
| 438 | |||
| 439 | /* Synchronous function not supported in non-quadrature mode */ | ||
| 440 | if (priv->synchronous_mode[chan->channel]) | ||
| 441 | quad8_set_synchronous_mode(indio_dev, chan, 0); | ||
| 442 | } | ||
| 443 | |||
| 444 | priv->quadrature_mode[chan->channel] = quadrature_mode; | ||
| 445 | |||
| 446 | /* Load mode configuration to Counter Mode Register */ | ||
| 447 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, | ||
| 453 | const struct iio_chan_spec *chan) | ||
| 454 | { | ||
| 455 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 456 | |||
| 457 | return priv->quadrature_mode[chan->channel]; | ||
| 458 | } | ||
| 459 | |||
| 460 | static const struct iio_enum quad8_quadrature_mode_enum = { | ||
| 461 | .items = quad8_quadrature_modes, | ||
| 462 | .num_items = ARRAY_SIZE(quad8_quadrature_modes), | ||
| 463 | .set = quad8_set_quadrature_mode, | ||
| 464 | .get = quad8_get_quadrature_mode | ||
| 465 | }; | ||
| 466 | |||
| 467 | static const char *const quad8_index_polarity_modes[] = { | ||
| 468 | "negative", | ||
| 469 | "positive" | ||
| 470 | }; | ||
| 471 | |||
| 472 | static int quad8_set_index_polarity(struct iio_dev *indio_dev, | ||
| 473 | const struct iio_chan_spec *chan, unsigned int index_polarity) | ||
| 474 | { | ||
| 475 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 476 | const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | | ||
| 477 | index_polarity << 1; | ||
| 478 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 479 | |||
| 480 | priv->index_polarity[chan->channel] = index_polarity; | ||
| 481 | |||
| 482 | /* Load Index Control configuration to Index Control Register */ | ||
| 483 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 484 | |||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | static int quad8_get_index_polarity(struct iio_dev *indio_dev, | ||
| 489 | const struct iio_chan_spec *chan) | ||
| 490 | { | ||
| 491 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 492 | |||
| 493 | return priv->index_polarity[chan->channel]; | ||
| 494 | } | ||
| 495 | |||
| 496 | static const struct iio_enum quad8_index_polarity_enum = { | ||
| 497 | .items = quad8_index_polarity_modes, | ||
| 498 | .num_items = ARRAY_SIZE(quad8_index_polarity_modes), | ||
| 499 | .set = quad8_set_index_polarity, | ||
| 500 | .get = quad8_get_index_polarity | ||
| 501 | }; | ||
| 502 | |||
| 503 | static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { | ||
| 504 | { | ||
| 505 | .name = "preset", | ||
| 506 | .shared = IIO_SEPARATE, | ||
| 507 | .read = quad8_read_preset, | ||
| 508 | .write = quad8_write_preset | ||
| 509 | }, | ||
| 510 | { | ||
| 511 | .name = "set_to_preset_on_index", | ||
| 512 | .shared = IIO_SEPARATE, | ||
| 513 | .read = quad8_read_set_to_preset_on_index, | ||
| 514 | .write = quad8_write_set_to_preset_on_index | ||
| 515 | }, | ||
| 516 | IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), | ||
| 517 | IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), | ||
| 518 | IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), | ||
| 519 | IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), | ||
| 520 | IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), | ||
| 521 | IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), | ||
| 522 | IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), | ||
| 523 | IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), | ||
| 524 | {} | ||
| 525 | }; | ||
| 526 | |||
| 527 | static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { | ||
| 528 | IIO_ENUM("synchronous_mode", IIO_SEPARATE, | ||
| 529 | &quad8_synchronous_mode_enum), | ||
| 530 | IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), | ||
| 531 | IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), | ||
| 532 | IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), | ||
| 533 | {} | ||
| 534 | }; | ||
| 535 | |||
| 536 | #define QUAD8_COUNT_CHAN(_chan) { \ | ||
| 537 | .type = IIO_COUNT, \ | ||
| 538 | .channel = (_chan), \ | ||
| 539 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 540 | BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 541 | .ext_info = quad8_count_ext_info, \ | ||
| 542 | .indexed = 1 \ | ||
| 543 | } | ||
| 544 | |||
| 545 | #define QUAD8_INDEX_CHAN(_chan) { \ | ||
| 546 | .type = IIO_INDEX, \ | ||
| 547 | .channel = (_chan), \ | ||
| 548 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 549 | .ext_info = quad8_index_ext_info, \ | ||
| 550 | .indexed = 1 \ | ||
| 551 | } | ||
| 552 | |||
| 553 | static const struct iio_chan_spec quad8_channels[] = { | ||
| 554 | QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), | ||
| 555 | QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), | ||
| 556 | QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), | ||
| 557 | QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), | ||
| 558 | QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), | ||
| 559 | QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), | ||
| 560 | QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), | ||
| 561 | QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) | ||
| 562 | }; | ||
| 563 | |||
| 564 | static int quad8_signal_read(struct counter_device *counter, | ||
| 565 | struct counter_signal *signal, struct counter_signal_read_value *val) | ||
| 566 | { | ||
| 567 | const struct quad8_iio *const priv = counter->priv; | ||
| 568 | unsigned int state; | ||
| 569 | enum counter_signal_level level; | ||
| 570 | |||
| 571 | /* Only Index signal levels can be read */ | ||
| 572 | if (signal->id < 16) | ||
| 573 | return -EINVAL; | ||
| 574 | |||
| 575 | state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) | ||
| 576 | & BIT(signal->id - 16); | ||
| 577 | |||
| 578 | level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW; | ||
| 579 | |||
| 580 | counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level); | ||
| 581 | |||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | static int quad8_count_read(struct counter_device *counter, | ||
| 586 | struct counter_count *count, struct counter_count_read_value *val) | ||
| 587 | { | ||
| 588 | const struct quad8_iio *const priv = counter->priv; | ||
| 589 | const int base_offset = priv->base + 2 * count->id; | ||
| 590 | unsigned int flags; | ||
| 591 | unsigned int borrow; | ||
| 592 | unsigned int carry; | ||
| 593 | unsigned long position; | ||
| 594 | int i; | ||
| 595 | |||
| 596 | flags = inb(base_offset + 1); | ||
| 597 | borrow = flags & QUAD8_FLAG_BT; | ||
| 598 | carry = !!(flags & QUAD8_FLAG_CT); | ||
| 599 | |||
| 600 | /* Borrow XOR Carry effectively doubles count range */ | ||
| 601 | position = (unsigned long)(borrow ^ carry) << 24; | ||
| 602 | |||
| 603 | /* Reset Byte Pointer; transfer Counter to Output Latch */ | ||
| 604 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, | ||
| 605 | base_offset + 1); | ||
| 606 | |||
| 607 | for (i = 0; i < 3; i++) | ||
| 608 | position |= (unsigned long)inb(base_offset) << (8 * i); | ||
| 609 | |||
| 610 | counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position); | ||
| 611 | |||
| 612 | return 0; | ||
| 613 | } | ||
| 614 | |||
| 615 | static int quad8_count_write(struct counter_device *counter, | ||
| 616 | struct counter_count *count, struct counter_count_write_value *val) | ||
| 617 | { | ||
| 618 | const struct quad8_iio *const priv = counter->priv; | ||
| 619 | const int base_offset = priv->base + 2 * count->id; | ||
| 620 | int err; | ||
| 621 | unsigned long position; | ||
| 622 | int i; | ||
| 623 | |||
| 624 | err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION, | ||
| 625 | val); | ||
| 626 | if (err) | ||
| 627 | return err; | ||
| 628 | |||
| 629 | /* Only 24-bit values are supported */ | ||
| 630 | if (position > 0xFFFFFF) | ||
| 631 | return -EINVAL; | ||
| 632 | |||
| 633 | /* Reset Byte Pointer */ | ||
| 634 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 635 | |||
| 636 | /* Counter can only be set via Preset Register */ | ||
| 637 | for (i = 0; i < 3; i++) | ||
| 638 | outb(position >> (8 * i), base_offset); | ||
| 639 | |||
| 640 | /* Transfer Preset Register to Counter */ | ||
| 641 | outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); | ||
| 642 | |||
| 643 | /* Reset Byte Pointer */ | ||
| 644 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 645 | |||
| 646 | /* Set Preset Register back to original value */ | ||
| 647 | position = priv->preset[count->id]; | ||
| 648 | for (i = 0; i < 3; i++) | ||
| 649 | outb(position >> (8 * i), base_offset); | ||
| 650 | |||
| 651 | /* Reset Borrow, Carry, Compare, and Sign flags */ | ||
| 652 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); | ||
| 653 | /* Reset Error flag */ | ||
| 654 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); | ||
| 655 | |||
| 656 | return 0; | ||
| 657 | } | ||
| 658 | |||
| 659 | enum quad8_count_function { | ||
| 660 | QUAD8_COUNT_FUNCTION_PULSE_DIRECTION = 0, | ||
| 661 | QUAD8_COUNT_FUNCTION_QUADRATURE_X1, | ||
| 662 | QUAD8_COUNT_FUNCTION_QUADRATURE_X2, | ||
| 663 | QUAD8_COUNT_FUNCTION_QUADRATURE_X4 | ||
| 664 | }; | ||
| 665 | |||
| 666 | static enum counter_count_function quad8_count_functions_list[] = { | ||
| 667 | [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION, | ||
| 668 | [QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A, | ||
| 669 | [QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A, | ||
| 670 | [QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4 | ||
| 671 | }; | ||
| 672 | |||
| 673 | static int quad8_function_get(struct counter_device *counter, | ||
| 674 | struct counter_count *count, size_t *function) | ||
| 675 | { | ||
| 676 | const struct quad8_iio *const priv = counter->priv; | ||
| 677 | const int id = count->id; | ||
| 678 | const unsigned int quadrature_mode = priv->quadrature_mode[id]; | ||
| 679 | const unsigned int scale = priv->quadrature_scale[id]; | ||
| 680 | |||
| 681 | if (quadrature_mode) | ||
| 682 | switch (scale) { | ||
| 683 | case 0: | ||
| 684 | *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1; | ||
| 685 | break; | ||
| 686 | case 1: | ||
| 687 | *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2; | ||
| 688 | break; | ||
| 689 | case 2: | ||
| 690 | *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4; | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | else | ||
| 694 | *function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION; | ||
| 695 | |||
| 696 | return 0; | ||
| 697 | } | ||
| 698 | |||
| 699 | static int quad8_function_set(struct counter_device *counter, | ||
| 700 | struct counter_count *count, size_t function) | ||
| 701 | { | ||
| 702 | struct quad8_iio *const priv = counter->priv; | ||
| 703 | const int id = count->id; | ||
| 704 | unsigned int *const quadrature_mode = priv->quadrature_mode + id; | ||
| 705 | unsigned int *const scale = priv->quadrature_scale + id; | ||
| 706 | unsigned int mode_cfg = priv->count_mode[id] << 1; | ||
| 707 | unsigned int *const synchronous_mode = priv->synchronous_mode + id; | ||
| 708 | const unsigned int idr_cfg = priv->index_polarity[id] << 1; | ||
| 709 | const int base_offset = priv->base + 2 * id + 1; | ||
| 710 | |||
| 711 | if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) { | ||
| 712 | *quadrature_mode = 0; | ||
| 713 | |||
| 714 | /* Quadrature scaling only available in quadrature mode */ | ||
| 715 | *scale = 0; | ||
| 716 | |||
| 717 | /* Synchronous function not supported in non-quadrature mode */ | ||
| 718 | if (*synchronous_mode) { | ||
| 719 | *synchronous_mode = 0; | ||
| 720 | /* Disable synchronous function mode */ | ||
| 721 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 722 | } | ||
| 723 | } else { | ||
| 724 | *quadrature_mode = 1; | ||
| 725 | |||
| 726 | switch (function) { | ||
| 727 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: | ||
| 728 | *scale = 0; | ||
| 729 | mode_cfg |= QUAD8_CMR_QUADRATURE_X1; | ||
| 730 | break; | ||
| 731 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: | ||
| 732 | *scale = 1; | ||
| 733 | mode_cfg |= QUAD8_CMR_QUADRATURE_X2; | ||
| 734 | break; | ||
| 735 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: | ||
| 736 | *scale = 2; | ||
| 737 | mode_cfg |= QUAD8_CMR_QUADRATURE_X4; | ||
| 738 | break; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | |||
| 742 | /* Load mode configuration to Counter Mode Register */ | ||
| 743 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | |||
| 748 | static void quad8_direction_get(struct counter_device *counter, | ||
| 749 | struct counter_count *count, enum counter_count_direction *direction) | ||
| 750 | { | ||
| 751 | const struct quad8_iio *const priv = counter->priv; | ||
| 752 | unsigned int ud_flag; | ||
| 753 | const unsigned int flag_addr = priv->base + 2 * count->id + 1; | ||
| 754 | |||
| 755 | /* U/D flag: nonzero = up, zero = down */ | ||
| 756 | ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; | ||
| 757 | |||
| 758 | *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : | ||
| 759 | COUNTER_COUNT_DIRECTION_BACKWARD; | ||
| 760 | } | ||
| 761 | |||
| 762 | enum quad8_synapse_action { | ||
| 763 | QUAD8_SYNAPSE_ACTION_NONE = 0, | ||
| 764 | QUAD8_SYNAPSE_ACTION_RISING_EDGE, | ||
| 765 | QUAD8_SYNAPSE_ACTION_FALLING_EDGE, | ||
| 766 | QUAD8_SYNAPSE_ACTION_BOTH_EDGES | ||
| 767 | }; | ||
| 768 | |||
| 769 | static enum counter_synapse_action quad8_index_actions_list[] = { | ||
| 770 | [QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, | ||
| 771 | [QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE | ||
| 772 | }; | ||
| 773 | |||
| 774 | static enum counter_synapse_action quad8_synapse_actions_list[] = { | ||
| 775 | [QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, | ||
| 776 | [QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE, | ||
| 777 | [QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE, | ||
| 778 | [QUAD8_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES | ||
| 779 | }; | ||
| 780 | |||
| 781 | static int quad8_action_get(struct counter_device *counter, | ||
| 782 | struct counter_count *count, struct counter_synapse *synapse, | ||
| 783 | size_t *action) | ||
| 784 | { | ||
| 785 | struct quad8_iio *const priv = counter->priv; | ||
| 786 | int err; | ||
| 787 | size_t function = 0; | ||
| 788 | const size_t signal_a_id = count->synapses[0].signal->id; | ||
| 789 | enum counter_count_direction direction; | ||
| 790 | |||
| 791 | /* Handle Index signals */ | ||
| 792 | if (synapse->signal->id >= 16) { | ||
| 793 | if (priv->preset_enable[count->id]) | ||
| 794 | *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; | ||
| 795 | else | ||
| 796 | *action = QUAD8_SYNAPSE_ACTION_NONE; | ||
| 797 | |||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | |||
| 801 | err = quad8_function_get(counter, count, &function); | ||
| 802 | if (err) | ||
| 803 | return err; | ||
| 804 | |||
| 805 | /* Default action mode */ | ||
| 806 | *action = QUAD8_SYNAPSE_ACTION_NONE; | ||
| 807 | |||
| 808 | /* Determine action mode based on current count function mode */ | ||
| 809 | switch (function) { | ||
| 810 | case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION: | ||
| 811 | if (synapse->signal->id == signal_a_id) | ||
| 812 | *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; | ||
| 813 | break; | ||
| 814 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: | ||
| 815 | if (synapse->signal->id == signal_a_id) { | ||
| 816 | quad8_direction_get(counter, count, &direction); | ||
| 817 | |||
| 818 | if (direction == COUNTER_COUNT_DIRECTION_FORWARD) | ||
| 819 | *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; | ||
| 820 | else | ||
| 821 | *action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE; | ||
| 822 | } | ||
| 823 | break; | ||
| 824 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: | ||
| 825 | if (synapse->signal->id == signal_a_id) | ||
| 826 | *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 827 | break; | ||
| 828 | case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: | ||
| 829 | *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 830 | break; | ||
| 831 | } | ||
| 832 | |||
| 833 | return 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | const struct counter_ops quad8_ops = { | ||
| 837 | .signal_read = quad8_signal_read, | ||
| 838 | .count_read = quad8_count_read, | ||
| 839 | .count_write = quad8_count_write, | ||
| 840 | .function_get = quad8_function_get, | ||
| 841 | .function_set = quad8_function_set, | ||
| 842 | .action_get = quad8_action_get | ||
| 843 | }; | ||
| 844 | |||
| 845 | static int quad8_index_polarity_get(struct counter_device *counter, | ||
| 846 | struct counter_signal *signal, size_t *index_polarity) | ||
| 847 | { | ||
| 848 | const struct quad8_iio *const priv = counter->priv; | ||
| 849 | const size_t channel_id = signal->id - 16; | ||
| 850 | |||
| 851 | *index_polarity = priv->index_polarity[channel_id]; | ||
| 852 | |||
| 853 | return 0; | ||
| 854 | } | ||
| 855 | |||
| 856 | static int quad8_index_polarity_set(struct counter_device *counter, | ||
| 857 | struct counter_signal *signal, size_t index_polarity) | ||
| 858 | { | ||
| 859 | struct quad8_iio *const priv = counter->priv; | ||
| 860 | const size_t channel_id = signal->id - 16; | ||
| 861 | const unsigned int idr_cfg = priv->synchronous_mode[channel_id] | | ||
| 862 | index_polarity << 1; | ||
| 863 | const int base_offset = priv->base + 2 * channel_id + 1; | ||
| 864 | |||
| 865 | priv->index_polarity[channel_id] = index_polarity; | ||
| 866 | |||
| 867 | /* Load Index Control configuration to Index Control Register */ | ||
| 868 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 869 | |||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | |||
| 873 | static struct counter_signal_enum_ext quad8_index_pol_enum = { | ||
| 874 | .items = quad8_index_polarity_modes, | ||
| 875 | .num_items = ARRAY_SIZE(quad8_index_polarity_modes), | ||
| 876 | .get = quad8_index_polarity_get, | ||
| 877 | .set = quad8_index_polarity_set | ||
| 878 | }; | ||
| 879 | |||
| 880 | static int quad8_synchronous_mode_get(struct counter_device *counter, | ||
| 881 | struct counter_signal *signal, size_t *synchronous_mode) | ||
| 882 | { | ||
| 883 | const struct quad8_iio *const priv = counter->priv; | ||
| 884 | const size_t channel_id = signal->id - 16; | ||
| 885 | |||
| 886 | *synchronous_mode = priv->synchronous_mode[channel_id]; | ||
| 887 | |||
| 888 | return 0; | ||
| 889 | } | ||
| 890 | |||
| 891 | static int quad8_synchronous_mode_set(struct counter_device *counter, | ||
| 892 | struct counter_signal *signal, size_t synchronous_mode) | ||
| 893 | { | ||
| 894 | struct quad8_iio *const priv = counter->priv; | ||
| 895 | const size_t channel_id = signal->id - 16; | ||
| 896 | const unsigned int idr_cfg = synchronous_mode | | ||
| 897 | priv->index_polarity[channel_id] << 1; | ||
| 898 | const int base_offset = priv->base + 2 * channel_id + 1; | ||
| 899 | |||
| 900 | /* Index function must be non-synchronous in non-quadrature mode */ | ||
| 901 | if (synchronous_mode && !priv->quadrature_mode[channel_id]) | ||
| 902 | return -EINVAL; | ||
| 903 | |||
| 904 | priv->synchronous_mode[channel_id] = synchronous_mode; | ||
| 905 | |||
| 906 | /* Load Index Control configuration to Index Control Register */ | ||
| 907 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 908 | |||
| 909 | return 0; | ||
| 910 | } | ||
| 911 | |||
| 912 | static struct counter_signal_enum_ext quad8_syn_mode_enum = { | ||
| 913 | .items = quad8_synchronous_modes, | ||
| 914 | .num_items = ARRAY_SIZE(quad8_synchronous_modes), | ||
| 915 | .get = quad8_synchronous_mode_get, | ||
| 916 | .set = quad8_synchronous_mode_set | ||
| 917 | }; | ||
| 918 | |||
| 919 | static ssize_t quad8_count_floor_read(struct counter_device *counter, | ||
| 920 | struct counter_count *count, void *private, char *buf) | ||
| 921 | { | ||
| 922 | /* Only a floor of 0 is supported */ | ||
| 923 | return sprintf(buf, "0\n"); | ||
| 924 | } | ||
| 925 | |||
| 926 | static int quad8_count_mode_get(struct counter_device *counter, | ||
| 927 | struct counter_count *count, size_t *cnt_mode) | ||
| 928 | { | ||
| 929 | const struct quad8_iio *const priv = counter->priv; | ||
| 930 | |||
| 931 | /* Map 104-QUAD-8 count mode to Generic Counter count mode */ | ||
| 932 | switch (priv->count_mode[count->id]) { | ||
| 933 | case 0: | ||
| 934 | *cnt_mode = COUNTER_COUNT_MODE_NORMAL; | ||
| 935 | break; | ||
| 936 | case 1: | ||
| 937 | *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT; | ||
| 938 | break; | ||
| 939 | case 2: | ||
| 940 | *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE; | ||
| 941 | break; | ||
| 942 | case 3: | ||
| 943 | *cnt_mode = COUNTER_COUNT_MODE_MODULO_N; | ||
| 944 | break; | ||
| 945 | } | ||
| 946 | |||
| 947 | return 0; | ||
| 948 | } | ||
| 949 | |||
| 950 | static int quad8_count_mode_set(struct counter_device *counter, | ||
| 951 | struct counter_count *count, size_t cnt_mode) | ||
| 952 | { | ||
| 953 | struct quad8_iio *const priv = counter->priv; | ||
| 954 | unsigned int mode_cfg; | ||
| 955 | const int base_offset = priv->base + 2 * count->id + 1; | ||
| 956 | |||
| 957 | /* Map Generic Counter count mode to 104-QUAD-8 count mode */ | ||
| 958 | switch (cnt_mode) { | ||
| 959 | case COUNTER_COUNT_MODE_NORMAL: | ||
| 960 | cnt_mode = 0; | ||
| 961 | break; | ||
| 962 | case COUNTER_COUNT_MODE_RANGE_LIMIT: | ||
| 963 | cnt_mode = 1; | ||
| 964 | break; | ||
| 965 | case COUNTER_COUNT_MODE_NON_RECYCLE: | ||
| 966 | cnt_mode = 2; | ||
| 967 | break; | ||
| 968 | case COUNTER_COUNT_MODE_MODULO_N: | ||
| 969 | cnt_mode = 3; | ||
| 970 | break; | ||
| 971 | } | ||
| 972 | |||
| 973 | priv->count_mode[count->id] = cnt_mode; | ||
| 974 | |||
| 975 | /* Set count mode configuration value */ | ||
| 976 | mode_cfg = cnt_mode << 1; | ||
| 977 | |||
| 978 | /* Add quadrature mode configuration */ | ||
| 979 | if (priv->quadrature_mode[count->id]) | ||
| 980 | mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; | ||
| 981 | |||
| 982 | /* Load mode configuration to Counter Mode Register */ | ||
| 983 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 984 | |||
| 985 | return 0; | ||
| 986 | } | ||
| 987 | |||
| 988 | static struct counter_count_enum_ext quad8_cnt_mode_enum = { | ||
| 989 | .items = counter_count_mode_str, | ||
| 990 | .num_items = ARRAY_SIZE(counter_count_mode_str), | ||
| 991 | .get = quad8_count_mode_get, | ||
| 992 | .set = quad8_count_mode_set | ||
| 993 | }; | ||
| 994 | |||
| 995 | static ssize_t quad8_count_direction_read(struct counter_device *counter, | ||
| 996 | struct counter_count *count, void *priv, char *buf) | ||
| 997 | { | ||
| 998 | enum counter_count_direction dir; | ||
| 999 | |||
| 1000 | quad8_direction_get(counter, count, &dir); | ||
| 1001 | |||
| 1002 | return sprintf(buf, "%s\n", counter_count_direction_str[dir]); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | static ssize_t quad8_count_enable_read(struct counter_device *counter, | ||
| 1006 | struct counter_count *count, void *private, char *buf) | ||
| 1007 | { | ||
| 1008 | const struct quad8_iio *const priv = counter->priv; | ||
| 1009 | |||
| 1010 | return sprintf(buf, "%u\n", priv->ab_enable[count->id]); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static ssize_t quad8_count_enable_write(struct counter_device *counter, | ||
| 1014 | struct counter_count *count, void *private, const char *buf, size_t len) | ||
| 1015 | { | ||
| 1016 | struct quad8_iio *const priv = counter->priv; | ||
| 1017 | const int base_offset = priv->base + 2 * count->id; | ||
| 1018 | int err; | ||
| 1019 | bool ab_enable; | ||
| 1020 | unsigned int ior_cfg; | ||
| 1021 | |||
| 1022 | err = kstrtobool(buf, &ab_enable); | ||
| 1023 | if (err) | ||
| 1024 | return err; | ||
| 1025 | |||
| 1026 | priv->ab_enable[count->id] = ab_enable; | ||
| 1027 | |||
| 1028 | ior_cfg = ab_enable | priv->preset_enable[count->id] << 1; | ||
| 1029 | |||
| 1030 | /* Load I/O control configuration */ | ||
| 1031 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); | ||
| 1032 | |||
| 1033 | return len; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | static int quad8_error_noise_get(struct counter_device *counter, | ||
| 1037 | struct counter_count *count, size_t *noise_error) | ||
| 1038 | { | ||
| 1039 | const struct quad8_iio *const priv = counter->priv; | ||
| 1040 | const int base_offset = priv->base + 2 * count->id + 1; | ||
| 1041 | |||
| 1042 | *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); | ||
| 1043 | |||
| 1044 | return 0; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | static struct counter_count_enum_ext quad8_error_noise_enum = { | ||
| 1048 | .items = quad8_noise_error_states, | ||
| 1049 | .num_items = ARRAY_SIZE(quad8_noise_error_states), | ||
| 1050 | .get = quad8_error_noise_get | ||
| 1051 | }; | ||
| 1052 | |||
| 1053 | static ssize_t quad8_count_preset_read(struct counter_device *counter, | ||
| 1054 | struct counter_count *count, void *private, char *buf) | ||
| 1055 | { | ||
| 1056 | const struct quad8_iio *const priv = counter->priv; | ||
| 1057 | |||
| 1058 | return sprintf(buf, "%u\n", priv->preset[count->id]); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | static ssize_t quad8_count_preset_write(struct counter_device *counter, | ||
| 1062 | struct counter_count *count, void *private, const char *buf, size_t len) | ||
| 1063 | { | ||
| 1064 | struct quad8_iio *const priv = counter->priv; | ||
| 1065 | const int base_offset = priv->base + 2 * count->id; | ||
| 1066 | unsigned int preset; | ||
| 1067 | int ret; | ||
| 1068 | int i; | ||
| 1069 | |||
| 1070 | ret = kstrtouint(buf, 0, &preset); | ||
| 1071 | if (ret) | ||
| 1072 | return ret; | ||
| 1073 | |||
| 1074 | /* Only 24-bit values are supported */ | ||
| 1075 | if (preset > 0xFFFFFF) | ||
| 1076 | return -EINVAL; | ||
| 1077 | |||
| 1078 | priv->preset[count->id] = preset; | ||
| 1079 | |||
| 1080 | /* Reset Byte Pointer */ | ||
| 1081 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 1082 | |||
| 1083 | /* Set Preset Register */ | ||
| 1084 | for (i = 0; i < 3; i++) | ||
| 1085 | outb(preset >> (8 * i), base_offset); | ||
| 1086 | |||
| 1087 | return len; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static ssize_t quad8_count_ceiling_read(struct counter_device *counter, | ||
| 1091 | struct counter_count *count, void *private, char *buf) | ||
| 1092 | { | ||
| 1093 | const struct quad8_iio *const priv = counter->priv; | ||
| 1094 | |||
| 1095 | /* Range Limit and Modulo-N count modes use preset value as ceiling */ | ||
| 1096 | switch (priv->count_mode[count->id]) { | ||
| 1097 | case 1: | ||
| 1098 | case 3: | ||
| 1099 | return quad8_count_preset_read(counter, count, private, buf); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ | ||
| 1103 | return sprintf(buf, "33554431\n"); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | static ssize_t quad8_count_ceiling_write(struct counter_device *counter, | ||
| 1107 | struct counter_count *count, void *private, const char *buf, size_t len) | ||
| 1108 | { | ||
| 1109 | struct quad8_iio *const priv = counter->priv; | ||
| 1110 | |||
| 1111 | /* Range Limit and Modulo-N count modes use preset value as ceiling */ | ||
| 1112 | switch (priv->count_mode[count->id]) { | ||
| 1113 | case 1: | ||
| 1114 | case 3: | ||
| 1115 | return quad8_count_preset_write(counter, count, private, buf, | ||
| 1116 | len); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | return len; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, | ||
| 1123 | struct counter_count *count, void *private, char *buf) | ||
| 1124 | { | ||
| 1125 | const struct quad8_iio *const priv = counter->priv; | ||
| 1126 | |||
| 1127 | return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static ssize_t quad8_count_preset_enable_write(struct counter_device *counter, | ||
| 1131 | struct counter_count *count, void *private, const char *buf, size_t len) | ||
| 1132 | { | ||
| 1133 | struct quad8_iio *const priv = counter->priv; | ||
| 1134 | const int base_offset = priv->base + 2 * count->id + 1; | ||
| 1135 | bool preset_enable; | ||
| 1136 | int ret; | ||
| 1137 | unsigned int ior_cfg; | ||
| 1138 | |||
| 1139 | ret = kstrtobool(buf, &preset_enable); | ||
| 1140 | if (ret) | ||
| 1141 | return ret; | ||
| 1142 | |||
| 1143 | /* Preset enable is active low in Input/Output Control register */ | ||
| 1144 | preset_enable = !preset_enable; | ||
| 1145 | |||
| 1146 | priv->preset_enable[count->id] = preset_enable; | ||
| 1147 | |||
| 1148 | ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1; | ||
| 1149 | |||
| 1150 | /* Load I/O control configuration to Input / Output Control Register */ | ||
| 1151 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset); | ||
| 1152 | |||
| 1153 | return len; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | static const struct counter_signal_ext quad8_index_ext[] = { | ||
| 1157 | COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum), | ||
| 1158 | COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum), | ||
| 1159 | COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum), | ||
| 1160 | COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum) | ||
| 1161 | }; | ||
| 1162 | |||
| 1163 | #define QUAD8_QUAD_SIGNAL(_id, _name) { \ | ||
| 1164 | .id = (_id), \ | ||
| 1165 | .name = (_name) \ | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | #define QUAD8_INDEX_SIGNAL(_id, _name) { \ | ||
| 1169 | .id = (_id), \ | ||
| 1170 | .name = (_name), \ | ||
| 1171 | .ext = quad8_index_ext, \ | ||
| 1172 | .num_ext = ARRAY_SIZE(quad8_index_ext) \ | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | static struct counter_signal quad8_signals[] = { | ||
| 1176 | QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"), | ||
| 1177 | QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"), | ||
| 1178 | QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"), | ||
| 1179 | QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"), | ||
| 1180 | QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"), | ||
| 1181 | QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"), | ||
| 1182 | QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"), | ||
| 1183 | QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"), | ||
| 1184 | QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"), | ||
| 1185 | QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"), | ||
| 1186 | QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"), | ||
| 1187 | QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"), | ||
| 1188 | QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"), | ||
| 1189 | QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"), | ||
| 1190 | QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"), | ||
| 1191 | QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"), | ||
| 1192 | QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"), | ||
| 1193 | QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"), | ||
| 1194 | QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"), | ||
| 1195 | QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"), | ||
| 1196 | QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"), | ||
| 1197 | QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"), | ||
| 1198 | QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"), | ||
| 1199 | QUAD8_INDEX_SIGNAL(23, "Channel 8 Index") | ||
| 1200 | }; | ||
| 1201 | |||
| 1202 | #define QUAD8_COUNT_SYNAPSES(_id) { \ | ||
| 1203 | { \ | ||
| 1204 | .actions_list = quad8_synapse_actions_list, \ | ||
| 1205 | .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ | ||
| 1206 | .signal = quad8_signals + 2 * (_id) \ | ||
| 1207 | }, \ | ||
| 1208 | { \ | ||
| 1209 | .actions_list = quad8_synapse_actions_list, \ | ||
| 1210 | .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ | ||
| 1211 | .signal = quad8_signals + 2 * (_id) + 1 \ | ||
| 1212 | }, \ | ||
| 1213 | { \ | ||
| 1214 | .actions_list = quad8_index_actions_list, \ | ||
| 1215 | .num_actions = ARRAY_SIZE(quad8_index_actions_list), \ | ||
| 1216 | .signal = quad8_signals + 2 * (_id) + 16 \ | ||
| 1217 | } \ | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static struct counter_synapse quad8_count_synapses[][3] = { | ||
| 1221 | QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1), | ||
| 1222 | QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3), | ||
| 1223 | QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5), | ||
| 1224 | QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7) | ||
| 1225 | }; | ||
| 1226 | |||
| 1227 | static const struct counter_count_ext quad8_count_ext[] = { | ||
| 1228 | { | ||
| 1229 | .name = "ceiling", | ||
| 1230 | .read = quad8_count_ceiling_read, | ||
| 1231 | .write = quad8_count_ceiling_write | ||
| 1232 | }, | ||
| 1233 | { | ||
| 1234 | .name = "floor", | ||
| 1235 | .read = quad8_count_floor_read | ||
| 1236 | }, | ||
| 1237 | COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum), | ||
| 1238 | COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum), | ||
| 1239 | { | ||
| 1240 | .name = "direction", | ||
| 1241 | .read = quad8_count_direction_read | ||
| 1242 | }, | ||
| 1243 | { | ||
| 1244 | .name = "enable", | ||
| 1245 | .read = quad8_count_enable_read, | ||
| 1246 | .write = quad8_count_enable_write | ||
| 1247 | }, | ||
| 1248 | COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum), | ||
| 1249 | COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum), | ||
| 1250 | { | ||
| 1251 | .name = "preset", | ||
| 1252 | .read = quad8_count_preset_read, | ||
| 1253 | .write = quad8_count_preset_write | ||
| 1254 | }, | ||
| 1255 | { | ||
| 1256 | .name = "preset_enable", | ||
| 1257 | .read = quad8_count_preset_enable_read, | ||
| 1258 | .write = quad8_count_preset_enable_write | ||
| 1259 | } | ||
| 1260 | }; | ||
| 1261 | |||
| 1262 | #define QUAD8_COUNT(_id, _cntname) { \ | ||
| 1263 | .id = (_id), \ | ||
| 1264 | .name = (_cntname), \ | ||
| 1265 | .functions_list = quad8_count_functions_list, \ | ||
| 1266 | .num_functions = ARRAY_SIZE(quad8_count_functions_list), \ | ||
| 1267 | .synapses = quad8_count_synapses[(_id)], \ | ||
| 1268 | .num_synapses = 2, \ | ||
| 1269 | .ext = quad8_count_ext, \ | ||
| 1270 | .num_ext = ARRAY_SIZE(quad8_count_ext) \ | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | static struct counter_count quad8_counts[] = { | ||
| 1274 | QUAD8_COUNT(0, "Channel 1 Count"), | ||
| 1275 | QUAD8_COUNT(1, "Channel 2 Count"), | ||
| 1276 | QUAD8_COUNT(2, "Channel 3 Count"), | ||
| 1277 | QUAD8_COUNT(3, "Channel 4 Count"), | ||
| 1278 | QUAD8_COUNT(4, "Channel 5 Count"), | ||
| 1279 | QUAD8_COUNT(5, "Channel 6 Count"), | ||
| 1280 | QUAD8_COUNT(6, "Channel 7 Count"), | ||
| 1281 | QUAD8_COUNT(7, "Channel 8 Count") | ||
| 1282 | }; | ||
| 1283 | |||
| 1284 | static int quad8_probe(struct device *dev, unsigned int id) | ||
| 1285 | { | ||
| 1286 | struct iio_dev *indio_dev; | ||
| 1287 | struct quad8_iio *quad8iio; | ||
| 1288 | int i, j; | ||
| 1289 | unsigned int base_offset; | ||
| 1290 | int err; | ||
| 1291 | |||
| 1292 | if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { | ||
| 1293 | dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", | ||
| 1294 | base[id], base[id] + QUAD8_EXTENT); | ||
| 1295 | return -EBUSY; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | /* Allocate IIO device; this also allocates driver data structure */ | ||
| 1299 | indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); | ||
| 1300 | if (!indio_dev) | ||
| 1301 | return -ENOMEM; | ||
| 1302 | |||
| 1303 | /* Initialize IIO device */ | ||
| 1304 | indio_dev->info = &quad8_info; | ||
| 1305 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 1306 | indio_dev->num_channels = ARRAY_SIZE(quad8_channels); | ||
| 1307 | indio_dev->channels = quad8_channels; | ||
| 1308 | indio_dev->name = dev_name(dev); | ||
| 1309 | indio_dev->dev.parent = dev; | ||
| 1310 | |||
| 1311 | /* Initialize Counter device and driver data */ | ||
| 1312 | quad8iio = iio_priv(indio_dev); | ||
| 1313 | quad8iio->counter.name = dev_name(dev); | ||
| 1314 | quad8iio->counter.parent = dev; | ||
| 1315 | quad8iio->counter.ops = &quad8_ops; | ||
| 1316 | quad8iio->counter.counts = quad8_counts; | ||
| 1317 | quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts); | ||
| 1318 | quad8iio->counter.signals = quad8_signals; | ||
| 1319 | quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals); | ||
| 1320 | quad8iio->counter.priv = quad8iio; | ||
| 1321 | quad8iio->base = base[id]; | ||
| 1322 | |||
| 1323 | /* Reset all counters and disable interrupt function */ | ||
| 1324 | outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); | ||
| 1325 | /* Set initial configuration for all counters */ | ||
| 1326 | for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { | ||
| 1327 | base_offset = base[id] + 2 * i; | ||
| 1328 | /* Reset Byte Pointer */ | ||
| 1329 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 1330 | /* Reset Preset Register */ | ||
| 1331 | for (j = 0; j < 3; j++) | ||
| 1332 | outb(0x00, base_offset); | ||
| 1333 | /* Reset Borrow, Carry, Compare, and Sign flags */ | ||
| 1334 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); | ||
| 1335 | /* Reset Error flag */ | ||
| 1336 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); | ||
| 1337 | /* Binary encoding; Normal count; non-quadrature mode */ | ||
| 1338 | outb(QUAD8_CTR_CMR, base_offset + 1); | ||
| 1339 | /* Disable A and B inputs; preset on index; FLG1 as Carry */ | ||
| 1340 | outb(QUAD8_CTR_IOR, base_offset + 1); | ||
| 1341 | /* Disable index function; negative index polarity */ | ||
| 1342 | outb(QUAD8_CTR_IDR, base_offset + 1); | ||
| 1343 | } | ||
| 1344 | /* Enable all counters */ | ||
| 1345 | outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); | ||
| 1346 | |||
| 1347 | /* Register IIO device */ | ||
| 1348 | err = devm_iio_device_register(dev, indio_dev); | ||
| 1349 | if (err) | ||
| 1350 | return err; | ||
| 1351 | |||
| 1352 | /* Register Counter device */ | ||
| 1353 | return devm_counter_register(dev, &quad8iio->counter); | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | static struct isa_driver quad8_driver = { | ||
| 1357 | .probe = quad8_probe, | ||
| 1358 | .driver = { | ||
| 1359 | .name = "104-quad-8" | ||
| 1360 | } | ||
| 1361 | }; | ||
| 1362 | |||
| 1363 | module_isa_driver(quad8_driver, num_quad8); | ||
| 1364 | |||
| 1365 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); | ||
| 1366 | MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); | ||
| 1367 | MODULE_LICENSE("GPL v2"); | ||
| @@ -0,0 +1,60 @@ | |||
| 1 | # | ||
| 2 | # Counter devices | ||
| 3 | # | ||
| 4 | |||
| 5 | menuconfig COUNTER | ||
| 6 | tristate "Counter support" | ||
| 7 | help | ||
| 8 | This enables counter device support through the Generic Counter | ||
| 9 | interface. You only need to enable this, if you also want to enable | ||
| 10 | one or more of the counter device drivers below. | ||
| 11 | |||
| 12 | if COUNTER | ||
| 13 | |||
| 14 | config 104_QUAD_8 | ||
| 15 | tristate "ACCES 104-QUAD-8 driver" | ||
| 16 | depends on PC104 && X86 && IIO | ||
| 17 | select ISA_BUS_API | ||
| 18 | help | ||
| 19 | Say yes here to build support for the ACCES 104-QUAD-8 quadrature | ||
| 20 | encoder counter/interface device family (104-QUAD-8, 104-QUAD-4). | ||
| 21 | |||
| 22 | A counter's respective error flag may be cleared by performing a write | ||
| 23 | operation on the respective count value attribute. Although the | ||
| 24 | 104-QUAD-8 counters have a 25-bit range, only the lower 24 bits may be | ||
| 25 | set, either directly or via the counter's preset attribute. Interrupts | ||
| 26 | are not supported by this driver. | ||
| 27 | |||
| 28 | The base port addresses for the devices may be configured via the base | ||
| 29 | array module parameter. | ||
| 30 | |||
| 31 | config STM32_TIMER_CNT | ||
| 32 | tristate "STM32 Timer encoder counter driver" | ||
| 33 | depends on MFD_STM32_TIMERS || COMPILE_TEST | ||
| 34 | help | ||
| 35 | Select this option to enable STM32 Timer quadrature encoder | ||
| 36 | and counter driver. | ||
| 37 | |||
| 38 | To compile this driver as a module, choose M here: the | ||
| 39 | module will be called stm32-timer-cnt. | ||
| 40 | |||
| 41 | config STM32_LPTIMER_CNT | ||
| 42 | tristate "STM32 LP Timer encoder counter driver" | ||
| 43 | depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO | ||
| 44 | help | ||
| 45 | Select this option to enable STM32 Low-Power Timer quadrature encoder | ||
| 46 | and counter driver. | ||
| 47 | |||
| 48 | To compile this driver as a module, choose M here: the | ||
| 49 | module will be called stm32-lptimer-cnt. | ||
| 50 | |||
| 51 | config FTM_QUADDEC | ||
| 52 | tristate "Flex Timer Module Quadrature decoder driver" | ||
| 53 | help | ||
| 54 | Select this option to enable the Flex Timer Quadrature decoder | ||
| 55 | driver. | ||
| 56 | |||
| 57 | To compile this driver as a module, choose M here: the | ||
| 58 | module will be called ftm-quaddec. | ||
| 59 | |||
| 60 | endif # COUNTER | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | # | ||
| 2 | # Makefile for Counter devices | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_COUNTER) += counter.o | ||
| 6 | |||
| 7 | obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o | ||
| 8 | obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o | ||
| 9 | obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o | ||
| 10 | obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o | ||
| @@ -0,0 +1,1567 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Generic Counter interface | ||
| 4 | * Copyright (C) 2018 William Breathitt Gray | ||
| 5 | */ | ||
| 6 | #include <linux/counter.h> | ||
| 7 | #include <linux/device.h> | ||
| 8 | #include <linux/err.h> | ||
| 9 | #include <linux/export.h> | ||
| 10 | #include <linux/fs.h> | ||
| 11 | #include <linux/gfp.h> | ||
| 12 | #include <linux/idr.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/printk.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/string.h> | ||
| 20 | #include <linux/sysfs.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | |||
| 23 | const char *const counter_count_direction_str[2] = { | ||
| 24 | [COUNTER_COUNT_DIRECTION_FORWARD] = "forward", | ||
| 25 | [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward" | ||
| 26 | }; | ||
| 27 | EXPORT_SYMBOL_GPL(counter_count_direction_str); | ||
| 28 | |||
| 29 | const char *const counter_count_mode_str[4] = { | ||
| 30 | [COUNTER_COUNT_MODE_NORMAL] = "normal", | ||
| 31 | [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit", | ||
| 32 | [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle", | ||
| 33 | [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n" | ||
| 34 | }; | ||
| 35 | EXPORT_SYMBOL_GPL(counter_count_mode_str); | ||
| 36 | |||
| 37 | ssize_t counter_signal_enum_read(struct counter_device *counter, | ||
| 38 | struct counter_signal *signal, void *priv, | ||
| 39 | char *buf) | ||
| 40 | { | ||
| 41 | const struct counter_signal_enum_ext *const e = priv; | ||
| 42 | int err; | ||
| 43 | size_t index; | ||
| 44 | |||
| 45 | if (!e->get) | ||
| 46 | return -EINVAL; | ||
| 47 | |||
| 48 | err = e->get(counter, signal, &index); | ||
| 49 | if (err) | ||
| 50 | return err; | ||
| 51 | |||
| 52 | if (index >= e->num_items) | ||
| 53 | return -EINVAL; | ||
| 54 | |||
| 55 | return sprintf(buf, "%s\n", e->items[index]); | ||
| 56 | } | ||
| 57 | EXPORT_SYMBOL_GPL(counter_signal_enum_read); | ||
| 58 | |||
| 59 | ssize_t counter_signal_enum_write(struct counter_device *counter, | ||
| 60 | struct counter_signal *signal, void *priv, | ||
| 61 | const char *buf, size_t len) | ||
| 62 | { | ||
| 63 | const struct counter_signal_enum_ext *const e = priv; | ||
| 64 | ssize_t index; | ||
| 65 | int err; | ||
| 66 | |||
| 67 | if (!e->set) | ||
| 68 | return -EINVAL; | ||
| 69 | |||
| 70 | index = __sysfs_match_string(e->items, e->num_items, buf); | ||
| 71 | if (index < 0) | ||
| 72 | return index; | ||
| 73 | |||
| 74 | err = e->set(counter, signal, index); | ||
| 75 | if (err) | ||
| 76 | return err; | ||
| 77 | |||
| 78 | return len; | ||
| 79 | } | ||
| 80 | EXPORT_SYMBOL_GPL(counter_signal_enum_write); | ||
| 81 | |||
| 82 | ssize_t counter_signal_enum_available_read(struct counter_device *counter, | ||
| 83 | struct counter_signal *signal, | ||
| 84 | void *priv, char *buf) | ||
| 85 | { | ||
| 86 | const struct counter_signal_enum_ext *const e = priv; | ||
| 87 | size_t i; | ||
| 88 | size_t len = 0; | ||
| 89 | |||
| 90 | if (!e->num_items) | ||
| 91 | return 0; | ||
| 92 | |||
| 93 | for (i = 0; i < e->num_items; i++) | ||
| 94 | len += sprintf(buf + len, "%s\n", e->items[i]); | ||
| 95 | |||
| 96 | return len; | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL_GPL(counter_signal_enum_available_read); | ||
| 99 | |||
| 100 | ssize_t counter_count_enum_read(struct counter_device *counter, | ||
| 101 | struct counter_count *count, void *priv, | ||
| 102 | char *buf) | ||
| 103 | { | ||
| 104 | const struct counter_count_enum_ext *const e = priv; | ||
| 105 | int err; | ||
| 106 | size_t index; | ||
| 107 | |||
| 108 | if (!e->get) | ||
| 109 | return -EINVAL; | ||
| 110 | |||
| 111 | err = e->get(counter, count, &index); | ||
| 112 | if (err) | ||
| 113 | return err; | ||
| 114 | |||
| 115 | if (index >= e->num_items) | ||
| 116 | return -EINVAL; | ||
| 117 | |||
| 118 | return sprintf(buf, "%s\n", e->items[index]); | ||
| 119 | } | ||
| 120 | EXPORT_SYMBOL_GPL(counter_count_enum_read); | ||
| 121 | |||
| 122 | ssize_t counter_count_enum_write(struct counter_device *counter, | ||
| 123 | struct counter_count *count, void *priv, | ||
| 124 | const char *buf, size_t len) | ||
| 125 | { | ||
| 126 | const struct counter_count_enum_ext *const e = priv; | ||
| 127 | ssize_t index; | ||
| 128 | int err; | ||
| 129 | |||
| 130 | if (!e->set) | ||
| 131 | return -EINVAL; | ||
| 132 | |||
| 133 | index = __sysfs_match_string(e->items, e->num_items, buf); | ||
| 134 | if (index < 0) | ||
| 135 | return index; | ||
| 136 | |||
| 137 | err = e->set(counter, count, index); | ||
| 138 | if (err) | ||
| 139 | return err; | ||
| 140 | |||
| 141 | return len; | ||
| 142 | } | ||
| 143 | EXPORT_SYMBOL_GPL(counter_count_enum_write); | ||
| 144 | |||
| 145 | ssize_t counter_count_enum_available_read(struct counter_device *counter, | ||
| 146 | struct counter_count *count, | ||
| 147 | void *priv, char *buf) | ||
| 148 | { | ||
| 149 | const struct counter_count_enum_ext *const e = priv; | ||
| 150 | size_t i; | ||
| 151 | size_t len = 0; | ||
| 152 | |||
| 153 | if (!e->num_items) | ||
| 154 | return 0; | ||
| 155 | |||
| 156 | for (i = 0; i < e->num_items; i++) | ||
| 157 | len += sprintf(buf + len, "%s\n", e->items[i]); | ||
| 158 | |||
| 159 | return len; | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL_GPL(counter_count_enum_available_read); | ||
| 162 | |||
| 163 | ssize_t counter_device_enum_read(struct counter_device *counter, void *priv, | ||
| 164 | char *buf) | ||
| 165 | { | ||
| 166 | const struct counter_device_enum_ext *const e = priv; | ||
| 167 | int err; | ||
| 168 | size_t index; | ||
| 169 | |||
| 170 | if (!e->get) | ||
| 171 | return -EINVAL; | ||
| 172 | |||
| 173 | err = e->get(counter, &index); | ||
| 174 | if (err) | ||
| 175 | return err; | ||
| 176 | |||
| 177 | if (index >= e->num_items) | ||
| 178 | return -EINVAL; | ||
| 179 | |||
| 180 | return sprintf(buf, "%s\n", e->items[index]); | ||
| 181 | } | ||
| 182 | EXPORT_SYMBOL_GPL(counter_device_enum_read); | ||
| 183 | |||
| 184 | ssize_t counter_device_enum_write(struct counter_device *counter, void *priv, | ||
| 185 | const char *buf, size_t len) | ||
| 186 | { | ||
| 187 | const struct counter_device_enum_ext *const e = priv; | ||
| 188 | ssize_t index; | ||
| 189 | int err; | ||
| 190 | |||
| 191 | if (!e->set) | ||
| 192 | return -EINVAL; | ||
| 193 | |||
| 194 | index = __sysfs_match_string(e->items, e->num_items, buf); | ||
| 195 | if (index < 0) | ||
| 196 | return index; | ||
| 197 | |||
| 198 | err = e->set(counter, index); | ||
| 199 | if (err) | ||
| 200 | return err; | ||
| 201 | |||
| 202 | return len; | ||
| 203 | } | ||
| 204 | EXPORT_SYMBOL_GPL(counter_device_enum_write); | ||
| 205 | |||
| 206 | ssize_t counter_device_enum_available_read(struct counter_device *counter, | ||
| 207 | void *priv, char *buf) | ||
| 208 | { | ||
| 209 | const struct counter_device_enum_ext *const e = priv; | ||
| 210 | size_t i; | ||
| 211 | size_t len = 0; | ||
| 212 | |||
| 213 | if (!e->num_items) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | for (i = 0; i < e->num_items; i++) | ||
| 217 | len += sprintf(buf + len, "%s\n", e->items[i]); | ||
| 218 | |||
| 219 | return len; | ||
| 220 | } | ||
| 221 | EXPORT_SYMBOL_GPL(counter_device_enum_available_read); | ||
| 222 | |||
| 223 | static const char *const counter_signal_level_str[] = { | ||
| 224 | [COUNTER_SIGNAL_LEVEL_LOW] = "low", | ||
| 225 | [COUNTER_SIGNAL_LEVEL_HIGH] = "high" | ||
| 226 | }; | ||
| 227 | |||
| 228 | /** | ||
| 229 | * counter_signal_read_value_set - set counter_signal_read_value data | ||
| 230 | * @val: counter_signal_read_value structure to set | ||
| 231 | * @type: property Signal data represents | ||
| 232 | * @data: Signal data | ||
| 233 | * | ||
| 234 | * This function sets an opaque counter_signal_read_value structure with the | ||
| 235 | * provided Signal data. | ||
| 236 | */ | ||
| 237 | void counter_signal_read_value_set(struct counter_signal_read_value *const val, | ||
| 238 | const enum counter_signal_value_type type, | ||
| 239 | void *const data) | ||
| 240 | { | ||
| 241 | if (type == COUNTER_SIGNAL_LEVEL) | ||
| 242 | val->len = sprintf(val->buf, "%s\n", | ||
| 243 | counter_signal_level_str[*(enum counter_signal_level *)data]); | ||
| 244 | else | ||
| 245 | val->len = 0; | ||
| 246 | } | ||
| 247 | EXPORT_SYMBOL_GPL(counter_signal_read_value_set); | ||
| 248 | |||
| 249 | /** | ||
| 250 | * counter_count_read_value_set - set counter_count_read_value data | ||
| 251 | * @val: counter_count_read_value structure to set | ||
| 252 | * @type: property Count data represents | ||
| 253 | * @data: Count data | ||
| 254 | * | ||
| 255 | * This function sets an opaque counter_count_read_value structure with the | ||
| 256 | * provided Count data. | ||
| 257 | */ | ||
| 258 | void counter_count_read_value_set(struct counter_count_read_value *const val, | ||
| 259 | const enum counter_count_value_type type, | ||
| 260 | void *const data) | ||
| 261 | { | ||
| 262 | switch (type) { | ||
| 263 | case COUNTER_COUNT_POSITION: | ||
| 264 | val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data); | ||
| 265 | break; | ||
| 266 | default: | ||
| 267 | val->len = 0; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | EXPORT_SYMBOL_GPL(counter_count_read_value_set); | ||
| 271 | |||
| 272 | /** | ||
| 273 | * counter_count_write_value_get - get counter_count_write_value data | ||
| 274 | * @data: Count data | ||
| 275 | * @type: property Count data represents | ||
| 276 | * @val: counter_count_write_value structure containing data | ||
| 277 | * | ||
| 278 | * This function extracts Count data from the provided opaque | ||
| 279 | * counter_count_write_value structure and stores it at the address provided by | ||
| 280 | * @data. | ||
| 281 | * | ||
| 282 | * RETURNS: | ||
| 283 | * 0 on success, negative error number on failure. | ||
| 284 | */ | ||
| 285 | int counter_count_write_value_get(void *const data, | ||
| 286 | const enum counter_count_value_type type, | ||
| 287 | const struct counter_count_write_value *const val) | ||
| 288 | { | ||
| 289 | int err; | ||
| 290 | |||
| 291 | switch (type) { | ||
| 292 | case COUNTER_COUNT_POSITION: | ||
| 293 | err = kstrtoul(val->buf, 0, data); | ||
| 294 | if (err) | ||
| 295 | return err; | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | EXPORT_SYMBOL_GPL(counter_count_write_value_get); | ||
| 302 | |||
| 303 | struct counter_attr_parm { | ||
| 304 | struct counter_device_attr_group *group; | ||
| 305 | const char *prefix; | ||
| 306 | const char *name; | ||
| 307 | ssize_t (*show)(struct device *dev, struct device_attribute *attr, | ||
| 308 | char *buf); | ||
| 309 | ssize_t (*store)(struct device *dev, struct device_attribute *attr, | ||
| 310 | const char *buf, size_t len); | ||
| 311 | void *component; | ||
| 312 | }; | ||
| 313 | |||
| 314 | struct counter_device_attr { | ||
| 315 | struct device_attribute dev_attr; | ||
| 316 | struct list_head l; | ||
| 317 | void *component; | ||
| 318 | }; | ||
| 319 | |||
| 320 | static int counter_attribute_create(const struct counter_attr_parm *const parm) | ||
| 321 | { | ||
| 322 | struct counter_device_attr *counter_attr; | ||
| 323 | struct device_attribute *dev_attr; | ||
| 324 | int err; | ||
| 325 | struct list_head *const attr_list = &parm->group->attr_list; | ||
| 326 | |||
| 327 | /* Allocate a Counter device attribute */ | ||
| 328 | counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL); | ||
| 329 | if (!counter_attr) | ||
| 330 | return -ENOMEM; | ||
| 331 | dev_attr = &counter_attr->dev_attr; | ||
| 332 | |||
| 333 | sysfs_attr_init(&dev_attr->attr); | ||
| 334 | |||
| 335 | /* Configure device attribute */ | ||
| 336 | dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", parm->prefix, | ||
| 337 | parm->name); | ||
| 338 | if (!dev_attr->attr.name) { | ||
| 339 | err = -ENOMEM; | ||
| 340 | goto err_free_counter_attr; | ||
| 341 | } | ||
| 342 | if (parm->show) { | ||
| 343 | dev_attr->attr.mode |= 0444; | ||
| 344 | dev_attr->show = parm->show; | ||
| 345 | } | ||
| 346 | if (parm->store) { | ||
| 347 | dev_attr->attr.mode |= 0200; | ||
| 348 | dev_attr->store = parm->store; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* Store associated Counter component with attribute */ | ||
| 352 | counter_attr->component = parm->component; | ||
| 353 | |||
| 354 | /* Keep track of the attribute for later cleanup */ | ||
| 355 | list_add(&counter_attr->l, attr_list); | ||
| 356 | parm->group->num_attr++; | ||
| 357 | |||
| 358 | return 0; | ||
| 359 | |||
| 360 | err_free_counter_attr: | ||
| 361 | kfree(counter_attr); | ||
| 362 | return err; | ||
| 363 | } | ||
| 364 | |||
| 365 | #define to_counter_attr(_dev_attr) \ | ||
| 366 | container_of(_dev_attr, struct counter_device_attr, dev_attr) | ||
| 367 | |||
| 368 | struct counter_signal_unit { | ||
| 369 | struct counter_signal *signal; | ||
| 370 | }; | ||
| 371 | |||
| 372 | static ssize_t counter_signal_show(struct device *dev, | ||
| 373 | struct device_attribute *attr, char *buf) | ||
| 374 | { | ||
| 375 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 376 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 377 | const struct counter_signal_unit *const component = devattr->component; | ||
| 378 | struct counter_signal *const signal = component->signal; | ||
| 379 | int err; | ||
| 380 | struct counter_signal_read_value val = { .buf = buf }; | ||
| 381 | |||
| 382 | err = counter->ops->signal_read(counter, signal, &val); | ||
| 383 | if (err) | ||
| 384 | return err; | ||
| 385 | |||
| 386 | return val.len; | ||
| 387 | } | ||
| 388 | |||
| 389 | struct counter_name_unit { | ||
| 390 | const char *name; | ||
| 391 | }; | ||
| 392 | |||
| 393 | static ssize_t counter_device_attr_name_show(struct device *dev, | ||
| 394 | struct device_attribute *attr, | ||
| 395 | char *buf) | ||
| 396 | { | ||
| 397 | const struct counter_name_unit *const comp = to_counter_attr(attr)->component; | ||
| 398 | |||
| 399 | return sprintf(buf, "%s\n", comp->name); | ||
| 400 | } | ||
| 401 | |||
| 402 | static int counter_name_attribute_create( | ||
| 403 | struct counter_device_attr_group *const group, | ||
| 404 | const char *const name) | ||
| 405 | { | ||
| 406 | struct counter_name_unit *name_comp; | ||
| 407 | struct counter_attr_parm parm; | ||
| 408 | int err; | ||
| 409 | |||
| 410 | /* Skip if no name */ | ||
| 411 | if (!name) | ||
| 412 | return 0; | ||
| 413 | |||
| 414 | /* Allocate name attribute component */ | ||
| 415 | name_comp = kmalloc(sizeof(*name_comp), GFP_KERNEL); | ||
| 416 | if (!name_comp) | ||
| 417 | return -ENOMEM; | ||
| 418 | name_comp->name = name; | ||
| 419 | |||
| 420 | /* Allocate Signal name attribute */ | ||
| 421 | parm.group = group; | ||
| 422 | parm.prefix = ""; | ||
| 423 | parm.name = "name"; | ||
| 424 | parm.show = counter_device_attr_name_show; | ||
| 425 | parm.store = NULL; | ||
| 426 | parm.component = name_comp; | ||
| 427 | err = counter_attribute_create(&parm); | ||
| 428 | if (err) | ||
| 429 | goto err_free_name_comp; | ||
| 430 | |||
| 431 | return 0; | ||
| 432 | |||
| 433 | err_free_name_comp: | ||
| 434 | kfree(name_comp); | ||
| 435 | return err; | ||
| 436 | } | ||
| 437 | |||
| 438 | struct counter_signal_ext_unit { | ||
| 439 | struct counter_signal *signal; | ||
| 440 | const struct counter_signal_ext *ext; | ||
| 441 | }; | ||
| 442 | |||
| 443 | static ssize_t counter_signal_ext_show(struct device *dev, | ||
| 444 | struct device_attribute *attr, char *buf) | ||
| 445 | { | ||
| 446 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 447 | const struct counter_signal_ext_unit *const comp = devattr->component; | ||
| 448 | const struct counter_signal_ext *const ext = comp->ext; | ||
| 449 | |||
| 450 | return ext->read(dev_get_drvdata(dev), comp->signal, ext->priv, buf); | ||
| 451 | } | ||
| 452 | |||
| 453 | static ssize_t counter_signal_ext_store(struct device *dev, | ||
| 454 | struct device_attribute *attr, | ||
| 455 | const char *buf, size_t len) | ||
| 456 | { | ||
| 457 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 458 | const struct counter_signal_ext_unit *const comp = devattr->component; | ||
| 459 | const struct counter_signal_ext *const ext = comp->ext; | ||
| 460 | |||
| 461 | return ext->write(dev_get_drvdata(dev), comp->signal, ext->priv, buf, | ||
| 462 | len); | ||
| 463 | } | ||
| 464 | |||
| 465 | static void counter_device_attr_list_free(struct list_head *attr_list) | ||
| 466 | { | ||
| 467 | struct counter_device_attr *p, *n; | ||
| 468 | |||
| 469 | list_for_each_entry_safe(p, n, attr_list, l) { | ||
| 470 | /* free attribute name and associated component memory */ | ||
| 471 | kfree(p->dev_attr.attr.name); | ||
| 472 | kfree(p->component); | ||
| 473 | list_del(&p->l); | ||
| 474 | kfree(p); | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | static int counter_signal_ext_register( | ||
| 479 | struct counter_device_attr_group *const group, | ||
| 480 | struct counter_signal *const signal) | ||
| 481 | { | ||
| 482 | const size_t num_ext = signal->num_ext; | ||
| 483 | size_t i; | ||
| 484 | const struct counter_signal_ext *ext; | ||
| 485 | struct counter_signal_ext_unit *signal_ext_comp; | ||
| 486 | struct counter_attr_parm parm; | ||
| 487 | int err; | ||
| 488 | |||
| 489 | /* Create an attribute for each extension */ | ||
| 490 | for (i = 0 ; i < num_ext; i++) { | ||
| 491 | ext = signal->ext + i; | ||
| 492 | |||
| 493 | /* Allocate signal_ext attribute component */ | ||
| 494 | signal_ext_comp = kmalloc(sizeof(*signal_ext_comp), GFP_KERNEL); | ||
| 495 | if (!signal_ext_comp) { | ||
| 496 | err = -ENOMEM; | ||
| 497 | goto err_free_attr_list; | ||
| 498 | } | ||
| 499 | signal_ext_comp->signal = signal; | ||
| 500 | signal_ext_comp->ext = ext; | ||
| 501 | |||
| 502 | /* Allocate a Counter device attribute */ | ||
| 503 | parm.group = group; | ||
| 504 | parm.prefix = ""; | ||
| 505 | parm.name = ext->name; | ||
| 506 | parm.show = (ext->read) ? counter_signal_ext_show : NULL; | ||
| 507 | parm.store = (ext->write) ? counter_signal_ext_store : NULL; | ||
| 508 | parm.component = signal_ext_comp; | ||
| 509 | err = counter_attribute_create(&parm); | ||
| 510 | if (err) { | ||
| 511 | kfree(signal_ext_comp); | ||
| 512 | goto err_free_attr_list; | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | return 0; | ||
| 517 | |||
| 518 | err_free_attr_list: | ||
| 519 | counter_device_attr_list_free(&group->attr_list); | ||
| 520 | return err; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int counter_signal_attributes_create( | ||
| 524 | struct counter_device_attr_group *const group, | ||
| 525 | const struct counter_device *const counter, | ||
| 526 | struct counter_signal *const signal) | ||
| 527 | { | ||
| 528 | struct counter_signal_unit *signal_comp; | ||
| 529 | struct counter_attr_parm parm; | ||
| 530 | int err; | ||
| 531 | |||
| 532 | /* Allocate Signal attribute component */ | ||
| 533 | signal_comp = kmalloc(sizeof(*signal_comp), GFP_KERNEL); | ||
| 534 | if (!signal_comp) | ||
| 535 | return -ENOMEM; | ||
| 536 | signal_comp->signal = signal; | ||
| 537 | |||
| 538 | /* Create main Signal attribute */ | ||
| 539 | parm.group = group; | ||
| 540 | parm.prefix = ""; | ||
| 541 | parm.name = "signal"; | ||
| 542 | parm.show = (counter->ops->signal_read) ? counter_signal_show : NULL; | ||
| 543 | parm.store = NULL; | ||
| 544 | parm.component = signal_comp; | ||
| 545 | err = counter_attribute_create(&parm); | ||
| 546 | if (err) { | ||
| 547 | kfree(signal_comp); | ||
| 548 | return err; | ||
| 549 | } | ||
| 550 | |||
| 551 | /* Create Signal name attribute */ | ||
| 552 | err = counter_name_attribute_create(group, signal->name); | ||
| 553 | if (err) | ||
| 554 | goto err_free_attr_list; | ||
| 555 | |||
| 556 | /* Register Signal extension attributes */ | ||
| 557 | err = counter_signal_ext_register(group, signal); | ||
| 558 | if (err) | ||
| 559 | goto err_free_attr_list; | ||
| 560 | |||
| 561 | return 0; | ||
| 562 | |||
| 563 | err_free_attr_list: | ||
| 564 | counter_device_attr_list_free(&group->attr_list); | ||
| 565 | return err; | ||
| 566 | } | ||
| 567 | |||
| 568 | static int counter_signals_register( | ||
| 569 | struct counter_device_attr_group *const groups_list, | ||
| 570 | const struct counter_device *const counter) | ||
| 571 | { | ||
| 572 | const size_t num_signals = counter->num_signals; | ||
| 573 | size_t i; | ||
| 574 | struct counter_signal *signal; | ||
| 575 | const char *name; | ||
| 576 | int err; | ||
| 577 | |||
| 578 | /* Register each Signal */ | ||
| 579 | for (i = 0; i < num_signals; i++) { | ||
| 580 | signal = counter->signals + i; | ||
| 581 | |||
| 582 | /* Generate Signal attribute directory name */ | ||
| 583 | name = kasprintf(GFP_KERNEL, "signal%d", signal->id); | ||
| 584 | if (!name) { | ||
| 585 | err = -ENOMEM; | ||
| 586 | goto err_free_attr_groups; | ||
| 587 | } | ||
| 588 | groups_list[i].attr_group.name = name; | ||
| 589 | |||
| 590 | /* Create all attributes associated with Signal */ | ||
| 591 | err = counter_signal_attributes_create(groups_list + i, counter, | ||
| 592 | signal); | ||
| 593 | if (err) | ||
| 594 | goto err_free_attr_groups; | ||
| 595 | } | ||
| 596 | |||
| 597 | return 0; | ||
| 598 | |||
| 599 | err_free_attr_groups: | ||
| 600 | do { | ||
| 601 | kfree(groups_list[i].attr_group.name); | ||
| 602 | counter_device_attr_list_free(&groups_list[i].attr_list); | ||
| 603 | } while (i--); | ||
| 604 | return err; | ||
| 605 | } | ||
| 606 | |||
| 607 | static const char *const counter_synapse_action_str[] = { | ||
| 608 | [COUNTER_SYNAPSE_ACTION_NONE] = "none", | ||
| 609 | [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge", | ||
| 610 | [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge", | ||
| 611 | [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges" | ||
| 612 | }; | ||
| 613 | |||
| 614 | struct counter_action_unit { | ||
| 615 | struct counter_synapse *synapse; | ||
| 616 | struct counter_count *count; | ||
| 617 | }; | ||
| 618 | |||
| 619 | static ssize_t counter_action_show(struct device *dev, | ||
| 620 | struct device_attribute *attr, char *buf) | ||
| 621 | { | ||
| 622 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 623 | int err; | ||
| 624 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 625 | const struct counter_action_unit *const component = devattr->component; | ||
| 626 | struct counter_count *const count = component->count; | ||
| 627 | struct counter_synapse *const synapse = component->synapse; | ||
| 628 | size_t action_index; | ||
| 629 | enum counter_synapse_action action; | ||
| 630 | |||
| 631 | err = counter->ops->action_get(counter, count, synapse, &action_index); | ||
| 632 | if (err) | ||
| 633 | return err; | ||
| 634 | |||
| 635 | synapse->action = action_index; | ||
| 636 | |||
| 637 | action = synapse->actions_list[action_index]; | ||
| 638 | return sprintf(buf, "%s\n", counter_synapse_action_str[action]); | ||
| 639 | } | ||
| 640 | |||
| 641 | static ssize_t counter_action_store(struct device *dev, | ||
| 642 | struct device_attribute *attr, | ||
| 643 | const char *buf, size_t len) | ||
| 644 | { | ||
| 645 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 646 | const struct counter_action_unit *const component = devattr->component; | ||
| 647 | struct counter_synapse *const synapse = component->synapse; | ||
| 648 | size_t action_index; | ||
| 649 | const size_t num_actions = synapse->num_actions; | ||
| 650 | enum counter_synapse_action action; | ||
| 651 | int err; | ||
| 652 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 653 | struct counter_count *const count = component->count; | ||
| 654 | |||
| 655 | /* Find requested action mode */ | ||
| 656 | for (action_index = 0; action_index < num_actions; action_index++) { | ||
| 657 | action = synapse->actions_list[action_index]; | ||
| 658 | if (sysfs_streq(buf, counter_synapse_action_str[action])) | ||
| 659 | break; | ||
| 660 | } | ||
| 661 | /* If requested action mode not found */ | ||
| 662 | if (action_index >= num_actions) | ||
| 663 | return -EINVAL; | ||
| 664 | |||
| 665 | err = counter->ops->action_set(counter, count, synapse, action_index); | ||
| 666 | if (err) | ||
| 667 | return err; | ||
| 668 | |||
| 669 | synapse->action = action_index; | ||
| 670 | |||
| 671 | return len; | ||
| 672 | } | ||
| 673 | |||
| 674 | struct counter_action_avail_unit { | ||
| 675 | const enum counter_synapse_action *actions_list; | ||
| 676 | size_t num_actions; | ||
| 677 | }; | ||
| 678 | |||
| 679 | static ssize_t counter_synapse_action_available_show(struct device *dev, | ||
| 680 | struct device_attribute *attr, char *buf) | ||
| 681 | { | ||
| 682 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 683 | const struct counter_action_avail_unit *const component = devattr->component; | ||
| 684 | size_t i; | ||
| 685 | enum counter_synapse_action action; | ||
| 686 | ssize_t len = 0; | ||
| 687 | |||
| 688 | for (i = 0; i < component->num_actions; i++) { | ||
| 689 | action = component->actions_list[i]; | ||
| 690 | len += sprintf(buf + len, "%s\n", | ||
| 691 | counter_synapse_action_str[action]); | ||
| 692 | } | ||
| 693 | |||
| 694 | return len; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int counter_synapses_register( | ||
| 698 | struct counter_device_attr_group *const group, | ||
| 699 | const struct counter_device *const counter, | ||
| 700 | struct counter_count *const count, const char *const count_attr_name) | ||
| 701 | { | ||
| 702 | size_t i; | ||
| 703 | struct counter_synapse *synapse; | ||
| 704 | const char *prefix; | ||
| 705 | struct counter_action_unit *action_comp; | ||
| 706 | struct counter_attr_parm parm; | ||
| 707 | int err; | ||
| 708 | struct counter_action_avail_unit *avail_comp; | ||
| 709 | |||
| 710 | /* Register each Synapse */ | ||
| 711 | for (i = 0; i < count->num_synapses; i++) { | ||
| 712 | synapse = count->synapses + i; | ||
| 713 | |||
| 714 | /* Generate attribute prefix */ | ||
| 715 | prefix = kasprintf(GFP_KERNEL, "signal%d_", | ||
| 716 | synapse->signal->id); | ||
| 717 | if (!prefix) { | ||
| 718 | err = -ENOMEM; | ||
| 719 | goto err_free_attr_list; | ||
| 720 | } | ||
| 721 | |||
| 722 | /* Allocate action attribute component */ | ||
| 723 | action_comp = kmalloc(sizeof(*action_comp), GFP_KERNEL); | ||
| 724 | if (!action_comp) { | ||
| 725 | err = -ENOMEM; | ||
| 726 | goto err_free_prefix; | ||
| 727 | } | ||
| 728 | action_comp->synapse = synapse; | ||
| 729 | action_comp->count = count; | ||
| 730 | |||
| 731 | /* Create action attribute */ | ||
| 732 | parm.group = group; | ||
| 733 | parm.prefix = prefix; | ||
| 734 | parm.name = "action"; | ||
| 735 | parm.show = (counter->ops->action_get) ? counter_action_show : NULL; | ||
| 736 | parm.store = (counter->ops->action_set) ? counter_action_store : NULL; | ||
| 737 | parm.component = action_comp; | ||
| 738 | err = counter_attribute_create(&parm); | ||
| 739 | if (err) { | ||
| 740 | kfree(action_comp); | ||
| 741 | goto err_free_prefix; | ||
| 742 | } | ||
| 743 | |||
| 744 | /* Allocate action available attribute component */ | ||
| 745 | avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL); | ||
| 746 | if (!avail_comp) { | ||
| 747 | err = -ENOMEM; | ||
| 748 | goto err_free_prefix; | ||
| 749 | } | ||
| 750 | avail_comp->actions_list = synapse->actions_list; | ||
| 751 | avail_comp->num_actions = synapse->num_actions; | ||
| 752 | |||
| 753 | /* Create action_available attribute */ | ||
| 754 | parm.group = group; | ||
| 755 | parm.prefix = prefix; | ||
| 756 | parm.name = "action_available"; | ||
| 757 | parm.show = counter_synapse_action_available_show; | ||
| 758 | parm.store = NULL; | ||
| 759 | parm.component = avail_comp; | ||
| 760 | err = counter_attribute_create(&parm); | ||
| 761 | if (err) { | ||
| 762 | kfree(avail_comp); | ||
| 763 | goto err_free_prefix; | ||
| 764 | } | ||
| 765 | |||
| 766 | kfree(prefix); | ||
| 767 | } | ||
| 768 | |||
| 769 | return 0; | ||
| 770 | |||
| 771 | err_free_prefix: | ||
| 772 | kfree(prefix); | ||
| 773 | err_free_attr_list: | ||
| 774 | counter_device_attr_list_free(&group->attr_list); | ||
| 775 | return err; | ||
| 776 | } | ||
| 777 | |||
| 778 | struct counter_count_unit { | ||
| 779 | struct counter_count *count; | ||
| 780 | }; | ||
| 781 | |||
| 782 | static ssize_t counter_count_show(struct device *dev, | ||
| 783 | struct device_attribute *attr, | ||
| 784 | char *buf) | ||
| 785 | { | ||
| 786 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 787 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 788 | const struct counter_count_unit *const component = devattr->component; | ||
| 789 | struct counter_count *const count = component->count; | ||
| 790 | int err; | ||
| 791 | struct counter_count_read_value val = { .buf = buf }; | ||
| 792 | |||
| 793 | err = counter->ops->count_read(counter, count, &val); | ||
| 794 | if (err) | ||
| 795 | return err; | ||
| 796 | |||
| 797 | return val.len; | ||
| 798 | } | ||
| 799 | |||
| 800 | static ssize_t counter_count_store(struct device *dev, | ||
| 801 | struct device_attribute *attr, | ||
| 802 | const char *buf, size_t len) | ||
| 803 | { | ||
| 804 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 805 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 806 | const struct counter_count_unit *const component = devattr->component; | ||
| 807 | struct counter_count *const count = component->count; | ||
| 808 | int err; | ||
| 809 | struct counter_count_write_value val = { .buf = buf }; | ||
| 810 | |||
| 811 | err = counter->ops->count_write(counter, count, &val); | ||
| 812 | if (err) | ||
| 813 | return err; | ||
| 814 | |||
| 815 | return len; | ||
| 816 | } | ||
| 817 | |||
| 818 | static const char *const counter_count_function_str[] = { | ||
| 819 | [COUNTER_COUNT_FUNCTION_INCREASE] = "increase", | ||
| 820 | [COUNTER_COUNT_FUNCTION_DECREASE] = "decrease", | ||
| 821 | [COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction", | ||
| 822 | [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a", | ||
| 823 | [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b", | ||
| 824 | [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a", | ||
| 825 | [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b", | ||
| 826 | [COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4" | ||
| 827 | }; | ||
| 828 | |||
| 829 | static ssize_t counter_function_show(struct device *dev, | ||
| 830 | struct device_attribute *attr, char *buf) | ||
| 831 | { | ||
| 832 | int err; | ||
| 833 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 834 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 835 | const struct counter_count_unit *const component = devattr->component; | ||
| 836 | struct counter_count *const count = component->count; | ||
| 837 | size_t func_index; | ||
| 838 | enum counter_count_function function; | ||
| 839 | |||
| 840 | err = counter->ops->function_get(counter, count, &func_index); | ||
| 841 | if (err) | ||
| 842 | return err; | ||
| 843 | |||
| 844 | count->function = func_index; | ||
| 845 | |||
| 846 | function = count->functions_list[func_index]; | ||
| 847 | return sprintf(buf, "%s\n", counter_count_function_str[function]); | ||
| 848 | } | ||
| 849 | |||
| 850 | static ssize_t counter_function_store(struct device *dev, | ||
| 851 | struct device_attribute *attr, | ||
| 852 | const char *buf, size_t len) | ||
| 853 | { | ||
| 854 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 855 | const struct counter_count_unit *const component = devattr->component; | ||
| 856 | struct counter_count *const count = component->count; | ||
| 857 | const size_t num_functions = count->num_functions; | ||
| 858 | size_t func_index; | ||
| 859 | enum counter_count_function function; | ||
| 860 | int err; | ||
| 861 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 862 | |||
| 863 | /* Find requested Count function mode */ | ||
| 864 | for (func_index = 0; func_index < num_functions; func_index++) { | ||
| 865 | function = count->functions_list[func_index]; | ||
| 866 | if (sysfs_streq(buf, counter_count_function_str[function])) | ||
| 867 | break; | ||
| 868 | } | ||
| 869 | /* Return error if requested Count function mode not found */ | ||
| 870 | if (func_index >= num_functions) | ||
| 871 | return -EINVAL; | ||
| 872 | |||
| 873 | err = counter->ops->function_set(counter, count, func_index); | ||
| 874 | if (err) | ||
| 875 | return err; | ||
| 876 | |||
| 877 | count->function = func_index; | ||
| 878 | |||
| 879 | return len; | ||
| 880 | } | ||
| 881 | |||
| 882 | struct counter_count_ext_unit { | ||
| 883 | struct counter_count *count; | ||
| 884 | const struct counter_count_ext *ext; | ||
| 885 | }; | ||
| 886 | |||
| 887 | static ssize_t counter_count_ext_show(struct device *dev, | ||
| 888 | struct device_attribute *attr, char *buf) | ||
| 889 | { | ||
| 890 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 891 | const struct counter_count_ext_unit *const comp = devattr->component; | ||
| 892 | const struct counter_count_ext *const ext = comp->ext; | ||
| 893 | |||
| 894 | return ext->read(dev_get_drvdata(dev), comp->count, ext->priv, buf); | ||
| 895 | } | ||
| 896 | |||
| 897 | static ssize_t counter_count_ext_store(struct device *dev, | ||
| 898 | struct device_attribute *attr, | ||
| 899 | const char *buf, size_t len) | ||
| 900 | { | ||
| 901 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 902 | const struct counter_count_ext_unit *const comp = devattr->component; | ||
| 903 | const struct counter_count_ext *const ext = comp->ext; | ||
| 904 | |||
| 905 | return ext->write(dev_get_drvdata(dev), comp->count, ext->priv, buf, | ||
| 906 | len); | ||
| 907 | } | ||
| 908 | |||
| 909 | static int counter_count_ext_register( | ||
| 910 | struct counter_device_attr_group *const group, | ||
| 911 | struct counter_count *const count) | ||
| 912 | { | ||
| 913 | size_t i; | ||
| 914 | const struct counter_count_ext *ext; | ||
| 915 | struct counter_count_ext_unit *count_ext_comp; | ||
| 916 | struct counter_attr_parm parm; | ||
| 917 | int err; | ||
| 918 | |||
| 919 | /* Create an attribute for each extension */ | ||
| 920 | for (i = 0 ; i < count->num_ext; i++) { | ||
| 921 | ext = count->ext + i; | ||
| 922 | |||
| 923 | /* Allocate count_ext attribute component */ | ||
| 924 | count_ext_comp = kmalloc(sizeof(*count_ext_comp), GFP_KERNEL); | ||
| 925 | if (!count_ext_comp) { | ||
| 926 | err = -ENOMEM; | ||
| 927 | goto err_free_attr_list; | ||
| 928 | } | ||
| 929 | count_ext_comp->count = count; | ||
| 930 | count_ext_comp->ext = ext; | ||
| 931 | |||
| 932 | /* Allocate count_ext attribute */ | ||
| 933 | parm.group = group; | ||
| 934 | parm.prefix = ""; | ||
| 935 | parm.name = ext->name; | ||
| 936 | parm.show = (ext->read) ? counter_count_ext_show : NULL; | ||
| 937 | parm.store = (ext->write) ? counter_count_ext_store : NULL; | ||
| 938 | parm.component = count_ext_comp; | ||
| 939 | err = counter_attribute_create(&parm); | ||
| 940 | if (err) { | ||
| 941 | kfree(count_ext_comp); | ||
| 942 | goto err_free_attr_list; | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | return 0; | ||
| 947 | |||
| 948 | err_free_attr_list: | ||
| 949 | counter_device_attr_list_free(&group->attr_list); | ||
| 950 | return err; | ||
| 951 | } | ||
| 952 | |||
| 953 | struct counter_func_avail_unit { | ||
| 954 | const enum counter_count_function *functions_list; | ||
| 955 | size_t num_functions; | ||
| 956 | }; | ||
| 957 | |||
| 958 | static ssize_t counter_count_function_available_show(struct device *dev, | ||
| 959 | struct device_attribute *attr, char *buf) | ||
| 960 | { | ||
| 961 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 962 | const struct counter_func_avail_unit *const component = devattr->component; | ||
| 963 | const enum counter_count_function *const func_list = component->functions_list; | ||
| 964 | const size_t num_functions = component->num_functions; | ||
| 965 | size_t i; | ||
| 966 | enum counter_count_function function; | ||
| 967 | ssize_t len = 0; | ||
| 968 | |||
| 969 | for (i = 0; i < num_functions; i++) { | ||
| 970 | function = func_list[i]; | ||
| 971 | len += sprintf(buf + len, "%s\n", | ||
| 972 | counter_count_function_str[function]); | ||
| 973 | } | ||
| 974 | |||
| 975 | return len; | ||
| 976 | } | ||
| 977 | |||
| 978 | static int counter_count_attributes_create( | ||
| 979 | struct counter_device_attr_group *const group, | ||
| 980 | const struct counter_device *const counter, | ||
| 981 | struct counter_count *const count) | ||
| 982 | { | ||
| 983 | struct counter_count_unit *count_comp; | ||
| 984 | struct counter_attr_parm parm; | ||
| 985 | int err; | ||
| 986 | struct counter_count_unit *func_comp; | ||
| 987 | struct counter_func_avail_unit *avail_comp; | ||
| 988 | |||
| 989 | /* Allocate count attribute component */ | ||
| 990 | count_comp = kmalloc(sizeof(*count_comp), GFP_KERNEL); | ||
| 991 | if (!count_comp) | ||
| 992 | return -ENOMEM; | ||
| 993 | count_comp->count = count; | ||
| 994 | |||
| 995 | /* Create main Count attribute */ | ||
| 996 | parm.group = group; | ||
| 997 | parm.prefix = ""; | ||
| 998 | parm.name = "count"; | ||
| 999 | parm.show = (counter->ops->count_read) ? counter_count_show : NULL; | ||
| 1000 | parm.store = (counter->ops->count_write) ? counter_count_store : NULL; | ||
| 1001 | parm.component = count_comp; | ||
| 1002 | err = counter_attribute_create(&parm); | ||
| 1003 | if (err) { | ||
| 1004 | kfree(count_comp); | ||
| 1005 | return err; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /* Allocate function attribute component */ | ||
| 1009 | func_comp = kmalloc(sizeof(*func_comp), GFP_KERNEL); | ||
| 1010 | if (!func_comp) { | ||
| 1011 | err = -ENOMEM; | ||
| 1012 | goto err_free_attr_list; | ||
| 1013 | } | ||
| 1014 | func_comp->count = count; | ||
| 1015 | |||
| 1016 | /* Create Count function attribute */ | ||
| 1017 | parm.group = group; | ||
| 1018 | parm.prefix = ""; | ||
| 1019 | parm.name = "function"; | ||
| 1020 | parm.show = (counter->ops->function_get) ? counter_function_show : NULL; | ||
| 1021 | parm.store = (counter->ops->function_set) ? counter_function_store : NULL; | ||
| 1022 | parm.component = func_comp; | ||
| 1023 | err = counter_attribute_create(&parm); | ||
| 1024 | if (err) { | ||
| 1025 | kfree(func_comp); | ||
| 1026 | goto err_free_attr_list; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /* Allocate function available attribute component */ | ||
| 1030 | avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL); | ||
| 1031 | if (!avail_comp) { | ||
| 1032 | err = -ENOMEM; | ||
| 1033 | goto err_free_attr_list; | ||
| 1034 | } | ||
| 1035 | avail_comp->functions_list = count->functions_list; | ||
| 1036 | avail_comp->num_functions = count->num_functions; | ||
| 1037 | |||
| 1038 | /* Create Count function_available attribute */ | ||
| 1039 | parm.group = group; | ||
| 1040 | parm.prefix = ""; | ||
| 1041 | parm.name = "function_available"; | ||
| 1042 | parm.show = counter_count_function_available_show; | ||
| 1043 | parm.store = NULL; | ||
| 1044 | parm.component = avail_comp; | ||
| 1045 | err = counter_attribute_create(&parm); | ||
| 1046 | if (err) { | ||
| 1047 | kfree(avail_comp); | ||
| 1048 | goto err_free_attr_list; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | /* Create Count name attribute */ | ||
| 1052 | err = counter_name_attribute_create(group, count->name); | ||
| 1053 | if (err) | ||
| 1054 | goto err_free_attr_list; | ||
| 1055 | |||
| 1056 | /* Register Count extension attributes */ | ||
| 1057 | err = counter_count_ext_register(group, count); | ||
| 1058 | if (err) | ||
| 1059 | goto err_free_attr_list; | ||
| 1060 | |||
| 1061 | return 0; | ||
| 1062 | |||
| 1063 | err_free_attr_list: | ||
| 1064 | counter_device_attr_list_free(&group->attr_list); | ||
| 1065 | return err; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | static int counter_counts_register( | ||
| 1069 | struct counter_device_attr_group *const groups_list, | ||
| 1070 | const struct counter_device *const counter) | ||
| 1071 | { | ||
| 1072 | size_t i; | ||
| 1073 | struct counter_count *count; | ||
| 1074 | const char *name; | ||
| 1075 | int err; | ||
| 1076 | |||
| 1077 | /* Register each Count */ | ||
| 1078 | for (i = 0; i < counter->num_counts; i++) { | ||
| 1079 | count = counter->counts + i; | ||
| 1080 | |||
| 1081 | /* Generate Count attribute directory name */ | ||
| 1082 | name = kasprintf(GFP_KERNEL, "count%d", count->id); | ||
| 1083 | if (!name) { | ||
| 1084 | err = -ENOMEM; | ||
| 1085 | goto err_free_attr_groups; | ||
| 1086 | } | ||
| 1087 | groups_list[i].attr_group.name = name; | ||
| 1088 | |||
| 1089 | /* Register the Synapses associated with each Count */ | ||
| 1090 | err = counter_synapses_register(groups_list + i, counter, count, | ||
| 1091 | name); | ||
| 1092 | if (err) | ||
| 1093 | goto err_free_attr_groups; | ||
| 1094 | |||
| 1095 | /* Create all attributes associated with Count */ | ||
| 1096 | err = counter_count_attributes_create(groups_list + i, counter, | ||
| 1097 | count); | ||
| 1098 | if (err) | ||
| 1099 | goto err_free_attr_groups; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | return 0; | ||
| 1103 | |||
| 1104 | err_free_attr_groups: | ||
| 1105 | do { | ||
| 1106 | kfree(groups_list[i].attr_group.name); | ||
| 1107 | counter_device_attr_list_free(&groups_list[i].attr_list); | ||
| 1108 | } while (i--); | ||
| 1109 | return err; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | struct counter_size_unit { | ||
| 1113 | size_t size; | ||
| 1114 | }; | ||
| 1115 | |||
| 1116 | static ssize_t counter_device_attr_size_show(struct device *dev, | ||
| 1117 | struct device_attribute *attr, | ||
| 1118 | char *buf) | ||
| 1119 | { | ||
| 1120 | const struct counter_size_unit *const comp = to_counter_attr(attr)->component; | ||
| 1121 | |||
| 1122 | return sprintf(buf, "%zu\n", comp->size); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | static int counter_size_attribute_create( | ||
| 1126 | struct counter_device_attr_group *const group, | ||
| 1127 | const size_t size, const char *const name) | ||
| 1128 | { | ||
| 1129 | struct counter_size_unit *size_comp; | ||
| 1130 | struct counter_attr_parm parm; | ||
| 1131 | int err; | ||
| 1132 | |||
| 1133 | /* Allocate size attribute component */ | ||
| 1134 | size_comp = kmalloc(sizeof(*size_comp), GFP_KERNEL); | ||
| 1135 | if (!size_comp) | ||
| 1136 | return -ENOMEM; | ||
| 1137 | size_comp->size = size; | ||
| 1138 | |||
| 1139 | parm.group = group; | ||
| 1140 | parm.prefix = ""; | ||
| 1141 | parm.name = name; | ||
| 1142 | parm.show = counter_device_attr_size_show; | ||
| 1143 | parm.store = NULL; | ||
| 1144 | parm.component = size_comp; | ||
| 1145 | err = counter_attribute_create(&parm); | ||
| 1146 | if (err) | ||
| 1147 | goto err_free_size_comp; | ||
| 1148 | |||
| 1149 | return 0; | ||
| 1150 | |||
| 1151 | err_free_size_comp: | ||
| 1152 | kfree(size_comp); | ||
| 1153 | return err; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | struct counter_ext_unit { | ||
| 1157 | const struct counter_device_ext *ext; | ||
| 1158 | }; | ||
| 1159 | |||
| 1160 | static ssize_t counter_device_ext_show(struct device *dev, | ||
| 1161 | struct device_attribute *attr, char *buf) | ||
| 1162 | { | ||
| 1163 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 1164 | const struct counter_ext_unit *const component = devattr->component; | ||
| 1165 | const struct counter_device_ext *const ext = component->ext; | ||
| 1166 | |||
| 1167 | return ext->read(dev_get_drvdata(dev), ext->priv, buf); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | static ssize_t counter_device_ext_store(struct device *dev, | ||
| 1171 | struct device_attribute *attr, | ||
| 1172 | const char *buf, size_t len) | ||
| 1173 | { | ||
| 1174 | const struct counter_device_attr *const devattr = to_counter_attr(attr); | ||
| 1175 | const struct counter_ext_unit *const component = devattr->component; | ||
| 1176 | const struct counter_device_ext *const ext = component->ext; | ||
| 1177 | |||
| 1178 | return ext->write(dev_get_drvdata(dev), ext->priv, buf, len); | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | static int counter_device_ext_register( | ||
| 1182 | struct counter_device_attr_group *const group, | ||
| 1183 | struct counter_device *const counter) | ||
| 1184 | { | ||
| 1185 | size_t i; | ||
| 1186 | struct counter_ext_unit *ext_comp; | ||
| 1187 | struct counter_attr_parm parm; | ||
| 1188 | int err; | ||
| 1189 | |||
| 1190 | /* Create an attribute for each extension */ | ||
| 1191 | for (i = 0 ; i < counter->num_ext; i++) { | ||
| 1192 | /* Allocate extension attribute component */ | ||
| 1193 | ext_comp = kmalloc(sizeof(*ext_comp), GFP_KERNEL); | ||
| 1194 | if (!ext_comp) { | ||
| 1195 | err = -ENOMEM; | ||
| 1196 | goto err_free_attr_list; | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | ext_comp->ext = counter->ext + i; | ||
| 1200 | |||
| 1201 | /* Allocate extension attribute */ | ||
| 1202 | parm.group = group; | ||
| 1203 | parm.prefix = ""; | ||
| 1204 | parm.name = counter->ext[i].name; | ||
| 1205 | parm.show = (counter->ext[i].read) ? counter_device_ext_show : NULL; | ||
| 1206 | parm.store = (counter->ext[i].write) ? counter_device_ext_store : NULL; | ||
| 1207 | parm.component = ext_comp; | ||
| 1208 | err = counter_attribute_create(&parm); | ||
| 1209 | if (err) { | ||
| 1210 | kfree(ext_comp); | ||
| 1211 | goto err_free_attr_list; | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | return 0; | ||
| 1216 | |||
| 1217 | err_free_attr_list: | ||
| 1218 | counter_device_attr_list_free(&group->attr_list); | ||
| 1219 | return err; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | static int counter_global_attr_register( | ||
| 1223 | struct counter_device_attr_group *const group, | ||
| 1224 | struct counter_device *const counter) | ||
| 1225 | { | ||
| 1226 | int err; | ||
| 1227 | |||
| 1228 | /* Create name attribute */ | ||
| 1229 | err = counter_name_attribute_create(group, counter->name); | ||
| 1230 | if (err) | ||
| 1231 | return err; | ||
| 1232 | |||
| 1233 | /* Create num_counts attribute */ | ||
| 1234 | err = counter_size_attribute_create(group, counter->num_counts, | ||
| 1235 | "num_counts"); | ||
| 1236 | if (err) | ||
| 1237 | goto err_free_attr_list; | ||
| 1238 | |||
| 1239 | /* Create num_signals attribute */ | ||
| 1240 | err = counter_size_attribute_create(group, counter->num_signals, | ||
| 1241 | "num_signals"); | ||
| 1242 | if (err) | ||
| 1243 | goto err_free_attr_list; | ||
| 1244 | |||
| 1245 | /* Register Counter device extension attributes */ | ||
| 1246 | err = counter_device_ext_register(group, counter); | ||
| 1247 | if (err) | ||
| 1248 | goto err_free_attr_list; | ||
| 1249 | |||
| 1250 | return 0; | ||
| 1251 | |||
| 1252 | err_free_attr_list: | ||
| 1253 | counter_device_attr_list_free(&group->attr_list); | ||
| 1254 | return err; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | static void counter_device_groups_list_free( | ||
| 1258 | struct counter_device_attr_group *const groups_list, | ||
| 1259 | const size_t num_groups) | ||
| 1260 | { | ||
| 1261 | struct counter_device_attr_group *group; | ||
| 1262 | size_t i; | ||
| 1263 | |||
| 1264 | /* loop through all attribute groups (signals, counts, global, etc.) */ | ||
| 1265 | for (i = 0; i < num_groups; i++) { | ||
| 1266 | group = groups_list + i; | ||
| 1267 | |||
| 1268 | /* free all attribute group and associated attributes memory */ | ||
| 1269 | kfree(group->attr_group.name); | ||
| 1270 | kfree(group->attr_group.attrs); | ||
| 1271 | counter_device_attr_list_free(&group->attr_list); | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | kfree(groups_list); | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | static int counter_device_groups_list_prepare( | ||
| 1278 | struct counter_device *const counter) | ||
| 1279 | { | ||
| 1280 | const size_t total_num_groups = | ||
| 1281 | counter->num_signals + counter->num_counts + 1; | ||
| 1282 | struct counter_device_attr_group *groups_list; | ||
| 1283 | size_t i; | ||
| 1284 | int err; | ||
| 1285 | size_t num_groups = 0; | ||
| 1286 | |||
| 1287 | /* Allocate space for attribute groups (signals, counts, and ext) */ | ||
| 1288 | groups_list = kcalloc(total_num_groups, sizeof(*groups_list), | ||
| 1289 | GFP_KERNEL); | ||
| 1290 | if (!groups_list) | ||
| 1291 | return -ENOMEM; | ||
| 1292 | |||
| 1293 | /* Initialize attribute lists */ | ||
| 1294 | for (i = 0; i < total_num_groups; i++) | ||
| 1295 | INIT_LIST_HEAD(&groups_list[i].attr_list); | ||
| 1296 | |||
| 1297 | /* Register Signals */ | ||
| 1298 | err = counter_signals_register(groups_list, counter); | ||
| 1299 | if (err) | ||
| 1300 | goto err_free_groups_list; | ||
| 1301 | num_groups += counter->num_signals; | ||
| 1302 | |||
| 1303 | /* Register Counts and respective Synapses */ | ||
| 1304 | err = counter_counts_register(groups_list + num_groups, counter); | ||
| 1305 | if (err) | ||
| 1306 | goto err_free_groups_list; | ||
| 1307 | num_groups += counter->num_counts; | ||
| 1308 | |||
| 1309 | /* Register Counter global attributes */ | ||
| 1310 | err = counter_global_attr_register(groups_list + num_groups, counter); | ||
| 1311 | if (err) | ||
| 1312 | goto err_free_groups_list; | ||
| 1313 | num_groups++; | ||
| 1314 | |||
| 1315 | /* Store groups_list in device_state */ | ||
| 1316 | counter->device_state->groups_list = groups_list; | ||
| 1317 | counter->device_state->num_groups = num_groups; | ||
| 1318 | |||
| 1319 | return 0; | ||
| 1320 | |||
| 1321 | err_free_groups_list: | ||
| 1322 | counter_device_groups_list_free(groups_list, num_groups); | ||
| 1323 | return err; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | static int counter_device_groups_prepare( | ||
| 1327 | struct counter_device_state *const device_state) | ||
| 1328 | { | ||
| 1329 | size_t i, j; | ||
| 1330 | struct counter_device_attr_group *group; | ||
| 1331 | int err; | ||
| 1332 | struct counter_device_attr *p; | ||
| 1333 | |||
| 1334 | /* Allocate attribute groups for association with device */ | ||
| 1335 | device_state->groups = kcalloc(device_state->num_groups + 1, | ||
| 1336 | sizeof(*device_state->groups), | ||
| 1337 | GFP_KERNEL); | ||
| 1338 | if (!device_state->groups) | ||
| 1339 | return -ENOMEM; | ||
| 1340 | |||
| 1341 | /* Prepare each group of attributes for association */ | ||
| 1342 | for (i = 0; i < device_state->num_groups; i++) { | ||
| 1343 | group = device_state->groups_list + i; | ||
| 1344 | |||
| 1345 | /* Allocate space for attribute pointers in attribute group */ | ||
| 1346 | group->attr_group.attrs = kcalloc(group->num_attr + 1, | ||
| 1347 | sizeof(*group->attr_group.attrs), GFP_KERNEL); | ||
| 1348 | if (!group->attr_group.attrs) { | ||
| 1349 | err = -ENOMEM; | ||
| 1350 | goto err_free_groups; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | /* Add attribute pointers to attribute group */ | ||
| 1354 | j = 0; | ||
| 1355 | list_for_each_entry(p, &group->attr_list, l) | ||
| 1356 | group->attr_group.attrs[j++] = &p->dev_attr.attr; | ||
| 1357 | |||
| 1358 | /* Group attributes in attribute group */ | ||
| 1359 | device_state->groups[i] = &group->attr_group; | ||
| 1360 | } | ||
| 1361 | /* Associate attributes with device */ | ||
| 1362 | device_state->dev.groups = device_state->groups; | ||
| 1363 | |||
| 1364 | return 0; | ||
| 1365 | |||
| 1366 | err_free_groups: | ||
| 1367 | do { | ||
| 1368 | group = device_state->groups_list + i; | ||
| 1369 | kfree(group->attr_group.attrs); | ||
| 1370 | group->attr_group.attrs = NULL; | ||
| 1371 | } while (i--); | ||
| 1372 | kfree(device_state->groups); | ||
| 1373 | return err; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | /* Provides a unique ID for each counter device */ | ||
| 1377 | static DEFINE_IDA(counter_ida); | ||
| 1378 | |||
| 1379 | static void counter_device_release(struct device *dev) | ||
| 1380 | { | ||
| 1381 | struct counter_device *const counter = dev_get_drvdata(dev); | ||
| 1382 | struct counter_device_state *const device_state = counter->device_state; | ||
| 1383 | |||
| 1384 | kfree(device_state->groups); | ||
| 1385 | counter_device_groups_list_free(device_state->groups_list, | ||
| 1386 | device_state->num_groups); | ||
| 1387 | ida_simple_remove(&counter_ida, device_state->id); | ||
| 1388 | kfree(device_state); | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | static struct device_type counter_device_type = { | ||
| 1392 | .name = "counter_device", | ||
| 1393 | .release = counter_device_release | ||
| 1394 | }; | ||
| 1395 | |||
| 1396 | static struct bus_type counter_bus_type = { | ||
| 1397 | .name = "counter" | ||
| 1398 | }; | ||
| 1399 | |||
| 1400 | /** | ||
| 1401 | * counter_register - register Counter to the system | ||
| 1402 | * @counter: pointer to Counter to register | ||
| 1403 | * | ||
| 1404 | * This function registers a Counter to the system. A sysfs "counter" directory | ||
| 1405 | * will be created and populated with sysfs attributes correlating with the | ||
| 1406 | * Counter Signals, Synapses, and Counts respectively. | ||
| 1407 | */ | ||
| 1408 | int counter_register(struct counter_device *const counter) | ||
| 1409 | { | ||
| 1410 | struct counter_device_state *device_state; | ||
| 1411 | int err; | ||
| 1412 | |||
| 1413 | /* Allocate internal state container for Counter device */ | ||
| 1414 | device_state = kzalloc(sizeof(*device_state), GFP_KERNEL); | ||
| 1415 | if (!device_state) | ||
| 1416 | return -ENOMEM; | ||
| 1417 | counter->device_state = device_state; | ||
| 1418 | |||
| 1419 | /* Acquire unique ID */ | ||
| 1420 | device_state->id = ida_simple_get(&counter_ida, 0, 0, GFP_KERNEL); | ||
| 1421 | if (device_state->id < 0) { | ||
| 1422 | err = device_state->id; | ||
| 1423 | goto err_free_device_state; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | /* Configure device structure for Counter */ | ||
| 1427 | device_state->dev.type = &counter_device_type; | ||
| 1428 | device_state->dev.bus = &counter_bus_type; | ||
| 1429 | if (counter->parent) { | ||
| 1430 | device_state->dev.parent = counter->parent; | ||
| 1431 | device_state->dev.of_node = counter->parent->of_node; | ||
| 1432 | } | ||
| 1433 | dev_set_name(&device_state->dev, "counter%d", device_state->id); | ||
| 1434 | device_initialize(&device_state->dev); | ||
| 1435 | dev_set_drvdata(&device_state->dev, counter); | ||
| 1436 | |||
| 1437 | /* Prepare device attributes */ | ||
| 1438 | err = counter_device_groups_list_prepare(counter); | ||
| 1439 | if (err) | ||
| 1440 | goto err_free_id; | ||
| 1441 | |||
| 1442 | /* Organize device attributes to groups and match to device */ | ||
| 1443 | err = counter_device_groups_prepare(device_state); | ||
| 1444 | if (err) | ||
| 1445 | goto err_free_groups_list; | ||
| 1446 | |||
| 1447 | /* Add device to system */ | ||
| 1448 | err = device_add(&device_state->dev); | ||
| 1449 | if (err) | ||
| 1450 | goto err_free_groups; | ||
| 1451 | |||
| 1452 | return 0; | ||
| 1453 | |||
| 1454 | err_free_groups: | ||
| 1455 | kfree(device_state->groups); | ||
| 1456 | err_free_groups_list: | ||
| 1457 | counter_device_groups_list_free(device_state->groups_list, | ||
| 1458 | device_state->num_groups); | ||
| 1459 | err_free_id: | ||
| 1460 | ida_simple_remove(&counter_ida, device_state->id); | ||
| 1461 | err_free_device_state: | ||
| 1462 | kfree(device_state); | ||
| 1463 | return err; | ||
| 1464 | } | ||
| 1465 | EXPORT_SYMBOL_GPL(counter_register); | ||
| 1466 | |||
| 1467 | /** | ||
| 1468 | * counter_unregister - unregister Counter from the system | ||
| 1469 | * @counter: pointer to Counter to unregister | ||
| 1470 | * | ||
| 1471 | * The Counter is unregistered from the system; all allocated memory is freed. | ||
| 1472 | */ | ||
| 1473 | void counter_unregister(struct counter_device *const counter) | ||
| 1474 | { | ||
| 1475 | if (counter) | ||
| 1476 | device_del(&counter->device_state->dev); | ||
| 1477 | } | ||
| 1478 | EXPORT_SYMBOL_GPL(counter_unregister); | ||
| 1479 | |||
| 1480 | static void devm_counter_unreg(struct device *dev, void *res) | ||
| 1481 | { | ||
| 1482 | counter_unregister(*(struct counter_device **)res); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | /** | ||
| 1486 | * devm_counter_register - Resource-managed counter_register | ||
| 1487 | * @dev: device to allocate counter_device for | ||
| 1488 | * @counter: pointer to Counter to register | ||
| 1489 | * | ||
| 1490 | * Managed counter_register. The Counter registered with this function is | ||
| 1491 | * automatically unregistered on driver detach. This function calls | ||
| 1492 | * counter_register internally. Refer to that function for more information. | ||
| 1493 | * | ||
| 1494 | * If an Counter registered with this function needs to be unregistered | ||
| 1495 | * separately, devm_counter_unregister must be used. | ||
| 1496 | * | ||
| 1497 | * RETURNS: | ||
| 1498 | * 0 on success, negative error number on failure. | ||
| 1499 | */ | ||
| 1500 | int devm_counter_register(struct device *dev, | ||
| 1501 | struct counter_device *const counter) | ||
| 1502 | { | ||
| 1503 | struct counter_device **ptr; | ||
| 1504 | int ret; | ||
| 1505 | |||
| 1506 | ptr = devres_alloc(devm_counter_unreg, sizeof(*ptr), GFP_KERNEL); | ||
| 1507 | if (!ptr) | ||
| 1508 | return -ENOMEM; | ||
| 1509 | |||
| 1510 | ret = counter_register(counter); | ||
| 1511 | if (!ret) { | ||
| 1512 | *ptr = counter; | ||
| 1513 | devres_add(dev, ptr); | ||
| 1514 | } else { | ||
| 1515 | devres_free(ptr); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | return ret; | ||
| 1519 | } | ||
| 1520 | EXPORT_SYMBOL_GPL(devm_counter_register); | ||
| 1521 | |||
| 1522 | static int devm_counter_match(struct device *dev, void *res, void *data) | ||
| 1523 | { | ||
| 1524 | struct counter_device **r = res; | ||
| 1525 | |||
| 1526 | if (!r || !*r) { | ||
| 1527 | WARN_ON(!r || !*r); | ||
| 1528 | return 0; | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | return *r == data; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | /** | ||
| 1535 | * devm_counter_unregister - Resource-managed counter_unregister | ||
| 1536 | * @dev: device this counter_device belongs to | ||
| 1537 | * @counter: pointer to Counter associated with the device | ||
| 1538 | * | ||
| 1539 | * Unregister Counter registered with devm_counter_register. | ||
| 1540 | */ | ||
| 1541 | void devm_counter_unregister(struct device *dev, | ||
| 1542 | struct counter_device *const counter) | ||
| 1543 | { | ||
| 1544 | int rc; | ||
| 1545 | |||
| 1546 | rc = devres_release(dev, devm_counter_unreg, devm_counter_match, | ||
| 1547 | counter); | ||
| 1548 | WARN_ON(rc); | ||
| 1549 | } | ||
| 1550 | EXPORT_SYMBOL_GPL(devm_counter_unregister); | ||
| 1551 | |||
| 1552 | static int __init counter_init(void) | ||
| 1553 | { | ||
| 1554 | return bus_register(&counter_bus_type); | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | static void __exit counter_exit(void) | ||
| 1558 | { | ||
| 1559 | bus_unregister(&counter_bus_type); | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | subsys_initcall(counter_init); | ||
| 1563 | module_exit(counter_exit); | ||
| 1564 | |||
| 1565 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); | ||
| 1566 | MODULE_DESCRIPTION("Generic Counter interface"); | ||
| 1567 | MODULE_LICENSE("GPL v2"); | ||
| @@ -0,0 +1,356 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Flex Timer Module Quadrature decoder | ||
| 4 | * | ||
| 5 | * This module implements a driver for decoding the FTM quadrature | ||
| 6 | * of ex. a LS1021A | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/fsl/ftm.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/of.h> | ||
| 13 | #include <linux/io.h> | ||
| 14 | #include <linux/mutex.h> | ||
| 15 | #include <linux/counter.h> | ||
| 16 | #include <linux/bitfield.h> | ||
| 17 | |||
| 18 | #define FTM_FIELD_UPDATE(ftm, offset, mask, val) \ | ||
| 19 | ({ \ | ||
| 20 | uint32_t flags; \ | ||
| 21 | ftm_read(ftm, offset, &flags); \ | ||
| 22 | flags &= ~mask; \ | ||
| 23 | flags |= FIELD_PREP(mask, val); \ | ||
| 24 | ftm_write(ftm, offset, flags); \ | ||
| 25 | }) | ||
| 26 | |||
| 27 | struct ftm_quaddec { | ||
| 28 | struct counter_device counter; | ||
| 29 | struct platform_device *pdev; | ||
| 30 | void __iomem *ftm_base; | ||
| 31 | bool big_endian; | ||
| 32 | struct mutex ftm_quaddec_mutex; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t *data) | ||
| 36 | { | ||
| 37 | if (ftm->big_endian) | ||
| 38 | *data = ioread32be(ftm->ftm_base + offset); | ||
| 39 | else | ||
| 40 | *data = ioread32(ftm->ftm_base + offset); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t data) | ||
| 44 | { | ||
| 45 | if (ftm->big_endian) | ||
| 46 | iowrite32be(data, ftm->ftm_base + offset); | ||
| 47 | else | ||
| 48 | iowrite32(data, ftm->ftm_base + offset); | ||
| 49 | } | ||
| 50 | |||
| 51 | /* Hold mutex before modifying write protection state */ | ||
| 52 | static void ftm_clear_write_protection(struct ftm_quaddec *ftm) | ||
| 53 | { | ||
| 54 | uint32_t flag; | ||
| 55 | |||
| 56 | /* First see if it is enabled */ | ||
| 57 | ftm_read(ftm, FTM_FMS, &flag); | ||
| 58 | |||
| 59 | if (flag & FTM_FMS_WPEN) | ||
| 60 | FTM_FIELD_UPDATE(ftm, FTM_MODE, FTM_MODE_WPDIS, 1); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void ftm_set_write_protection(struct ftm_quaddec *ftm) | ||
| 64 | { | ||
| 65 | FTM_FIELD_UPDATE(ftm, FTM_FMS, FTM_FMS_WPEN, 1); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void ftm_reset_counter(struct ftm_quaddec *ftm) | ||
| 69 | { | ||
| 70 | /* Reset hardware counter to CNTIN */ | ||
| 71 | ftm_write(ftm, FTM_CNT, 0x0); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void ftm_quaddec_init(struct ftm_quaddec *ftm) | ||
| 75 | { | ||
| 76 | ftm_clear_write_protection(ftm); | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Do not write in the region from the CNTIN register through the | ||
| 80 | * PWMLOAD register when FTMEN = 0. | ||
| 81 | * Also reset other fields to zero | ||
| 82 | */ | ||
| 83 | ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN); | ||
| 84 | ftm_write(ftm, FTM_CNTIN, 0x0000); | ||
| 85 | ftm_write(ftm, FTM_MOD, 0xffff); | ||
| 86 | ftm_write(ftm, FTM_CNT, 0x0); | ||
| 87 | /* Set prescaler, reset other fields to zero */ | ||
| 88 | ftm_write(ftm, FTM_SC, FTM_SC_PS_1); | ||
| 89 | |||
| 90 | /* Select quad mode, reset other fields to zero */ | ||
| 91 | ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN); | ||
| 92 | |||
| 93 | /* Unused features and reset to default section */ | ||
| 94 | ftm_write(ftm, FTM_POL, 0x0); | ||
| 95 | ftm_write(ftm, FTM_FLTCTRL, 0x0); | ||
| 96 | ftm_write(ftm, FTM_SYNCONF, 0x0); | ||
| 97 | ftm_write(ftm, FTM_SYNC, 0xffff); | ||
| 98 | |||
| 99 | /* Lock the FTM */ | ||
| 100 | ftm_set_write_protection(ftm); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void ftm_quaddec_disable(struct ftm_quaddec *ftm) | ||
| 104 | { | ||
| 105 | ftm_clear_write_protection(ftm); | ||
| 106 | ftm_write(ftm, FTM_MODE, 0); | ||
| 107 | ftm_write(ftm, FTM_QDCTRL, 0); | ||
| 108 | /* | ||
| 109 | * This is enough to disable the counter. No clock has been | ||
| 110 | * selected by writing to FTM_SC in init() | ||
| 111 | */ | ||
| 112 | ftm_set_write_protection(ftm); | ||
| 113 | } | ||
| 114 | |||
| 115 | static int ftm_quaddec_get_prescaler(struct counter_device *counter, | ||
| 116 | struct counter_count *count, | ||
| 117 | size_t *cnt_mode) | ||
| 118 | { | ||
| 119 | struct ftm_quaddec *ftm = counter->priv; | ||
| 120 | uint32_t scflags; | ||
| 121 | |||
| 122 | ftm_read(ftm, FTM_SC, &scflags); | ||
| 123 | |||
| 124 | *cnt_mode = FIELD_GET(FTM_SC_PS_MASK, scflags); | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int ftm_quaddec_set_prescaler(struct counter_device *counter, | ||
| 130 | struct counter_count *count, | ||
| 131 | size_t cnt_mode) | ||
| 132 | { | ||
| 133 | struct ftm_quaddec *ftm = counter->priv; | ||
| 134 | |||
| 135 | mutex_lock(&ftm->ftm_quaddec_mutex); | ||
| 136 | |||
| 137 | ftm_clear_write_protection(ftm); | ||
| 138 | FTM_FIELD_UPDATE(ftm, FTM_SC, FTM_SC_PS_MASK, cnt_mode); | ||
| 139 | ftm_set_write_protection(ftm); | ||
| 140 | |||
| 141 | /* Also resets the counter as it is undefined anyway now */ | ||
| 142 | ftm_reset_counter(ftm); | ||
| 143 | |||
| 144 | mutex_unlock(&ftm->ftm_quaddec_mutex); | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static const char * const ftm_quaddec_prescaler[] = { | ||
| 149 | "1", "2", "4", "8", "16", "32", "64", "128" | ||
| 150 | }; | ||
| 151 | |||
| 152 | static struct counter_count_enum_ext ftm_quaddec_prescaler_enum = { | ||
| 153 | .items = ftm_quaddec_prescaler, | ||
| 154 | .num_items = ARRAY_SIZE(ftm_quaddec_prescaler), | ||
| 155 | .get = ftm_quaddec_get_prescaler, | ||
| 156 | .set = ftm_quaddec_set_prescaler | ||
| 157 | }; | ||
| 158 | |||
| 159 | enum ftm_quaddec_synapse_action { | ||
| 160 | FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static enum counter_synapse_action ftm_quaddec_synapse_actions[] = { | ||
| 164 | [FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES] = | ||
| 165 | COUNTER_SYNAPSE_ACTION_BOTH_EDGES | ||
| 166 | }; | ||
| 167 | |||
| 168 | enum ftm_quaddec_count_function { | ||
| 169 | FTM_QUADDEC_COUNT_ENCODER_MODE_1, | ||
| 170 | }; | ||
| 171 | |||
| 172 | static const enum counter_count_function ftm_quaddec_count_functions[] = { | ||
| 173 | [FTM_QUADDEC_COUNT_ENCODER_MODE_1] = | ||
| 174 | COUNTER_COUNT_FUNCTION_QUADRATURE_X4 | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int ftm_quaddec_count_read(struct counter_device *counter, | ||
| 178 | struct counter_count *count, | ||
| 179 | struct counter_count_read_value *val) | ||
| 180 | { | ||
| 181 | struct ftm_quaddec *const ftm = counter->priv; | ||
| 182 | uint32_t cntval; | ||
| 183 | |||
| 184 | ftm_read(ftm, FTM_CNT, &cntval); | ||
| 185 | |||
| 186 | counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval); | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int ftm_quaddec_count_write(struct counter_device *counter, | ||
| 192 | struct counter_count *count, | ||
| 193 | struct counter_count_write_value *val) | ||
| 194 | { | ||
| 195 | struct ftm_quaddec *const ftm = counter->priv; | ||
| 196 | u32 cnt; | ||
| 197 | int err; | ||
| 198 | |||
| 199 | err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val); | ||
| 200 | if (err) | ||
| 201 | return err; | ||
| 202 | |||
| 203 | if (cnt != 0) { | ||
| 204 | dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n"); | ||
| 205 | return -EINVAL; | ||
| 206 | } | ||
| 207 | |||
| 208 | ftm_reset_counter(ftm); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int ftm_quaddec_count_function_get(struct counter_device *counter, | ||
| 214 | struct counter_count *count, | ||
| 215 | size_t *function) | ||
| 216 | { | ||
| 217 | *function = FTM_QUADDEC_COUNT_ENCODER_MODE_1; | ||
| 218 | |||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int ftm_quaddec_action_get(struct counter_device *counter, | ||
| 223 | struct counter_count *count, | ||
| 224 | struct counter_synapse *synapse, | ||
| 225 | size_t *action) | ||
| 226 | { | ||
| 227 | *action = FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | static const struct counter_ops ftm_quaddec_cnt_ops = { | ||
| 233 | .count_read = ftm_quaddec_count_read, | ||
| 234 | .count_write = ftm_quaddec_count_write, | ||
| 235 | .function_get = ftm_quaddec_count_function_get, | ||
| 236 | .action_get = ftm_quaddec_action_get, | ||
| 237 | }; | ||
| 238 | |||
| 239 | static struct counter_signal ftm_quaddec_signals[] = { | ||
| 240 | { | ||
| 241 | .id = 0, | ||
| 242 | .name = "Channel 1 Phase A" | ||
| 243 | }, | ||
| 244 | { | ||
| 245 | .id = 1, | ||
| 246 | .name = "Channel 1 Phase B" | ||
| 247 | } | ||
| 248 | }; | ||
| 249 | |||
| 250 | static struct counter_synapse ftm_quaddec_count_synapses[] = { | ||
| 251 | { | ||
| 252 | .actions_list = ftm_quaddec_synapse_actions, | ||
| 253 | .num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions), | ||
| 254 | .signal = &ftm_quaddec_signals[0] | ||
| 255 | }, | ||
| 256 | { | ||
| 257 | .actions_list = ftm_quaddec_synapse_actions, | ||
| 258 | .num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions), | ||
| 259 | .signal = &ftm_quaddec_signals[1] | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | |||
| 263 | static const struct counter_count_ext ftm_quaddec_count_ext[] = { | ||
| 264 | COUNTER_COUNT_ENUM("prescaler", &ftm_quaddec_prescaler_enum), | ||
| 265 | COUNTER_COUNT_ENUM_AVAILABLE("prescaler", &ftm_quaddec_prescaler_enum), | ||
| 266 | }; | ||
| 267 | |||
| 268 | static struct counter_count ftm_quaddec_counts = { | ||
| 269 | .id = 0, | ||
| 270 | .name = "Channel 1 Count", | ||
| 271 | .functions_list = ftm_quaddec_count_functions, | ||
| 272 | .num_functions = ARRAY_SIZE(ftm_quaddec_count_functions), | ||
| 273 | .synapses = ftm_quaddec_count_synapses, | ||
| 274 | .num_synapses = ARRAY_SIZE(ftm_quaddec_count_synapses), | ||
| 275 | .ext = ftm_quaddec_count_ext, | ||
| 276 | .num_ext = ARRAY_SIZE(ftm_quaddec_count_ext) | ||
| 277 | }; | ||
| 278 | |||
| 279 | static int ftm_quaddec_probe(struct platform_device *pdev) | ||
| 280 | { | ||
| 281 | struct ftm_quaddec *ftm; | ||
| 282 | |||
| 283 | struct device_node *node = pdev->dev.of_node; | ||
| 284 | struct resource *io; | ||
| 285 | int ret; | ||
| 286 | |||
| 287 | ftm = devm_kzalloc(&pdev->dev, sizeof(*ftm), GFP_KERNEL); | ||
| 288 | if (!ftm) | ||
| 289 | return -ENOMEM; | ||
| 290 | |||
| 291 | platform_set_drvdata(pdev, ftm); | ||
| 292 | |||
| 293 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 294 | if (!io) { | ||
| 295 | dev_err(&pdev->dev, "Failed to get memory region\n"); | ||
| 296 | return -ENODEV; | ||
| 297 | } | ||
| 298 | |||
| 299 | ftm->pdev = pdev; | ||
| 300 | ftm->big_endian = of_property_read_bool(node, "big-endian"); | ||
| 301 | ftm->ftm_base = devm_ioremap(&pdev->dev, io->start, resource_size(io)); | ||
| 302 | |||
| 303 | if (!ftm->ftm_base) { | ||
| 304 | dev_err(&pdev->dev, "Failed to map memory region\n"); | ||
| 305 | return -EINVAL; | ||
| 306 | } | ||
| 307 | ftm->counter.name = dev_name(&pdev->dev); | ||
| 308 | ftm->counter.parent = &pdev->dev; | ||
| 309 | ftm->counter.ops = &ftm_quaddec_cnt_ops; | ||
| 310 | ftm->counter.counts = &ftm_quaddec_counts; | ||
| 311 | ftm->counter.num_counts = 1; | ||
| 312 | ftm->counter.signals = ftm_quaddec_signals; | ||
| 313 | ftm->counter.num_signals = ARRAY_SIZE(ftm_quaddec_signals); | ||
| 314 | ftm->counter.priv = ftm; | ||
| 315 | |||
| 316 | mutex_init(&ftm->ftm_quaddec_mutex); | ||
| 317 | |||
| 318 | ftm_quaddec_init(ftm); | ||
| 319 | |||
| 320 | ret = counter_register(&ftm->counter); | ||
| 321 | if (ret) | ||
| 322 | ftm_quaddec_disable(ftm); | ||
| 323 | |||
| 324 | return ret; | ||
| 325 | } | ||
| 326 | |||
| 327 | static int ftm_quaddec_remove(struct platform_device *pdev) | ||
| 328 | { | ||
| 329 | struct ftm_quaddec *ftm = platform_get_drvdata(pdev); | ||
| 330 | |||
| 331 | counter_unregister(&ftm->counter); | ||
| 332 | |||
| 333 | ftm_quaddec_disable(ftm); | ||
| 334 | |||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static const struct of_device_id ftm_quaddec_match[] = { | ||
| 339 | { .compatible = "fsl,ftm-quaddec" }, | ||
| 340 | {}, | ||
| 341 | }; | ||
| 342 | |||
| 343 | static struct platform_driver ftm_quaddec_driver = { | ||
| 344 | .driver = { | ||
| 345 | .name = "ftm-quaddec", | ||
| 346 | .of_match_table = ftm_quaddec_match, | ||
| 347 | }, | ||
| 348 | .probe = ftm_quaddec_probe, | ||
| 349 | .remove = ftm_quaddec_remove, | ||
| 350 | }; | ||
| 351 | |||
| 352 | module_platform_driver(ftm_quaddec_driver); | ||
| 353 | |||
| 354 | MODULE_LICENSE("GPL"); | ||
| 355 | MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com"); | ||
| 356 | MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com"); | ||
| @@ -0,0 +1,754 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * STM32 Low-Power Timer Encoder and Counter driver | ||
| 4 | * | ||
| 5 | * Copyright (C) STMicroelectronics 2017 | ||
| 6 | * | ||
| 7 | * Author: Fabrice Gasnier <fabrice.gasnier@st.com> | ||
| 8 | * | ||
| 9 | * Inspired by 104-quad-8 and stm32-timer-trigger drivers. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/bitfield.h> | ||
| 14 | #include <linux/counter.h> | ||
| 15 | #include <linux/iio/iio.h> | ||
| 16 | #include <linux/mfd/stm32-lptimer.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/pinctrl/consumer.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | |||
| 21 | struct stm32_lptim_cnt { | ||
| 22 | struct counter_device counter; | ||
| 23 | struct device *dev; | ||
| 24 | struct regmap *regmap; | ||
| 25 | struct clk *clk; | ||
| 26 | u32 ceiling; | ||
| 27 | u32 polarity; | ||
| 28 | u32 quadrature_mode; | ||
| 29 | bool enabled; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) | ||
| 33 | { | ||
| 34 | u32 val; | ||
| 35 | int ret; | ||
| 36 | |||
| 37 | ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val); | ||
| 38 | if (ret) | ||
| 39 | return ret; | ||
| 40 | |||
| 41 | return FIELD_GET(STM32_LPTIM_ENABLE, val); | ||
| 42 | } | ||
| 43 | |||
| 44 | static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, | ||
| 45 | int enable) | ||
| 46 | { | ||
| 47 | int ret; | ||
| 48 | u32 val; | ||
| 49 | |||
| 50 | val = FIELD_PREP(STM32_LPTIM_ENABLE, enable); | ||
| 51 | ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val); | ||
| 52 | if (ret) | ||
| 53 | return ret; | ||
| 54 | |||
| 55 | if (!enable) { | ||
| 56 | clk_disable(priv->clk); | ||
| 57 | priv->enabled = false; | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* LP timer must be enabled before writing CMP & ARR */ | ||
| 62 | ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->ceiling); | ||
| 63 | if (ret) | ||
| 64 | return ret; | ||
| 65 | |||
| 66 | ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0); | ||
| 67 | if (ret) | ||
| 68 | return ret; | ||
| 69 | |||
| 70 | /* ensure CMP & ARR registers are properly written */ | ||
| 71 | ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, | ||
| 72 | (val & STM32_LPTIM_CMPOK_ARROK), | ||
| 73 | 100, 1000); | ||
| 74 | if (ret) | ||
| 75 | return ret; | ||
| 76 | |||
| 77 | ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, | ||
| 78 | STM32_LPTIM_CMPOKCF_ARROKCF); | ||
| 79 | if (ret) | ||
| 80 | return ret; | ||
| 81 | |||
| 82 | ret = clk_enable(priv->clk); | ||
| 83 | if (ret) { | ||
| 84 | regmap_write(priv->regmap, STM32_LPTIM_CR, 0); | ||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | priv->enabled = true; | ||
| 88 | |||
| 89 | /* Start LP timer in continuous mode */ | ||
| 90 | return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, | ||
| 91 | STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT); | ||
| 92 | } | ||
| 93 | |||
| 94 | static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) | ||
| 95 | { | ||
| 96 | u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE | | ||
| 97 | STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC; | ||
| 98 | u32 val; | ||
| 99 | |||
| 100 | /* Setup LP timer encoder/counter and polarity, without prescaler */ | ||
| 101 | if (priv->quadrature_mode) | ||
| 102 | val = enable ? STM32_LPTIM_ENC : 0; | ||
| 103 | else | ||
| 104 | val = enable ? STM32_LPTIM_COUNTMODE : 0; | ||
| 105 | val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0); | ||
| 106 | |||
| 107 | return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); | ||
| 108 | } | ||
| 109 | |||
| 110 | static int stm32_lptim_write_raw(struct iio_dev *indio_dev, | ||
| 111 | struct iio_chan_spec const *chan, | ||
| 112 | int val, int val2, long mask) | ||
| 113 | { | ||
| 114 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 115 | int ret; | ||
| 116 | |||
| 117 | switch (mask) { | ||
| 118 | case IIO_CHAN_INFO_ENABLE: | ||
| 119 | if (val < 0 || val > 1) | ||
| 120 | return -EINVAL; | ||
| 121 | |||
| 122 | /* Check nobody uses the timer, or already disabled/enabled */ | ||
| 123 | ret = stm32_lptim_is_enabled(priv); | ||
| 124 | if ((ret < 0) || (!ret && !val)) | ||
| 125 | return ret; | ||
| 126 | if (val && ret) | ||
| 127 | return -EBUSY; | ||
| 128 | |||
| 129 | ret = stm32_lptim_setup(priv, val); | ||
| 130 | if (ret) | ||
| 131 | return ret; | ||
| 132 | return stm32_lptim_set_enable_state(priv, val); | ||
| 133 | |||
| 134 | default: | ||
| 135 | return -EINVAL; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static int stm32_lptim_read_raw(struct iio_dev *indio_dev, | ||
| 140 | struct iio_chan_spec const *chan, | ||
| 141 | int *val, int *val2, long mask) | ||
| 142 | { | ||
| 143 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 144 | u32 dat; | ||
| 145 | int ret; | ||
| 146 | |||
| 147 | switch (mask) { | ||
| 148 | case IIO_CHAN_INFO_RAW: | ||
| 149 | ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat); | ||
| 150 | if (ret) | ||
| 151 | return ret; | ||
| 152 | *val = dat; | ||
| 153 | return IIO_VAL_INT; | ||
| 154 | |||
| 155 | case IIO_CHAN_INFO_ENABLE: | ||
| 156 | ret = stm32_lptim_is_enabled(priv); | ||
| 157 | if (ret < 0) | ||
| 158 | return ret; | ||
| 159 | *val = ret; | ||
| 160 | return IIO_VAL_INT; | ||
| 161 | |||
| 162 | case IIO_CHAN_INFO_SCALE: | ||
| 163 | /* Non-quadrature mode: scale = 1 */ | ||
| 164 | *val = 1; | ||
| 165 | *val2 = 0; | ||
| 166 | if (priv->quadrature_mode) { | ||
| 167 | /* | ||
| 168 | * Quadrature encoder mode: | ||
| 169 | * - both edges, quarter cycle, scale is 0.25 | ||
| 170 | * - either rising/falling edge scale is 0.5 | ||
| 171 | */ | ||
| 172 | if (priv->polarity > 1) | ||
| 173 | *val2 = 2; | ||
| 174 | else | ||
| 175 | *val2 = 1; | ||
| 176 | } | ||
| 177 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 178 | |||
| 179 | default: | ||
| 180 | return -EINVAL; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | static const struct iio_info stm32_lptim_cnt_iio_info = { | ||
| 185 | .read_raw = stm32_lptim_read_raw, | ||
| 186 | .write_raw = stm32_lptim_write_raw, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static const char *const stm32_lptim_quadrature_modes[] = { | ||
| 190 | "non-quadrature", | ||
| 191 | "quadrature", | ||
| 192 | }; | ||
| 193 | |||
| 194 | static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev, | ||
| 195 | const struct iio_chan_spec *chan) | ||
| 196 | { | ||
| 197 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 198 | |||
| 199 | return priv->quadrature_mode; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev, | ||
| 203 | const struct iio_chan_spec *chan, | ||
| 204 | unsigned int type) | ||
| 205 | { | ||
| 206 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 207 | |||
| 208 | if (stm32_lptim_is_enabled(priv)) | ||
| 209 | return -EBUSY; | ||
| 210 | |||
| 211 | priv->quadrature_mode = type; | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct iio_enum stm32_lptim_quadrature_mode_en = { | ||
| 217 | .items = stm32_lptim_quadrature_modes, | ||
| 218 | .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes), | ||
| 219 | .get = stm32_lptim_get_quadrature_mode, | ||
| 220 | .set = stm32_lptim_set_quadrature_mode, | ||
| 221 | }; | ||
| 222 | |||
| 223 | static const char * const stm32_lptim_cnt_polarity[] = { | ||
| 224 | "rising-edge", "falling-edge", "both-edges", | ||
| 225 | }; | ||
| 226 | |||
| 227 | static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev, | ||
| 228 | const struct iio_chan_spec *chan) | ||
| 229 | { | ||
| 230 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 231 | |||
| 232 | return priv->polarity; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev, | ||
| 236 | const struct iio_chan_spec *chan, | ||
| 237 | unsigned int type) | ||
| 238 | { | ||
| 239 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 240 | |||
| 241 | if (stm32_lptim_is_enabled(priv)) | ||
| 242 | return -EBUSY; | ||
| 243 | |||
| 244 | priv->polarity = type; | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static const struct iio_enum stm32_lptim_cnt_polarity_en = { | ||
| 250 | .items = stm32_lptim_cnt_polarity, | ||
| 251 | .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity), | ||
| 252 | .get = stm32_lptim_cnt_get_polarity, | ||
| 253 | .set = stm32_lptim_cnt_set_polarity, | ||
| 254 | }; | ||
| 255 | |||
| 256 | static ssize_t stm32_lptim_cnt_get_ceiling(struct stm32_lptim_cnt *priv, | ||
| 257 | char *buf) | ||
| 258 | { | ||
| 259 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling); | ||
| 260 | } | ||
| 261 | |||
| 262 | static ssize_t stm32_lptim_cnt_set_ceiling(struct stm32_lptim_cnt *priv, | ||
| 263 | const char *buf, size_t len) | ||
| 264 | { | ||
| 265 | int ret; | ||
| 266 | |||
| 267 | if (stm32_lptim_is_enabled(priv)) | ||
| 268 | return -EBUSY; | ||
| 269 | |||
| 270 | ret = kstrtouint(buf, 0, &priv->ceiling); | ||
| 271 | if (ret) | ||
| 272 | return ret; | ||
| 273 | |||
| 274 | if (priv->ceiling > STM32_LPTIM_MAX_ARR) | ||
| 275 | return -EINVAL; | ||
| 276 | |||
| 277 | return len; | ||
| 278 | } | ||
| 279 | |||
| 280 | static ssize_t stm32_lptim_cnt_get_preset_iio(struct iio_dev *indio_dev, | ||
| 281 | uintptr_t private, | ||
| 282 | const struct iio_chan_spec *chan, | ||
| 283 | char *buf) | ||
| 284 | { | ||
| 285 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 286 | |||
| 287 | return stm32_lptim_cnt_get_ceiling(priv, buf); | ||
| 288 | } | ||
| 289 | |||
| 290 | static ssize_t stm32_lptim_cnt_set_preset_iio(struct iio_dev *indio_dev, | ||
| 291 | uintptr_t private, | ||
| 292 | const struct iio_chan_spec *chan, | ||
| 293 | const char *buf, size_t len) | ||
| 294 | { | ||
| 295 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 296 | |||
| 297 | return stm32_lptim_cnt_set_ceiling(priv, buf, len); | ||
| 298 | } | ||
| 299 | |||
| 300 | /* LP timer with encoder */ | ||
| 301 | static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = { | ||
| 302 | { | ||
| 303 | .name = "preset", | ||
| 304 | .shared = IIO_SEPARATE, | ||
| 305 | .read = stm32_lptim_cnt_get_preset_iio, | ||
| 306 | .write = stm32_lptim_cnt_set_preset_iio, | ||
| 307 | }, | ||
| 308 | IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), | ||
| 309 | IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), | ||
| 310 | IIO_ENUM("quadrature_mode", IIO_SEPARATE, | ||
| 311 | &stm32_lptim_quadrature_mode_en), | ||
| 312 | IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en), | ||
| 313 | {} | ||
| 314 | }; | ||
| 315 | |||
| 316 | static const struct iio_chan_spec stm32_lptim_enc_channels = { | ||
| 317 | .type = IIO_COUNT, | ||
| 318 | .channel = 0, | ||
| 319 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 320 | BIT(IIO_CHAN_INFO_ENABLE) | | ||
| 321 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 322 | .ext_info = stm32_lptim_enc_ext_info, | ||
| 323 | .indexed = 1, | ||
| 324 | }; | ||
| 325 | |||
| 326 | /* LP timer without encoder (counter only) */ | ||
| 327 | static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = { | ||
| 328 | { | ||
| 329 | .name = "preset", | ||
| 330 | .shared = IIO_SEPARATE, | ||
| 331 | .read = stm32_lptim_cnt_get_preset_iio, | ||
| 332 | .write = stm32_lptim_cnt_set_preset_iio, | ||
| 333 | }, | ||
| 334 | IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), | ||
| 335 | IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), | ||
| 336 | {} | ||
| 337 | }; | ||
| 338 | |||
| 339 | static const struct iio_chan_spec stm32_lptim_cnt_channels = { | ||
| 340 | .type = IIO_COUNT, | ||
| 341 | .channel = 0, | ||
| 342 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 343 | BIT(IIO_CHAN_INFO_ENABLE) | | ||
| 344 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 345 | .ext_info = stm32_lptim_cnt_ext_info, | ||
| 346 | .indexed = 1, | ||
| 347 | }; | ||
| 348 | |||
| 349 | /** | ||
| 350 | * stm32_lptim_cnt_function - enumerates stm32 LPTimer counter & encoder modes | ||
| 351 | * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges | ||
| 352 | * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) | ||
| 353 | */ | ||
| 354 | enum stm32_lptim_cnt_function { | ||
| 355 | STM32_LPTIM_COUNTER_INCREASE, | ||
| 356 | STM32_LPTIM_ENCODER_BOTH_EDGE, | ||
| 357 | }; | ||
| 358 | |||
| 359 | static enum counter_count_function stm32_lptim_cnt_functions[] = { | ||
| 360 | [STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE, | ||
| 361 | [STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4, | ||
| 362 | }; | ||
| 363 | |||
| 364 | enum stm32_lptim_synapse_action { | ||
| 365 | STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE, | ||
| 366 | STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE, | ||
| 367 | STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES, | ||
| 368 | STM32_LPTIM_SYNAPSE_ACTION_NONE, | ||
| 369 | }; | ||
| 370 | |||
| 371 | static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = { | ||
| 372 | /* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */ | ||
| 373 | [STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE, | ||
| 374 | [STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE, | ||
| 375 | [STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES, | ||
| 376 | [STM32_LPTIM_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, | ||
| 377 | }; | ||
| 378 | |||
| 379 | static int stm32_lptim_cnt_read(struct counter_device *counter, | ||
| 380 | struct counter_count *count, | ||
| 381 | struct counter_count_read_value *val) | ||
| 382 | { | ||
| 383 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 384 | u32 cnt; | ||
| 385 | int ret; | ||
| 386 | |||
| 387 | ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &cnt); | ||
| 388 | if (ret) | ||
| 389 | return ret; | ||
| 390 | |||
| 391 | counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt); | ||
| 392 | |||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | static int stm32_lptim_cnt_function_get(struct counter_device *counter, | ||
| 397 | struct counter_count *count, | ||
| 398 | size_t *function) | ||
| 399 | { | ||
| 400 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 401 | |||
| 402 | if (!priv->quadrature_mode) { | ||
| 403 | *function = STM32_LPTIM_COUNTER_INCREASE; | ||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | if (priv->polarity == STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES) { | ||
| 408 | *function = STM32_LPTIM_ENCODER_BOTH_EDGE; | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | return -EINVAL; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int stm32_lptim_cnt_function_set(struct counter_device *counter, | ||
| 416 | struct counter_count *count, | ||
| 417 | size_t function) | ||
| 418 | { | ||
| 419 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 420 | |||
| 421 | if (stm32_lptim_is_enabled(priv)) | ||
| 422 | return -EBUSY; | ||
| 423 | |||
| 424 | switch (function) { | ||
| 425 | case STM32_LPTIM_COUNTER_INCREASE: | ||
| 426 | priv->quadrature_mode = 0; | ||
| 427 | return 0; | ||
| 428 | case STM32_LPTIM_ENCODER_BOTH_EDGE: | ||
| 429 | priv->quadrature_mode = 1; | ||
| 430 | priv->polarity = STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | return -EINVAL; | ||
| 435 | } | ||
| 436 | |||
| 437 | static ssize_t stm32_lptim_cnt_enable_read(struct counter_device *counter, | ||
| 438 | struct counter_count *count, | ||
| 439 | void *private, char *buf) | ||
| 440 | { | ||
| 441 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 442 | int ret; | ||
| 443 | |||
| 444 | ret = stm32_lptim_is_enabled(priv); | ||
| 445 | if (ret < 0) | ||
| 446 | return ret; | ||
| 447 | |||
| 448 | return scnprintf(buf, PAGE_SIZE, "%u\n", ret); | ||
| 449 | } | ||
| 450 | |||
| 451 | static ssize_t stm32_lptim_cnt_enable_write(struct counter_device *counter, | ||
| 452 | struct counter_count *count, | ||
| 453 | void *private, | ||
| 454 | const char *buf, size_t len) | ||
| 455 | { | ||
| 456 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 457 | bool enable; | ||
| 458 | int ret; | ||
| 459 | |||
| 460 | ret = kstrtobool(buf, &enable); | ||
| 461 | if (ret) | ||
| 462 | return ret; | ||
| 463 | |||
| 464 | /* Check nobody uses the timer, or already disabled/enabled */ | ||
| 465 | ret = stm32_lptim_is_enabled(priv); | ||
| 466 | if ((ret < 0) || (!ret && !enable)) | ||
| 467 | return ret; | ||
| 468 | if (enable && ret) | ||
| 469 | return -EBUSY; | ||
| 470 | |||
| 471 | ret = stm32_lptim_setup(priv, enable); | ||
| 472 | if (ret) | ||
| 473 | return ret; | ||
| 474 | |||
| 475 | ret = stm32_lptim_set_enable_state(priv, enable); | ||
| 476 | if (ret) | ||
| 477 | return ret; | ||
| 478 | |||
| 479 | return len; | ||
| 480 | } | ||
| 481 | |||
| 482 | static ssize_t stm32_lptim_cnt_ceiling_read(struct counter_device *counter, | ||
| 483 | struct counter_count *count, | ||
| 484 | void *private, char *buf) | ||
| 485 | { | ||
| 486 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 487 | |||
| 488 | return stm32_lptim_cnt_get_ceiling(priv, buf); | ||
| 489 | } | ||
| 490 | |||
| 491 | static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter, | ||
| 492 | struct counter_count *count, | ||
| 493 | void *private, | ||
| 494 | const char *buf, size_t len) | ||
| 495 | { | ||
| 496 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 497 | |||
| 498 | return stm32_lptim_cnt_set_ceiling(priv, buf, len); | ||
| 499 | } | ||
| 500 | |||
| 501 | static const struct counter_count_ext stm32_lptim_cnt_ext[] = { | ||
| 502 | { | ||
| 503 | .name = "enable", | ||
| 504 | .read = stm32_lptim_cnt_enable_read, | ||
| 505 | .write = stm32_lptim_cnt_enable_write | ||
| 506 | }, | ||
| 507 | { | ||
| 508 | .name = "ceiling", | ||
| 509 | .read = stm32_lptim_cnt_ceiling_read, | ||
| 510 | .write = stm32_lptim_cnt_ceiling_write | ||
| 511 | }, | ||
| 512 | }; | ||
| 513 | |||
| 514 | static int stm32_lptim_cnt_action_get(struct counter_device *counter, | ||
| 515 | struct counter_count *count, | ||
| 516 | struct counter_synapse *synapse, | ||
| 517 | size_t *action) | ||
| 518 | { | ||
| 519 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 520 | size_t function; | ||
| 521 | int err; | ||
| 522 | |||
| 523 | err = stm32_lptim_cnt_function_get(counter, count, &function); | ||
| 524 | if (err) | ||
| 525 | return err; | ||
| 526 | |||
| 527 | switch (function) { | ||
| 528 | case STM32_LPTIM_COUNTER_INCREASE: | ||
| 529 | /* LP Timer acts as up-counter on input 1 */ | ||
| 530 | if (synapse->signal->id == count->synapses[0].signal->id) | ||
| 531 | *action = priv->polarity; | ||
| 532 | else | ||
| 533 | *action = STM32_LPTIM_SYNAPSE_ACTION_NONE; | ||
| 534 | return 0; | ||
| 535 | case STM32_LPTIM_ENCODER_BOTH_EDGE: | ||
| 536 | *action = priv->polarity; | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | return -EINVAL; | ||
| 541 | } | ||
| 542 | |||
| 543 | static int stm32_lptim_cnt_action_set(struct counter_device *counter, | ||
| 544 | struct counter_count *count, | ||
| 545 | struct counter_synapse *synapse, | ||
| 546 | size_t action) | ||
| 547 | { | ||
| 548 | struct stm32_lptim_cnt *const priv = counter->priv; | ||
| 549 | size_t function; | ||
| 550 | int err; | ||
| 551 | |||
| 552 | if (stm32_lptim_is_enabled(priv)) | ||
| 553 | return -EBUSY; | ||
| 554 | |||
| 555 | err = stm32_lptim_cnt_function_get(counter, count, &function); | ||
| 556 | if (err) | ||
| 557 | return err; | ||
| 558 | |||
| 559 | /* only set polarity when in counter mode (on input 1) */ | ||
| 560 | if (function == STM32_LPTIM_COUNTER_INCREASE | ||
| 561 | && synapse->signal->id == count->synapses[0].signal->id) { | ||
| 562 | switch (action) { | ||
| 563 | case STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE: | ||
| 564 | case STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE: | ||
| 565 | case STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES: | ||
| 566 | priv->polarity = action; | ||
| 567 | return 0; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | return -EINVAL; | ||
| 572 | } | ||
| 573 | |||
| 574 | static const struct counter_ops stm32_lptim_cnt_ops = { | ||
| 575 | .count_read = stm32_lptim_cnt_read, | ||
| 576 | .function_get = stm32_lptim_cnt_function_get, | ||
| 577 | .function_set = stm32_lptim_cnt_function_set, | ||
| 578 | .action_get = stm32_lptim_cnt_action_get, | ||
| 579 | .action_set = stm32_lptim_cnt_action_set, | ||
| 580 | }; | ||
| 581 | |||
| 582 | static struct counter_signal stm32_lptim_cnt_signals[] = { | ||
| 583 | { | ||
| 584 | .id = 0, | ||
| 585 | .name = "Channel 1 Quadrature A" | ||
| 586 | }, | ||
| 587 | { | ||
| 588 | .id = 1, | ||
| 589 | .name = "Channel 1 Quadrature B" | ||
| 590 | } | ||
| 591 | }; | ||
| 592 | |||
| 593 | static struct counter_synapse stm32_lptim_cnt_synapses[] = { | ||
| 594 | { | ||
| 595 | .actions_list = stm32_lptim_cnt_synapse_actions, | ||
| 596 | .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions), | ||
| 597 | .signal = &stm32_lptim_cnt_signals[0] | ||
| 598 | }, | ||
| 599 | { | ||
| 600 | .actions_list = stm32_lptim_cnt_synapse_actions, | ||
| 601 | .num_actions = ARRAY_SIZE(stm32_lptim_cnt_synapse_actions), | ||
| 602 | .signal = &stm32_lptim_cnt_signals[1] | ||
| 603 | } | ||
| 604 | }; | ||
| 605 | |||
| 606 | /* LP timer with encoder */ | ||
| 607 | static struct counter_count stm32_lptim_enc_counts = { | ||
| 608 | .id = 0, | ||
| 609 | .name = "LPTimer Count", | ||
| 610 | .functions_list = stm32_lptim_cnt_functions, | ||
| 611 | .num_functions = ARRAY_SIZE(stm32_lptim_cnt_functions), | ||
| 612 | .synapses = stm32_lptim_cnt_synapses, | ||
| 613 | .num_synapses = ARRAY_SIZE(stm32_lptim_cnt_synapses), | ||
| 614 | .ext = stm32_lptim_cnt_ext, | ||
| 615 | .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext) | ||
| 616 | }; | ||
| 617 | |||
| 618 | /* LP timer without encoder (counter only) */ | ||
| 619 | static struct counter_count stm32_lptim_in1_counts = { | ||
| 620 | .id = 0, | ||
| 621 | .name = "LPTimer Count", | ||
| 622 | .functions_list = stm32_lptim_cnt_functions, | ||
| 623 | .num_functions = 1, | ||
| 624 | .synapses = stm32_lptim_cnt_synapses, | ||
| 625 | .num_synapses = 1, | ||
| 626 | .ext = stm32_lptim_cnt_ext, | ||
| 627 | .num_ext = ARRAY_SIZE(stm32_lptim_cnt_ext) | ||
| 628 | }; | ||
| 629 | |||
| 630 | static int stm32_lptim_cnt_probe(struct platform_device *pdev) | ||
| 631 | { | ||
| 632 | struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); | ||
| 633 | struct stm32_lptim_cnt *priv; | ||
| 634 | struct iio_dev *indio_dev; | ||
| 635 | int ret; | ||
| 636 | |||
| 637 | if (IS_ERR_OR_NULL(ddata)) | ||
| 638 | return -EINVAL; | ||
| 639 | |||
| 640 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); | ||
| 641 | if (!indio_dev) | ||
| 642 | return -ENOMEM; | ||
| 643 | |||
| 644 | priv = iio_priv(indio_dev); | ||
| 645 | priv->dev = &pdev->dev; | ||
| 646 | priv->regmap = ddata->regmap; | ||
| 647 | priv->clk = ddata->clk; | ||
| 648 | priv->ceiling = STM32_LPTIM_MAX_ARR; | ||
| 649 | |||
| 650 | /* Initialize IIO device */ | ||
| 651 | indio_dev->name = dev_name(&pdev->dev); | ||
| 652 | indio_dev->dev.parent = &pdev->dev; | ||
| 653 | indio_dev->dev.of_node = pdev->dev.of_node; | ||
| 654 | indio_dev->info = &stm32_lptim_cnt_iio_info; | ||
| 655 | if (ddata->has_encoder) | ||
| 656 | indio_dev->channels = &stm32_lptim_enc_channels; | ||
| 657 | else | ||
| 658 | indio_dev->channels = &stm32_lptim_cnt_channels; | ||
| 659 | indio_dev->num_channels = 1; | ||
| 660 | |||
| 661 | /* Initialize Counter device */ | ||
| 662 | priv->counter.name = dev_name(&pdev->dev); | ||
| 663 | priv->counter.parent = &pdev->dev; | ||
| 664 | priv->counter.ops = &stm32_lptim_cnt_ops; | ||
| 665 | if (ddata->has_encoder) { | ||
| 666 | priv->counter.counts = &stm32_lptim_enc_counts; | ||
| 667 | priv->counter.num_signals = ARRAY_SIZE(stm32_lptim_cnt_signals); | ||
| 668 | } else { | ||
| 669 | priv->counter.counts = &stm32_lptim_in1_counts; | ||
| 670 | priv->counter.num_signals = 1; | ||
| 671 | } | ||
| 672 | priv->counter.num_counts = 1; | ||
| 673 | priv->counter.signals = stm32_lptim_cnt_signals; | ||
| 674 | priv->counter.priv = priv; | ||
| 675 | |||
| 676 | platform_set_drvdata(pdev, priv); | ||
| 677 | |||
| 678 | ret = devm_iio_device_register(&pdev->dev, indio_dev); | ||
| 679 | if (ret) | ||
| 680 | return ret; | ||
| 681 | |||
| 682 | return devm_counter_register(&pdev->dev, &priv->counter); | ||
| 683 | } | ||
| 684 | |||
| 685 | #ifdef CONFIG_PM_SLEEP | ||
| 686 | static int stm32_lptim_cnt_suspend(struct device *dev) | ||
| 687 | { | ||
| 688 | struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); | ||
| 689 | int ret; | ||
| 690 | |||
| 691 | /* Only take care of enabled counter: don't disturb other MFD child */ | ||
| 692 | if (priv->enabled) { | ||
| 693 | ret = stm32_lptim_setup(priv, 0); | ||
| 694 | if (ret) | ||
| 695 | return ret; | ||
| 696 | |||
| 697 | ret = stm32_lptim_set_enable_state(priv, 0); | ||
| 698 | if (ret) | ||
| 699 | return ret; | ||
| 700 | |||
| 701 | /* Force enable state for later resume */ | ||
| 702 | priv->enabled = true; | ||
| 703 | } | ||
| 704 | |||
| 705 | return pinctrl_pm_select_sleep_state(dev); | ||
| 706 | } | ||
| 707 | |||
| 708 | static int stm32_lptim_cnt_resume(struct device *dev) | ||
| 709 | { | ||
| 710 | struct stm32_lptim_cnt *priv = dev_get_drvdata(dev); | ||
| 711 | int ret; | ||
| 712 | |||
| 713 | ret = pinctrl_pm_select_default_state(dev); | ||
| 714 | if (ret) | ||
| 715 | return ret; | ||
| 716 | |||
| 717 | if (priv->enabled) { | ||
| 718 | priv->enabled = false; | ||
| 719 | ret = stm32_lptim_setup(priv, 1); | ||
| 720 | if (ret) | ||
| 721 | return ret; | ||
| 722 | |||
| 723 | ret = stm32_lptim_set_enable_state(priv, 1); | ||
| 724 | if (ret) | ||
| 725 | return ret; | ||
| 726 | } | ||
| 727 | |||
| 728 | return 0; | ||
| 729 | } | ||
| 730 | #endif | ||
| 731 | |||
| 732 | static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend, | ||
| 733 | stm32_lptim_cnt_resume); | ||
| 734 | |||
| 735 | static const struct of_device_id stm32_lptim_cnt_of_match[] = { | ||
| 736 | { .compatible = "st,stm32-lptimer-counter", }, | ||
| 737 | {}, | ||
| 738 | }; | ||
| 739 | MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match); | ||
| 740 | |||
| 741 | static struct platform_driver stm32_lptim_cnt_driver = { | ||
| 742 | .probe = stm32_lptim_cnt_probe, | ||
| 743 | .driver = { | ||
| 744 | .name = "stm32-lptimer-counter", | ||
| 745 | .of_match_table = stm32_lptim_cnt_of_match, | ||
| 746 | .pm = &stm32_lptim_cnt_pm_ops, | ||
| 747 | }, | ||
| 748 | }; | ||
| 749 | module_platform_driver(stm32_lptim_cnt_driver); | ||
| 750 | |||
| 751 | MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); | ||
| 752 | MODULE_ALIAS("platform:stm32-lptimer-counter"); | ||
| 753 | MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver"); | ||
| 754 | MODULE_LICENSE("GPL v2"); | ||
| @@ -0,0 +1,390 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * STM32 Timer Encoder and Counter driver | ||
| 4 | * | ||
| 5 | * Copyright (C) STMicroelectronics 2018 | ||
| 6 | * | ||
| 7 | * Author: Benjamin Gaignard <benjamin.gaignard@st.com> | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | #include <linux/counter.h> | ||
| 11 | #include <linux/iio/iio.h> | ||
| 12 | #include <linux/iio/types.h> | ||
| 13 | #include <linux/mfd/stm32-timers.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | |||
| 17 | #define TIM_CCMR_CCXS (BIT(8) | BIT(0)) | ||
| 18 | #define TIM_CCMR_MASK (TIM_CCMR_CC1S | TIM_CCMR_CC2S | \ | ||
| 19 | TIM_CCMR_IC1F | TIM_CCMR_IC2F) | ||
| 20 | #define TIM_CCER_MASK (TIM_CCER_CC1P | TIM_CCER_CC1NP | \ | ||
| 21 | TIM_CCER_CC2P | TIM_CCER_CC2NP) | ||
| 22 | |||
| 23 | struct stm32_timer_cnt { | ||
| 24 | struct counter_device counter; | ||
| 25 | struct regmap *regmap; | ||
| 26 | struct clk *clk; | ||
| 27 | u32 ceiling; | ||
| 28 | }; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * stm32_count_function - enumerates stm32 timer counter encoder modes | ||
| 32 | * @STM32_COUNT_SLAVE_MODE_DISABLED: counts on internal clock when CEN=1 | ||
| 33 | * @STM32_COUNT_ENCODER_MODE_1: counts TI1FP1 edges, depending on TI2FP2 level | ||
| 34 | * @STM32_COUNT_ENCODER_MODE_2: counts TI2FP2 edges, depending on TI1FP1 level | ||
| 35 | * @STM32_COUNT_ENCODER_MODE_3: counts on both TI1FP1 and TI2FP2 edges | ||
| 36 | */ | ||
| 37 | enum stm32_count_function { | ||
| 38 | STM32_COUNT_SLAVE_MODE_DISABLED = -1, | ||
| 39 | STM32_COUNT_ENCODER_MODE_1, | ||
| 40 | STM32_COUNT_ENCODER_MODE_2, | ||
| 41 | STM32_COUNT_ENCODER_MODE_3, | ||
| 42 | }; | ||
| 43 | |||
| 44 | static enum counter_count_function stm32_count_functions[] = { | ||
| 45 | [STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A, | ||
| 46 | [STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B, | ||
| 47 | [STM32_COUNT_ENCODER_MODE_3] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static int stm32_count_read(struct counter_device *counter, | ||
| 51 | struct counter_count *count, | ||
| 52 | struct counter_count_read_value *val) | ||
| 53 | { | ||
| 54 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 55 | u32 cnt; | ||
| 56 | |||
| 57 | regmap_read(priv->regmap, TIM_CNT, &cnt); | ||
| 58 | counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt); | ||
| 59 | |||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int stm32_count_write(struct counter_device *counter, | ||
| 64 | struct counter_count *count, | ||
| 65 | struct counter_count_write_value *val) | ||
| 66 | { | ||
| 67 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 68 | u32 cnt; | ||
| 69 | int err; | ||
| 70 | |||
| 71 | err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val); | ||
| 72 | if (err) | ||
| 73 | return err; | ||
| 74 | |||
| 75 | if (cnt > priv->ceiling) | ||
| 76 | return -EINVAL; | ||
| 77 | |||
| 78 | return regmap_write(priv->regmap, TIM_CNT, cnt); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int stm32_count_function_get(struct counter_device *counter, | ||
| 82 | struct counter_count *count, | ||
| 83 | size_t *function) | ||
| 84 | { | ||
| 85 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 86 | u32 smcr; | ||
| 87 | |||
| 88 | regmap_read(priv->regmap, TIM_SMCR, &smcr); | ||
| 89 | |||
| 90 | switch (smcr & TIM_SMCR_SMS) { | ||
| 91 | case 1: | ||
| 92 | *function = STM32_COUNT_ENCODER_MODE_1; | ||
| 93 | return 0; | ||
| 94 | case 2: | ||
| 95 | *function = STM32_COUNT_ENCODER_MODE_2; | ||
| 96 | return 0; | ||
| 97 | case 3: | ||
| 98 | *function = STM32_COUNT_ENCODER_MODE_3; | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | return -EINVAL; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int stm32_count_function_set(struct counter_device *counter, | ||
| 106 | struct counter_count *count, | ||
| 107 | size_t function) | ||
| 108 | { | ||
| 109 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 110 | u32 cr1, sms; | ||
| 111 | |||
| 112 | switch (function) { | ||
| 113 | case STM32_COUNT_ENCODER_MODE_1: | ||
| 114 | sms = 1; | ||
| 115 | break; | ||
| 116 | case STM32_COUNT_ENCODER_MODE_2: | ||
| 117 | sms = 2; | ||
| 118 | break; | ||
| 119 | case STM32_COUNT_ENCODER_MODE_3: | ||
| 120 | sms = 3; | ||
| 121 | break; | ||
| 122 | default: | ||
| 123 | sms = 0; | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | |||
| 127 | /* Store enable status */ | ||
| 128 | regmap_read(priv->regmap, TIM_CR1, &cr1); | ||
| 129 | |||
| 130 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); | ||
| 131 | |||
| 132 | /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ | ||
| 133 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); | ||
| 134 | regmap_write(priv->regmap, TIM_ARR, priv->ceiling); | ||
| 135 | |||
| 136 | regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); | ||
| 137 | |||
| 138 | /* Make sure that registers are updated */ | ||
| 139 | regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); | ||
| 140 | |||
| 141 | /* Restore the enable status */ | ||
| 142 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, cr1); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static ssize_t stm32_count_direction_read(struct counter_device *counter, | ||
| 148 | struct counter_count *count, | ||
| 149 | void *private, char *buf) | ||
| 150 | { | ||
| 151 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 152 | const char *direction; | ||
| 153 | u32 cr1; | ||
| 154 | |||
| 155 | regmap_read(priv->regmap, TIM_CR1, &cr1); | ||
| 156 | direction = (cr1 & TIM_CR1_DIR) ? "backward" : "forward"; | ||
| 157 | |||
| 158 | return scnprintf(buf, PAGE_SIZE, "%s\n", direction); | ||
| 159 | } | ||
| 160 | |||
| 161 | static ssize_t stm32_count_ceiling_read(struct counter_device *counter, | ||
| 162 | struct counter_count *count, | ||
| 163 | void *private, char *buf) | ||
| 164 | { | ||
| 165 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 166 | u32 arr; | ||
| 167 | |||
| 168 | regmap_read(priv->regmap, TIM_ARR, &arr); | ||
| 169 | |||
| 170 | return snprintf(buf, PAGE_SIZE, "%u\n", arr); | ||
| 171 | } | ||
| 172 | |||
| 173 | static ssize_t stm32_count_ceiling_write(struct counter_device *counter, | ||
| 174 | struct counter_count *count, | ||
| 175 | void *private, | ||
| 176 | const char *buf, size_t len) | ||
| 177 | { | ||
| 178 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 179 | unsigned int ceiling; | ||
| 180 | int ret; | ||
| 181 | |||
| 182 | ret = kstrtouint(buf, 0, &ceiling); | ||
| 183 | if (ret) | ||
| 184 | return ret; | ||
| 185 | |||
| 186 | /* TIMx_ARR register shouldn't be buffered (ARPE=0) */ | ||
| 187 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0); | ||
| 188 | regmap_write(priv->regmap, TIM_ARR, ceiling); | ||
| 189 | |||
| 190 | priv->ceiling = ceiling; | ||
| 191 | return len; | ||
| 192 | } | ||
| 193 | |||
| 194 | static ssize_t stm32_count_enable_read(struct counter_device *counter, | ||
| 195 | struct counter_count *count, | ||
| 196 | void *private, char *buf) | ||
| 197 | { | ||
| 198 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 199 | u32 cr1; | ||
| 200 | |||
| 201 | regmap_read(priv->regmap, TIM_CR1, &cr1); | ||
| 202 | |||
| 203 | return scnprintf(buf, PAGE_SIZE, "%d\n", (bool)(cr1 & TIM_CR1_CEN)); | ||
| 204 | } | ||
| 205 | |||
| 206 | static ssize_t stm32_count_enable_write(struct counter_device *counter, | ||
| 207 | struct counter_count *count, | ||
| 208 | void *private, | ||
| 209 | const char *buf, size_t len) | ||
| 210 | { | ||
| 211 | struct stm32_timer_cnt *const priv = counter->priv; | ||
| 212 | int err; | ||
| 213 | u32 cr1; | ||
| 214 | bool enable; | ||
| 215 | |||
| 216 | err = kstrtobool(buf, &enable); | ||
| 217 | if (err) | ||
| 218 | return err; | ||
| 219 | |||
| 220 | if (enable) { | ||
| 221 | regmap_read(priv->regmap, TIM_CR1, &cr1); | ||
| 222 | if (!(cr1 & TIM_CR1_CEN)) | ||
| 223 | clk_enable(priv->clk); | ||
| 224 | |||
| 225 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, | ||
| 226 | TIM_CR1_CEN); | ||
| 227 | } else { | ||
| 228 | regmap_read(priv->regmap, TIM_CR1, &cr1); | ||
| 229 | regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); | ||
| 230 | if (cr1 & TIM_CR1_CEN) | ||
| 231 | clk_disable(priv->clk); | ||
| 232 | } | ||
| 233 | |||
| 234 | return len; | ||
| 235 | } | ||
| 236 | |||
| 237 | static const struct counter_count_ext stm32_count_ext[] = { | ||
| 238 | { | ||
| 239 | .name = "direction", | ||
| 240 | .read = stm32_count_direction_read, | ||
| 241 | }, | ||
| 242 | { | ||
| 243 | .name = "enable", | ||
| 244 | .read = stm32_count_enable_read, | ||
| 245 | .write = stm32_count_enable_write | ||
| 246 | }, | ||
| 247 | { | ||
| 248 | .name = "ceiling", | ||
| 249 | .read = stm32_count_ceiling_read, | ||
| 250 | .write = stm32_count_ceiling_write | ||
| 251 | }, | ||
| 252 | }; | ||
| 253 | |||
| 254 | enum stm32_synapse_action { | ||
| 255 | STM32_SYNAPSE_ACTION_NONE, | ||
| 256 | STM32_SYNAPSE_ACTION_BOTH_EDGES | ||
| 257 | }; | ||
| 258 | |||
| 259 | static enum counter_synapse_action stm32_synapse_actions[] = { | ||
| 260 | [STM32_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, | ||
| 261 | [STM32_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES | ||
| 262 | }; | ||
| 263 | |||
| 264 | static int stm32_action_get(struct counter_device *counter, | ||
| 265 | struct counter_count *count, | ||
| 266 | struct counter_synapse *synapse, | ||
| 267 | size_t *action) | ||
| 268 | { | ||
| 269 | size_t function; | ||
| 270 | int err; | ||
| 271 | |||
| 272 | /* Default action mode (e.g. STM32_COUNT_SLAVE_MODE_DISABLED) */ | ||
| 273 | *action = STM32_SYNAPSE_ACTION_NONE; | ||
| 274 | |||
| 275 | err = stm32_count_function_get(counter, count, &function); | ||
| 276 | if (err) | ||
| 277 | return 0; | ||
| 278 | |||
| 279 | switch (function) { | ||
| 280 | case STM32_COUNT_ENCODER_MODE_1: | ||
| 281 | /* counts up/down on TI1FP1 edge depending on TI2FP2 level */ | ||
| 282 | if (synapse->signal->id == count->synapses[0].signal->id) | ||
| 283 | *action = STM32_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 284 | break; | ||
| 285 | case STM32_COUNT_ENCODER_MODE_2: | ||
| 286 | /* counts up/down on TI2FP2 edge depending on TI1FP1 level */ | ||
| 287 | if (synapse->signal->id == count->synapses[1].signal->id) | ||
| 288 | *action = STM32_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 289 | break; | ||
| 290 | case STM32_COUNT_ENCODER_MODE_3: | ||
| 291 | /* counts up/down on both TI1FP1 and TI2FP2 edges */ | ||
| 292 | *action = STM32_SYNAPSE_ACTION_BOTH_EDGES; | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | |||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | static const struct counter_ops stm32_timer_cnt_ops = { | ||
| 300 | .count_read = stm32_count_read, | ||
| 301 | .count_write = stm32_count_write, | ||
| 302 | .function_get = stm32_count_function_get, | ||
| 303 | .function_set = stm32_count_function_set, | ||
| 304 | .action_get = stm32_action_get, | ||
| 305 | }; | ||
| 306 | |||
| 307 | static struct counter_signal stm32_signals[] = { | ||
| 308 | { | ||
| 309 | .id = 0, | ||
| 310 | .name = "Channel 1 Quadrature A" | ||
| 311 | }, | ||
| 312 | { | ||
| 313 | .id = 1, | ||
| 314 | .name = "Channel 1 Quadrature B" | ||
| 315 | } | ||
| 316 | }; | ||
| 317 | |||
| 318 | static struct counter_synapse stm32_count_synapses[] = { | ||
| 319 | { | ||
| 320 | .actions_list = stm32_synapse_actions, | ||
| 321 | .num_actions = ARRAY_SIZE(stm32_synapse_actions), | ||
| 322 | .signal = &stm32_signals[0] | ||
| 323 | }, | ||
| 324 | { | ||
| 325 | .actions_list = stm32_synapse_actions, | ||
| 326 | .num_actions = ARRAY_SIZE(stm32_synapse_actions), | ||
| 327 | .signal = &stm32_signals[1] | ||
| 328 | } | ||
| 329 | }; | ||
| 330 | |||
| 331 | static struct counter_count stm32_counts = { | ||
| 332 | .id = 0, | ||
| 333 | .name = "Channel 1 Count", | ||
| 334 | .functions_list = stm32_count_functions, | ||
| 335 | .num_functions = ARRAY_SIZE(stm32_count_functions), | ||
| 336 | .synapses = stm32_count_synapses, | ||
| 337 | .num_synapses = ARRAY_SIZE(stm32_count_synapses), | ||
| 338 | .ext = stm32_count_ext, | ||
| 339 | .num_ext = ARRAY_SIZE(stm32_count_ext) | ||
| 340 | }; | ||
| 341 | |||
| 342 | static int stm32_timer_cnt_probe(struct platform_device *pdev) | ||
| 343 | { | ||
| 344 | struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent); | ||
| 345 | struct device *dev = &pdev->dev; | ||
| 346 | struct stm32_timer_cnt *priv; | ||
| 347 | |||
| 348 | if (IS_ERR_OR_NULL(ddata)) | ||
| 349 | return -EINVAL; | ||
| 350 | |||
| 351 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 352 | if (!priv) | ||
| 353 | return -ENOMEM; | ||
| 354 | |||
| 355 | priv->regmap = ddata->regmap; | ||
| 356 | priv->clk = ddata->clk; | ||
| 357 | priv->ceiling = ddata->max_arr; | ||
| 358 | |||
| 359 | priv->counter.name = dev_name(dev); | ||
| 360 | priv->counter.parent = dev; | ||
| 361 | priv->counter.ops = &stm32_timer_cnt_ops; | ||
| 362 | priv->counter.counts = &stm32_counts; | ||
| 363 | priv->counter.num_counts = 1; | ||
| 364 | priv->counter.signals = stm32_signals; | ||
| 365 | priv->counter.num_signals = ARRAY_SIZE(stm32_signals); | ||
| 366 | priv->counter.priv = priv; | ||
| 367 | |||
| 368 | /* Register Counter device */ | ||
| 369 | return devm_counter_register(dev, &priv->counter); | ||
| 370 | } | ||
| 371 | |||
| 372 | static const struct of_device_id stm32_timer_cnt_of_match[] = { | ||
| 373 | { .compatible = "st,stm32-timer-counter", }, | ||
| 374 | {}, | ||
| 375 | }; | ||
| 376 | MODULE_DEVICE_TABLE(of, stm32_timer_cnt_of_match); | ||
| 377 | |||
| 378 | static struct platform_driver stm32_timer_cnt_driver = { | ||
| 379 | .probe = stm32_timer_cnt_probe, | ||
| 380 | .driver = { | ||
| 381 | .name = "stm32-timer-counter", | ||
| 382 | .of_match_table = stm32_timer_cnt_of_match, | ||
| 383 | }, | ||
| 384 | }; | ||
| 385 | module_platform_driver(stm32_timer_cnt_driver); | ||
| 386 | |||
| 387 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); | ||
| 388 | MODULE_ALIAS("platform:stm32-timer-counter"); | ||
| 389 | MODULE_DESCRIPTION("STMicroelectronics STM32 TIMER counter driver"); | ||
| 390 | MODULE_LICENSE("GPL v2"); | ||
| @@ -38,28 +38,28 @@ config IIO_TRIGGER · 37 unmodified lines | |||
| 38 | data now' interrupt. | 38 | data now' interrupt. |
| 39 | 39 | ||
| 40 | config IIO_CONSUMERS_PER_TRIGGER | 40 | config IIO_CONSUMERS_PER_TRIGGER |
| 41 | int "Maximum number of consumers per trigger" | 41 | int "Maximum number of consumers per trigger" |
| 42 | depends on IIO_TRIGGER | 42 | depends on IIO_TRIGGER |
| 43 | default "2" | 43 | default "2" |
| 44 | help | 44 | help |
| 45 | This value controls the maximum number of consumers that a | 45 | This value controls the maximum number of consumers that a |
| 46 | given trigger may handle. Default is 2. | 46 | given trigger may handle. Default is 2. |
| 47 | 47 | ||
| 48 | config IIO_SW_DEVICE | 48 | config IIO_SW_DEVICE |
| 49 | tristate "Enable software IIO device support" | 49 | tristate "Enable software IIO device support" |
| 50 | select IIO_CONFIGFS | 50 | select IIO_CONFIGFS |
| 51 | help | 51 | help |
| 52 | Provides IIO core support for software devices. A software | 52 | Provides IIO core support for software devices. A software |
| 53 | device can be created via configfs or directly by a driver | 53 | device can be created via configfs or directly by a driver |
| 54 | using the API provided. | 54 | using the API provided. |
| 55 | 55 | ||
| 56 | config IIO_SW_TRIGGER | 56 | config IIO_SW_TRIGGER |
| 57 | tristate "Enable software triggers support" | 57 | tristate "Enable software triggers support" |
| 58 | select IIO_CONFIGFS | 58 | select IIO_CONFIGFS |
| 59 | help | 59 | help |
| 60 | Provides IIO core support for software triggers. A software | 60 | Provides IIO core support for software triggers. A software |
| 61 | trigger can be created via configfs or directly by a driver | 61 | trigger can be created via configfs or directly by a driver |
| 62 | using the API provided. | 62 | using the API provided. |
| 63 | 63 | ||
| 64 | config IIO_TRIGGERED_EVENT | 64 | config IIO_TRIGGERED_EVENT |
| 65 | tristate | 65 | tristate |
| @@ -73,7 +73,6 @@ source "drivers/iio/afe/Kconfig" · 7 unmodified lines | |||
| 73 | source "drivers/iio/amplifiers/Kconfig" | 73 | source "drivers/iio/amplifiers/Kconfig" |
| 74 | source "drivers/iio/chemical/Kconfig" | 74 | source "drivers/iio/chemical/Kconfig" |
| 75 | source "drivers/iio/common/Kconfig" | 75 | source "drivers/iio/common/Kconfig" |
| 76 | source "drivers/iio/counter/Kconfig" | ||
| 77 | source "drivers/iio/dac/Kconfig" | 76 | source "drivers/iio/dac/Kconfig" |
| 78 | source "drivers/iio/dummy/Kconfig" | 77 | source "drivers/iio/dummy/Kconfig" |
| 79 | source "drivers/iio/frequency/Kconfig" | 78 | source "drivers/iio/frequency/Kconfig" |
| @@ -20,7 +20,6 @@ obj-y += amplifiers/ · 19 unmodified lines | |||
| 20 | obj-y += buffer/ | 20 | obj-y += buffer/ |
| 21 | obj-y += chemical/ | 21 | obj-y += chemical/ |
| 22 | obj-y += common/ | 22 | obj-y += common/ |
| 23 | obj-y += counter/ | ||
| 24 | obj-y += dac/ | 23 | obj-y += dac/ |
| 25 | obj-y += dummy/ | 24 | obj-y += dummy/ |
| 26 | obj-y += gyro/ | 25 | obj-y += gyro/ |
| @@ -6,28 +6,28 @@ · 5 unmodified lines | |||
| 6 | menu "Accelerometers" | 6 | menu "Accelerometers" |
| 7 | 7 | ||
| 8 | config ADIS16201 | 8 | config ADIS16201 |
| 9 | tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" | 9 | tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" |
| 10 | depends on SPI | 10 | depends on SPI |
| 11 | select IIO_ADIS_LIB | 11 | select IIO_ADIS_LIB |
| 12 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER | 12 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER |
| 13 | help | 13 | help |
| 14 | Say Y here to build support for Analog Devices adis16201 dual-axis | 14 | Say Y here to build support for Analog Devices adis16201 dual-axis |
| 15 | digital inclinometer and accelerometer. | 15 | digital inclinometer and accelerometer. |
| 16 | 16 | ||
| 17 | To compile this driver as a module, say M here: the module will | 17 | To compile this driver as a module, say M here: the module will |
| 18 | be called adis16201. | 18 | be called adis16201. |
| 19 | 19 | ||
| 20 | config ADIS16209 | 20 | config ADIS16209 |
| 21 | tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" | 21 | tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" |
| 22 | depends on SPI | 22 | depends on SPI |
| 23 | select IIO_ADIS_LIB | 23 | select IIO_ADIS_LIB |
| 24 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER | 24 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER |
| 25 | help | 25 | help |
| 26 | Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer | 26 | Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer |
| 27 | and accelerometer. | 27 | and accelerometer. |
| 28 | 28 | ||
| 29 | To compile this driver as a module, say M here: the module will be | 29 | To compile this driver as a module, say M here: the module will be |
| 30 | called adis16209. | 30 | called adis16209. |
| 31 | 31 | ||
| 32 | config ADXL345 | 32 | config ADXL345 |
| 33 | tristate | 33 | tristate |
| @@ -100,16 +100,16 @@ config BMA180 · 66 unmodified lines | |||
| 100 | module will be called bma180. | 100 | module will be called bma180. |
| 101 | 101 | ||
| 102 | config BMA220 | 102 | config BMA220 |
| 103 | tristate "Bosch BMA220 3-Axis Accelerometer Driver" | 103 | tristate "Bosch BMA220 3-Axis Accelerometer Driver" |
| 104 | depends on SPI | 104 | depends on SPI |
| 105 | select IIO_BUFFER | 105 | select IIO_BUFFER |
| 106 | select IIO_TRIGGERED_BUFFER | 106 | select IIO_TRIGGERED_BUFFER |
| 107 | help | 107 | help |
| 108 | Say yes here to add support for the Bosch BMA220 triaxial | 108 | Say yes here to add support for the Bosch BMA220 triaxial |
| 109 | acceleration sensor. | 109 | acceleration sensor. |
| 110 | 110 | ||
| 111 | To compile this driver as a module, choose M here: the | 111 | To compile this driver as a module, choose M here: the |
| 112 | module will be called bma220_spi. | 112 | module will be called bma220_spi. |
| 113 | 113 | ||
| 114 | config BMC150_ACCEL | 114 | config BMC150_ACCEL |
| 115 | tristate "Bosch BMC150 Accelerometer Driver" | 115 | tristate "Bosch BMC150 Accelerometer Driver" |
| @@ -223,7 +223,7 @@ config IIO_ST_ACCEL_3AXIS · 107 unmodified lines | |||
| 223 | Say yes here to build support for STMicroelectronics accelerometers: | 223 | Say yes here to build support for STMicroelectronics accelerometers: |
| 224 | LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, | 224 | LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, |
| 225 | LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL, | 225 | LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL, |
| 226 | LNG2DM, LIS3DE | 226 | LNG2DM, LIS3DE, LIS2DE12 |
| 227 | 227 | ||
| 228 | This driver can also be built as a module. If so, these modules | 228 | This driver can also be built as a module. If so, these modules |
| 229 | will be created: | 229 | will be created: |
| @@ -116,6 +116,7 @@ struct bma180_data { · 115 unmodified lines | |||
| 116 | struct i2c_client *client; | 116 | struct i2c_client *client; |
| 117 | struct iio_trigger *trig; | 117 | struct iio_trigger *trig; |
| 118 | const struct bma180_part_info *part_info; | 118 | const struct bma180_part_info *part_info; |
| 119 | struct iio_mount_matrix orientation; | ||
| 119 | struct mutex mutex; | 120 | struct mutex mutex; |
| 120 | bool sleep_state; | 121 | bool sleep_state; |
| 121 | int scale; | 122 | int scale; |
| @@ -561,6 +562,15 @@ static int bma180_set_power_mode(struct iio_dev *indio_dev, · 439 unmodified lines | |||
| 561 | return ret; | 562 | return ret; |
| 562 | } | 563 | } |
| 563 | 564 | ||
| 565 | static const struct iio_mount_matrix * | ||
| 566 | bma180_accel_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 567 | const struct iio_chan_spec *chan) | ||
| 568 | { | ||
| 569 | struct bma180_data *data = iio_priv(indio_dev); | ||
| 570 | |||
| 571 | return &data->orientation; | ||
| 572 | } | ||
| 573 | |||
| 564 | static const struct iio_enum bma180_power_mode_enum = { | 574 | static const struct iio_enum bma180_power_mode_enum = { |
| 565 | .items = bma180_power_modes, | 575 | .items = bma180_power_modes, |
| 566 | .num_items = ARRAY_SIZE(bma180_power_modes), | 576 | .num_items = ARRAY_SIZE(bma180_power_modes), |
| @@ -571,7 +581,8 @@ static const struct iio_enum bma180_power_mode_enum = { · 4 unmodified lines | |||
| 571 | static const struct iio_chan_spec_ext_info bma180_ext_info[] = { | 581 | static const struct iio_chan_spec_ext_info bma180_ext_info[] = { |
| 572 | IIO_ENUM("power_mode", true, &bma180_power_mode_enum), | 582 | IIO_ENUM("power_mode", true, &bma180_power_mode_enum), |
| 573 | IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum), | 583 | IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum), |
| 574 | { }, | 584 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma180_accel_get_mount_matrix), |
| 585 | { } | ||
| 575 | }; | 586 | }; |
| 576 | 587 | ||
| 577 | #define BMA180_ACC_CHANNEL(_axis, _bits) { \ | 588 | #define BMA180_ACC_CHANNEL(_axis, _bits) { \ |
| @@ -722,6 +733,11 @@ static int bma180_probe(struct i2c_client *client, · 144 unmodified lines | |||
| 722 | chip = id->driver_data; | 733 | chip = id->driver_data; |
| 723 | data->part_info = &bma180_part_info[chip]; | 734 | data->part_info = &bma180_part_info[chip]; |
| 724 | 735 | ||
| 736 | ret = iio_read_mount_matrix(&client->dev, "mount-matrix", | ||
| 737 | &data->orientation); | ||
| 738 | if (ret) | ||
| 739 | return ret; | ||
| 740 | |||
| 725 | ret = data->part_info->chip_config(data); | 741 | ret = data->part_info->chip_config(data); |
| 726 | if (ret < 0) | 742 | if (ret < 0) |
| 727 | goto err_chip_disable; | 743 | goto err_chip_disable; |
| @@ -204,6 +204,7 @@ struct bmc150_accel_data { · 203 unmodified lines | |||
| 204 | int ev_enable_state; | 204 | int ev_enable_state; |
| 205 | int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ | 205 | int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ |
| 206 | const struct bmc150_accel_chip_info *chip_info; | 206 | const struct bmc150_accel_chip_info *chip_info; |
| 207 | struct iio_mount_matrix orientation; | ||
| 207 | }; | 208 | }; |
| 208 | 209 | ||
| 209 | static const struct { | 210 | static const struct { |
| @@ -393,7 +394,7 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) · 183 unmodified lines | |||
| 393 | 394 | ||
| 394 | if (ret < 0) { | 395 | if (ret < 0) { |
| 395 | dev_err(dev, | 396 | dev_err(dev, |
| 396 | "Failed: bmc150_accel_set_power_state for %d\n", on); | 397 | "Failed: %s for %d\n", __func__, on); |
| 397 | if (on) | 398 | if (on) |
| 398 | pm_runtime_put_noidle(dev); | 399 | pm_runtime_put_noidle(dev); |
| 399 | 400 | ||
| @@ -796,6 +797,20 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev, · 396 unmodified lines | |||
| 796 | return sprintf(buf, "%d\n", state); | 797 | return sprintf(buf, "%d\n", state); |
| 797 | } | 798 | } |
| 798 | 799 | ||
| 800 | static const struct iio_mount_matrix * | ||
| 801 | bmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 802 | const struct iio_chan_spec *chan) | ||
| 803 | { | ||
| 804 | struct bmc150_accel_data *data = iio_priv(indio_dev); | ||
| 805 | |||
| 806 | return &data->orientation; | ||
| 807 | } | ||
| 808 | |||
| 809 | static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = { | ||
| 810 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix), | ||
| 811 | { } | ||
| 812 | }; | ||
| 813 | |||
| 799 | static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); | 814 | static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); |
| 800 | static IIO_CONST_ATTR(hwfifo_watermark_max, | 815 | static IIO_CONST_ATTR(hwfifo_watermark_max, |
| 801 | __stringify(BMC150_ACCEL_FIFO_LENGTH)); | 816 | __stringify(BMC150_ACCEL_FIFO_LENGTH)); |
| @@ -978,6 +993,7 @@ static const struct iio_event_spec bmc150_accel_event = { · 176 unmodified lines | |||
| 978 | .shift = 16 - (bits), \ | 993 | .shift = 16 - (bits), \ |
| 979 | .endianness = IIO_LE, \ | 994 | .endianness = IIO_LE, \ |
| 980 | }, \ | 995 | }, \ |
| 996 | .ext_info = bmc150_accel_ext_info, \ | ||
| 981 | .event_spec = &bmc150_accel_event, \ | 997 | .event_spec = &bmc150_accel_event, \ |
| 982 | .num_event_specs = 1 \ | 998 | .num_event_specs = 1 \ |
| 983 | } | 999 | } |
| @@ -1555,6 +1571,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, · 571 unmodified lines | |||
| 1555 | 1571 | ||
| 1556 | data->regmap = regmap; | 1572 | data->regmap = regmap; |
| 1557 | 1573 | ||
| 1574 | ret = iio_read_mount_matrix(dev, "mount-matrix", | ||
| 1575 | &data->orientation); | ||
| 1576 | if (ret) | ||
| 1577 | return ret; | ||
| 1578 | |||
| 1558 | ret = bmc150_accel_chip_init(data); | 1579 | ret = bmc150_accel_chip_init(data); |
| 1559 | if (ret < 0) | 1580 | if (ret < 0) |
| 1560 | return ret; | 1581 | return ret; |
| @@ -1,17 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * Driver for older Chrome OS EC accelerometer | 3 | * Driver for older Chrome OS EC accelerometer |
| 3 | * | 4 | * |
| 4 | * Copyright 2017 Google, Inc | 5 | * Copyright 2017 Google, Inc |
| 5 | * | 6 | * |
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the memory mapper cros-ec interface to communicate | 7 | * This driver uses the memory mapper cros-ec interface to communicate |
| 16 | * with the Chrome OS EC about accelerometer data. | 8 | * with the Chrome OS EC about accelerometer data. |
| 17 | * Accelerometer access is presented through iio sysfs. | 9 | * Accelerometer access is presented through iio sysfs. |
| @@ -29,7 +21,6 @@ · 11 unmodified lines | |||
| 29 | #include <linux/mfd/cros_ec_commands.h> | 21 | #include <linux/mfd/cros_ec_commands.h> |
| 30 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 31 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 32 | #include <linux/sysfs.h> | ||
| 33 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 34 | 25 | ||
| 35 | #define DRV_NAME "cros-ec-accel-legacy" | 26 | #define DRV_NAME "cros-ec-accel-legacy" |
| @@ -353,7 +344,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) · 317 unmodified lines | |||
| 353 | struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); | 344 | struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); |
| 354 | struct iio_dev *indio_dev; | 345 | struct iio_dev *indio_dev; |
| 355 | struct cros_ec_accel_legacy_state *state; | 346 | struct cros_ec_accel_legacy_state *state; |
| 356 | int ret, i; | 347 | int ret; |
| 357 | 348 | ||
| 358 | if (!ec || !ec->ec_dev) { | 349 | if (!ec || !ec->ec_dev) { |
| 359 | dev_warn(&pdev->dev, "No EC device found.\n"); | 350 | dev_warn(&pdev->dev, "No EC device found.\n"); |
| @@ -381,20 +372,17 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) · 21 unmodified lines | |||
| 381 | * Present the channel using HTML5 standard: | 372 | * Present the channel using HTML5 standard: |
| 382 | * need to invert X and Y and invert some lid axis. | 373 | * need to invert X and Y and invert some lid axis. |
| 383 | */ | 374 | */ |
| 384 | for (i = X ; i < MAX_AXIS; i++) { | 375 | ec_accel_channels[X].scan_index = Y; |
| 385 | switch (i) { | 376 | ec_accel_channels[Y].scan_index = X; |
| 386 | case X: | 377 | ec_accel_channels[Z].scan_index = Z; |
| 387 | ec_accel_channels[X].scan_index = Y; | 378 | |
| 388 | case Y: | 379 | state->sign[Y] = 1; |
| 389 | ec_accel_channels[Y].scan_index = X; | 380 | |
| 390 | case Z: | 381 | if (state->sensor_num == MOTIONSENSE_LOC_LID) |
| 391 | ec_accel_channels[Z].scan_index = Z; | 382 | state->sign[X] = state->sign[Z] = -1; |
| 392 | } | 383 | else |
| 393 | if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y) | 384 | state->sign[X] = state->sign[Z] = 1; |
| 394 | state->sign[i] = -1; | 385 | |
| 395 | else | ||
| 396 | state->sign[i] = 1; | ||
| 397 | } | ||
| 398 | indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); | 386 | indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); |
| 399 | indio_dev->dev.parent = &pdev->dev; | 387 | indio_dev->dev.parent = &pdev->dev; |
| 400 | indio_dev->info = &cros_ec_accel_legacy_info; | 388 | indio_dev->info = &cros_ec_accel_legacy_info; |
| @@ -419,5 +407,5 @@ module_platform_driver(cros_ec_accel_platform_driver); · 18 unmodified lines | |||
| 419 | 407 | ||
| 420 | MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver"); | 408 | MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver"); |
| 421 | MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); | 409 | MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); |
| 422 | MODULE_LICENSE("GPL"); | 410 | MODULE_LICENSE("GPL v2"); |
| 423 | MODULE_ALIAS("platform:" DRV_NAME); | 411 | MODULE_ALIAS("platform:" DRV_NAME); |
| @@ -451,7 +451,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) · 450 unmodified lines | |||
| 451 | } | 451 | } |
| 452 | if (ret < 0) { | 452 | if (ret < 0) { |
| 453 | dev_err(&data->client->dev, | 453 | dev_err(&data->client->dev, |
| 454 | "Failed: kxcjk1013_set_power_state for %d\n", on); | 454 | "Failed: %s for %d\n", __func__, on); |
| 455 | if (on) | 455 | if (on) |
| 456 | pm_runtime_put_noidle(&data->client->dev); | 456 | pm_runtime_put_noidle(&data->client->dev); |
| 457 | return ret; | 457 | return ret; |
| @@ -1491,6 +1491,7 @@ static const struct acpi_device_id kx_acpi_match[] = { · 1033 unmodified lines | |||
| 1491 | {"KXCJ1013", KXCJK1013}, | 1491 | {"KXCJ1013", KXCJK1013}, |
| 1492 | {"KXCJ1008", KXCJ91008}, | 1492 | {"KXCJ1008", KXCJ91008}, |
| 1493 | {"KXCJ9000", KXCJ91008}, | 1493 | {"KXCJ9000", KXCJ91008}, |
| 1494 | {"KIOX0008", KXCJ91008}, | ||
| 1494 | {"KIOX0009", KXTJ21009}, | 1495 | {"KIOX0009", KXTJ21009}, |
| 1495 | {"KIOX000A", KXCJ91008}, | 1496 | {"KIOX000A", KXCJ91008}, |
| 1496 | {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */ | 1497 | {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */ |
| @@ -1512,10 +1513,20 @@ static const struct i2c_device_id kxcjk1013_id[] = { · 15 unmodified lines | |||
| 1512 | 1513 | ||
| 1513 | MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); | 1514 | MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); |
| 1514 | 1515 | ||
| 1516 | static const struct of_device_id kxcjk1013_of_match[] = { | ||
| 1517 | { .compatible = "kionix,kxcjk1013", }, | ||
| 1518 | { .compatible = "kionix,kxcj91008", }, | ||
| 1519 | { .compatible = "kionix,kxtj21009", }, | ||
| 1520 | { .compatible = "kionix,kxtf9", }, | ||
| 1521 | { } | ||
| 1522 | }; | ||
| 1523 | MODULE_DEVICE_TABLE(of, kxcjk1013_of_match); | ||
| 1524 | |||
| 1515 | static struct i2c_driver kxcjk1013_driver = { | 1525 | static struct i2c_driver kxcjk1013_driver = { |
| 1516 | .driver = { | 1526 | .driver = { |
| 1517 | .name = KXCJK1013_DRV_NAME, | 1527 | .name = KXCJK1013_DRV_NAME, |
| 1518 | .acpi_match_table = ACPI_PTR(kx_acpi_match), | 1528 | .acpi_match_table = ACPI_PTR(kx_acpi_match), |
| 1529 | .of_match_table = kxcjk1013_of_match, | ||
| 1519 | .pm = &kxcjk1013_pm_ops, | 1530 | .pm = &kxcjk1013_pm_ops, |
| 1520 | }, | 1531 | }, |
| 1521 | .probe = kxcjk1013_probe, | 1532 | .probe = kxcjk1013_probe, |
| @@ -420,9 +420,7 @@ int kxsd9_common_probe(struct device *dev, · 419 unmodified lines | |||
| 420 | indio_dev->available_scan_masks = kxsd9_scan_masks; | 420 | indio_dev->available_scan_masks = kxsd9_scan_masks; |
| 421 | 421 | ||
| 422 | /* Read the mounting matrix, if present */ | 422 | /* Read the mounting matrix, if present */ |
| 423 | ret = of_iio_read_mount_matrix(dev, | 423 | ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation); |
| 424 | "mount-matrix", | ||
| 425 | &st->orientation); | ||
| 426 | if (ret) | 424 | if (ret) |
| 427 | return ret; | 425 | return ret; |
| 428 | 426 | ||
| @@ -1580,7 +1580,7 @@ static int mma8452_probe(struct i2c_client *client, · 1579 unmodified lines | |||
| 1580 | case FXLS8471_DEVICE_ID: | 1580 | case FXLS8471_DEVICE_ID: |
| 1581 | if (ret == data->chip_info->chip_id) | 1581 | if (ret == data->chip_info->chip_id) |
| 1582 | break; | 1582 | break; |
| 1583 | /* else: fall through */ | 1583 | /* fall through */ |
| 1584 | default: | 1584 | default: |
| 1585 | ret = -ENODEV; | 1585 | ret = -ENODEV; |
| 1586 | goto disable_regulators; | 1586 | goto disable_regulators; |
| @@ -34,6 +34,7 @@ enum st_accel_type { · 33 unmodified lines | |||
| 34 | LIS3LV02DL, | 34 | LIS3LV02DL, |
| 35 | LIS2DW12, | 35 | LIS2DW12, |
| 36 | LIS3DHH, | 36 | LIS3DHH, |
| 37 | LIS2DE12, | ||
| 37 | ST_ACCEL_MAX, | 38 | ST_ACCEL_MAX, |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| @@ -57,6 +58,7 @@ enum st_accel_type { · 17 unmodified lines | |||
| 57 | #define LIS2DW12_ACCEL_DEV_NAME "lis2dw12" | 58 | #define LIS2DW12_ACCEL_DEV_NAME "lis2dw12" |
| 58 | #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" | 59 | #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" |
| 59 | #define LIS3DE_ACCEL_DEV_NAME "lis3de" | 60 | #define LIS3DE_ACCEL_DEV_NAME "lis3de" |
| 61 | #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" | ||
| 60 | 62 | ||
| 61 | /** | 63 | /** |
| 62 | * struct st_sensors_platform_data - default accel platform data | 64 | * struct st_sensors_platform_data - default accel platform data |
| @@ -831,6 +831,82 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { · 830 unmodified lines | |||
| 831 | .multi_read_bit = false, | 831 | .multi_read_bit = false, |
| 832 | .bootime = 2, | 832 | .bootime = 2, |
| 833 | }, | 833 | }, |
| 834 | { | ||
| 835 | .wai = 0x33, | ||
| 836 | .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, | ||
| 837 | .sensors_supported = { | ||
| 838 | [0] = LIS2DE12_ACCEL_DEV_NAME, | ||
| 839 | }, | ||
| 840 | .ch = (struct iio_chan_spec *)st_accel_8bit_channels, | ||
| 841 | .odr = { | ||
| 842 | .addr = 0x20, | ||
| 843 | .mask = 0xf0, | ||
| 844 | .odr_avl = { | ||
| 845 | { .hz = 1, .value = 0x01, }, | ||
| 846 | { .hz = 10, .value = 0x02, }, | ||
| 847 | { .hz = 25, .value = 0x03, }, | ||
| 848 | { .hz = 50, .value = 0x04, }, | ||
| 849 | { .hz = 100, .value = 0x05, }, | ||
| 850 | { .hz = 200, .value = 0x06, }, | ||
| 851 | { .hz = 400, .value = 0x07, }, | ||
| 852 | { .hz = 1620, .value = 0x08, }, | ||
| 853 | { .hz = 5376, .value = 0x09, }, | ||
| 854 | }, | ||
| 855 | }, | ||
| 856 | .pw = { | ||
| 857 | .addr = 0x20, | ||
| 858 | .mask = 0xf0, | ||
| 859 | .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, | ||
| 860 | }, | ||
| 861 | .enable_axis = { | ||
| 862 | .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, | ||
| 863 | .mask = ST_SENSORS_DEFAULT_AXIS_MASK, | ||
| 864 | }, | ||
| 865 | .fs = { | ||
| 866 | .addr = 0x23, | ||
| 867 | .mask = 0x30, | ||
| 868 | .fs_avl = { | ||
| 869 | [0] = { | ||
| 870 | .num = ST_ACCEL_FS_AVL_2G, | ||
| 871 | .value = 0x00, | ||
| 872 | .gain = IIO_G_TO_M_S_2(15600), | ||
| 873 | }, | ||
| 874 | [1] = { | ||
| 875 | .num = ST_ACCEL_FS_AVL_4G, | ||
| 876 | .value = 0x01, | ||
| 877 | .gain = IIO_G_TO_M_S_2(31200), | ||
| 878 | }, | ||
| 879 | [2] = { | ||
| 880 | .num = ST_ACCEL_FS_AVL_8G, | ||
| 881 | .value = 0x02, | ||
| 882 | .gain = IIO_G_TO_M_S_2(62500), | ||
| 883 | }, | ||
| 884 | [3] = { | ||
| 885 | .num = ST_ACCEL_FS_AVL_16G, | ||
| 886 | .value = 0x03, | ||
| 887 | .gain = IIO_G_TO_M_S_2(187500), | ||
| 888 | }, | ||
| 889 | }, | ||
| 890 | }, | ||
| 891 | .drdy_irq = { | ||
| 892 | .int1 = { | ||
| 893 | .addr = 0x22, | ||
| 894 | .mask = 0x10, | ||
| 895 | }, | ||
| 896 | .addr_ihl = 0x25, | ||
| 897 | .mask_ihl = 0x02, | ||
| 898 | .stat_drdy = { | ||
| 899 | .addr = ST_SENSORS_DEFAULT_STAT_ADDR, | ||
| 900 | .mask = 0x07, | ||
| 901 | }, | ||
| 902 | }, | ||
| 903 | .sim = { | ||
| 904 | .addr = 0x23, | ||
| 905 | .value = BIT(0), | ||
| 906 | }, | ||
| 907 | .multi_read_bit = true, | ||
| 908 | .bootime = 2, | ||
| 909 | }, | ||
| 834 | }; | 910 | }; |
| 835 | 911 | ||
| 836 | static int st_accel_read_raw(struct iio_dev *indio_dev, | 912 | static int st_accel_read_raw(struct iio_dev *indio_dev, |
| @@ -992,7 +1068,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, · 155 unmodified lines | |||
| 992 | goto out; | 1068 | goto out; |
| 993 | 1069 | ||
| 994 | val = elements[i].integer.value; | 1070 | val = elements[i].integer.value; |
| 995 | if (val < 0 || val > 2) | 1071 | if (val > 2) |
| 996 | goto out; | 1072 | goto out; |
| 997 | 1073 | ||
| 998 | /* Avoiding full matrix multiplication, we simply reorder the | 1074 | /* Avoiding full matrix multiplication, we simply reorder the |
| @@ -102,6 +102,10 @@ static const struct of_device_id st_accel_of_match[] = { · 101 unmodified lines | |||
| 102 | .compatible = "st,lis3de", | 102 | .compatible = "st,lis3de", |
| 103 | .data = LIS3DE_ACCEL_DEV_NAME, | 103 | .data = LIS3DE_ACCEL_DEV_NAME, |
| 104 | }, | 104 | }, |
| 105 | { | ||
| 106 | .compatible = "st,lis2de12", | ||
| 107 | .data = LIS2DE12_ACCEL_DEV_NAME, | ||
| 108 | }, | ||
| 105 | {}, | 109 | {}, |
| 106 | }; | 110 | }; |
| 107 | MODULE_DEVICE_TABLE(of, st_accel_of_match); | 111 | MODULE_DEVICE_TABLE(of, st_accel_of_match); |
| @@ -140,6 +144,7 @@ static const struct i2c_device_id st_accel_id_table[] = { · 32 unmodified lines | |||
| 140 | { LIS3LV02DL_ACCEL_DEV_NAME }, | 144 | { LIS3LV02DL_ACCEL_DEV_NAME }, |
| 141 | { LIS2DW12_ACCEL_DEV_NAME }, | 145 | { LIS2DW12_ACCEL_DEV_NAME }, |
| 142 | { LIS3DE_ACCEL_DEV_NAME }, | 146 | { LIS3DE_ACCEL_DEV_NAME }, |
| 147 | { LIS2DE12_ACCEL_DEV_NAME }, | ||
| 143 | {}, | 148 | {}, |
| 144 | }; | 149 | }; |
| 145 | MODULE_DEVICE_TABLE(i2c, st_accel_id_table); | 150 | MODULE_DEVICE_TABLE(i2c, st_accel_id_table); |
| @@ -124,6 +124,18 @@ config AD7768_1 · 123 unmodified lines | |||
| 124 | To compile this driver as a module, choose M here: the module will be | 124 | To compile this driver as a module, choose M here: the module will be |
| 125 | called ad7768-1. | 125 | called ad7768-1. |
| 126 | 126 | ||
| 127 | config AD7780 | ||
| 128 | tristate "Analog Devices AD7780 and similar ADCs driver" | ||
| 129 | depends on SPI | ||
| 130 | depends on GPIOLIB || COMPILE_TEST | ||
| 131 | select AD_SIGMA_DELTA | ||
| 132 | help | ||
| 133 | Say yes here to build support for Analog Devices AD7170, AD7171, | ||
| 134 | AD7780 and AD7781 SPI analog to digital converters (ADC). | ||
| 135 | |||
| 136 | To compile this driver as a module, choose M here: the | ||
| 137 | module will be called ad7780. | ||
| 138 | |||
| 127 | config AD7791 | 139 | config AD7791 |
| 128 | tristate "Analog Devices AD7791 ADC driver" | 140 | tristate "Analog Devices AD7791 ADC driver" |
| 129 | depends on SPI | 141 | depends on SPI |
| @@ -390,7 +402,7 @@ config HX711 · 260 unmodified lines | |||
| 390 | 402 | ||
| 391 | This driver uses two GPIOs, one acts as the clock and controls the | 403 | This driver uses two GPIOs, one acts as the clock and controls the |
| 392 | channel selection and gain, the other one is used for the measurement | 404 | channel selection and gain, the other one is used for the measurement |
| 393 | data | 405 | data |
| 394 | 406 | ||
| 395 | Currently the raw value is read from the chip and delivered. | 407 | Currently the raw value is read from the chip and delivered. |
| 396 | To get an actual weight one needs to subtract the | 408 | To get an actual weight one needs to subtract the |
| @@ -541,7 +553,7 @@ config MAX1363 · 144 unmodified lines | |||
| 541 | To compile this driver as a module, choose M here: the module will be | 553 | To compile this driver as a module, choose M here: the module will be |
| 542 | called max1363. | 554 | called max1363. |
| 543 | 555 | ||
| 544 | config MAX9611 | 556 | config MAX9611 |
| 545 | tristate "Maxim max9611/max9612 ADC driver" | 557 | tristate "Maxim max9611/max9612 ADC driver" |
| 546 | depends on I2C | 558 | depends on I2C |
| 547 | help | 559 | help |
| @@ -585,17 +597,17 @@ config MCP3911 · 37 unmodified lines | |||
| 585 | called mcp3911. | 597 | called mcp3911. |
| 586 | 598 | ||
| 587 | config MEDIATEK_MT6577_AUXADC | 599 | config MEDIATEK_MT6577_AUXADC |
| 588 | tristate "MediaTek AUXADC driver" | 600 | tristate "MediaTek AUXADC driver" |
| 589 | depends on ARCH_MEDIATEK || COMPILE_TEST | 601 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 590 | depends on HAS_IOMEM | 602 | depends on HAS_IOMEM |
| 591 | help | 603 | help |
| 592 | Say yes here to enable support for MediaTek mt65xx AUXADC. | 604 | Say yes here to enable support for MediaTek mt65xx AUXADC. |
| 593 | 605 | ||
| 594 | The driver supports immediate mode operation to read from one of sixteen | 606 | The driver supports immediate mode operation to read from one of sixteen |
| 595 | channels (external or internal). | 607 | channels (external or internal). |
| 596 | 608 | ||
| 597 | This driver can also be built as a module. If so, the module will be | 609 | This driver can also be built as a module. If so, the module will be |
| 598 | called mt6577_auxadc. | 610 | called mt6577_auxadc. |
| 599 | 611 | ||
| 600 | config MEN_Z188_ADC | 612 | config MEN_Z188_ADC |
| 601 | tristate "MEN 16z188 ADC IP Core support" | 613 | tristate "MEN 16z188 ADC IP Core support" |
| @@ -809,7 +821,9 @@ config STM32_DFSDM_ADC · 207 unmodified lines | |||
| 809 | depends on (ARCH_STM32 && OF) || COMPILE_TEST | 821 | depends on (ARCH_STM32 && OF) || COMPILE_TEST |
| 810 | select STM32_DFSDM_CORE | 822 | select STM32_DFSDM_CORE |
| 811 | select REGMAP_MMIO | 823 | select REGMAP_MMIO |
| 824 | select IIO_BUFFER | ||
| 812 | select IIO_BUFFER_HW_CONSUMER | 825 | select IIO_BUFFER_HW_CONSUMER |
| 826 | select IIO_TRIGGERED_BUFFER | ||
| 813 | help | 827 | help |
| 814 | Select this option to support ADCSigma delta modulator for | 828 | Select this option to support ADCSigma delta modulator for |
| 815 | STMicroelectronics STM32 digital filter for sigma delta converter. | 829 | STMicroelectronics STM32 digital filter for sigma delta converter. |
| @@ -956,7 +970,7 @@ config TI_ADS1015 · 140 unmodified lines | |||
| 956 | 970 | ||
| 957 | config TI_ADS7950 | 971 | config TI_ADS7950 |
| 958 | tristate "Texas Instruments ADS7950 ADC driver" | 972 | tristate "Texas Instruments ADS7950 ADC driver" |
| 959 | depends on SPI | 973 | depends on SPI && GPIOLIB |
| 960 | select IIO_BUFFER | 974 | select IIO_BUFFER |
| 961 | select IIO_TRIGGERED_BUFFER | 975 | select IIO_TRIGGERED_BUFFER |
| 962 | help | 976 | help |
| @@ -967,6 +981,16 @@ config TI_ADS7950 · 4 unmodified lines | |||
| 967 | To compile this driver as a module, choose M here: the | 981 | To compile this driver as a module, choose M here: the |
| 968 | module will be called ti-ads7950. | 982 | module will be called ti-ads7950. |
| 969 | 983 | ||
| 984 | config TI_ADS8344 | ||
| 985 | tristate "Texas Instruments ADS8344" | ||
| 986 | depends on SPI && OF | ||
| 987 | help | ||
| 988 | If you say yes here you get support for Texas Instruments ADS8344 | ||
| 989 | ADC chips | ||
| 990 | |||
| 991 | This driver can also be built as a module. If so, the module will be | ||
| 992 | called ti-ads8344. | ||
| 993 | |||
| 970 | config TI_ADS8688 | 994 | config TI_ADS8688 |
| 971 | tristate "Texas Instruments ADS8688" | 995 | tristate "Texas Instruments ADS8688" |
| 972 | depends on SPI && OF | 996 | depends on SPI && OF |
| @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o · 15 unmodified lines | |||
| 16 | obj-$(CONFIG_AD7606) += ad7606.o | 16 | obj-$(CONFIG_AD7606) += ad7606.o |
| 17 | obj-$(CONFIG_AD7766) += ad7766.o | 17 | obj-$(CONFIG_AD7766) += ad7766.o |
| 18 | obj-$(CONFIG_AD7768_1) += ad7768-1.o | 18 | obj-$(CONFIG_AD7768_1) += ad7768-1.o |
| 19 | obj-$(CONFIG_AD7780) += ad7780.o | ||
| 19 | obj-$(CONFIG_AD7791) += ad7791.o | 20 | obj-$(CONFIG_AD7791) += ad7791.o |
| 20 | obj-$(CONFIG_AD7793) += ad7793.o | 21 | obj-$(CONFIG_AD7793) += ad7793.o |
| 21 | obj-$(CONFIG_AD7887) += ad7887.o | 22 | obj-$(CONFIG_AD7887) += ad7887.o |
| @@ -87,6 +88,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o · 65 unmodified lines | |||
| 87 | obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o | 88 | obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o |
| 88 | obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o | 89 | obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o |
| 89 | obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o | 90 | obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o |
| 91 | obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o | ||
| 90 | obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o | 92 | obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o |
| 91 | obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o | 93 | obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o |
| 92 | obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o | 94 | obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o |
| @@ -411,7 +411,7 @@ static int ad7124_init_channel_vref(struct ad7124_state *st, · 410 unmodified lines | |||
| 411 | dev_err(&st->sd.spi->dev, | 411 | dev_err(&st->sd.spi->dev, |
| 412 | "Error, trying to use external voltage reference without a %s regulator.\n", | 412 | "Error, trying to use external voltage reference without a %s regulator.\n", |
| 413 | ad7124_ref_names[refsel]); | 413 | ad7124_ref_names[refsel]); |
| 414 | return PTR_ERR(st->vref[refsel]); | 414 | return PTR_ERR(st->vref[refsel]); |
| 415 | } | 415 | } |
| 416 | st->channel_config[channel_number].vref_mv = | 416 | st->channel_config[channel_number].vref_mv = |
| 417 | regulator_get_voltage(st->vref[refsel]); | 417 | regulator_get_voltage(st->vref[refsel]); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | |||
| 31 | * Scales are computed as 5000/32768 and 10000/32768 respectively, | 31 | * Scales are computed as 5000/32768 and 10000/32768 respectively, |
| 32 | * so that when applied to the raw values they provide mV values | 32 | * so that when applied to the raw values they provide mV values |
| 33 | */ | 33 | */ |
| 34 | static const unsigned int scale_avail[2] = { | 34 | static const unsigned int ad7606_scale_avail[2] = { |
| 35 | 152588, 305176 | 35 | 152588, 305176 |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| @@ -39,6 +39,10 @@ static const unsigned int ad7606_oversampling_avail[7] = { · 1 unmodified line | |||
| 39 | 1, 2, 4, 8, 16, 32, 64, | 39 | 1, 2, 4, 8, 16, 32, 64, |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | static const unsigned int ad7616_oversampling_avail[8] = { | ||
| 43 | 1, 2, 4, 8, 16, 32, 64, 128, | ||
| 44 | }; | ||
| 45 | |||
| 42 | static int ad7606_reset(struct ad7606_state *st) | 46 | static int ad7606_reset(struct ad7606_state *st) |
| 43 | { | 47 | { |
| 44 | if (st->gpio_reset) { | 48 | if (st->gpio_reset) { |
| @@ -154,7 +158,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, · 109 unmodified lines | |||
| 154 | return IIO_VAL_INT; | 158 | return IIO_VAL_INT; |
| 155 | case IIO_CHAN_INFO_SCALE: | 159 | case IIO_CHAN_INFO_SCALE: |
| 156 | *val = 0; | 160 | *val = 0; |
| 157 | *val2 = scale_avail[st->range]; | 161 | *val2 = st->scale_avail[st->range]; |
| 158 | return IIO_VAL_INT_PLUS_MICRO; | 162 | return IIO_VAL_INT_PLUS_MICRO; |
| 159 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 163 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 160 | *val = st->oversampling; | 164 | *val = st->oversampling; |
| @@ -163,21 +167,31 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 163 | return -EINVAL; | 167 | return -EINVAL; |
| 164 | } | 168 | } |
| 165 | 169 | ||
| 166 | static ssize_t in_voltage_scale_available_show(struct device *dev, | 170 | static ssize_t ad7606_show_avail(char *buf, const unsigned int *vals, |
| 167 | struct device_attribute *attr, | 171 | unsigned int n, bool micros) |
| 168 | char *buf) | ||
| 169 | { | 172 | { |
| 170 | int i, len = 0; | 173 | size_t len = 0; |
| 171 | 174 | int i; | |
| 172 | for (i = 0; i < ARRAY_SIZE(scale_avail); i++) | ||
| 173 | len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", | ||
| 174 | scale_avail[i]); | ||
| 175 | 175 | ||
| 176 | for (i = 0; i < n; i++) { | ||
| 177 | len += scnprintf(buf + len, PAGE_SIZE - len, | ||
| 178 | micros ? "0.%06u " : "%u ", vals[i]); | ||
| 179 | } | ||
| 176 | buf[len - 1] = '\n'; | 180 | buf[len - 1] = '\n'; |
| 177 | 181 | ||
| 178 | return len; | 182 | return len; |
| 179 | } | 183 | } |
| 180 | 184 | ||
| 185 | static ssize_t in_voltage_scale_available_show(struct device *dev, | ||
| 186 | struct device_attribute *attr, | ||
| 187 | char *buf) | ||
| 188 | { | ||
| 189 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
| 190 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 191 | |||
| 192 | return ad7606_show_avail(buf, st->scale_avail, st->num_scales, true); | ||
| 193 | } | ||
| 194 | |||
| 181 | static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); | 195 | static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); |
| 182 | 196 | ||
| 183 | static int ad7606_write_raw(struct iio_dev *indio_dev, | 197 | static int ad7606_write_raw(struct iio_dev *indio_dev, |
| @@ -193,7 +207,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, · 9 unmodified lines | |||
| 193 | switch (mask) { | 207 | switch (mask) { |
| 194 | case IIO_CHAN_INFO_SCALE: | 208 | case IIO_CHAN_INFO_SCALE: |
| 195 | mutex_lock(&st->lock); | 209 | mutex_lock(&st->lock); |
| 196 | i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail)); | 210 | i = find_closest(val2, st->scale_avail, st->num_scales); |
| 197 | gpiod_set_value(st->gpio_range, i); | 211 | gpiod_set_value(st->gpio_range, i); |
| 198 | st->range = i; | 212 | st->range = i; |
| 199 | mutex_unlock(&st->lock); | 213 | mutex_unlock(&st->lock); |
| @@ -202,15 +216,20 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 202 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 216 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 203 | if (val2) | 217 | if (val2) |
| 204 | return -EINVAL; | 218 | return -EINVAL; |
| 205 | i = find_closest(val, ad7606_oversampling_avail, | 219 | i = find_closest(val, st->oversampling_avail, |
| 206 | ARRAY_SIZE(ad7606_oversampling_avail)); | 220 | st->num_os_ratios); |
| 207 | 221 | ||
| 208 | values[0] = i; | 222 | values[0] = i; |
| 209 | 223 | ||
| 210 | mutex_lock(&st->lock); | 224 | mutex_lock(&st->lock); |
| 211 | gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, | 225 | gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, |
| 212 | st->gpio_os->info, values); | 226 | st->gpio_os->info, values); |
| 213 | st->oversampling = ad7606_oversampling_avail[i]; | 227 | |
| 228 | /* AD7616 requires a reset to update value */ | ||
| 229 | if (st->chip_info->os_req_reset) | ||
| 230 | ad7606_reset(st); | ||
| 231 | |||
| 232 | st->oversampling = st->oversampling_avail[i]; | ||
| 214 | mutex_unlock(&st->lock); | 233 | mutex_unlock(&st->lock); |
| 215 | 234 | ||
| 216 | return 0; | 235 | return 0; |
| @@ -219,11 +238,23 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 219 | } | 238 | } |
| 220 | } | 239 | } |
| 221 | 240 | ||
| 222 | static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); | 241 | static ssize_t ad7606_oversampling_ratio_avail(struct device *dev, |
| 242 | struct device_attribute *attr, | ||
| 243 | char *buf) | ||
| 244 | { | ||
| 245 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
| 246 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 247 | |||
| 248 | return ad7606_show_avail(buf, st->oversampling_avail, | ||
| 249 | st->num_os_ratios, false); | ||
| 250 | } | ||
| 251 | |||
| 252 | static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444, | ||
| 253 | ad7606_oversampling_ratio_avail, NULL, 0); | ||
| 223 | 254 | ||
| 224 | static struct attribute *ad7606_attributes_os_and_range[] = { | 255 | static struct attribute *ad7606_attributes_os_and_range[] = { |
| 225 | &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, | 256 | &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, |
| 226 | &iio_const_attr_oversampling_ratio_available.dev_attr.attr, | 257 | &iio_dev_attr_oversampling_ratio_available.dev_attr.attr, |
| 227 | NULL, | 258 | NULL, |
| 228 | }; | 259 | }; |
| 229 | 260 | ||
| @@ -232,7 +263,7 @@ static const struct attribute_group ad7606_attribute_group_os_and_range = { · 2 unmodified lines | |||
| 232 | }; | 263 | }; |
| 233 | 264 | ||
| 234 | static struct attribute *ad7606_attributes_os[] = { | 265 | static struct attribute *ad7606_attributes_os[] = { |
| 235 | &iio_const_attr_oversampling_ratio_available.dev_attr.attr, | 266 | &iio_dev_attr_oversampling_ratio_available.dev_attr.attr, |
| 236 | NULL, | 267 | NULL, |
| 237 | }; | 268 | }; |
| 238 | 269 | ||
| @@ -292,6 +323,36 @@ static const struct iio_chan_spec ad7606_channels[] = { · 53 unmodified lines | |||
| 292 | AD7606_CHANNEL(7), | 323 | AD7606_CHANNEL(7), |
| 293 | }; | 324 | }; |
| 294 | 325 | ||
| 326 | /* | ||
| 327 | * The current assumption that this driver makes for AD7616, is that it's | ||
| 328 | * working in Hardware Mode with Serial, Burst and Sequencer modes activated. | ||
| 329 | * To activate them, following pins must be pulled high: | ||
| 330 | * -SER/PAR | ||
| 331 | * -SEQEN | ||
| 332 | * And following pins must be pulled low: | ||
| 333 | * -WR/BURST | ||
| 334 | * -DB4/SER1W | ||
| 335 | */ | ||
| 336 | static const struct iio_chan_spec ad7616_channels[] = { | ||
| 337 | IIO_CHAN_SOFT_TIMESTAMP(16), | ||
| 338 | AD7606_CHANNEL(0), | ||
| 339 | AD7606_CHANNEL(1), | ||
| 340 | AD7606_CHANNEL(2), | ||
| 341 | AD7606_CHANNEL(3), | ||
| 342 | AD7606_CHANNEL(4), | ||
| 343 | AD7606_CHANNEL(5), | ||
| 344 | AD7606_CHANNEL(6), | ||
| 345 | AD7606_CHANNEL(7), | ||
| 346 | AD7606_CHANNEL(8), | ||
| 347 | AD7606_CHANNEL(9), | ||
| 348 | AD7606_CHANNEL(10), | ||
| 349 | AD7606_CHANNEL(11), | ||
| 350 | AD7606_CHANNEL(12), | ||
| 351 | AD7606_CHANNEL(13), | ||
| 352 | AD7606_CHANNEL(14), | ||
| 353 | AD7606_CHANNEL(15), | ||
| 354 | }; | ||
| 355 | |||
| 295 | static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { | 356 | static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { |
| 296 | /* More devices added in future */ | 357 | /* More devices added in future */ |
| 297 | [ID_AD7605_4] = { | 358 | [ID_AD7605_4] = { |
| @@ -301,17 +362,27 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { · 3 unmodified lines | |||
| 301 | [ID_AD7606_8] = { | 362 | [ID_AD7606_8] = { |
| 302 | .channels = ad7606_channels, | 363 | .channels = ad7606_channels, |
| 303 | .num_channels = 9, | 364 | .num_channels = 9, |
| 304 | .has_oversampling = true, | 365 | .oversampling_avail = ad7606_oversampling_avail, |
| 366 | .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), | ||
| 305 | }, | 367 | }, |
| 306 | [ID_AD7606_6] = { | 368 | [ID_AD7606_6] = { |
| 307 | .channels = ad7606_channels, | 369 | .channels = ad7606_channels, |
| 308 | .num_channels = 7, | 370 | .num_channels = 7, |
| 309 | .has_oversampling = true, | 371 | .oversampling_avail = ad7606_oversampling_avail, |
| 372 | .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), | ||
| 310 | }, | 373 | }, |
| 311 | [ID_AD7606_4] = { | 374 | [ID_AD7606_4] = { |
| 312 | .channels = ad7606_channels, | 375 | .channels = ad7606_channels, |
| 313 | .num_channels = 5, | 376 | .num_channels = 5, |
| 314 | .has_oversampling = true, | 377 | .oversampling_avail = ad7606_oversampling_avail, |
| 378 | .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), | ||
| 379 | }, | ||
| 380 | [ID_AD7616] = { | ||
| 381 | .channels = ad7616_channels, | ||
| 382 | .num_channels = 17, | ||
| 383 | .oversampling_avail = ad7616_oversampling_avail, | ||
| 384 | .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), | ||
| 385 | .os_req_reset = true, | ||
| 315 | }, | 386 | }, |
| 316 | }; | 387 | }; |
| 317 | 388 | ||
| @@ -343,7 +414,7 @@ static int ad7606_request_gpios(struct ad7606_state *st) · 25 unmodified lines | |||
| 343 | if (IS_ERR(st->gpio_frstdata)) | 414 | if (IS_ERR(st->gpio_frstdata)) |
| 344 | return PTR_ERR(st->gpio_frstdata); | 415 | return PTR_ERR(st->gpio_frstdata); |
| 345 | 416 | ||
| 346 | if (!st->chip_info->has_oversampling) | 417 | if (!st->chip_info->oversampling_num) |
| 347 | return 0; | 418 | return 0; |
| 348 | 419 | ||
| 349 | st->gpio_os = devm_gpiod_get_array_optional(dev, | 420 | st->gpio_os = devm_gpiod_get_array_optional(dev, |
| @@ -467,6 +538,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, · 117 unmodified lines | |||
| 467 | /* tied to logic low, analog input range is +/- 5V */ | 538 | /* tied to logic low, analog input range is +/- 5V */ |
| 468 | st->range = 0; | 539 | st->range = 0; |
| 469 | st->oversampling = 1; | 540 | st->oversampling = 1; |
| 541 | st->scale_avail = ad7606_scale_avail; | ||
| 542 | st->num_scales = ARRAY_SIZE(ad7606_scale_avail); | ||
| 470 | 543 | ||
| 471 | st->reg = devm_regulator_get(dev, "avcc"); | 544 | st->reg = devm_regulator_get(dev, "avcc"); |
| 472 | if (IS_ERR(st->reg)) | 545 | if (IS_ERR(st->reg)) |
| @@ -484,6 +557,11 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, · 11 unmodified lines | |||
| 484 | 557 | ||
| 485 | st->chip_info = &ad7606_chip_info_tbl[id]; | 558 | st->chip_info = &ad7606_chip_info_tbl[id]; |
| 486 | 559 | ||
| 560 | if (st->chip_info->oversampling_num) { | ||
| 561 | st->oversampling_avail = st->chip_info->oversampling_avail; | ||
| 562 | st->num_os_ratios = st->chip_info->oversampling_num; | ||
| 563 | } | ||
| 564 | |||
| 487 | ret = ad7606_request_gpios(st); | 565 | ret = ad7606_request_gpios(st); |
| 488 | if (ret) | 566 | if (ret) |
| 489 | return ret; | 567 | return ret; |
| @@ -12,12 +12,17 @@ · 11 unmodified lines | |||
| 12 | * struct ad7606_chip_info - chip specific information | 12 | * struct ad7606_chip_info - chip specific information |
| 13 | * @channels: channel specification | 13 | * @channels: channel specification |
| 14 | * @num_channels: number of channels | 14 | * @num_channels: number of channels |
| 15 | * @has_oversampling: whether the device has oversampling support | 15 | * @oversampling_avail pointer to the array which stores the available |
| 16 | * oversampling ratios. | ||
| 17 | * @oversampling_num number of elements stored in oversampling_avail array | ||
| 18 | * @os_req_reset some devices require a reset to update oversampling | ||
| 16 | */ | 19 | */ |
| 17 | struct ad7606_chip_info { | 20 | struct ad7606_chip_info { |
| 18 | const struct iio_chan_spec *channels; | 21 | const struct iio_chan_spec *channels; |
| 19 | unsigned int num_channels; | 22 | unsigned int num_channels; |
| 20 | bool has_oversampling; | 23 | const unsigned int *oversampling_avail; |
| 24 | unsigned int oversampling_num; | ||
| 25 | bool os_req_reset; | ||
| 21 | }; | 26 | }; |
| 22 | 27 | ||
| 23 | /** | 28 | /** |
| @@ -29,6 +34,11 @@ struct ad7606_chip_info { · 5 unmodified lines | |||
| 29 | * @range voltage range selection, selects which scale to apply | 34 | * @range voltage range selection, selects which scale to apply |
| 30 | * @oversampling oversampling selection | 35 | * @oversampling oversampling selection |
| 31 | * @base_address address from where to read data in parallel operation | 36 | * @base_address address from where to read data in parallel operation |
| 37 | * @scale_avail pointer to the array which stores the available scales | ||
| 38 | * @num_scales number of elements stored in the scale_avail array | ||
| 39 | * @oversampling_avail pointer to the array which stores the available | ||
| 40 | * oversampling ratios. | ||
| 41 | * @num_os_ratios number of elements stored in oversampling_avail array | ||
| 32 | * @lock protect sensor state from concurrent accesses to GPIOs | 42 | * @lock protect sensor state from concurrent accesses to GPIOs |
| 33 | * @gpio_convst GPIO descriptor for conversion start signal (CONVST) | 43 | * @gpio_convst GPIO descriptor for conversion start signal (CONVST) |
| 34 | * @gpio_reset GPIO descriptor for device hard-reset | 44 | * @gpio_reset GPIO descriptor for device hard-reset |
| @@ -50,6 +60,10 @@ struct ad7606_state { · 15 unmodified lines | |||
| 50 | unsigned int range; | 60 | unsigned int range; |
| 51 | unsigned int oversampling; | 61 | unsigned int oversampling; |
| 52 | void __iomem *base_address; | 62 | void __iomem *base_address; |
| 63 | const unsigned int *scale_avail; | ||
| 64 | unsigned int num_scales; | ||
| 65 | const unsigned int *oversampling_avail; | ||
| 66 | unsigned int num_os_ratios; | ||
| 53 | 67 | ||
| 54 | struct mutex lock; /* protect sensor state */ | 68 | struct mutex lock; /* protect sensor state */ |
| 55 | struct gpio_desc *gpio_convst; | 69 | struct gpio_desc *gpio_convst; |
| @@ -64,9 +78,9 @@ struct ad7606_state { · 8 unmodified lines | |||
| 64 | /* | 78 | /* |
| 65 | * DMA (thus cache coherency maintenance) requires the | 79 | * DMA (thus cache coherency maintenance) requires the |
| 66 | * transfer buffers to live in their own cache lines. | 80 | * transfer buffers to live in their own cache lines. |
| 67 | * 8 * 16-bit samples + 64-bit timestamp | 81 | * 16 * 16-bit samples + 64-bit timestamp |
| 68 | */ | 82 | */ |
| 69 | unsigned short data[12] ____cacheline_aligned; | 83 | unsigned short data[20] ____cacheline_aligned; |
| 70 | }; | 84 | }; |
| 71 | 85 | ||
| 72 | /** | 86 | /** |
| @@ -86,7 +100,8 @@ enum ad7606_supported_device_ids { · 13 unmodified lines | |||
| 86 | ID_AD7605_4, | 100 | ID_AD7605_4, |
| 87 | ID_AD7606_8, | 101 | ID_AD7606_8, |
| 88 | ID_AD7606_6, | 102 | ID_AD7606_6, |
| 89 | ID_AD7606_4 | 103 | ID_AD7606_4, |
| 104 | ID_AD7616, | ||
| 90 | }; | 105 | }; |
| 91 | 106 | ||
| 92 | #ifdef CONFIG_PM_SLEEP | 107 | #ifdef CONFIG_PM_SLEEP |
| @@ -53,6 +53,7 @@ static const struct spi_device_id ad7606_id_table[] = { · 52 unmodified lines | |||
| 53 | { "ad7606-4", ID_AD7606_4 }, | 53 | { "ad7606-4", ID_AD7606_4 }, |
| 54 | { "ad7606-6", ID_AD7606_6 }, | 54 | { "ad7606-6", ID_AD7606_6 }, |
| 55 | { "ad7606-8", ID_AD7606_8 }, | 55 | { "ad7606-8", ID_AD7606_8 }, |
| 56 | { "ad7616", ID_AD7616 }, | ||
| 56 | {} | 57 | {} |
| 57 | }; | 58 | }; |
| 58 | MODULE_DEVICE_TABLE(spi, ad7606_id_table); | 59 | MODULE_DEVICE_TABLE(spi, ad7606_id_table); |
| @@ -62,6 +63,7 @@ static const struct of_device_id ad7606_of_match[] = { · 3 unmodified lines | |||
| 62 | { .compatible = "adi,ad7606-4" }, | 63 | { .compatible = "adi,ad7606-4" }, |
| 63 | { .compatible = "adi,ad7606-6" }, | 64 | { .compatible = "adi,ad7606-6" }, |
| 64 | { .compatible = "adi,ad7606-8" }, | 65 | { .compatible = "adi,ad7606-8" }, |
| 66 | { .compatible = "adi,ad7616" }, | ||
| 65 | { }, | 67 | { }, |
| 66 | }; | 68 | }; |
| 67 | MODULE_DEVICE_TABLE(of, ad7606_of_match); | 69 | MODULE_DEVICE_TABLE(of, ad7606_of_match); |
| @@ -1,9 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver | 3 | * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver |
| 3 | * | 4 | * |
| 4 | * Copyright 2011 Analog Devices Inc. | 5 | * Copyright 2011 Analog Devices Inc. |
| 5 | * | 6 | * Copyright 2019 Renato Lui Geh |
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
| @@ -17,6 +17,7 @@ · 7 unmodified lines | |||
| 17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
| 18 | #include <linux/gpio/consumer.h> | 18 | #include <linux/gpio/consumer.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/bits.h> | ||
| 20 | 21 | ||
| 21 | #include <linux/iio/iio.h> | 22 | #include <linux/iio/iio.h> |
| 22 | #include <linux/iio/sysfs.h> | 23 | #include <linux/iio/sysfs.h> |
| @@ -28,16 +29,25 @@ · 5 unmodified lines | |||
| 28 | #define AD7780_ID1 BIT(4) | 29 | #define AD7780_ID1 BIT(4) |
| 29 | #define AD7780_ID0 BIT(3) | 30 | #define AD7780_ID0 BIT(3) |
| 30 | #define AD7780_GAIN BIT(2) | 31 | #define AD7780_GAIN BIT(2) |
| 31 | #define AD7780_PAT1 BIT(1) | ||
| 32 | #define AD7780_PAT0 BIT(0) | ||
| 33 | 32 | ||
| 34 | #define AD7780_PATTERN (AD7780_PAT0) | 33 | #define AD7170_ID 0 |
| 35 | #define AD7780_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1) | 34 | #define AD7171_ID 1 |
| 35 | #define AD7780_ID 1 | ||
| 36 | #define AD7781_ID 0 | ||
| 37 | |||
| 38 | #define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1) | ||
| 39 | |||
| 40 | #define AD7780_PATTERN_GOOD 1 | ||
| 41 | #define AD7780_PATTERN_MASK GENMASK(1, 0) | ||
| 36 | 42 | ||
| 37 | #define AD7170_PAT2 BIT(2) | 43 | #define AD7170_PATTERN_GOOD 5 |
| 44 | #define AD7170_PATTERN_MASK GENMASK(2, 0) | ||
| 38 | 45 | ||
| 39 | #define AD7170_PATTERN (AD7780_PAT0 | AD7170_PAT2) | 46 | #define AD7780_GAIN_MIDPOINT 64 |
| 40 | #define AD7170_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1 | AD7170_PAT2) | 47 | #define AD7780_FILTER_MIDPOINT 13350 |
| 48 | |||
| 49 | static const unsigned int ad778x_gain[2] = { 1, 128 }; | ||
| 50 | static const unsigned int ad778x_odr_avail[2] = { 10000, 16700 }; | ||
| 41 | 51 | ||
| 42 | struct ad7780_chip_info { | 52 | struct ad7780_chip_info { |
| 43 | struct iio_chan_spec channel; | 53 | struct iio_chan_spec channel; |
| @@ -50,7 +60,11 @@ struct ad7780_state { · 6 unmodified lines | |||
| 50 | const struct ad7780_chip_info *chip_info; | 60 | const struct ad7780_chip_info *chip_info; |
| 51 | struct regulator *reg; | 61 | struct regulator *reg; |
| 52 | struct gpio_desc *powerdown_gpio; | 62 | struct gpio_desc *powerdown_gpio; |
| 53 | unsigned int gain; | 63 | struct gpio_desc *gain_gpio; |
| 64 | struct gpio_desc *filter_gpio; | ||
| 65 | unsigned int gain; | ||
| 66 | unsigned int odr; | ||
| 67 | unsigned int int_vref_mv; | ||
| 54 | 68 | ||
| 55 | struct ad_sigma_delta sd; | 69 | struct ad_sigma_delta sd; |
| 56 | }; | 70 | }; |
| @@ -104,17 +118,69 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, · 47 unmodified lines | |||
| 104 | voltage_uv = regulator_get_voltage(st->reg); | 118 | voltage_uv = regulator_get_voltage(st->reg); |
| 105 | if (voltage_uv < 0) | 119 | if (voltage_uv < 0) |
| 106 | return voltage_uv; | 120 | return voltage_uv; |
| 107 | *val = (voltage_uv / 1000) * st->gain; | 121 | voltage_uv /= 1000; |
| 122 | *val = voltage_uv * st->gain; | ||
| 108 | *val2 = chan->scan_type.realbits - 1; | 123 | *val2 = chan->scan_type.realbits - 1; |
| 124 | st->int_vref_mv = voltage_uv; | ||
| 109 | return IIO_VAL_FRACTIONAL_LOG2; | 125 | return IIO_VAL_FRACTIONAL_LOG2; |
| 110 | case IIO_CHAN_INFO_OFFSET: | 126 | case IIO_CHAN_INFO_OFFSET: |
| 111 | *val = -(1 << (chan->scan_type.realbits - 1)); | 127 | *val = -(1 << (chan->scan_type.realbits - 1)); |
| 112 | return IIO_VAL_INT; | 128 | return IIO_VAL_INT; |
| 129 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 130 | *val = st->odr; | ||
| 131 | return IIO_VAL_INT; | ||
| 132 | default: | ||
| 133 | break; | ||
| 113 | } | 134 | } |
| 114 | 135 | ||
| 115 | return -EINVAL; | 136 | return -EINVAL; |
| 116 | } | 137 | } |
| 117 | 138 | ||
| 139 | static int ad7780_write_raw(struct iio_dev *indio_dev, | ||
| 140 | struct iio_chan_spec const *chan, | ||
| 141 | int val, | ||
| 142 | int val2, | ||
| 143 | long m) | ||
| 144 | { | ||
| 145 | struct ad7780_state *st = iio_priv(indio_dev); | ||
| 146 | const struct ad7780_chip_info *chip_info = st->chip_info; | ||
| 147 | unsigned long long vref; | ||
| 148 | unsigned int full_scale, gain; | ||
| 149 | |||
| 150 | if (!chip_info->is_ad778x) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | switch (m) { | ||
| 154 | case IIO_CHAN_INFO_SCALE: | ||
| 155 | if (val != 0) | ||
| 156 | return -EINVAL; | ||
| 157 | |||
| 158 | vref = st->int_vref_mv * 1000000LL; | ||
| 159 | full_scale = 1 << (chip_info->channel.scan_type.realbits - 1); | ||
| 160 | gain = DIV_ROUND_CLOSEST_ULL(vref, full_scale); | ||
| 161 | gain = DIV_ROUND_CLOSEST(gain, val2); | ||
| 162 | st->gain = gain; | ||
| 163 | if (gain < AD7780_GAIN_MIDPOINT) | ||
| 164 | gain = 0; | ||
| 165 | else | ||
| 166 | gain = 1; | ||
| 167 | gpiod_set_value(st->gain_gpio, gain); | ||
| 168 | break; | ||
| 169 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 170 | if (1000*val + val2/1000 < AD7780_FILTER_MIDPOINT) | ||
| 171 | val = 0; | ||
| 172 | else | ||
| 173 | val = 1; | ||
| 174 | st->odr = ad778x_odr_avail[val]; | ||
| 175 | gpiod_set_value(st->filter_gpio, val); | ||
| 176 | break; | ||
| 177 | default: | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 118 | static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, | 184 | static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, |
| 119 | unsigned int raw_sample) | 185 | unsigned int raw_sample) |
| 120 | { | 186 | { |
| @@ -126,10 +192,8 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, · 5 unmodified lines | |||
| 126 | return -EIO; | 192 | return -EIO; |
| 127 | 193 | ||
| 128 | if (chip_info->is_ad778x) { | 194 | if (chip_info->is_ad778x) { |
| 129 | if (raw_sample & AD7780_GAIN) | 195 | st->gain = ad778x_gain[raw_sample & AD7780_GAIN]; |
| 130 | st->gain = 1; | 196 | st->odr = ad778x_odr_avail[raw_sample & AD7780_FILTER]; |
| 131 | else | ||
| 132 | st->gain = 128; | ||
| 133 | } | 197 | } |
| 134 | 198 | ||
| 135 | return 0; | 199 | return 0; |
| @@ -142,30 +206,32 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { · 6 unmodified lines | |||
| 142 | }; | 206 | }; |
| 143 | 207 | ||
| 144 | #define AD7780_CHANNEL(bits, wordsize) \ | 208 | #define AD7780_CHANNEL(bits, wordsize) \ |
| 145 | AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits) | 209 | AD_SD_CHANNEL(1, 0, 0, bits, 32, (wordsize) - (bits)) |
| 210 | #define AD7170_CHANNEL(bits, wordsize) \ | ||
| 211 | AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, (wordsize) - (bits)) | ||
| 146 | 212 | ||
| 147 | static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { | 213 | static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { |
| 148 | [ID_AD7170] = { | 214 | [ID_AD7170] = { |
| 149 | .channel = AD7780_CHANNEL(12, 24), | 215 | .channel = AD7170_CHANNEL(12, 24), |
| 150 | .pattern = AD7170_PATTERN, | 216 | .pattern = AD7170_PATTERN_GOOD, |
| 151 | .pattern_mask = AD7170_PATTERN_MASK, | 217 | .pattern_mask = AD7170_PATTERN_MASK, |
| 152 | .is_ad778x = false, | 218 | .is_ad778x = false, |
| 153 | }, | 219 | }, |
| 154 | [ID_AD7171] = { | 220 | [ID_AD7171] = { |
| 155 | .channel = AD7780_CHANNEL(16, 24), | 221 | .channel = AD7170_CHANNEL(16, 24), |
| 156 | .pattern = AD7170_PATTERN, | 222 | .pattern = AD7170_PATTERN_GOOD, |
| 157 | .pattern_mask = AD7170_PATTERN_MASK, | 223 | .pattern_mask = AD7170_PATTERN_MASK, |
| 158 | .is_ad778x = false, | 224 | .is_ad778x = false, |
| 159 | }, | 225 | }, |
| 160 | [ID_AD7780] = { | 226 | [ID_AD7780] = { |
| 161 | .channel = AD7780_CHANNEL(24, 32), | 227 | .channel = AD7780_CHANNEL(24, 32), |
| 162 | .pattern = AD7780_PATTERN, | 228 | .pattern = AD7780_PATTERN_GOOD, |
| 163 | .pattern_mask = AD7780_PATTERN_MASK, | 229 | .pattern_mask = AD7780_PATTERN_MASK, |
| 164 | .is_ad778x = true, | 230 | .is_ad778x = true, |
| 165 | }, | 231 | }, |
| 166 | [ID_AD7781] = { | 232 | [ID_AD7781] = { |
| 167 | .channel = AD7780_CHANNEL(20, 32), | 233 | .channel = AD7780_CHANNEL(20, 32), |
| 168 | .pattern = AD7780_PATTERN, | 234 | .pattern = AD7780_PATTERN_GOOD, |
| 169 | .pattern_mask = AD7780_PATTERN_MASK, | 235 | .pattern_mask = AD7780_PATTERN_MASK, |
| 170 | .is_ad778x = true, | 236 | .is_ad778x = true, |
| 171 | }, | 237 | }, |
| @@ -173,8 +239,47 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { · 1 unmodified line | |||
| 173 | 239 | ||
| 174 | static const struct iio_info ad7780_info = { | 240 | static const struct iio_info ad7780_info = { |
| 175 | .read_raw = ad7780_read_raw, | 241 | .read_raw = ad7780_read_raw, |
| 242 | .write_raw = ad7780_write_raw, | ||
| 176 | }; | 243 | }; |
| 177 | 244 | ||
| 245 | static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) | ||
| 246 | { | ||
| 247 | int ret; | ||
| 248 | |||
| 249 | st->powerdown_gpio = devm_gpiod_get_optional(dev, | ||
| 250 | "powerdown", | ||
| 251 | GPIOD_OUT_LOW); | ||
| 252 | if (IS_ERR(st->powerdown_gpio)) { | ||
| 253 | ret = PTR_ERR(st->powerdown_gpio); | ||
| 254 | dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret); | ||
| 255 | return ret; | ||
| 256 | } | ||
| 257 | |||
| 258 | if (!st->chip_info->is_ad778x) | ||
| 259 | return 0; | ||
| 260 | |||
| 261 | |||
| 262 | st->gain_gpio = devm_gpiod_get_optional(dev, | ||
| 263 | "adi,gain", | ||
| 264 | GPIOD_OUT_HIGH); | ||
| 265 | if (IS_ERR(st->gain_gpio)) { | ||
| 266 | ret = PTR_ERR(st->gain_gpio); | ||
| 267 | dev_err(dev, "Failed to request gain GPIO: %d\n", ret); | ||
| 268 | return ret; | ||
| 269 | } | ||
| 270 | |||
| 271 | st->filter_gpio = devm_gpiod_get_optional(dev, | ||
| 272 | "adi,filter", | ||
| 273 | GPIOD_OUT_HIGH); | ||
| 274 | if (IS_ERR(st->filter_gpio)) { | ||
| 275 | ret = PTR_ERR(st->filter_gpio); | ||
| 276 | dev_err(dev, "Failed to request filter GPIO: %d\n", ret); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 178 | static int ad7780_probe(struct spi_device *spi) | 283 | static int ad7780_probe(struct spi_device *spi) |
| 179 | { | 284 | { |
| 180 | struct ad7780_state *st; | 285 | struct ad7780_state *st; |
| @@ -190,16 +295,6 @@ static int ad7780_probe(struct spi_device *spi) · 9 unmodified lines | |||
| 190 | 295 | ||
| 191 | ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); | 296 | ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); |
| 192 | 297 | ||
| 193 | st->reg = devm_regulator_get(&spi->dev, "avdd"); | ||
| 194 | if (IS_ERR(st->reg)) | ||
| 195 | return PTR_ERR(st->reg); | ||
| 196 | |||
| 197 | ret = regulator_enable(st->reg); | ||
| 198 | if (ret) { | ||
| 199 | dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); | ||
| 200 | return ret; | ||
| 201 | } | ||
| 202 | |||
| 203 | st->chip_info = | 298 | st->chip_info = |
| 204 | &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | 299 | &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; |
| 205 | 300 | ||
| @@ -212,14 +307,18 @@ static int ad7780_probe(struct spi_device *spi) · 6 unmodified lines | |||
| 212 | indio_dev->num_channels = 1; | 307 | indio_dev->num_channels = 1; |
| 213 | indio_dev->info = &ad7780_info; | 308 | indio_dev->info = &ad7780_info; |
| 214 | 309 | ||
| 215 | st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev, | 310 | ret = ad7780_init_gpios(&spi->dev, st); |
| 216 | "powerdown", | 311 | if (ret) |
| 217 | GPIOD_OUT_LOW); | 312 | goto error_cleanup_buffer_and_trigger; |
| 218 | if (IS_ERR(st->powerdown_gpio)) { | 313 | |
| 219 | ret = PTR_ERR(st->powerdown_gpio); | 314 | st->reg = devm_regulator_get(&spi->dev, "avdd"); |
| 220 | dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n", | 315 | if (IS_ERR(st->reg)) |
| 221 | ret); | 316 | return PTR_ERR(st->reg); |
| 222 | goto error_disable_reg; | 317 | |
| 318 | ret = regulator_enable(st->reg); | ||
| 319 | if (ret) { | ||
| 320 | dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); | ||
| 321 | return ret; | ||
| 223 | } | 322 | } |
| 224 | 323 | ||
| 225 | ret = ad_sd_setup_buffer_and_trigger(indio_dev); | 324 | ret = ad_sd_setup_buffer_and_trigger(indio_dev); |
| @@ -24,9 +24,9 @@ · 23 unmodified lines | |||
| 24 | #include <linux/iio/trigger_consumer.h> | 24 | #include <linux/iio/trigger_consumer.h> |
| 25 | #include <linux/iio/triggered_buffer.h> | 25 | #include <linux/iio/triggered_buffer.h> |
| 26 | 26 | ||
| 27 | #define AD7923_WRITE_CR (1 << 11) /* write control register */ | 27 | #define AD7923_WRITE_CR BIT(11) /* write control register */ |
| 28 | #define AD7923_RANGE (1 << 1) /* range to REFin */ | 28 | #define AD7923_RANGE BIT(1) /* range to REFin */ |
| 29 | #define AD7923_CODING (1 << 0) /* coding is straight binary */ | 29 | #define AD7923_CODING BIT(0) /* coding is straight binary */ |
| 30 | #define AD7923_PM_MODE_AS (1) /* auto shutdown */ | 30 | #define AD7923_PM_MODE_AS (1) /* auto shutdown */ |
| 31 | #define AD7923_PM_MODE_FS (2) /* full shutdown */ | 31 | #define AD7923_PM_MODE_FS (2) /* full shutdown */ |
| 32 | #define AD7923_PM_MODE_OPS (3) /* normal operation */ | 32 | #define AD7923_PM_MODE_OPS (3) /* normal operation */ |
| @@ -40,16 +40,16 @@ · 7 unmodified lines | |||
| 40 | 40 | ||
| 41 | #define AD7923_MAX_CHAN 4 | 41 | #define AD7923_MAX_CHAN 4 |
| 42 | 42 | ||
| 43 | #define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */ | 43 | #define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */ |
| 44 | #define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */ | 44 | #define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */ |
| 45 | #define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \ | 45 | #define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \ |
| 46 | + ((sequence & 2) << 9)) | 46 | + (((sequence) & 2) << 9)) |
| 47 | /* write sequence fonction */ | 47 | /* write sequence fonction */ |
| 48 | /* left shift for CR : bit 11 transmit in first */ | 48 | /* left shift for CR : bit 11 transmit in first */ |
| 49 | #define AD7923_SHIFT_REGISTER 4 | 49 | #define AD7923_SHIFT_REGISTER 4 |
| 50 | 50 | ||
| 51 | /* val = value, dec = left shift, bits = number of bits of the mask */ | 51 | /* val = value, dec = left shift, bits = number of bits of the mask */ |
| 52 | #define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1)) | 52 | #define EXTRACT(val, dec, bits) (((val) >> (dec)) & ((1 << (bits)) - 1)) |
| 53 | 53 | ||
| 54 | struct ad7923_state { | 54 | struct ad7923_state { |
| 55 | struct spi_device *spi; | 55 | struct spi_device *spi; |
| @@ -130,7 +130,7 @@ static const struct ad7923_chip_info ad7923_chip_info[] = { · 74 unmodified lines | |||
| 130 | * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask | 130 | * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask |
| 131 | **/ | 131 | **/ |
| 132 | static int ad7923_update_scan_mode(struct iio_dev *indio_dev, | 132 | static int ad7923_update_scan_mode(struct iio_dev *indio_dev, |
| 133 | const unsigned long *active_scan_mask) | 133 | const unsigned long *active_scan_mask) |
| 134 | { | 134 | { |
| 135 | struct ad7923_state *st = iio_priv(indio_dev); | 135 | struct ad7923_state *st = iio_priv(indio_dev); |
| 136 | int i, cmd, len; | 136 | int i, cmd, len; |
| @@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) · 44 unmodified lines | |||
| 181 | goto done; | 181 | goto done; |
| 182 | 182 | ||
| 183 | iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, | 183 | iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, |
| 184 | iio_get_time_ns(indio_dev)); | 184 | iio_get_time_ns(indio_dev)); |
| 185 | 185 | ||
| 186 | done: | 186 | done: |
| 187 | iio_trigger_notify_done(indio_dev->trig); | 187 | iio_trigger_notify_done(indio_dev->trig); |
| @@ -272,7 +272,7 @@ static int ad7923_probe(struct spi_device *spi) · 84 unmodified lines | |||
| 272 | int ret; | 272 | int ret; |
| 273 | 273 | ||
| 274 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | 274 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
| 275 | if (indio_dev == NULL) | 275 | if (!indio_dev) |
| 276 | return -ENOMEM; | 276 | return -ENOMEM; |
| 277 | 277 | ||
| 278 | st = iio_priv(indio_dev); | 278 | st = iio_priv(indio_dev); |
| @@ -314,7 +314,7 @@ static int ad7923_probe(struct spi_device *spi) · 35 unmodified lines | |||
| 314 | return ret; | 314 | return ret; |
| 315 | 315 | ||
| 316 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | 316 | ret = iio_triggered_buffer_setup(indio_dev, NULL, |
| 317 | &ad7923_trigger_handler, NULL); | 317 | &ad7923_trigger_handler, NULL); |
| 318 | if (ret) | 318 | if (ret) |
| 319 | goto error_disable_reg; | 319 | goto error_disable_reg; |
| 320 | 320 | ||
| @@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, · 61 unmodified lines | |||
| 62 | struct spi_transfer t = { | 62 | struct spi_transfer t = { |
| 63 | .tx_buf = data, | 63 | .tx_buf = data, |
| 64 | .len = size + 1, | 64 | .len = size + 1, |
| 65 | .cs_change = sigma_delta->bus_locked, | 65 | .cs_change = sigma_delta->keep_cs_asserted, |
| 66 | }; | 66 | }; |
| 67 | struct spi_message m; | 67 | struct spi_message m; |
| 68 | int ret; | 68 | int ret; |
| @@ -218,6 +218,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, · 149 unmodified lines | |||
| 218 | 218 | ||
| 219 | spi_bus_lock(sigma_delta->spi->master); | 219 | spi_bus_lock(sigma_delta->spi->master); |
| 220 | sigma_delta->bus_locked = true; | 220 | sigma_delta->bus_locked = true; |
| 221 | sigma_delta->keep_cs_asserted = true; | ||
| 221 | reinit_completion(&sigma_delta->completion); | 222 | reinit_completion(&sigma_delta->completion); |
| 222 | 223 | ||
| 223 | ret = ad_sigma_delta_set_mode(sigma_delta, mode); | 224 | ret = ad_sigma_delta_set_mode(sigma_delta, mode); |
| @@ -235,9 +236,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, · 11 unmodified lines | |||
| 235 | ret = 0; | 236 | ret = 0; |
| 236 | } | 237 | } |
| 237 | out: | 238 | out: |
| 239 | sigma_delta->keep_cs_asserted = false; | ||
| 240 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | ||
| 238 | sigma_delta->bus_locked = false; | 241 | sigma_delta->bus_locked = false; |
| 239 | spi_bus_unlock(sigma_delta->spi->master); | 242 | spi_bus_unlock(sigma_delta->spi->master); |
| 240 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | ||
| 241 | 243 | ||
| 242 | return ret; | 244 | return ret; |
| 243 | } | 245 | } |
| @@ -290,6 +292,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, · 46 unmodified lines | |||
| 290 | 292 | ||
| 291 | spi_bus_lock(sigma_delta->spi->master); | 293 | spi_bus_lock(sigma_delta->spi->master); |
| 292 | sigma_delta->bus_locked = true; | 294 | sigma_delta->bus_locked = true; |
| 295 | sigma_delta->keep_cs_asserted = true; | ||
| 293 | reinit_completion(&sigma_delta->completion); | 296 | reinit_completion(&sigma_delta->completion); |
| 294 | 297 | ||
| 295 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); | 298 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); |
| @@ -299,9 +302,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 299 | ret = wait_for_completion_interruptible_timeout( | 302 | ret = wait_for_completion_interruptible_timeout( |
| 300 | &sigma_delta->completion, HZ); | 303 | &sigma_delta->completion, HZ); |
| 301 | 304 | ||
| 302 | sigma_delta->bus_locked = false; | ||
| 303 | spi_bus_unlock(sigma_delta->spi->master); | ||
| 304 | |||
| 305 | if (ret == 0) | 305 | if (ret == 0) |
| 306 | ret = -EIO; | 306 | ret = -EIO; |
| 307 | if (ret < 0) | 307 | if (ret < 0) |
| @@ -322,7 +322,10 @@ out: · 14 unmodified lines | |||
| 322 | sigma_delta->irq_dis = true; | 322 | sigma_delta->irq_dis = true; |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | sigma_delta->keep_cs_asserted = false; | ||
| 325 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | 326 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); |
| 327 | sigma_delta->bus_locked = false; | ||
| 328 | spi_bus_unlock(sigma_delta->spi->master); | ||
| 326 | mutex_unlock(&indio_dev->mlock); | 329 | mutex_unlock(&indio_dev->mlock); |
| 327 | 330 | ||
| 328 | if (ret) | 331 | if (ret) |
| @@ -359,6 +362,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) · 30 unmodified lines | |||
| 359 | 362 | ||
| 360 | spi_bus_lock(sigma_delta->spi->master); | 363 | spi_bus_lock(sigma_delta->spi->master); |
| 361 | sigma_delta->bus_locked = true; | 364 | sigma_delta->bus_locked = true; |
| 365 | sigma_delta->keep_cs_asserted = true; | ||
| 366 | |||
| 362 | ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); | 367 | ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); |
| 363 | if (ret) | 368 | if (ret) |
| 364 | goto err_unlock; | 369 | goto err_unlock; |
| @@ -387,6 +392,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) · 22 unmodified lines | |||
| 387 | sigma_delta->irq_dis = true; | 392 | sigma_delta->irq_dis = true; |
| 388 | } | 393 | } |
| 389 | 394 | ||
| 395 | sigma_delta->keep_cs_asserted = false; | ||
| 390 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | 396 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); |
| 391 | 397 | ||
| 392 | sigma_delta->bus_locked = false; | 398 | sigma_delta->bus_locked = false; |
| @@ -388,8 +388,9 @@ static irqreturn_t imx7d_adc_isr(int irq, void *dev_id) · 387 unmodified lines | |||
| 388 | * timeout flags. | 388 | * timeout flags. |
| 389 | */ | 389 | */ |
| 390 | if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT) { | 390 | if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT) { |
| 391 | pr_err("%s: ADC got conversion time out interrupt: 0x%08x\n", | 391 | dev_err(info->dev, |
| 392 | dev_name(info->dev), status); | 392 | "ADC got conversion time out interrupt: 0x%08x\n", |
| 393 | status); | ||
| 393 | status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT; | 394 | status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT; |
| 394 | writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS); | 395 | writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS); |
| 395 | } | 396 | } |
| @@ -433,167 +434,139 @@ static void imx7d_adc_power_down(struct imx7d_adc *info) · 37 unmodified lines | |||
| 433 | writel(adc_cfg, info->regs + IMX7D_REG_ADC_ADC_CFG); | 434 | writel(adc_cfg, info->regs + IMX7D_REG_ADC_ADC_CFG); |
| 434 | } | 435 | } |
| 435 | 436 | ||
| 437 | static int imx7d_adc_enable(struct device *dev) | ||
| 438 | { | ||
| 439 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 440 | struct imx7d_adc *info = iio_priv(indio_dev); | ||
| 441 | int ret; | ||
| 442 | |||
| 443 | ret = regulator_enable(info->vref); | ||
| 444 | if (ret) { | ||
| 445 | dev_err(info->dev, | ||
| 446 | "Can't enable adc reference top voltage, err = %d\n", | ||
| 447 | ret); | ||
| 448 | return ret; | ||
| 449 | } | ||
| 450 | |||
| 451 | ret = clk_prepare_enable(info->clk); | ||
| 452 | if (ret) { | ||
| 453 | dev_err(info->dev, | ||
| 454 | "Could not prepare or enable clock.\n"); | ||
| 455 | regulator_disable(info->vref); | ||
| 456 | return ret; | ||
| 457 | } | ||
| 458 | |||
| 459 | imx7d_adc_hw_init(info); | ||
| 460 | |||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | static int imx7d_adc_disable(struct device *dev) | ||
| 465 | { | ||
| 466 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 467 | struct imx7d_adc *info = iio_priv(indio_dev); | ||
| 468 | |||
| 469 | imx7d_adc_power_down(info); | ||
| 470 | |||
| 471 | clk_disable_unprepare(info->clk); | ||
| 472 | regulator_disable(info->vref); | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void __imx7d_adc_disable(void *data) | ||
| 478 | { | ||
| 479 | imx7d_adc_disable(data); | ||
| 480 | } | ||
| 481 | |||
| 436 | static int imx7d_adc_probe(struct platform_device *pdev) | 482 | static int imx7d_adc_probe(struct platform_device *pdev) |
| 437 | { | 483 | { |
| 438 | struct imx7d_adc *info; | 484 | struct imx7d_adc *info; |
| 439 | struct iio_dev *indio_dev; | 485 | struct iio_dev *indio_dev; |
| 440 | struct resource *mem; | 486 | struct device *dev = &pdev->dev; |
| 441 | int irq; | 487 | int irq; |
| 442 | int ret; | 488 | int ret; |
| 443 | 489 | ||
| 444 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); | 490 | indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); |
| 445 | if (!indio_dev) { | 491 | if (!indio_dev) { |
| 446 | dev_err(&pdev->dev, "Failed allocating iio device\n"); | 492 | dev_err(&pdev->dev, "Failed allocating iio device\n"); |
| 447 | return -ENOMEM; | 493 | return -ENOMEM; |
| 448 | } | 494 | } |
| 449 | 495 | ||
| 450 | info = iio_priv(indio_dev); | 496 | info = iio_priv(indio_dev); |
| 451 | info->dev = &pdev->dev; | 497 | info->dev = dev; |
| 452 | 498 | ||
| 453 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 499 | info->regs = devm_platform_ioremap_resource(pdev, 0); |
| 454 | info->regs = devm_ioremap_resource(&pdev->dev, mem); | ||
| 455 | if (IS_ERR(info->regs)) { | 500 | if (IS_ERR(info->regs)) { |
| 456 | ret = PTR_ERR(info->regs); | 501 | ret = PTR_ERR(info->regs); |
| 457 | dev_err(&pdev->dev, | 502 | dev_err(dev, "Failed to remap adc memory, err = %d\n", ret); |
| 458 | "Failed to remap adc memory, err = %d\n", ret); | ||
| 459 | return ret; | 503 | return ret; |
| 460 | } | 504 | } |
| 461 | 505 | ||
| 462 | irq = platform_get_irq(pdev, 0); | 506 | irq = platform_get_irq(pdev, 0); |
| 463 | if (irq < 0) { | 507 | if (irq < 0) { |
| 464 | dev_err(&pdev->dev, "No irq resource?\n"); | 508 | dev_err(dev, "No irq resource?\n"); |
| 465 | return irq; | 509 | return irq; |
| 466 | } | 510 | } |
| 467 | 511 | ||
| 468 | info->clk = devm_clk_get(&pdev->dev, "adc"); | 512 | info->clk = devm_clk_get(dev, "adc"); |
| 469 | if (IS_ERR(info->clk)) { | 513 | if (IS_ERR(info->clk)) { |
| 470 | ret = PTR_ERR(info->clk); | 514 | ret = PTR_ERR(info->clk); |
| 471 | dev_err(&pdev->dev, "Failed getting clock, err = %d\n", ret); | 515 | dev_err(dev, "Failed getting clock, err = %d\n", ret); |
| 472 | return ret; | 516 | return ret; |
| 473 | } | 517 | } |
| 474 | 518 | ||
| 475 | info->vref = devm_regulator_get(&pdev->dev, "vref"); | 519 | info->vref = devm_regulator_get(dev, "vref"); |
| 476 | if (IS_ERR(info->vref)) { | 520 | if (IS_ERR(info->vref)) { |
| 477 | ret = PTR_ERR(info->vref); | 521 | ret = PTR_ERR(info->vref); |
| 478 | dev_err(&pdev->dev, | 522 | dev_err(dev, |
| 479 | "Failed getting reference voltage, err = %d\n", ret); | 523 | "Failed getting reference voltage, err = %d\n", ret); |
| 480 | return ret; | 524 | return ret; |
| 481 | } | 525 | } |
| 482 | 526 | ||
| 483 | ret = regulator_enable(info->vref); | ||
| 484 | if (ret) { | ||
| 485 | dev_err(&pdev->dev, | ||
| 486 | "Can't enable adc reference top voltage, err = %d\n", | ||
| 487 | ret); | ||
| 488 | return ret; | ||
| 489 | } | ||
| 490 | |||
| 491 | platform_set_drvdata(pdev, indio_dev); | 527 | platform_set_drvdata(pdev, indio_dev); |
| 492 | 528 | ||
| 493 | init_completion(&info->completion); | 529 | init_completion(&info->completion); |
| 494 | 530 | ||
| 495 | indio_dev->name = dev_name(&pdev->dev); | 531 | indio_dev->name = dev_name(dev); |
| 496 | indio_dev->dev.parent = &pdev->dev; | 532 | indio_dev->dev.parent = dev; |
| 497 | indio_dev->info = &imx7d_adc_iio_info; | 533 | indio_dev->info = &imx7d_adc_iio_info; |
| 498 | indio_dev->modes = INDIO_DIRECT_MODE; | 534 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 499 | indio_dev->channels = imx7d_adc_iio_channels; | 535 | indio_dev->channels = imx7d_adc_iio_channels; |
| 500 | indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels); | 536 | indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels); |
| 501 | 537 | ||
| 502 | ret = clk_prepare_enable(info->clk); | 538 | ret = devm_request_irq(dev, irq, |
| 503 | if (ret) { | 539 | imx7d_adc_isr, 0, |
| 504 | dev_err(&pdev->dev, | 540 | dev_name(dev), info); |
| 505 | "Could not prepare or enable the clock.\n"); | ||
| 506 | goto error_adc_clk_enable; | ||
| 507 | } | ||
| 508 | |||
| 509 | ret = devm_request_irq(info->dev, irq, | ||
| 510 | imx7d_adc_isr, 0, | ||
| 511 | dev_name(&pdev->dev), info); | ||
| 512 | if (ret < 0) { | 541 | if (ret < 0) { |
| 513 | dev_err(&pdev->dev, "Failed requesting irq, irq = %d\n", irq); | 542 | dev_err(dev, "Failed requesting irq, irq = %d\n", irq); |
| 514 | goto error_iio_device_register; | 543 | return ret; |
| 515 | } | 544 | } |
| 516 | 545 | ||
| 517 | imx7d_adc_feature_config(info); | 546 | imx7d_adc_feature_config(info); |
| 518 | imx7d_adc_hw_init(info); | ||
| 519 | |||
| 520 | ret = iio_device_register(indio_dev); | ||
| 521 | if (ret) { | ||
| 522 | imx7d_adc_power_down(info); | ||
| 523 | dev_err(&pdev->dev, "Couldn't register the device.\n"); | ||
| 524 | goto error_iio_device_register; | ||
| 525 | } | ||
| 526 | |||
| 527 | return 0; | ||
| 528 | |||
| 529 | error_iio_device_register: | ||
| 530 | clk_disable_unprepare(info->clk); | ||
| 531 | error_adc_clk_enable: | ||
| 532 | regulator_disable(info->vref); | ||
| 533 | |||
| 534 | return ret; | ||
| 535 | } | ||
| 536 | |||
| 537 | static int imx7d_adc_remove(struct platform_device *pdev) | ||
| 538 | { | ||
| 539 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
| 540 | struct imx7d_adc *info = iio_priv(indio_dev); | ||
| 541 | |||
| 542 | iio_device_unregister(indio_dev); | ||
| 543 | |||
| 544 | imx7d_adc_power_down(info); | ||
| 545 | |||
| 546 | clk_disable_unprepare(info->clk); | ||
| 547 | regulator_disable(info->vref); | ||
| 548 | |||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | |||
| 552 | static int __maybe_unused imx7d_adc_suspend(struct device *dev) | ||
| 553 | { | ||
| 554 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 555 | struct imx7d_adc *info = iio_priv(indio_dev); | ||
| 556 | |||
| 557 | imx7d_adc_power_down(info); | ||
| 558 | |||
| 559 | clk_disable_unprepare(info->clk); | ||
| 560 | regulator_disable(info->vref); | ||
| 561 | |||
| 562 | return 0; | ||
| 563 | } | ||
| 564 | 547 | ||
| 565 | static int __maybe_unused imx7d_adc_resume(struct device *dev) | 548 | ret = imx7d_adc_enable(&indio_dev->dev); |
| 566 | { | 549 | if (ret) |
| 567 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 550 | return ret; |
| 568 | struct imx7d_adc *info = iio_priv(indio_dev); | ||
| 569 | int ret; | ||
| 570 | 551 | ||
| 571 | ret = regulator_enable(info->vref); | 552 | ret = devm_add_action_or_reset(dev, __imx7d_adc_disable, |
| 572 | if (ret) { | 553 | &indio_dev->dev); |
| 573 | dev_err(info->dev, | 554 | if (ret) |
| 574 | "Can't enable adc reference top voltage, err = %d\n", | ||
| 575 | ret); | ||
| 576 | return ret; | 555 | return ret; |
| 577 | } | ||
| 578 | 556 | ||
| 579 | ret = clk_prepare_enable(info->clk); | 557 | ret = devm_iio_device_register(dev, indio_dev); |
| 580 | if (ret) { | 558 | if (ret) { |
| 581 | dev_err(info->dev, | 559 | dev_err(&pdev->dev, "Couldn't register the device.\n"); |
| 582 | "Could not prepare or enable clock.\n"); | ||
| 583 | regulator_disable(info->vref); | ||
| 584 | return ret; | 560 | return ret; |
| 585 | } | 561 | } |
| 586 | 562 | ||
| 587 | imx7d_adc_hw_init(info); | ||
| 588 | |||
| 589 | return 0; | 563 | return 0; |
| 590 | } | 564 | } |
| 591 | 565 | ||
| 592 | static SIMPLE_DEV_PM_OPS(imx7d_adc_pm_ops, imx7d_adc_suspend, imx7d_adc_resume); | 566 | static SIMPLE_DEV_PM_OPS(imx7d_adc_pm_ops, imx7d_adc_disable, imx7d_adc_enable); |
| 593 | 567 | ||
| 594 | static struct platform_driver imx7d_adc_driver = { | 568 | static struct platform_driver imx7d_adc_driver = { |
| 595 | .probe = imx7d_adc_probe, | 569 | .probe = imx7d_adc_probe, |
| 596 | .remove = imx7d_adc_remove, | ||
| 597 | .driver = { | 570 | .driver = { |
| 598 | .name = "imx7d_adc", | 571 | .name = "imx7d_adc", |
| 599 | .of_match_table = imx7d_adc_match, | 572 | .of_match_table = imx7d_adc_match, |
| @@ -302,10 +302,8 @@ static int ingenic_adc_probe(struct platform_device *pdev) · 301 unmodified lines | |||
| 302 | 302 | ||
| 303 | mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 303 | mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 304 | adc->base = devm_ioremap_resource(dev, mem_base); | 304 | adc->base = devm_ioremap_resource(dev, mem_base); |
| 305 | if (IS_ERR(adc->base)) { | 305 | if (IS_ERR(adc->base)) |
| 306 | dev_err(dev, "Unable to ioremap mmio resource\n"); | ||
| 307 | return PTR_ERR(adc->base); | 306 | return PTR_ERR(adc->base); |
| 308 | } | ||
| 309 | 307 | ||
| 310 | adc->clk = devm_clk_get(dev, "adc"); | 308 | adc->clk = devm_clk_get(dev, "adc"); |
| 311 | if (IS_ERR(adc->clk)) { | 309 | if (IS_ERR(adc->clk)) { |
| @@ -7,20 +7,15 @@ · 6 unmodified lines | |||
| 7 | * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> | 7 | * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/interrupt.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| 18 | #include <linux/err.h> | ||
| 19 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
| 20 | #include <linux/of.h> | 12 | #include <linux/err.h> |
| 21 | |||
| 22 | #include <linux/iio/iio.h> | 13 | #include <linux/iio/iio.h> |
| 23 | #include <linux/iio/sysfs.h> | 14 | #include <linux/interrupt.h> |
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/regulator/consumer.h> | ||
| 24 | 19 | ||
| 25 | /* | 20 | /* |
| 26 | * LPC32XX registers definitions | 21 | * LPC32XX registers definitions |
| @@ -52,6 +47,7 @@ struct lpc32xx_adc_state { · 25 unmodified lines | |||
| 52 | void __iomem *adc_base; | 47 | void __iomem *adc_base; |
| 53 | struct clk *clk; | 48 | struct clk *clk; |
| 54 | struct completion completion; | 49 | struct completion completion; |
| 50 | struct regulator *vref; | ||
| 55 | 51 | ||
| 56 | u32 value; | 52 | u32 value; |
| 57 | }; | 53 | }; |
| @@ -64,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 64 | { | 60 | { |
| 65 | struct lpc32xx_adc_state *st = iio_priv(indio_dev); | 61 | struct lpc32xx_adc_state *st = iio_priv(indio_dev); |
| 66 | int ret; | 62 | int ret; |
| 67 | if (mask == IIO_CHAN_INFO_RAW) { | 63 | |
| 64 | switch (mask) { | ||
| 65 | case IIO_CHAN_INFO_RAW: | ||
| 68 | mutex_lock(&indio_dev->mlock); | 66 | mutex_lock(&indio_dev->mlock); |
| 69 | ret = clk_prepare_enable(st->clk); | 67 | ret = clk_prepare_enable(st->clk); |
| 70 | if (ret) { | 68 | if (ret) { |
| @@ -84,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, · 13 unmodified lines | |||
| 84 | mutex_unlock(&indio_dev->mlock); | 82 | mutex_unlock(&indio_dev->mlock); |
| 85 | 83 | ||
| 86 | return IIO_VAL_INT; | 84 | return IIO_VAL_INT; |
| 87 | } | ||
| 88 | 85 | ||
| 89 | return -EINVAL; | 86 | case IIO_CHAN_INFO_SCALE: |
| 87 | *val = regulator_get_voltage(st->vref) / 1000; | ||
| 88 | *val2 = 10; | ||
| 89 | |||
| 90 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 91 | default: | ||
| 92 | return -EINVAL; | ||
| 93 | } | ||
| 90 | } | 94 | } |
| 91 | 95 | ||
| 92 | static const struct iio_info lpc32xx_adc_iio_info = { | 96 | static const struct iio_info lpc32xx_adc_iio_info = { |
| 93 | .read_raw = &lpc32xx_read_raw, | 97 | .read_raw = &lpc32xx_read_raw, |
| 94 | }; | 98 | }; |
| 95 | 99 | ||
| 96 | #define LPC32XX_ADC_CHANNEL(_index) { \ | 100 | #define LPC32XX_ADC_CHANNEL_BASE(_index) \ |
| 97 | .type = IIO_VOLTAGE, \ | 101 | .type = IIO_VOLTAGE, \ |
| 98 | .indexed = 1, \ | 102 | .indexed = 1, \ |
| 99 | .channel = _index, \ | 103 | .channel = _index, \ |
| 100 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | 104 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
| 101 | .address = LPC32XXAD_IN * _index, \ | 105 | .address = LPC32XXAD_IN * _index, \ |
| 102 | .scan_index = _index, \ | 106 | .scan_index = _index, |
| 107 | |||
| 108 | #define LPC32XX_ADC_CHANNEL(_index) { \ | ||
| 109 | LPC32XX_ADC_CHANNEL_BASE(_index) \ | ||
| 110 | } | ||
| 111 | |||
| 112 | #define LPC32XX_ADC_SCALE_CHANNEL(_index) { \ | ||
| 113 | LPC32XX_ADC_CHANNEL_BASE(_index) \ | ||
| 114 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ | ||
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { | 117 | static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { |
| @@ -108,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { · 2 unmodified lines | |||
| 108 | LPC32XX_ADC_CHANNEL(2), | 120 | LPC32XX_ADC_CHANNEL(2), |
| 109 | }; | 121 | }; |
| 110 | 122 | ||
| 123 | static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = { | ||
| 124 | LPC32XX_ADC_SCALE_CHANNEL(0), | ||
| 125 | LPC32XX_ADC_SCALE_CHANNEL(1), | ||
| 126 | LPC32XX_ADC_SCALE_CHANNEL(2), | ||
| 127 | }; | ||
| 128 | |||
| 111 | static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) | 129 | static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) |
| 112 | { | 130 | { |
| 113 | struct lpc32xx_adc_state *st = dev_id; | 131 | struct lpc32xx_adc_state *st = dev_id; |
| @@ -166,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) · 52 unmodified lines | |||
| 166 | return retval; | 184 | return retval; |
| 167 | } | 185 | } |
| 168 | 186 | ||
| 187 | st->vref = devm_regulator_get(&pdev->dev, "vref"); | ||
| 188 | if (IS_ERR(st->vref)) { | ||
| 189 | iodev->channels = lpc32xx_adc_iio_channels; | ||
| 190 | dev_info(&pdev->dev, | ||
| 191 | "Missing vref regulator: No scaling available\n"); | ||
| 192 | } else { | ||
| 193 | iodev->channels = lpc32xx_adc_iio_scale_channels; | ||
| 194 | } | ||
| 195 | |||
| 169 | platform_set_drvdata(pdev, iodev); | 196 | platform_set_drvdata(pdev, iodev); |
| 170 | 197 | ||
| 171 | init_completion(&st->completion); | 198 | init_completion(&st->completion); |
| @@ -174,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 174 | iodev->dev.parent = &pdev->dev; | 201 | iodev->dev.parent = &pdev->dev; |
| 175 | iodev->info = &lpc32xx_adc_iio_info; | 202 | iodev->info = &lpc32xx_adc_iio_info; |
| 176 | iodev->modes = INDIO_DIRECT_MODE; | 203 | iodev->modes = INDIO_DIRECT_MODE; |
| 177 | iodev->channels = lpc32xx_adc_iio_channels; | ||
| 178 | iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); | 204 | iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); |
| 179 | 205 | ||
| 180 | retval = devm_iio_device_register(&pdev->dev, iodev); | 206 | retval = devm_iio_device_register(&pdev->dev, iodev); |
| @@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { · 1149 unmodified lines | |||
| 1150 | .name = "meson-axg-saradc", | 1150 | .name = "meson-axg-saradc", |
| 1151 | }; | 1151 | }; |
| 1152 | 1152 | ||
| 1153 | static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { | ||
| 1154 | .param = &meson_sar_adc_gxl_param, | ||
| 1155 | .name = "meson-g12a-saradc", | ||
| 1156 | }; | ||
| 1157 | |||
| 1153 | static const struct of_device_id meson_sar_adc_of_match[] = { | 1158 | static const struct of_device_id meson_sar_adc_of_match[] = { |
| 1154 | { | 1159 | { |
| 1155 | .compatible = "amlogic,meson8-saradc", | 1160 | .compatible = "amlogic,meson8-saradc", |
| @@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { · 19 unmodified lines | |||
| 1175 | }, { | 1180 | }, { |
| 1176 | .compatible = "amlogic,meson-axg-saradc", | 1181 | .compatible = "amlogic,meson-axg-saradc", |
| 1177 | .data = &meson_sar_adc_axg_data, | 1182 | .data = &meson_sar_adc_axg_data, |
| 1183 | }, { | ||
| 1184 | .compatible = "amlogic,meson-g12a-saradc", | ||
| 1185 | .data = &meson_sar_adc_g12a_data, | ||
| 1178 | }, | 1186 | }, |
| 1179 | {}, | 1187 | {}, |
| 1180 | }; | 1188 | }; |
| @@ -465,6 +465,8 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio) · 464 unmodified lines | |||
| 465 | 465 | ||
| 466 | trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name, | 466 | trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name, |
| 467 | iio->id); | 467 | iio->id); |
| 468 | if (!trig) | ||
| 469 | return -ENOMEM; | ||
| 468 | 470 | ||
| 469 | trig->dev.parent = adc->dev; | 471 | trig->dev.parent = adc->dev; |
| 470 | iio_trigger_set_drvdata(trig, iio); | 472 | iio_trigger_set_drvdata(trig, iio); |
| @@ -664,6 +664,7 @@ static const struct of_device_id adc5_match_table[] = { · 663 unmodified lines | |||
| 664 | }, | 664 | }, |
| 665 | { } | 665 | { } |
| 666 | }; | 666 | }; |
| 667 | MODULE_DEVICE_TABLE(of, adc5_match_table); | ||
| 667 | 668 | ||
| 668 | static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) | 669 | static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) |
| 669 | { | 670 | { |
| @@ -12,6 +12,11 @@ · 11 unmodified lines | |||
| 12 | #include <linux/iio/buffer.h> | 12 | #include <linux/iio/buffer.h> |
| 13 | #include <linux/iio/hw-consumer.h> | 13 | #include <linux/iio/hw-consumer.h> |
| 14 | #include <linux/iio/sysfs.h> | 14 | #include <linux/iio/sysfs.h> |
| 15 | #include <linux/iio/timer/stm32-lptim-trigger.h> | ||
| 16 | #include <linux/iio/timer/stm32-timer-trigger.h> | ||
| 17 | #include <linux/iio/trigger.h> | ||
| 18 | #include <linux/iio/trigger_consumer.h> | ||
| 19 | #include <linux/iio/triggered_buffer.h> | ||
| 15 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
| 16 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 17 | #include <linux/of_device.h> | 22 | #include <linux/of_device.h> |
| @@ -38,6 +43,11 @@ · 20 unmodified lines | |||
| 38 | #define DFSDM_MAX_RES BIT(31) | 43 | #define DFSDM_MAX_RES BIT(31) |
| 39 | #define DFSDM_DATA_RES BIT(23) | 44 | #define DFSDM_DATA_RES BIT(23) |
| 40 | 45 | ||
| 46 | /* Filter configuration */ | ||
| 47 | #define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \ | ||
| 48 | DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \ | ||
| 49 | DFSDM_CR1_JSCAN_MASK) | ||
| 50 | |||
| 41 | enum sd_converter_type { | 51 | enum sd_converter_type { |
| 42 | DFSDM_AUDIO, | 52 | DFSDM_AUDIO, |
| 43 | DFSDM_IIO, | 53 | DFSDM_IIO, |
| @@ -54,6 +64,8 @@ struct stm32_dfsdm_adc { · 10 unmodified lines | |||
| 54 | struct stm32_dfsdm *dfsdm; | 64 | struct stm32_dfsdm *dfsdm; |
| 55 | const struct stm32_dfsdm_dev_data *dev_data; | 65 | const struct stm32_dfsdm_dev_data *dev_data; |
| 56 | unsigned int fl_id; | 66 | unsigned int fl_id; |
| 67 | unsigned int nconv; | ||
| 68 | unsigned long smask; | ||
| 57 | 69 | ||
| 58 | /* ADC specific */ | 70 | /* ADC specific */ |
| 59 | unsigned int oversamp; | 71 | unsigned int oversamp; |
| @@ -114,6 +126,61 @@ static int stm32_dfsdm_str2val(const char *str, · 54 unmodified lines | |||
| 114 | return -EINVAL; | 126 | return -EINVAL; |
| 115 | } | 127 | } |
| 116 | 128 | ||
| 129 | /** | ||
| 130 | * struct stm32_dfsdm_trig_info - DFSDM trigger info | ||
| 131 | * @name: name of the trigger, corresponding to its source | ||
| 132 | * @jextsel: trigger signal selection | ||
| 133 | */ | ||
| 134 | struct stm32_dfsdm_trig_info { | ||
| 135 | const char *name; | ||
| 136 | unsigned int jextsel; | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* hardware injected trigger enable, edge selection */ | ||
| 140 | enum stm32_dfsdm_jexten { | ||
| 141 | STM32_DFSDM_JEXTEN_DISABLED, | ||
| 142 | STM32_DFSDM_JEXTEN_RISING_EDGE, | ||
| 143 | STM32_DFSDM_JEXTEN_FALLING_EDGE, | ||
| 144 | STM32_DFSDM_EXTEN_BOTH_EDGES, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = { | ||
| 148 | { TIM1_TRGO, 0 }, | ||
| 149 | { TIM1_TRGO2, 1 }, | ||
| 150 | { TIM8_TRGO, 2 }, | ||
| 151 | { TIM8_TRGO2, 3 }, | ||
| 152 | { TIM3_TRGO, 4 }, | ||
| 153 | { TIM4_TRGO, 5 }, | ||
| 154 | { TIM16_OC1, 6 }, | ||
| 155 | { TIM6_TRGO, 7 }, | ||
| 156 | { TIM7_TRGO, 8 }, | ||
| 157 | { LPTIM1_OUT, 26 }, | ||
| 158 | { LPTIM2_OUT, 27 }, | ||
| 159 | { LPTIM3_OUT, 28 }, | ||
| 160 | {}, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev, | ||
| 164 | struct iio_trigger *trig) | ||
| 165 | { | ||
| 166 | int i; | ||
| 167 | |||
| 168 | /* lookup triggers registered by stm32 timer trigger driver */ | ||
| 169 | for (i = 0; stm32_dfsdm_trigs[i].name; i++) { | ||
| 170 | /** | ||
| 171 | * Checking both stm32 timer trigger type and trig name | ||
| 172 | * should be safe against arbitrary trigger names. | ||
| 173 | */ | ||
| 174 | if ((is_stm32_timer_trigger(trig) || | ||
| 175 | is_stm32_lptim_trigger(trig)) && | ||
| 176 | !strcmp(stm32_dfsdm_trigs[i].name, trig->name)) { | ||
| 177 | return stm32_dfsdm_trigs[i].jextsel; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | return -EINVAL; | ||
| 182 | } | ||
| 183 | |||
| 117 | static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, | 184 | static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, |
| 118 | unsigned int fast, unsigned int oversamp) | 185 | unsigned int fast, unsigned int oversamp) |
| 119 | { | 186 | { |
| @@ -200,19 +267,39 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, · 80 unmodified lines | |||
| 200 | return 0; | 267 | return 0; |
| 201 | } | 268 | } |
| 202 | 269 | ||
| 203 | static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm, | 270 | static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc) |
| 204 | unsigned int ch_id) | ||
| 205 | { | 271 | { |
| 206 | return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), | 272 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); |
| 207 | DFSDM_CHCFGR1_CHEN_MASK, | 273 | struct regmap *regmap = adc->dfsdm->regmap; |
| 208 | DFSDM_CHCFGR1_CHEN(1)); | 274 | const struct iio_chan_spec *chan; |
| 275 | unsigned int bit; | ||
| 276 | int ret; | ||
| 277 | |||
| 278 | for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { | ||
| 279 | chan = indio_dev->channels + bit; | ||
| 280 | ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), | ||
| 281 | DFSDM_CHCFGR1_CHEN_MASK, | ||
| 282 | DFSDM_CHCFGR1_CHEN(1)); | ||
| 283 | if (ret < 0) | ||
| 284 | return ret; | ||
| 285 | } | ||
| 286 | |||
| 287 | return 0; | ||
| 209 | } | 288 | } |
| 210 | 289 | ||
| 211 | static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, | 290 | static void stm32_dfsdm_stop_channel(struct stm32_dfsdm_adc *adc) |
| 212 | unsigned int ch_id) | ||
| 213 | { | 291 | { |
| 214 | regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), | 292 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); |
| 215 | DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0)); | 293 | struct regmap *regmap = adc->dfsdm->regmap; |
| 294 | const struct iio_chan_spec *chan; | ||
| 295 | unsigned int bit; | ||
| 296 | |||
| 297 | for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) { | ||
| 298 | chan = indio_dev->channels + bit; | ||
| 299 | regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel), | ||
| 300 | DFSDM_CHCFGR1_CHEN_MASK, | ||
| 301 | DFSDM_CHCFGR1_CHEN(0)); | ||
| 302 | } | ||
| 216 | } | 303 | } |
| 217 | 304 | ||
| 218 | static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, | 305 | static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, |
| @@ -237,9 +324,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, · 18 unmodified lines | |||
| 237 | DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); | 324 | DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); |
| 238 | } | 325 | } |
| 239 | 326 | ||
| 240 | static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, | 327 | static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc, |
| 241 | unsigned int fl_id) | 328 | unsigned int fl_id, |
| 329 | struct iio_trigger *trig) | ||
| 242 | { | 330 | { |
| 331 | struct stm32_dfsdm *dfsdm = adc->dfsdm; | ||
| 243 | int ret; | 332 | int ret; |
| 244 | 333 | ||
| 245 | /* Enable filter */ | 334 | /* Enable filter */ |
| @@ -248,7 +337,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, · 2 unmodified lines | |||
| 248 | if (ret < 0) | 337 | if (ret < 0) |
| 249 | return ret; | 338 | return ret; |
| 250 | 339 | ||
| 251 | /* Start conversion */ | 340 | /* Nothing more to do for injected (scan mode/triggered) conversions */ |
| 341 | if (adc->nconv > 1 || trig) | ||
| 342 | return 0; | ||
| 343 | |||
| 344 | /* Software start (single or continuous) regular conversion */ | ||
| 252 | return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), | 345 | return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), |
| 253 | DFSDM_CR1_RSWSTART_MASK, | 346 | DFSDM_CR1_RSWSTART_MASK, |
| 254 | DFSDM_CR1_RSWSTART(1)); | 347 | DFSDM_CR1_RSWSTART(1)); |
| @@ -262,11 +355,45 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, · 7 unmodified lines | |||
| 262 | DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); | 355 | DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); |
| 263 | } | 356 | } |
| 264 | 357 | ||
| 265 | static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, | 358 | static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc, |
| 266 | unsigned int fl_id, unsigned int ch_id) | 359 | unsigned int fl_id, |
| 360 | struct iio_trigger *trig) | ||
| 267 | { | 361 | { |
| 268 | struct regmap *regmap = dfsdm->regmap; | 362 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); |
| 269 | struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id]; | 363 | struct regmap *regmap = adc->dfsdm->regmap; |
| 364 | u32 jextsel = 0, jexten = STM32_DFSDM_JEXTEN_DISABLED; | ||
| 365 | int ret; | ||
| 366 | |||
| 367 | if (trig) { | ||
| 368 | ret = stm32_dfsdm_get_jextsel(indio_dev, trig); | ||
| 369 | if (ret < 0) | ||
| 370 | return ret; | ||
| 371 | |||
| 372 | /* set trigger source and polarity (default to rising edge) */ | ||
| 373 | jextsel = ret; | ||
| 374 | jexten = STM32_DFSDM_JEXTEN_RISING_EDGE; | ||
| 375 | } | ||
| 376 | |||
| 377 | ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), | ||
| 378 | DFSDM_CR1_JEXTSEL_MASK | DFSDM_CR1_JEXTEN_MASK, | ||
| 379 | DFSDM_CR1_JEXTSEL(jextsel) | | ||
| 380 | DFSDM_CR1_JEXTEN(jexten)); | ||
| 381 | if (ret < 0) | ||
| 382 | return ret; | ||
| 383 | |||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc, | ||
| 388 | unsigned int fl_id, | ||
| 389 | struct iio_trigger *trig) | ||
| 390 | { | ||
| 391 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); | ||
| 392 | struct regmap *regmap = adc->dfsdm->regmap; | ||
| 393 | struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id]; | ||
| 394 | u32 cr1; | ||
| 395 | const struct iio_chan_spec *chan; | ||
| 396 | unsigned int bit, jchg = 0; | ||
| 270 | int ret; | 397 | int ret; |
| 271 | 398 | ||
| 272 | /* Average integrator oversampling */ | 399 | /* Average integrator oversampling */ |
| @@ -286,15 +413,68 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, · 13 unmodified lines | |||
| 286 | if (ret) | 413 | if (ret) |
| 287 | return ret; | 414 | return ret; |
| 288 | 415 | ||
| 289 | /* No scan mode supported for the moment */ | 416 | ret = stm32_dfsdm_filter_set_trig(adc, fl_id, trig); |
| 290 | ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, | ||
| 291 | DFSDM_CR1_RCH(ch_id)); | ||
| 292 | if (ret) | 417 | if (ret) |
| 293 | return ret; | 418 | return ret; |
| 294 | 419 | ||
| 295 | return regmap_update_bits(regmap, DFSDM_CR1(fl_id), | 420 | /* |
| 296 | DFSDM_CR1_RSYNC_MASK, | 421 | * DFSDM modes configuration W.R.T audio/iio type modes |
| 297 | DFSDM_CR1_RSYNC(fl->sync_mode)); | 422 | * ---------------------------------------------------------------- |
| 423 | * Modes | regular | regular | injected | injected | | ||
| 424 | * | | continuous | | + scan | | ||
| 425 | * --------------|---------|--------------|----------|------------| | ||
| 426 | * single conv | x | | | | | ||
| 427 | * (1 chan) | | | | | | ||
| 428 | * --------------|---------|--------------|----------|------------| | ||
| 429 | * 1 Audio chan | | sample freq | | | | ||
| 430 | * | | or sync_mode | | | | ||
| 431 | * --------------|---------|--------------|----------|------------| | ||
| 432 | * 1 IIO chan | | sample freq | trigger | | | ||
| 433 | * | | or sync_mode | | | | ||
| 434 | * --------------|---------|--------------|----------|------------| | ||
| 435 | * 2+ IIO chans | | | | trigger or | | ||
| 436 | * | | | | sync_mode | | ||
| 437 | * ---------------------------------------------------------------- | ||
| 438 | */ | ||
| 439 | if (adc->nconv == 1 && !trig) { | ||
| 440 | bit = __ffs(adc->smask); | ||
| 441 | chan = indio_dev->channels + bit; | ||
| 442 | |||
| 443 | /* Use regular conversion for single channel without trigger */ | ||
| 444 | cr1 = DFSDM_CR1_RCH(chan->channel); | ||
| 445 | |||
| 446 | /* Continuous conversions triggered by SPI clk in buffer mode */ | ||
| 447 | if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE) | ||
| 448 | cr1 |= DFSDM_CR1_RCONT(1); | ||
| 449 | |||
| 450 | cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode); | ||
| 451 | } else { | ||
| 452 | /* Use injected conversion for multiple channels */ | ||
| 453 | for_each_set_bit(bit, &adc->smask, | ||
| 454 | sizeof(adc->smask) * BITS_PER_BYTE) { | ||
| 455 | chan = indio_dev->channels + bit; | ||
| 456 | jchg |= BIT(chan->channel); | ||
| 457 | } | ||
| 458 | ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg); | ||
| 459 | if (ret < 0) | ||
| 460 | return ret; | ||
| 461 | |||
| 462 | /* Use scan mode for multiple channels */ | ||
| 463 | cr1 = DFSDM_CR1_JSCAN((adc->nconv > 1) ? 1 : 0); | ||
| 464 | |||
| 465 | /* | ||
| 466 | * Continuous conversions not supported in injected mode, | ||
| 467 | * either use: | ||
| 468 | * - conversions in sync with filter 0 | ||
| 469 | * - triggered conversions | ||
| 470 | */ | ||
| 471 | if (!fl->sync_mode && !trig) | ||
| 472 | return -EINVAL; | ||
| 473 | cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode); | ||
| 474 | } | ||
| 475 | |||
| 476 | return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK, | ||
| 477 | cr1); | ||
| 298 | } | 478 | } |
| 299 | 479 | ||
| 300 | static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, | 480 | static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, |
| @@ -378,13 +558,38 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, · 77 unmodified lines | |||
| 378 | return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); | 558 | return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); |
| 379 | } | 559 | } |
| 380 | 560 | ||
| 561 | static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev, | ||
| 562 | unsigned int sample_freq, | ||
| 563 | unsigned int spi_freq) | ||
| 564 | { | ||
| 565 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
| 566 | struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; | ||
| 567 | unsigned int oversamp; | ||
| 568 | int ret; | ||
| 569 | |||
| 570 | oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq); | ||
| 571 | if (spi_freq % sample_freq) | ||
| 572 | dev_dbg(&indio_dev->dev, | ||
| 573 | "Rate not accurate. requested (%u), actual (%u)\n", | ||
| 574 | sample_freq, spi_freq / oversamp); | ||
| 575 | |||
| 576 | ret = stm32_dfsdm_set_osrs(fl, 0, oversamp); | ||
| 577 | if (ret < 0) { | ||
| 578 | dev_err(&indio_dev->dev, "No filter parameters that match!\n"); | ||
| 579 | return ret; | ||
| 580 | } | ||
| 581 | adc->sample_freq = spi_freq / oversamp; | ||
| 582 | adc->oversamp = oversamp; | ||
| 583 | |||
| 584 | return 0; | ||
| 585 | } | ||
| 586 | |||
| 381 | static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, | 587 | static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, |
| 382 | uintptr_t priv, | 588 | uintptr_t priv, |
| 383 | const struct iio_chan_spec *chan, | 589 | const struct iio_chan_spec *chan, |
| 384 | const char *buf, size_t len) | 590 | const char *buf, size_t len) |
| 385 | { | 591 | { |
| 386 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 592 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 387 | struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; | ||
| 388 | struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; | 593 | struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; |
| 389 | unsigned int sample_freq = adc->sample_freq; | 594 | unsigned int sample_freq = adc->sample_freq; |
| 390 | unsigned int spi_freq; | 595 | unsigned int spi_freq; |
| @@ -403,17 +608,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, · 12 unmodified lines | |||
| 403 | return -EINVAL; | 608 | return -EINVAL; |
| 404 | 609 | ||
| 405 | if (sample_freq) { | 610 | if (sample_freq) { |
| 406 | if (spi_freq % sample_freq) | 611 | ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq); |
| 407 | dev_warn(&indio_dev->dev, | 612 | if (ret < 0) |
| 408 | "Sampling rate not accurate (%d)\n", | ||
| 409 | spi_freq / (spi_freq / sample_freq)); | ||
| 410 | |||
| 411 | ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq)); | ||
| 412 | if (ret < 0) { | ||
| 413 | dev_err(&indio_dev->dev, | ||
| 414 | "No filter parameters that match!\n"); | ||
| 415 | return ret; | 613 | return ret; |
| 416 | } | ||
| 417 | } | 614 | } |
| 418 | adc->spi_freq = spi_freq; | 615 | adc->spi_freq = spi_freq; |
| 419 | 616 | ||
| @@ -421,72 +618,44 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 421 | } | 618 | } |
| 422 | 619 | ||
| 423 | static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, | 620 | static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, |
| 424 | const struct iio_chan_spec *chan, | 621 | struct iio_trigger *trig) |
| 425 | bool dma) | ||
| 426 | { | 622 | { |
| 427 | struct regmap *regmap = adc->dfsdm->regmap; | 623 | struct regmap *regmap = adc->dfsdm->regmap; |
| 428 | int ret; | 624 | int ret; |
| 429 | unsigned int dma_en = 0, cont_en = 0; | ||
| 430 | 625 | ||
| 431 | ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel); | 626 | ret = stm32_dfsdm_start_channel(adc); |
| 432 | if (ret < 0) | 627 | if (ret < 0) |
| 433 | return ret; | 628 | return ret; |
| 434 | 629 | ||
| 435 | ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, | 630 | ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, trig); |
| 436 | chan->channel); | ||
| 437 | if (ret < 0) | 631 | if (ret < 0) |
| 438 | goto stop_channels; | 632 | goto stop_channels; |
| 439 | 633 | ||
| 440 | if (dma) { | 634 | ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig); |
| 441 | /* Enable DMA transfer*/ | ||
| 442 | dma_en = DFSDM_CR1_RDMAEN(1); | ||
| 443 | /* Enable conversion triggered by SPI clock*/ | ||
| 444 | cont_en = DFSDM_CR1_RCONT(1); | ||
| 445 | } | ||
| 446 | /* Enable DMA transfer*/ | ||
| 447 | ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
| 448 | DFSDM_CR1_RDMAEN_MASK, dma_en); | ||
| 449 | if (ret < 0) | 635 | if (ret < 0) |
| 450 | goto stop_channels; | 636 | goto filter_unconfigure; |
| 451 | |||
| 452 | /* Enable conversion triggered by SPI clock*/ | ||
| 453 | ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
| 454 | DFSDM_CR1_RCONT_MASK, cont_en); | ||
| 455 | if (ret < 0) | ||
| 456 | goto stop_channels; | ||
| 457 | |||
| 458 | ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); | ||
| 459 | if (ret < 0) | ||
| 460 | goto stop_channels; | ||
| 461 | 637 | ||
| 462 | return 0; | 638 | return 0; |
| 463 | 639 | ||
| 464 | stop_channels: | 640 | filter_unconfigure: |
| 465 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
| 466 | DFSDM_CR1_RDMAEN_MASK, 0); | ||
| 467 | |||
| 468 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | 641 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), |
| 469 | DFSDM_CR1_RCONT_MASK, 0); | 642 | DFSDM_CR1_CFG_MASK, 0); |
| 470 | stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); | 643 | stop_channels: |
| 644 | stm32_dfsdm_stop_channel(adc); | ||
| 471 | 645 | ||
| 472 | return ret; | 646 | return ret; |
| 473 | } | 647 | } |
| 474 | 648 | ||
| 475 | static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc, | 649 | static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) |
| 476 | const struct iio_chan_spec *chan) | ||
| 477 | { | 650 | { |
| 478 | struct regmap *regmap = adc->dfsdm->regmap; | 651 | struct regmap *regmap = adc->dfsdm->regmap; |
| 479 | 652 | ||
| 480 | stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); | 653 | stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); |
| 481 | 654 | ||
| 482 | /* Clean conversion options */ | ||
| 483 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | ||
| 484 | DFSDM_CR1_RDMAEN_MASK, 0); | ||
| 485 | |||
| 486 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), | 655 | regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), |
| 487 | DFSDM_CR1_RCONT_MASK, 0); | 656 | DFSDM_CR1_CFG_MASK, 0); |
| 488 | 657 | ||
| 489 | stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); | 658 | stm32_dfsdm_stop_channel(adc); |
| 490 | } | 659 | } |
| 491 | 660 | ||
| 492 | static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, | 661 | static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, |
| @@ -494,6 +663,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 494 | { | 663 | { |
| 495 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 664 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 496 | unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; | 665 | unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; |
| 666 | unsigned int rx_buf_sz = DFSDM_DMA_BUFFER_SIZE; | ||
| 497 | 667 | ||
| 498 | /* | 668 | /* |
| 499 | * DMA cyclic transfers are used, buffer is split into two periods. | 669 | * DMA cyclic transfers are used, buffer is split into two periods. |
| @@ -502,7 +672,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 502 | * - one buffer (period) driver pushed to ASoC side. | 672 | * - one buffer (period) driver pushed to ASoC side. |
| 503 | */ | 673 | */ |
| 504 | watermark = min(watermark, val * (unsigned int)(sizeof(u32))); | 674 | watermark = min(watermark, val * (unsigned int)(sizeof(u32))); |
| 505 | adc->buf_sz = watermark * 2; | 675 | adc->buf_sz = min(rx_buf_sz, watermark * 2 * adc->nconv); |
| 506 | 676 | ||
| 507 | return 0; | 677 | return 0; |
| 508 | } | 678 | } |
| @@ -532,13 +702,41 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) · 23 unmodified lines | |||
| 532 | return 0; | 702 | return 0; |
| 533 | } | 703 | } |
| 534 | 704 | ||
| 535 | static void stm32_dfsdm_audio_dma_buffer_done(void *data) | 705 | static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p) |
| 706 | { | ||
| 707 | struct iio_poll_func *pf = p; | ||
| 708 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 709 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
| 710 | int available = stm32_dfsdm_adc_dma_residue(adc); | ||
| 711 | |||
| 712 | while (available >= indio_dev->scan_bytes) { | ||
| 713 | u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi]; | ||
| 714 | |||
| 715 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, | ||
| 716 | pf->timestamp); | ||
| 717 | available -= indio_dev->scan_bytes; | ||
| 718 | adc->bufi += indio_dev->scan_bytes; | ||
| 719 | if (adc->bufi >= adc->buf_sz) | ||
| 720 | adc->bufi = 0; | ||
| 721 | } | ||
| 722 | |||
| 723 | iio_trigger_notify_done(indio_dev->trig); | ||
| 724 | |||
| 725 | return IRQ_HANDLED; | ||
| 726 | } | ||
| 727 | |||
| 728 | static void stm32_dfsdm_dma_buffer_done(void *data) | ||
| 536 | { | 729 | { |
| 537 | struct iio_dev *indio_dev = data; | 730 | struct iio_dev *indio_dev = data; |
| 538 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 731 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 539 | int available = stm32_dfsdm_adc_dma_residue(adc); | 732 | int available = stm32_dfsdm_adc_dma_residue(adc); |
| 540 | size_t old_pos; | 733 | size_t old_pos; |
| 541 | 734 | ||
| 735 | if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) { | ||
| 736 | iio_trigger_poll_chained(indio_dev->trig); | ||
| 737 | return; | ||
| 738 | } | ||
| 739 | |||
| 542 | /* | 740 | /* |
| 543 | * FIXME: In Kernel interface does not support cyclic DMA buffer,and | 741 | * FIXME: In Kernel interface does not support cyclic DMA buffer,and |
| 544 | * offers only an interface to push data samples per samples. | 742 | * offers only an interface to push data samples per samples. |
| @@ -566,6 +764,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) · 21 unmodified lines | |||
| 566 | adc->bufi = 0; | 764 | adc->bufi = 0; |
| 567 | old_pos = 0; | 765 | old_pos = 0; |
| 568 | } | 766 | } |
| 767 | /* regular iio buffer without trigger */ | ||
| 768 | if (adc->dev_data->type == DFSDM_IIO) | ||
| 769 | iio_push_to_buffers(indio_dev, buffer); | ||
| 569 | } | 770 | } |
| 570 | if (adc->cb) | 771 | if (adc->cb) |
| 571 | adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, | 772 | adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, |
| @@ -575,6 +776,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) · 3 unmodified lines | |||
| 575 | static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) | 776 | static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) |
| 576 | { | 777 | { |
| 577 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 778 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 779 | struct dma_slave_config config = { | ||
| 780 | .src_addr = (dma_addr_t)adc->dfsdm->phys_base, | ||
| 781 | .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, | ||
| 782 | }; | ||
| 578 | struct dma_async_tx_descriptor *desc; | 783 | struct dma_async_tx_descriptor *desc; |
| 579 | dma_cookie_t cookie; | 784 | dma_cookie_t cookie; |
| 580 | int ret; | 785 | int ret; |
| @@ -585,6 +790,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) · 4 unmodified lines | |||
| 585 | dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, | 790 | dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, |
| 586 | adc->buf_sz, adc->buf_sz / 2); | 791 | adc->buf_sz, adc->buf_sz / 2); |
| 587 | 792 | ||
| 793 | if (adc->nconv == 1 && !indio_dev->trig) | ||
| 794 | config.src_addr += DFSDM_RDATAR(adc->fl_id); | ||
| 795 | else | ||
| 796 | config.src_addr += DFSDM_JDATAR(adc->fl_id); | ||
| 797 | ret = dmaengine_slave_config(adc->dma_chan, &config); | ||
| 798 | if (ret) | ||
| 799 | return ret; | ||
| 800 | |||
| 588 | /* Prepare a DMA cyclic transaction */ | 801 | /* Prepare a DMA cyclic transaction */ |
| 589 | desc = dmaengine_prep_dma_cyclic(adc->dma_chan, | 802 | desc = dmaengine_prep_dma_cyclic(adc->dma_chan, |
| 590 | adc->dma_buf, | 803 | adc->dma_buf, |
| @@ -594,71 +807,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) · 3 unmodified lines | |||
| 594 | if (!desc) | 807 | if (!desc) |
| 595 | return -EBUSY; | 808 | return -EBUSY; |
| 596 | 809 | ||
| 597 | desc->callback = stm32_dfsdm_audio_dma_buffer_done; | 810 | desc->callback = stm32_dfsdm_dma_buffer_done; |
| 598 | desc->callback_param = indio_dev; | 811 | desc->callback_param = indio_dev; |
| 599 | 812 | ||
| 600 | cookie = dmaengine_submit(desc); | 813 | cookie = dmaengine_submit(desc); |
| 601 | ret = dma_submit_error(cookie); | 814 | ret = dma_submit_error(cookie); |
| 602 | if (ret) { | 815 | if (ret) |
| 603 | dmaengine_terminate_all(adc->dma_chan); | 816 | goto err_stop_dma; |
| 604 | return ret; | ||
| 605 | } | ||
| 606 | 817 | ||
| 607 | /* Issue pending DMA requests */ | 818 | /* Issue pending DMA requests */ |
| 608 | dma_async_issue_pending(adc->dma_chan); | 819 | dma_async_issue_pending(adc->dma_chan); |
| 609 | 820 | ||
| 821 | if (adc->nconv == 1 && !indio_dev->trig) { | ||
| 822 | /* Enable regular DMA transfer*/ | ||
| 823 | ret = regmap_update_bits(adc->dfsdm->regmap, | ||
| 824 | DFSDM_CR1(adc->fl_id), | ||
| 825 | DFSDM_CR1_RDMAEN_MASK, | ||
| 826 | DFSDM_CR1_RDMAEN_MASK); | ||
| 827 | } else { | ||
| 828 | /* Enable injected DMA transfer*/ | ||
| 829 | ret = regmap_update_bits(adc->dfsdm->regmap, | ||
| 830 | DFSDM_CR1(adc->fl_id), | ||
| 831 | DFSDM_CR1_JDMAEN_MASK, | ||
| 832 | DFSDM_CR1_JDMAEN_MASK); | ||
| 833 | } | ||
| 834 | |||
| 835 | if (ret < 0) | ||
| 836 | goto err_stop_dma; | ||
| 837 | |||
| 610 | return 0; | 838 | return 0; |
| 839 | |||
| 840 | err_stop_dma: | ||
| 841 | dmaengine_terminate_all(adc->dma_chan); | ||
| 842 | |||
| 843 | return ret; | ||
| 611 | } | 844 | } |
| 612 | 845 | ||
| 613 | static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) | 846 | static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev) |
| 847 | { | ||
| 848 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
| 849 | |||
| 850 | if (!adc->dma_chan) | ||
| 851 | return; | ||
| 852 | |||
| 853 | regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id), | ||
| 854 | DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0); | ||
| 855 | dmaengine_terminate_all(adc->dma_chan); | ||
| 856 | } | ||
| 857 | |||
| 858 | static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev, | ||
| 859 | const unsigned long *scan_mask) | ||
| 860 | { | ||
| 861 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | ||
| 862 | |||
| 863 | adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength); | ||
| 864 | adc->smask = *scan_mask; | ||
| 865 | |||
| 866 | dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask); | ||
| 867 | |||
| 868 | return 0; | ||
| 869 | } | ||
| 870 | |||
| 871 | static int __stm32_dfsdm_postenable(struct iio_dev *indio_dev) | ||
| 614 | { | 872 | { |
| 615 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 873 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 616 | const struct iio_chan_spec *chan = &indio_dev->channels[0]; | ||
| 617 | int ret; | 874 | int ret; |
| 618 | 875 | ||
| 619 | /* Reset adc buffer index */ | 876 | /* Reset adc buffer index */ |
| 620 | adc->bufi = 0; | 877 | adc->bufi = 0; |
| 621 | 878 | ||
| 879 | if (adc->hwc) { | ||
| 880 | ret = iio_hw_consumer_enable(adc->hwc); | ||
| 881 | if (ret < 0) | ||
| 882 | return ret; | ||
| 883 | } | ||
| 884 | |||
| 622 | ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); | 885 | ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); |
| 623 | if (ret < 0) | 886 | if (ret < 0) |
| 624 | return ret; | 887 | goto err_stop_hwc; |
| 625 | 888 | ||
| 626 | ret = stm32_dfsdm_start_conv(adc, chan, true); | 889 | ret = stm32_dfsdm_adc_dma_start(indio_dev); |
| 627 | if (ret) { | 890 | if (ret) { |
| 628 | dev_err(&indio_dev->dev, "Can't start conversion\n"); | 891 | dev_err(&indio_dev->dev, "Can't start DMA\n"); |
| 629 | goto stop_dfsdm; | 892 | goto stop_dfsdm; |
| 630 | } | 893 | } |
| 631 | 894 | ||
| 632 | if (adc->dma_chan) { | 895 | ret = stm32_dfsdm_start_conv(adc, indio_dev->trig); |
| 633 | ret = stm32_dfsdm_adc_dma_start(indio_dev); | 896 | if (ret) { |
| 634 | if (ret) { | 897 | dev_err(&indio_dev->dev, "Can't start conversion\n"); |
| 635 | dev_err(&indio_dev->dev, "Can't start DMA\n"); | 898 | goto err_stop_dma; |
| 636 | goto err_stop_conv; | ||
| 637 | } | ||
| 638 | } | 899 | } |
| 639 | 900 | ||
| 640 | return 0; | 901 | return 0; |
| 641 | 902 | ||
| 642 | err_stop_conv: | 903 | err_stop_dma: |
| 643 | stm32_dfsdm_stop_conv(adc, chan); | 904 | stm32_dfsdm_adc_dma_stop(indio_dev); |
| 644 | stop_dfsdm: | 905 | stop_dfsdm: |
| 645 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | 906 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); |
| 907 | err_stop_hwc: | ||
| 908 | if (adc->hwc) | ||
| 909 | iio_hw_consumer_disable(adc->hwc); | ||
| 646 | 910 | ||
| 647 | return ret; | 911 | return ret; |
| 648 | } | 912 | } |
| 649 | 913 | ||
| 650 | static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) | 914 | static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) |
| 915 | { | ||
| 916 | int ret; | ||
| 917 | |||
| 918 | if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { | ||
| 919 | ret = iio_triggered_buffer_postenable(indio_dev); | ||
| 920 | if (ret < 0) | ||
| 921 | return ret; | ||
| 922 | } | ||
| 923 | |||
| 924 | ret = __stm32_dfsdm_postenable(indio_dev); | ||
| 925 | if (ret < 0) | ||
| 926 | goto err_predisable; | ||
| 927 | |||
| 928 | return 0; | ||
| 929 | |||
| 930 | err_predisable: | ||
| 931 | if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) | ||
| 932 | iio_triggered_buffer_predisable(indio_dev); | ||
| 933 | |||
| 934 | return ret; | ||
| 935 | } | ||
| 936 | |||
| 937 | static void __stm32_dfsdm_predisable(struct iio_dev *indio_dev) | ||
| 651 | { | 938 | { |
| 652 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 939 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 653 | const struct iio_chan_spec *chan = &indio_dev->channels[0]; | ||
| 654 | 940 | ||
| 655 | if (adc->dma_chan) | 941 | stm32_dfsdm_stop_conv(adc); |
| 656 | dmaengine_terminate_all(adc->dma_chan); | ||
| 657 | 942 | ||
| 658 | stm32_dfsdm_stop_conv(adc, chan); | 943 | stm32_dfsdm_adc_dma_stop(indio_dev); |
| 659 | 944 | ||
| 660 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | 945 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); |
| 661 | 946 | ||
| 947 | if (adc->hwc) | ||
| 948 | iio_hw_consumer_disable(adc->hwc); | ||
| 949 | } | ||
| 950 | |||
| 951 | static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) | ||
| 952 | { | ||
| 953 | __stm32_dfsdm_predisable(indio_dev); | ||
| 954 | |||
| 955 | if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) | ||
| 956 | iio_triggered_buffer_predisable(indio_dev); | ||
| 957 | |||
| 662 | return 0; | 958 | return 0; |
| 663 | } | 959 | } |
| 664 | 960 | ||
| @@ -736,7 +1032,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, · 71 unmodified lines | |||
| 736 | if (ret < 0) | 1032 | if (ret < 0) |
| 737 | goto stop_dfsdm; | 1033 | goto stop_dfsdm; |
| 738 | 1034 | ||
| 739 | ret = stm32_dfsdm_start_conv(adc, chan, false); | 1035 | adc->nconv = 1; |
| 1036 | adc->smask = BIT(chan->scan_index); | ||
| 1037 | ret = stm32_dfsdm_start_conv(adc, NULL); | ||
| 740 | if (ret < 0) { | 1038 | if (ret < 0) { |
| 741 | regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), | 1039 | regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), |
| 742 | DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); | 1040 | DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); |
| @@ -757,7 +1055,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, · 14 unmodified lines | |||
| 757 | else | 1055 | else |
| 758 | ret = IIO_VAL_INT; | 1056 | ret = IIO_VAL_INT; |
| 759 | 1057 | ||
| 760 | stm32_dfsdm_stop_conv(adc, chan); | 1058 | stm32_dfsdm_stop_conv(adc); |
| 761 | 1059 | ||
| 762 | stop_dfsdm: | 1060 | stop_dfsdm: |
| 763 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); | 1061 | stm32_dfsdm_stop_dfsdm(adc->dfsdm); |
| @@ -777,16 +1075,23 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, · 13 unmodified lines | |||
| 777 | 1075 | ||
| 778 | switch (mask) { | 1076 | switch (mask) { |
| 779 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 1077 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| 1078 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 1079 | if (ret) | ||
| 1080 | return ret; | ||
| 780 | ret = stm32_dfsdm_set_osrs(fl, 0, val); | 1081 | ret = stm32_dfsdm_set_osrs(fl, 0, val); |
| 781 | if (!ret) | 1082 | if (!ret) |
| 782 | adc->oversamp = val; | 1083 | adc->oversamp = val; |
| 783 | 1084 | iio_device_release_direct_mode(indio_dev); | |
| 784 | return ret; | 1085 | return ret; |
| 785 | 1086 | ||
| 786 | case IIO_CHAN_INFO_SAMP_FREQ: | 1087 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 787 | if (!val) | 1088 | if (!val) |
| 788 | return -EINVAL; | 1089 | return -EINVAL; |
| 789 | 1090 | ||
| 1091 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 1092 | if (ret) | ||
| 1093 | return ret; | ||
| 1094 | |||
| 790 | switch (ch->src) { | 1095 | switch (ch->src) { |
| 791 | case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: | 1096 | case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: |
| 792 | spi_freq = adc->dfsdm->spi_master_freq; | 1097 | spi_freq = adc->dfsdm->spi_master_freq; |
| @@ -799,20 +1104,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 799 | spi_freq = adc->spi_freq; | 1104 | spi_freq = adc->spi_freq; |
| 800 | } | 1105 | } |
| 801 | 1106 | ||
| 802 | if (spi_freq % val) | 1107 | ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq); |
| 803 | dev_warn(&indio_dev->dev, | 1108 | iio_device_release_direct_mode(indio_dev); |
| 804 | "Sampling rate not accurate (%d)\n", | 1109 | return ret; |
| 805 | spi_freq / (spi_freq / val)); | ||
| 806 | |||
| 807 | ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val)); | ||
| 808 | if (ret < 0) { | ||
| 809 | dev_err(&indio_dev->dev, | ||
| 810 | "Not able to find parameter that match!\n"); | ||
| 811 | return ret; | ||
| 812 | } | ||
| 813 | adc->sample_freq = val; | ||
| 814 | |||
| 815 | return 0; | ||
| 816 | } | 1110 | } |
| 817 | 1111 | ||
| 818 | return -EINVAL; | 1112 | return -EINVAL; |
| @@ -827,11 +1121,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, · 8 unmodified lines | |||
| 827 | 1121 | ||
| 828 | switch (mask) { | 1122 | switch (mask) { |
| 829 | case IIO_CHAN_INFO_RAW: | 1123 | case IIO_CHAN_INFO_RAW: |
| 1124 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 1125 | if (ret) | ||
| 1126 | return ret; | ||
| 830 | ret = iio_hw_consumer_enable(adc->hwc); | 1127 | ret = iio_hw_consumer_enable(adc->hwc); |
| 831 | if (ret < 0) { | 1128 | if (ret < 0) { |
| 832 | dev_err(&indio_dev->dev, | 1129 | dev_err(&indio_dev->dev, |
| 833 | "%s: IIO enable failed (channel %d)\n", | 1130 | "%s: IIO enable failed (channel %d)\n", |
| 834 | __func__, chan->channel); | 1131 | __func__, chan->channel); |
| 1132 | iio_device_release_direct_mode(indio_dev); | ||
| 835 | return ret; | 1133 | return ret; |
| 836 | } | 1134 | } |
| 837 | ret = stm32_dfsdm_single_conv(indio_dev, chan, val); | 1135 | ret = stm32_dfsdm_single_conv(indio_dev, chan, val); |
| @@ -840,8 +1138,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 840 | dev_err(&indio_dev->dev, | 1138 | dev_err(&indio_dev->dev, |
| 841 | "%s: Conversion failed (channel %d)\n", | 1139 | "%s: Conversion failed (channel %d)\n", |
| 842 | __func__, chan->channel); | 1140 | __func__, chan->channel); |
| 1141 | iio_device_release_direct_mode(indio_dev); | ||
| 843 | return ret; | 1142 | return ret; |
| 844 | } | 1143 | } |
| 1144 | iio_device_release_direct_mode(indio_dev); | ||
| 845 | return IIO_VAL_INT; | 1145 | return IIO_VAL_INT; |
| 846 | 1146 | ||
| 847 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: | 1147 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
| @@ -858,15 +1158,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, · 10 unmodified lines | |||
| 858 | return -EINVAL; | 1158 | return -EINVAL; |
| 859 | } | 1159 | } |
| 860 | 1160 | ||
| 1161 | static int stm32_dfsdm_validate_trigger(struct iio_dev *indio_dev, | ||
| 1162 | struct iio_trigger *trig) | ||
| 1163 | { | ||
| 1164 | return stm32_dfsdm_get_jextsel(indio_dev, trig) < 0 ? -EINVAL : 0; | ||
| 1165 | } | ||
| 1166 | |||
| 861 | static const struct iio_info stm32_dfsdm_info_audio = { | 1167 | static const struct iio_info stm32_dfsdm_info_audio = { |
| 862 | .hwfifo_set_watermark = stm32_dfsdm_set_watermark, | 1168 | .hwfifo_set_watermark = stm32_dfsdm_set_watermark, |
| 863 | .read_raw = stm32_dfsdm_read_raw, | 1169 | .read_raw = stm32_dfsdm_read_raw, |
| 864 | .write_raw = stm32_dfsdm_write_raw, | 1170 | .write_raw = stm32_dfsdm_write_raw, |
| 1171 | .update_scan_mode = stm32_dfsdm_update_scan_mode, | ||
| 865 | }; | 1172 | }; |
| 866 | 1173 | ||
| 867 | static const struct iio_info stm32_dfsdm_info_adc = { | 1174 | static const struct iio_info stm32_dfsdm_info_adc = { |
| 1175 | .hwfifo_set_watermark = stm32_dfsdm_set_watermark, | ||
| 868 | .read_raw = stm32_dfsdm_read_raw, | 1176 | .read_raw = stm32_dfsdm_read_raw, |
| 869 | .write_raw = stm32_dfsdm_write_raw, | 1177 | .write_raw = stm32_dfsdm_write_raw, |
| 1178 | .update_scan_mode = stm32_dfsdm_update_scan_mode, | ||
| 1179 | .validate_trigger = stm32_dfsdm_validate_trigger, | ||
| 870 | }; | 1180 | }; |
| 871 | 1181 | ||
| 872 | static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) | 1182 | static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) |
| @@ -926,12 +1236,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) · 53 unmodified lines | |||
| 926 | static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) | 1236 | static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) |
| 927 | { | 1237 | { |
| 928 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); | 1238 | struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); |
| 929 | struct dma_slave_config config = { | ||
| 930 | .src_addr = (dma_addr_t)adc->dfsdm->phys_base + | ||
| 931 | DFSDM_RDATAR(adc->fl_id), | ||
| 932 | .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, | ||
| 933 | }; | ||
| 934 | int ret; | ||
| 935 | 1239 | ||
| 936 | adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); | 1240 | adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); |
| 937 | if (!adc->dma_chan) | 1241 | if (!adc->dma_chan) |
| @@ -941,23 +1245,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) · 3 unmodified lines | |||
| 941 | DFSDM_DMA_BUFFER_SIZE, | 1245 | DFSDM_DMA_BUFFER_SIZE, |
| 942 | &adc->dma_buf, GFP_KERNEL); | 1246 | &adc->dma_buf, GFP_KERNEL); |
| 943 | if (!adc->rx_buf) { | 1247 | if (!adc->rx_buf) { |
| 944 | ret = -ENOMEM; | 1248 | dma_release_channel(adc->dma_chan); |
| 945 | goto err_release; | 1249 | return -ENOMEM; |
| 946 | } | 1250 | } |
| 947 | 1251 | ||
| 948 | ret = dmaengine_slave_config(adc->dma_chan, &config); | 1252 | indio_dev->modes |= INDIO_BUFFER_SOFTWARE; |
| 949 | if (ret) | 1253 | indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; |
| 950 | goto err_free; | ||
| 951 | 1254 | ||
| 952 | return 0; | 1255 | return 0; |
| 953 | |||
| 954 | err_free: | ||
| 955 | dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE, | ||
| 956 | adc->rx_buf, adc->dma_buf); | ||
| 957 | err_release: | ||
| 958 | dma_release_channel(adc->dma_chan); | ||
| 959 | |||
| 960 | return ret; | ||
| 961 | } | 1256 | } |
| 962 | 1257 | ||
| 963 | static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, | 1258 | static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, |
| @@ -978,7 +1273,8 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, · 14 unmodified lines | |||
| 978 | * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling | 1273 | * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling |
| 979 | */ | 1274 | */ |
| 980 | ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); | 1275 | ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
| 981 | ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); | 1276 | ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | |
| 1277 | BIT(IIO_CHAN_INFO_SAMP_FREQ); | ||
| 982 | 1278 | ||
| 983 | if (adc->dev_data->type == DFSDM_AUDIO) { | 1279 | if (adc->dev_data->type == DFSDM_AUDIO) { |
| 984 | ch->scan_type.sign = 's'; | 1280 | ch->scan_type.sign = 's'; |
| @@ -1000,9 +1296,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) · 15 unmodified lines | |||
| 1000 | struct stm32_dfsdm_channel *d_ch; | 1296 | struct stm32_dfsdm_channel *d_ch; |
| 1001 | int ret; | 1297 | int ret; |
| 1002 | 1298 | ||
| 1003 | indio_dev->modes |= INDIO_BUFFER_SOFTWARE; | ||
| 1004 | indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; | ||
| 1005 | |||
| 1006 | ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); | 1299 | ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); |
| 1007 | if (!ch) | 1300 | if (!ch) |
| 1008 | return -ENOMEM; | 1301 | return -ENOMEM; |
| @@ -1070,6 +1363,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) · 61 unmodified lines | |||
| 1070 | 1363 | ||
| 1071 | init_completion(&adc->completion); | 1364 | init_completion(&adc->completion); |
| 1072 | 1365 | ||
| 1366 | /* Optionally request DMA */ | ||
| 1367 | if (stm32_dfsdm_dma_request(indio_dev)) { | ||
| 1368 | dev_dbg(&indio_dev->dev, "No DMA support\n"); | ||
| 1369 | return 0; | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | ret = iio_triggered_buffer_setup(indio_dev, | ||
| 1373 | &iio_pollfunc_store_time, | ||
| 1374 | &stm32_dfsdm_adc_trigger_handler, | ||
| 1375 | &stm32_dfsdm_buffer_setup_ops); | ||
| 1376 | if (ret) { | ||
| 1377 | stm32_dfsdm_dma_release(indio_dev); | ||
| 1378 | dev_err(&indio_dev->dev, "buffer setup failed\n"); | ||
| 1379 | return ret; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | /* lptimer/timer hardware triggers */ | ||
| 1383 | indio_dev->modes |= INDIO_HARDWARE_TRIGGERED; | ||
| 1384 | |||
| 1073 | return 0; | 1385 | return 0; |
| 1074 | } | 1386 | } |
| 1075 | 1387 | ||
| @@ -1117,7 +1429,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) · 41 unmodified lines | |||
| 1117 | 1429 | ||
| 1118 | iio->dev.parent = dev; | 1430 | iio->dev.parent = dev; |
| 1119 | iio->dev.of_node = np; | 1431 | iio->dev.of_node = np; |
| 1120 | iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; | 1432 | iio->modes = INDIO_DIRECT_MODE; |
| 1121 | 1433 | ||
| 1122 | platform_set_drvdata(pdev, adc); | 1434 | platform_set_drvdata(pdev, adc); |
| 1123 | 1435 | ||
| @@ -1203,10 +1515,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) · 79 unmodified lines | |||
| 1203 | return 0; | 1515 | return 0; |
| 1204 | } | 1516 | } |
| 1205 | 1517 | ||
| 1518 | static int __maybe_unused stm32_dfsdm_adc_suspend(struct device *dev) | ||
| 1519 | { | ||
| 1520 | struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); | ||
| 1521 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); | ||
| 1522 | |||
| 1523 | if (iio_buffer_enabled(indio_dev)) | ||
| 1524 | __stm32_dfsdm_predisable(indio_dev); | ||
| 1525 | |||
| 1526 | return 0; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | static int __maybe_unused stm32_dfsdm_adc_resume(struct device *dev) | ||
| 1530 | { | ||
| 1531 | struct stm32_dfsdm_adc *adc = dev_get_drvdata(dev); | ||
| 1532 | struct iio_dev *indio_dev = iio_priv_to_dev(adc); | ||
| 1533 | const struct iio_chan_spec *chan; | ||
| 1534 | struct stm32_dfsdm_channel *ch; | ||
| 1535 | int i, ret; | ||
| 1536 | |||
| 1537 | /* restore channels configuration */ | ||
| 1538 | for (i = 0; i < indio_dev->num_channels; i++) { | ||
| 1539 | chan = indio_dev->channels + i; | ||
| 1540 | ch = &adc->dfsdm->ch_list[chan->channel]; | ||
| 1541 | ret = stm32_dfsdm_chan_configure(adc->dfsdm, ch); | ||
| 1542 | if (ret) | ||
| 1543 | return ret; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | if (iio_buffer_enabled(indio_dev)) | ||
| 1547 | __stm32_dfsdm_postenable(indio_dev); | ||
| 1548 | |||
| 1549 | return 0; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | static SIMPLE_DEV_PM_OPS(stm32_dfsdm_adc_pm_ops, | ||
| 1553 | stm32_dfsdm_adc_suspend, stm32_dfsdm_adc_resume); | ||
| 1554 | |||
| 1206 | static struct platform_driver stm32_dfsdm_adc_driver = { | 1555 | static struct platform_driver stm32_dfsdm_adc_driver = { |
| 1207 | .driver = { | 1556 | .driver = { |
| 1208 | .name = "stm32-dfsdm-adc", | 1557 | .name = "stm32-dfsdm-adc", |
| 1209 | .of_match_table = stm32_dfsdm_adc_match, | 1558 | .of_match_table = stm32_dfsdm_adc_match, |
| 1559 | .pm = &stm32_dfsdm_adc_pm_ops, | ||
| 1210 | }, | 1560 | }, |
| 1211 | .probe = stm32_dfsdm_adc_probe, | 1561 | .probe = stm32_dfsdm_adc_probe, |
| 1212 | .remove = stm32_dfsdm_adc_remove, | 1562 | .remove = stm32_dfsdm_adc_remove, |
| @@ -12,6 +12,8 @@ · 11 unmodified lines | |||
| 12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/of_device.h> | 14 | #include <linux/of_device.h> |
| 15 | #include <linux/pinctrl/consumer.h> | ||
| 16 | #include <linux/pm_runtime.h> | ||
| 15 | #include <linux/regmap.h> | 17 | #include <linux/regmap.h> |
| 16 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 17 | 19 | ||
| @@ -90,6 +92,36 @@ struct dfsdm_priv { · 72 unmodified lines | |||
| 90 | struct clk *aclk; /* audio clock */ | 92 | struct clk *aclk; /* audio clock */ |
| 91 | }; | 93 | }; |
| 92 | 94 | ||
| 95 | static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm) | ||
| 96 | { | ||
| 97 | return container_of(dfsdm, struct dfsdm_priv, dfsdm); | ||
| 98 | } | ||
| 99 | |||
| 100 | static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm) | ||
| 101 | { | ||
| 102 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); | ||
| 103 | int ret; | ||
| 104 | |||
| 105 | ret = clk_prepare_enable(priv->clk); | ||
| 106 | if (ret || !priv->aclk) | ||
| 107 | return ret; | ||
| 108 | |||
| 109 | ret = clk_prepare_enable(priv->aclk); | ||
| 110 | if (ret) | ||
| 111 | clk_disable_unprepare(priv->clk); | ||
| 112 | |||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | |||
| 116 | static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) | ||
| 117 | { | ||
| 118 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); | ||
| 119 | |||
| 120 | if (priv->aclk) | ||
| 121 | clk_disable_unprepare(priv->aclk); | ||
| 122 | clk_disable_unprepare(priv->clk); | ||
| 123 | } | ||
| 124 | |||
| 93 | /** | 125 | /** |
| 94 | * stm32_dfsdm_start_dfsdm - start global dfsdm interface. | 126 | * stm32_dfsdm_start_dfsdm - start global dfsdm interface. |
| 95 | * | 127 | * |
| @@ -98,24 +130,17 @@ struct dfsdm_priv { · 2 unmodified lines | |||
| 98 | */ | 130 | */ |
| 99 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) | 131 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) |
| 100 | { | 132 | { |
| 101 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | 133 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); |
| 102 | struct device *dev = &priv->pdev->dev; | 134 | struct device *dev = &priv->pdev->dev; |
| 103 | unsigned int clk_div = priv->spi_clk_out_div, clk_src; | 135 | unsigned int clk_div = priv->spi_clk_out_div, clk_src; |
| 104 | int ret; | 136 | int ret; |
| 105 | 137 | ||
| 106 | if (atomic_inc_return(&priv->n_active_ch) == 1) { | 138 | if (atomic_inc_return(&priv->n_active_ch) == 1) { |
| 107 | ret = clk_prepare_enable(priv->clk); | 139 | ret = pm_runtime_get_sync(dev); |
| 108 | if (ret < 0) { | 140 | if (ret < 0) { |
| 109 | dev_err(dev, "Failed to start clock\n"); | 141 | pm_runtime_put_noidle(dev); |
| 110 | goto error_ret; | 142 | goto error_ret; |
| 111 | } | 143 | } |
| 112 | if (priv->aclk) { | ||
| 113 | ret = clk_prepare_enable(priv->aclk); | ||
| 114 | if (ret < 0) { | ||
| 115 | dev_err(dev, "Failed to start audio clock\n"); | ||
| 116 | goto disable_clk; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | 144 | ||
| 120 | /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ | 145 | /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ |
| 121 | clk_src = priv->aclk ? 1 : 0; | 146 | clk_src = priv->aclk ? 1 : 0; |
| @@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) · 1 unmodified line | |||
| 123 | DFSDM_CHCFGR1_CKOUTSRC_MASK, | 148 | DFSDM_CHCFGR1_CKOUTSRC_MASK, |
| 124 | DFSDM_CHCFGR1_CKOUTSRC(clk_src)); | 149 | DFSDM_CHCFGR1_CKOUTSRC(clk_src)); |
| 125 | if (ret < 0) | 150 | if (ret < 0) |
| 126 | goto disable_aclk; | 151 | goto pm_put; |
| 127 | 152 | ||
| 128 | /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ | 153 | /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ |
| 129 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | 154 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), |
| 130 | DFSDM_CHCFGR1_CKOUTDIV_MASK, | 155 | DFSDM_CHCFGR1_CKOUTDIV_MASK, |
| 131 | DFSDM_CHCFGR1_CKOUTDIV(clk_div)); | 156 | DFSDM_CHCFGR1_CKOUTDIV(clk_div)); |
| 132 | if (ret < 0) | 157 | if (ret < 0) |
| 133 | goto disable_aclk; | 158 | goto pm_put; |
| 134 | 159 | ||
| 135 | /* Global enable of DFSDM interface */ | 160 | /* Global enable of DFSDM interface */ |
| 136 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | 161 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), |
| 137 | DFSDM_CHCFGR1_DFSDMEN_MASK, | 162 | DFSDM_CHCFGR1_DFSDMEN_MASK, |
| 138 | DFSDM_CHCFGR1_DFSDMEN(1)); | 163 | DFSDM_CHCFGR1_DFSDMEN(1)); |
| 139 | if (ret < 0) | 164 | if (ret < 0) |
| 140 | goto disable_aclk; | 165 | goto pm_put; |
| 141 | } | 166 | } |
| 142 | 167 | ||
| 143 | dev_dbg(dev, "%s: n_active_ch %d\n", __func__, | 168 | dev_dbg(dev, "%s: n_active_ch %d\n", __func__, |
| @@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) · 1 unmodified line | |||
| 145 | 170 | ||
| 146 | return 0; | 171 | return 0; |
| 147 | 172 | ||
| 148 | disable_aclk: | 173 | pm_put: |
| 149 | clk_disable_unprepare(priv->aclk); | 174 | pm_runtime_put_sync(dev); |
| 150 | disable_clk: | ||
| 151 | clk_disable_unprepare(priv->clk); | ||
| 152 | |||
| 153 | error_ret: | 175 | error_ret: |
| 154 | atomic_dec(&priv->n_active_ch); | 176 | atomic_dec(&priv->n_active_ch); |
| 155 | 177 | ||
| @@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); · 9 unmodified lines | |||
| 165 | */ | 187 | */ |
| 166 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) | 188 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) |
| 167 | { | 189 | { |
| 168 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | 190 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); |
| 169 | int ret; | 191 | int ret; |
| 170 | 192 | ||
| 171 | if (atomic_dec_and_test(&priv->n_active_ch)) { | 193 | if (atomic_dec_and_test(&priv->n_active_ch)) { |
| @@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) · 11 unmodified lines | |||
| 183 | if (ret < 0) | 205 | if (ret < 0) |
| 184 | return ret; | 206 | return ret; |
| 185 | 207 | ||
| 186 | clk_disable_unprepare(priv->clk); | 208 | pm_runtime_put_sync(&priv->pdev->dev); |
| 187 | if (priv->aclk) | ||
| 188 | clk_disable_unprepare(priv->aclk); | ||
| 189 | } | 209 | } |
| 190 | dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, | 210 | dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, |
| 191 | atomic_read(&priv->n_active_ch)); | 211 | atomic_read(&priv->n_active_ch)); |
| @@ -199,7 +219,7 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, · 7 unmodified lines | |||
| 199 | { | 219 | { |
| 200 | struct device_node *node = pdev->dev.of_node; | 220 | struct device_node *node = pdev->dev.of_node; |
| 201 | struct resource *res; | 221 | struct resource *res; |
| 202 | unsigned long clk_freq; | 222 | unsigned long clk_freq, divider; |
| 203 | unsigned int spi_freq, rem; | 223 | unsigned int spi_freq, rem; |
| 204 | int ret; | 224 | int ret; |
| 205 | 225 | ||
| @@ -243,13 +263,20 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, · 37 unmodified lines | |||
| 243 | return 0; | 263 | return 0; |
| 244 | } | 264 | } |
| 245 | 265 | ||
| 246 | priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; | 266 | divider = div_u64_rem(clk_freq, spi_freq, &rem); |
| 247 | if (!priv->spi_clk_out_div) { | 267 | /* Round up divider when ckout isn't precise, not to exceed spi_freq */ |
| 248 | /* spi_clk_out_div == 0 means ckout is OFF */ | 268 | if (rem) |
| 269 | divider++; | ||
| 270 | |||
| 271 | /* programmable divider is in range of [2:256] */ | ||
| 272 | if (divider < 2 || divider > 256) { | ||
| 249 | dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); | 273 | dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); |
| 250 | return -EINVAL; | 274 | return -EINVAL; |
| 251 | } | 275 | } |
| 252 | priv->dfsdm.spi_master_freq = spi_freq; | 276 | |
| 277 | /* SPI clock output divider is: divider = CKOUTDIV + 1 */ | ||
| 278 | priv->spi_clk_out_div = divider - 1; | ||
| 279 | priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1); | ||
| 253 | 280 | ||
| 254 | if (rem) { | 281 | if (rem) { |
| 255 | dev_warn(&pdev->dev, "SPI clock not accurate\n"); | 282 | dev_warn(&pdev->dev, "SPI clock not accurate\n"); |
| @@ -318,14 +345,111 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) · 62 unmodified lines | |||
| 318 | 345 | ||
| 319 | platform_set_drvdata(pdev, dfsdm); | 346 | platform_set_drvdata(pdev, dfsdm); |
| 320 | 347 | ||
| 321 | return devm_of_platform_populate(&pdev->dev); | 348 | ret = stm32_dfsdm_clk_prepare_enable(dfsdm); |
| 349 | if (ret) { | ||
| 350 | dev_err(&pdev->dev, "Failed to start clock\n"); | ||
| 351 | return ret; | ||
| 352 | } | ||
| 353 | |||
| 354 | pm_runtime_get_noresume(&pdev->dev); | ||
| 355 | pm_runtime_set_active(&pdev->dev); | ||
| 356 | pm_runtime_enable(&pdev->dev); | ||
| 357 | |||
| 358 | ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); | ||
| 359 | if (ret) | ||
| 360 | goto pm_put; | ||
| 361 | |||
| 362 | pm_runtime_put(&pdev->dev); | ||
| 363 | |||
| 364 | return 0; | ||
| 365 | |||
| 366 | pm_put: | ||
| 367 | pm_runtime_disable(&pdev->dev); | ||
| 368 | pm_runtime_set_suspended(&pdev->dev); | ||
| 369 | pm_runtime_put_noidle(&pdev->dev); | ||
| 370 | stm32_dfsdm_clk_disable_unprepare(dfsdm); | ||
| 371 | |||
| 372 | return ret; | ||
| 373 | } | ||
| 374 | |||
| 375 | static int stm32_dfsdm_core_remove(struct platform_device *pdev) | ||
| 376 | { | ||
| 377 | struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); | ||
| 378 | |||
| 379 | pm_runtime_get_sync(&pdev->dev); | ||
| 380 | of_platform_depopulate(&pdev->dev); | ||
| 381 | pm_runtime_disable(&pdev->dev); | ||
| 382 | pm_runtime_set_suspended(&pdev->dev); | ||
| 383 | pm_runtime_put_noidle(&pdev->dev); | ||
| 384 | stm32_dfsdm_clk_disable_unprepare(dfsdm); | ||
| 385 | |||
| 386 | return 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev) | ||
| 390 | { | ||
| 391 | struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); | ||
| 392 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); | ||
| 393 | int ret; | ||
| 394 | |||
| 395 | ret = pm_runtime_force_suspend(dev); | ||
| 396 | if (ret) | ||
| 397 | return ret; | ||
| 398 | |||
| 399 | /* Balance devm_regmap_init_mmio_clk() clk_prepare() */ | ||
| 400 | clk_unprepare(priv->clk); | ||
| 401 | |||
| 402 | return pinctrl_pm_select_sleep_state(dev); | ||
| 322 | } | 403 | } |
| 323 | 404 | ||
| 405 | static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev) | ||
| 406 | { | ||
| 407 | struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); | ||
| 408 | struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); | ||
| 409 | int ret; | ||
| 410 | |||
| 411 | ret = pinctrl_pm_select_default_state(dev); | ||
| 412 | if (ret) | ||
| 413 | return ret; | ||
| 414 | |||
| 415 | ret = clk_prepare(priv->clk); | ||
| 416 | if (ret) | ||
| 417 | return ret; | ||
| 418 | |||
| 419 | return pm_runtime_force_resume(dev); | ||
| 420 | } | ||
| 421 | |||
| 422 | static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev) | ||
| 423 | { | ||
| 424 | struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); | ||
| 425 | |||
| 426 | stm32_dfsdm_clk_disable_unprepare(dfsdm); | ||
| 427 | |||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev) | ||
| 432 | { | ||
| 433 | struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); | ||
| 434 | |||
| 435 | return stm32_dfsdm_clk_prepare_enable(dfsdm); | ||
| 436 | } | ||
| 437 | |||
| 438 | static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { | ||
| 439 | SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, | ||
| 440 | stm32_dfsdm_core_resume) | ||
| 441 | SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, | ||
| 442 | stm32_dfsdm_core_runtime_resume, | ||
| 443 | NULL) | ||
| 444 | }; | ||
| 445 | |||
| 324 | static struct platform_driver stm32_dfsdm_driver = { | 446 | static struct platform_driver stm32_dfsdm_driver = { |
| 325 | .probe = stm32_dfsdm_probe, | 447 | .probe = stm32_dfsdm_probe, |
| 448 | .remove = stm32_dfsdm_core_remove, | ||
| 326 | .driver = { | 449 | .driver = { |
| 327 | .name = "stm32-dfsdm", | 450 | .name = "stm32-dfsdm", |
| 328 | .of_match_table = stm32_dfsdm_of_match, | 451 | .of_match_table = stm32_dfsdm_of_match, |
| 452 | .pm = &stm32_dfsdm_core_pm_ops, | ||
| 329 | }, | 453 | }, |
| 330 | }; | 454 | }; |
| 331 | 455 | ||
| @@ -184,9 +184,6 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) · 183 unmodified lines | |||
| 184 | struct stmpe_adc *info = (struct stmpe_adc *)dev_id; | 184 | struct stmpe_adc *info = (struct stmpe_adc *)dev_id; |
| 185 | u16 data; | 185 | u16 data; |
| 186 | 186 | ||
| 187 | if (info->channel > STMPE_TEMP_CHANNEL) | ||
| 188 | return IRQ_NONE; | ||
| 189 | |||
| 190 | if (info->channel <= STMPE_ADC_LAST_NR) { | 187 | if (info->channel <= STMPE_ADC_LAST_NR) { |
| 191 | int int_sta; | 188 | int int_sta; |
| 192 | 189 | ||
| @@ -205,6 +202,8 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) · 12 unmodified lines | |||
| 205 | /* Read value */ | 202 | /* Read value */ |
| 206 | stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2, | 203 | stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2, |
| 207 | (u8 *) &data); | 204 | (u8 *) &data); |
| 205 | } else { | ||
| 206 | return IRQ_NONE; | ||
| 208 | } | 207 | } |
| 209 | 208 | ||
| 210 | info->value = (u32) be16_to_cpu(data); | 209 | info->value = (u32) be16_to_cpu(data); |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
| 18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
| 19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
| 20 | #include <linux/gpio/driver.h> | ||
| 20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| @@ -36,12 +37,15 @@ · 13 unmodified lines | |||
| 36 | */ | 37 | */ |
| 37 | #define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000 | 38 | #define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000 |
| 38 | 39 | ||
| 40 | #define TI_ADS7950_CR_GPIO BIT(14) | ||
| 39 | #define TI_ADS7950_CR_MANUAL BIT(12) | 41 | #define TI_ADS7950_CR_MANUAL BIT(12) |
| 40 | #define TI_ADS7950_CR_WRITE BIT(11) | 42 | #define TI_ADS7950_CR_WRITE BIT(11) |
| 41 | #define TI_ADS7950_CR_CHAN(ch) ((ch) << 7) | 43 | #define TI_ADS7950_CR_CHAN(ch) ((ch) << 7) |
| 42 | #define TI_ADS7950_CR_RANGE_5V BIT(6) | 44 | #define TI_ADS7950_CR_RANGE_5V BIT(6) |
| 45 | #define TI_ADS7950_CR_GPIO_DATA BIT(4) | ||
| 43 | 46 | ||
| 44 | #define TI_ADS7950_MAX_CHAN 16 | 47 | #define TI_ADS7950_MAX_CHAN 16 |
| 48 | #define TI_ADS7950_NUM_GPIOS 4 | ||
| 45 | 49 | ||
| 46 | #define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) | 50 | #define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) |
| 47 | 51 | ||
| @@ -49,6 +53,16 @@ · 1 unmodified line | |||
| 49 | #define TI_ADS7950_EXTRACT(val, dec, bits) \ | 53 | #define TI_ADS7950_EXTRACT(val, dec, bits) \ |
| 50 | (((val) >> (dec)) & ((1 << (bits)) - 1)) | 54 | (((val) >> (dec)) & ((1 << (bits)) - 1)) |
| 51 | 55 | ||
| 56 | #define TI_ADS7950_MAN_CMD(cmd) (TI_ADS7950_CR_MANUAL | (cmd)) | ||
| 57 | #define TI_ADS7950_GPIO_CMD(cmd) (TI_ADS7950_CR_GPIO | (cmd)) | ||
| 58 | |||
| 59 | /* Manual mode configuration */ | ||
| 60 | #define TI_ADS7950_MAN_CMD_SETTINGS(st) \ | ||
| 61 | (TI_ADS7950_MAN_CMD(TI_ADS7950_CR_WRITE | st->cmd_settings_bitmask)) | ||
| 62 | /* GPIO mode configuration */ | ||
| 63 | #define TI_ADS7950_GPIO_CMD_SETTINGS(st) \ | ||
| 64 | (TI_ADS7950_GPIO_CMD(st->gpio_cmd_settings_bitmask)) | ||
| 65 | |||
| 52 | struct ti_ads7950_state { | 66 | struct ti_ads7950_state { |
| 53 | struct spi_device *spi; | 67 | struct spi_device *spi; |
| 54 | struct spi_transfer ring_xfer; | 68 | struct spi_transfer ring_xfer; |
| @@ -56,10 +70,36 @@ struct ti_ads7950_state { · 1 unmodified line | |||
| 56 | struct spi_message ring_msg; | 70 | struct spi_message ring_msg; |
| 57 | struct spi_message scan_single_msg; | 71 | struct spi_message scan_single_msg; |
| 58 | 72 | ||
| 73 | /* Lock to protect the spi xfer buffers */ | ||
| 74 | struct mutex slock; | ||
| 75 | struct gpio_chip chip; | ||
| 76 | |||
| 59 | struct regulator *reg; | 77 | struct regulator *reg; |
| 60 | unsigned int vref_mv; | 78 | unsigned int vref_mv; |
| 61 | 79 | ||
| 62 | unsigned int settings; | 80 | /* |
| 81 | * Bitmask of lower 7 bits used for configuration | ||
| 82 | * These bits only can be written when TI_ADS7950_CR_WRITE | ||
| 83 | * is set, otherwise it retains its original state. | ||
| 84 | * [0-3] GPIO signal | ||
| 85 | * [4] Set following frame to return GPIO signal values | ||
| 86 | * [5] Powers down device | ||
| 87 | * [6] Sets Vref range1(2.5v) or range2(5v) | ||
| 88 | * | ||
| 89 | * Bits present on Manual/Auto1/Auto2 commands | ||
| 90 | */ | ||
| 91 | unsigned int cmd_settings_bitmask; | ||
| 92 | |||
| 93 | /* | ||
| 94 | * Bitmask of GPIO command | ||
| 95 | * [0-3] GPIO direction | ||
| 96 | * [4-6] Different GPIO alarm mode configurations | ||
| 97 | * [7] GPIO 2 as device range input | ||
| 98 | * [8] GPIO 3 as device power down input | ||
| 99 | * [9] Reset all registers | ||
| 100 | * [10-11] N/A | ||
| 101 | */ | ||
| 102 | unsigned int gpio_cmd_settings_bitmask; | ||
| 63 | 103 | ||
| 64 | /* | 104 | /* |
| 65 | * DMA (thus cache coherency maintenance) requires the | 105 | * DMA (thus cache coherency maintenance) requires the |
| @@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, · 182 unmodified lines | |||
| 248 | 288 | ||
| 249 | len = 0; | 289 | len = 0; |
| 250 | for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { | 290 | for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { |
| 251 | cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings; | 291 | cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); |
| 252 | st->tx_buf[len++] = cmd; | 292 | st->tx_buf[len++] = cmd; |
| 253 | } | 293 | } |
| 254 | 294 | ||
| @@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) · 13 unmodified lines | |||
| 268 | struct ti_ads7950_state *st = iio_priv(indio_dev); | 308 | struct ti_ads7950_state *st = iio_priv(indio_dev); |
| 269 | int ret; | 309 | int ret; |
| 270 | 310 | ||
| 311 | mutex_lock(&st->slock); | ||
| 271 | ret = spi_sync(st->spi, &st->ring_msg); | 312 | ret = spi_sync(st->spi, &st->ring_msg); |
| 272 | if (ret < 0) | 313 | if (ret < 0) |
| 273 | goto out; | 314 | goto out; |
| @@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) · 2 unmodified lines | |||
| 276 | iio_get_time_ns(indio_dev)); | 317 | iio_get_time_ns(indio_dev)); |
| 277 | 318 | ||
| 278 | out: | 319 | out: |
| 320 | mutex_unlock(&st->slock); | ||
| 279 | iio_trigger_notify_done(indio_dev->trig); | 321 | iio_trigger_notify_done(indio_dev->trig); |
| 280 | 322 | ||
| 281 | return IRQ_HANDLED; | 323 | return IRQ_HANDLED; |
| @@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) · 4 unmodified lines | |||
| 286 | struct ti_ads7950_state *st = iio_priv(indio_dev); | 328 | struct ti_ads7950_state *st = iio_priv(indio_dev); |
| 287 | int ret, cmd; | 329 | int ret, cmd; |
| 288 | 330 | ||
| 289 | mutex_lock(&indio_dev->mlock); | 331 | mutex_lock(&st->slock); |
| 290 | 332 | cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch)); | |
| 291 | cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; | ||
| 292 | st->single_tx = cmd; | 333 | st->single_tx = cmd; |
| 293 | 334 | ||
| 294 | ret = spi_sync(st->spi, &st->scan_single_msg); | 335 | ret = spi_sync(st->spi, &st->scan_single_msg); |
| @@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) · 3 unmodified lines | |||
| 298 | ret = st->single_rx; | 339 | ret = st->single_rx; |
| 299 | 340 | ||
| 300 | out: | 341 | out: |
| 301 | mutex_unlock(&indio_dev->mlock); | 342 | mutex_unlock(&st->slock); |
| 302 | 343 | ||
| 303 | return ret; | 344 | return ret; |
| 304 | } | 345 | } |
| @@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st) · 12 unmodified lines | |||
| 317 | vref /= 1000; | 358 | vref /= 1000; |
| 318 | } | 359 | } |
| 319 | 360 | ||
| 320 | if (st->settings & TI_ADS7950_CR_RANGE_5V) | 361 | if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V) |
| 321 | vref *= 2; | 362 | vref *= 2; |
| 322 | 363 | ||
| 323 | return vref; | 364 | return vref; |
| @@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = { · 38 unmodified lines | |||
| 362 | .update_scan_mode = ti_ads7950_update_scan_mode, | 403 | .update_scan_mode = ti_ads7950_update_scan_mode, |
| 363 | }; | 404 | }; |
| 364 | 405 | ||
| 406 | static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, | ||
| 407 | int value) | ||
| 408 | { | ||
| 409 | struct ti_ads7950_state *st = gpiochip_get_data(chip); | ||
| 410 | |||
| 411 | mutex_lock(&st->slock); | ||
| 412 | |||
| 413 | if (value) | ||
| 414 | st->cmd_settings_bitmask |= BIT(offset); | ||
| 415 | else | ||
| 416 | st->cmd_settings_bitmask &= ~BIT(offset); | ||
| 417 | |||
| 418 | st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); | ||
| 419 | spi_sync(st->spi, &st->scan_single_msg); | ||
| 420 | |||
| 421 | mutex_unlock(&st->slock); | ||
| 422 | } | ||
| 423 | |||
| 424 | static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) | ||
| 425 | { | ||
| 426 | struct ti_ads7950_state *st = gpiochip_get_data(chip); | ||
| 427 | int ret; | ||
| 428 | |||
| 429 | mutex_lock(&st->slock); | ||
| 430 | |||
| 431 | /* If set as output, return the output */ | ||
| 432 | if (st->gpio_cmd_settings_bitmask & BIT(offset)) { | ||
| 433 | ret = st->cmd_settings_bitmask & BIT(offset); | ||
| 434 | goto out; | ||
| 435 | } | ||
| 436 | |||
| 437 | /* GPIO data bit sets SDO bits 12-15 to GPIO input */ | ||
| 438 | st->cmd_settings_bitmask |= TI_ADS7950_CR_GPIO_DATA; | ||
| 439 | st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); | ||
| 440 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 441 | if (ret) | ||
| 442 | goto out; | ||
| 443 | |||
| 444 | ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0; | ||
| 445 | |||
| 446 | /* Revert back to original settings */ | ||
| 447 | st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA; | ||
| 448 | st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); | ||
| 449 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 450 | if (ret) | ||
| 451 | goto out; | ||
| 452 | |||
| 453 | out: | ||
| 454 | mutex_unlock(&st->slock); | ||
| 455 | |||
| 456 | return ret; | ||
| 457 | } | ||
| 458 | |||
| 459 | static int ti_ads7950_get_direction(struct gpio_chip *chip, | ||
| 460 | unsigned int offset) | ||
| 461 | { | ||
| 462 | struct ti_ads7950_state *st = gpiochip_get_data(chip); | ||
| 463 | |||
| 464 | /* Bitmask is inverted from GPIO framework 0=input/1=output */ | ||
| 465 | return !(st->gpio_cmd_settings_bitmask & BIT(offset)); | ||
| 466 | } | ||
| 467 | |||
| 468 | static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, | ||
| 469 | int input) | ||
| 470 | { | ||
| 471 | struct ti_ads7950_state *st = gpiochip_get_data(chip); | ||
| 472 | int ret = 0; | ||
| 473 | |||
| 474 | mutex_lock(&st->slock); | ||
| 475 | |||
| 476 | /* Only change direction if needed */ | ||
| 477 | if (input && (st->gpio_cmd_settings_bitmask & BIT(offset))) | ||
| 478 | st->gpio_cmd_settings_bitmask &= ~BIT(offset); | ||
| 479 | else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset))) | ||
| 480 | st->gpio_cmd_settings_bitmask |= BIT(offset); | ||
| 481 | else | ||
| 482 | goto out; | ||
| 483 | |||
| 484 | st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); | ||
| 485 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 486 | |||
| 487 | out: | ||
| 488 | mutex_unlock(&st->slock); | ||
| 489 | |||
| 490 | return ret; | ||
| 491 | } | ||
| 492 | |||
| 493 | static int ti_ads7950_direction_input(struct gpio_chip *chip, | ||
| 494 | unsigned int offset) | ||
| 495 | { | ||
| 496 | return _ti_ads7950_set_direction(chip, offset, 1); | ||
| 497 | } | ||
| 498 | |||
| 499 | static int ti_ads7950_direction_output(struct gpio_chip *chip, | ||
| 500 | unsigned int offset, int value) | ||
| 501 | { | ||
| 502 | ti_ads7950_set(chip, offset, value); | ||
| 503 | |||
| 504 | return _ti_ads7950_set_direction(chip, offset, 0); | ||
| 505 | } | ||
| 506 | |||
| 507 | static int ti_ads7950_init_hw(struct ti_ads7950_state *st) | ||
| 508 | { | ||
| 509 | int ret = 0; | ||
| 510 | |||
| 511 | mutex_lock(&st->slock); | ||
| 512 | |||
| 513 | /* Settings for Manual/Auto1/Auto2 commands */ | ||
| 514 | /* Default to 5v ref */ | ||
| 515 | st->cmd_settings_bitmask = TI_ADS7950_CR_RANGE_5V; | ||
| 516 | st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); | ||
| 517 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 518 | if (ret) | ||
| 519 | goto out; | ||
| 520 | |||
| 521 | /* Settings for GPIO command */ | ||
| 522 | st->gpio_cmd_settings_bitmask = 0x0; | ||
| 523 | st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); | ||
| 524 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 525 | |||
| 526 | out: | ||
| 527 | mutex_unlock(&st->slock); | ||
| 528 | |||
| 529 | return ret; | ||
| 530 | } | ||
| 531 | |||
| 365 | static int ti_ads7950_probe(struct spi_device *spi) | 532 | static int ti_ads7950_probe(struct spi_device *spi) |
| 366 | { | 533 | { |
| 367 | struct ti_ads7950_state *st; | 534 | struct ti_ads7950_state *st; |
| @@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi) · 18 unmodified lines | |||
| 386 | spi_set_drvdata(spi, indio_dev); | 553 | spi_set_drvdata(spi, indio_dev); |
| 387 | 554 | ||
| 388 | st->spi = spi; | 555 | st->spi = spi; |
| 389 | st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V; | ||
| 390 | 556 | ||
| 391 | info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; | 557 | info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; |
| 392 | 558 | ||
| @@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi) · 39 unmodified lines | |||
| 432 | if (ACPI_COMPANION(&spi->dev)) | 598 | if (ACPI_COMPANION(&spi->dev)) |
| 433 | st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; | 599 | st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; |
| 434 | 600 | ||
| 601 | mutex_init(&st->slock); | ||
| 602 | |||
| 435 | st->reg = devm_regulator_get(&spi->dev, "vref"); | 603 | st->reg = devm_regulator_get(&spi->dev, "vref"); |
| 436 | if (IS_ERR(st->reg)) { | 604 | if (IS_ERR(st->reg)) { |
| 437 | dev_err(&spi->dev, "Failed get get regulator \"vref\"\n"); | 605 | dev_err(&spi->dev, "Failed get get regulator \"vref\"\n"); |
| 438 | return PTR_ERR(st->reg); | 606 | ret = PTR_ERR(st->reg); |
| 607 | goto error_destroy_mutex; | ||
| 439 | } | 608 | } |
| 440 | 609 | ||
| 441 | ret = regulator_enable(st->reg); | 610 | ret = regulator_enable(st->reg); |
| 442 | if (ret) { | 611 | if (ret) { |
| 443 | dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); | 612 | dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); |
| 444 | return ret; | 613 | goto error_destroy_mutex; |
| 445 | } | 614 | } |
| 446 | 615 | ||
| 447 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | 616 | ret = iio_triggered_buffer_setup(indio_dev, NULL, |
| @@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi) · 3 unmodified lines | |||
| 451 | goto error_disable_reg; | 620 | goto error_disable_reg; |
| 452 | } | 621 | } |
| 453 | 622 | ||
| 623 | ret = ti_ads7950_init_hw(st); | ||
| 624 | if (ret) { | ||
| 625 | dev_err(&spi->dev, "Failed to init adc chip\n"); | ||
| 626 | goto error_cleanup_ring; | ||
| 627 | } | ||
| 628 | |||
| 454 | ret = iio_device_register(indio_dev); | 629 | ret = iio_device_register(indio_dev); |
| 455 | if (ret) { | 630 | if (ret) { |
| 456 | dev_err(&spi->dev, "Failed to register iio device\n"); | 631 | dev_err(&spi->dev, "Failed to register iio device\n"); |
| 457 | goto error_cleanup_ring; | 632 | goto error_cleanup_ring; |
| 458 | } | 633 | } |
| 459 | 634 | ||
| 635 | /* Add GPIO chip */ | ||
| 636 | st->chip.label = dev_name(&st->spi->dev); | ||
| 637 | st->chip.parent = &st->spi->dev; | ||
| 638 | st->chip.owner = THIS_MODULE; | ||
| 639 | st->chip.base = -1; | ||
| 640 | st->chip.ngpio = TI_ADS7950_NUM_GPIOS; | ||
| 641 | st->chip.get_direction = ti_ads7950_get_direction; | ||
| 642 | st->chip.direction_input = ti_ads7950_direction_input; | ||
| 643 | st->chip.direction_output = ti_ads7950_direction_output; | ||
| 644 | st->chip.get = ti_ads7950_get; | ||
| 645 | st->chip.set = ti_ads7950_set; | ||
| 646 | |||
| 647 | ret = gpiochip_add_data(&st->chip, st); | ||
| 648 | if (ret) { | ||
| 649 | dev_err(&spi->dev, "Failed to init GPIOs\n"); | ||
| 650 | goto error_iio_device; | ||
| 651 | } | ||
| 652 | |||
| 460 | return 0; | 653 | return 0; |
| 461 | 654 | ||
| 655 | error_iio_device: | ||
| 656 | iio_device_unregister(indio_dev); | ||
| 462 | error_cleanup_ring: | 657 | error_cleanup_ring: |
| 463 | iio_triggered_buffer_cleanup(indio_dev); | 658 | iio_triggered_buffer_cleanup(indio_dev); |
| 464 | error_disable_reg: | 659 | error_disable_reg: |
| 465 | regulator_disable(st->reg); | 660 | regulator_disable(st->reg); |
| 661 | error_destroy_mutex: | ||
| 662 | mutex_destroy(&st->slock); | ||
| 466 | 663 | ||
| 467 | return ret; | 664 | return ret; |
| 468 | } | 665 | } |
| @@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi) · 3 unmodified lines | |||
| 472 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | 669 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
| 473 | struct ti_ads7950_state *st = iio_priv(indio_dev); | 670 | struct ti_ads7950_state *st = iio_priv(indio_dev); |
| 474 | 671 | ||
| 672 | gpiochip_remove(&st->chip); | ||
| 475 | iio_device_unregister(indio_dev); | 673 | iio_device_unregister(indio_dev); |
| 476 | iio_triggered_buffer_cleanup(indio_dev); | 674 | iio_triggered_buffer_cleanup(indio_dev); |
| 477 | regulator_disable(st->reg); | 675 | regulator_disable(st->reg); |
| 676 | mutex_destroy(&st->slock); | ||
| 478 | 677 | ||
| 479 | return 0; | 678 | return 0; |
| 480 | } | 679 | } |
| @@ -0,0 +1,204 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * ADS8344 16-bit 8-Channel ADC driver | ||
| 4 | * | ||
| 5 | * Author: Gregory CLEMENT <gregory.clement@bootlin.com> | ||
| 6 | * | ||
| 7 | * Datasheet: http://www.ti.com/lit/ds/symlink/ads8344.pdf | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <linux/iio/buffer.h> | ||
| 12 | #include <linux/iio/iio.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | |||
| 17 | #define ADS8344_START BIT(7) | ||
| 18 | #define ADS8344_SINGLE_END BIT(2) | ||
| 19 | #define ADS8344_CHANNEL(channel) ((channel) << 4) | ||
| 20 | #define ADS8344_CLOCK_INTERNAL 0x2 /* PD1 = 1 and PD0 = 0 */ | ||
| 21 | |||
| 22 | struct ads8344 { | ||
| 23 | struct spi_device *spi; | ||
| 24 | struct regulator *reg; | ||
| 25 | /* | ||
| 26 | * Lock protecting access to adc->tx_buff and rx_buff, | ||
| 27 | * especially from concurrent read on sysfs file. | ||
| 28 | */ | ||
| 29 | struct mutex lock; | ||
| 30 | |||
| 31 | u8 tx_buf ____cacheline_aligned; | ||
| 32 | u16 rx_buf; | ||
| 33 | }; | ||
| 34 | |||
| 35 | #define ADS8344_VOLTAGE_CHANNEL(chan, si) \ | ||
| 36 | { \ | ||
| 37 | .type = IIO_VOLTAGE, \ | ||
| 38 | .indexed = 1, \ | ||
| 39 | .channel = chan, \ | ||
| 40 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 41 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 42 | } | ||
| 43 | |||
| 44 | #define ADS8344_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \ | ||
| 45 | { \ | ||
| 46 | .type = IIO_VOLTAGE, \ | ||
| 47 | .indexed = 1, \ | ||
| 48 | .channel = (chan1), \ | ||
| 49 | .channel2 = (chan2), \ | ||
| 50 | .differential = 1, \ | ||
| 51 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 52 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 53 | } | ||
| 54 | |||
| 55 | static const struct iio_chan_spec ads8344_channels[] = { | ||
| 56 | ADS8344_VOLTAGE_CHANNEL(0, 0), | ||
| 57 | ADS8344_VOLTAGE_CHANNEL(1, 4), | ||
| 58 | ADS8344_VOLTAGE_CHANNEL(2, 1), | ||
| 59 | ADS8344_VOLTAGE_CHANNEL(3, 5), | ||
| 60 | ADS8344_VOLTAGE_CHANNEL(4, 2), | ||
| 61 | ADS8344_VOLTAGE_CHANNEL(5, 6), | ||
| 62 | ADS8344_VOLTAGE_CHANNEL(6, 3), | ||
| 63 | ADS8344_VOLTAGE_CHANNEL(7, 7), | ||
| 64 | ADS8344_VOLTAGE_CHANNEL_DIFF(0, 1, 8), | ||
| 65 | ADS8344_VOLTAGE_CHANNEL_DIFF(2, 3, 9), | ||
| 66 | ADS8344_VOLTAGE_CHANNEL_DIFF(4, 5, 10), | ||
| 67 | ADS8344_VOLTAGE_CHANNEL_DIFF(6, 7, 11), | ||
| 68 | ADS8344_VOLTAGE_CHANNEL_DIFF(1, 0, 12), | ||
| 69 | ADS8344_VOLTAGE_CHANNEL_DIFF(3, 2, 13), | ||
| 70 | ADS8344_VOLTAGE_CHANNEL_DIFF(5, 4, 14), | ||
| 71 | ADS8344_VOLTAGE_CHANNEL_DIFF(7, 6, 15), | ||
| 72 | }; | ||
| 73 | |||
| 74 | static int ads8344_adc_conversion(struct ads8344 *adc, int channel, | ||
| 75 | bool differential) | ||
| 76 | { | ||
| 77 | struct spi_device *spi = adc->spi; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | adc->tx_buf = ADS8344_START; | ||
| 81 | if (!differential) | ||
| 82 | adc->tx_buf |= ADS8344_SINGLE_END; | ||
| 83 | adc->tx_buf |= ADS8344_CHANNEL(channel); | ||
| 84 | adc->tx_buf |= ADS8344_CLOCK_INTERNAL; | ||
| 85 | |||
| 86 | ret = spi_write(spi, &adc->tx_buf, 1); | ||
| 87 | if (ret) | ||
| 88 | return ret; | ||
| 89 | |||
| 90 | udelay(9); | ||
| 91 | |||
| 92 | ret = spi_read(spi, &adc->rx_buf, 2); | ||
| 93 | if (ret) | ||
| 94 | return ret; | ||
| 95 | |||
| 96 | return adc->rx_buf; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int ads8344_read_raw(struct iio_dev *iio, | ||
| 100 | struct iio_chan_spec const *channel, int *value, | ||
| 101 | int *shift, long mask) | ||
| 102 | { | ||
| 103 | struct ads8344 *adc = iio_priv(iio); | ||
| 104 | |||
| 105 | switch (mask) { | ||
| 106 | case IIO_CHAN_INFO_RAW: | ||
| 107 | mutex_lock(&adc->lock); | ||
| 108 | *value = ads8344_adc_conversion(adc, channel->scan_index, | ||
| 109 | channel->differential); | ||
| 110 | mutex_unlock(&adc->lock); | ||
| 111 | if (*value < 0) | ||
| 112 | return *value; | ||
| 113 | |||
| 114 | return IIO_VAL_INT; | ||
| 115 | case IIO_CHAN_INFO_SCALE: | ||
| 116 | *value = regulator_get_voltage(adc->reg); | ||
| 117 | if (*value < 0) | ||
| 118 | return *value; | ||
| 119 | |||
| 120 | /* convert regulator output voltage to mV */ | ||
| 121 | *value /= 1000; | ||
| 122 | *shift = 16; | ||
| 123 | |||
| 124 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 125 | default: | ||
| 126 | return -EINVAL; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | static const struct iio_info ads8344_info = { | ||
| 131 | .read_raw = ads8344_read_raw, | ||
| 132 | }; | ||
| 133 | |||
| 134 | static int ads8344_probe(struct spi_device *spi) | ||
| 135 | { | ||
| 136 | struct iio_dev *indio_dev; | ||
| 137 | struct ads8344 *adc; | ||
| 138 | int ret; | ||
| 139 | |||
| 140 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); | ||
| 141 | if (!indio_dev) | ||
| 142 | return -ENOMEM; | ||
| 143 | |||
| 144 | adc = iio_priv(indio_dev); | ||
| 145 | adc->spi = spi; | ||
| 146 | mutex_init(&adc->lock); | ||
| 147 | |||
| 148 | indio_dev->name = dev_name(&spi->dev); | ||
| 149 | indio_dev->dev.parent = &spi->dev; | ||
| 150 | indio_dev->dev.of_node = spi->dev.of_node; | ||
| 151 | indio_dev->info = &ads8344_info; | ||
| 152 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 153 | indio_dev->channels = ads8344_channels; | ||
| 154 | indio_dev->num_channels = ARRAY_SIZE(ads8344_channels); | ||
| 155 | |||
| 156 | adc->reg = devm_regulator_get(&spi->dev, "vref"); | ||
| 157 | if (IS_ERR(adc->reg)) | ||
| 158 | return PTR_ERR(adc->reg); | ||
| 159 | |||
| 160 | ret = regulator_enable(adc->reg); | ||
| 161 | if (ret) | ||
| 162 | return ret; | ||
| 163 | |||
| 164 | spi_set_drvdata(spi, indio_dev); | ||
| 165 | |||
| 166 | ret = iio_device_register(indio_dev); | ||
| 167 | if (ret) { | ||
| 168 | regulator_disable(adc->reg); | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int ads8344_remove(struct spi_device *spi) | ||
| 176 | { | ||
| 177 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 178 | struct ads8344 *adc = iio_priv(indio_dev); | ||
| 179 | |||
| 180 | iio_device_unregister(indio_dev); | ||
| 181 | regulator_disable(adc->reg); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | static const struct of_device_id ads8344_of_match[] = { | ||
| 187 | { .compatible = "ti,ads8344", }, | ||
| 188 | {} | ||
| 189 | }; | ||
| 190 | MODULE_DEVICE_TABLE(of, ads8344_of_match); | ||
| 191 | |||
| 192 | static struct spi_driver ads8344_driver = { | ||
| 193 | .driver = { | ||
| 194 | .name = "ads8344", | ||
| 195 | .of_match_table = ads8344_of_match, | ||
| 196 | }, | ||
| 197 | .probe = ads8344_probe, | ||
| 198 | .remove = ads8344_remove, | ||
| 199 | }; | ||
| 200 | module_spi_driver(ads8344_driver); | ||
| 201 | |||
| 202 | MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@bootlin.com>"); | ||
| 203 | MODULE_DESCRIPTION("ADS8344 driver"); | ||
| 204 | MODULE_LICENSE("GPL"); | ||
| @@ -523,6 +523,6 @@ static struct spi_driver ads8688_driver = { · 522 unmodified lines | |||
| 523 | }; | 523 | }; |
| 524 | module_spi_driver(ads8688_driver); | 524 | module_spi_driver(ads8688_driver); |
| 525 | 525 | ||
| 526 | MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); | 526 | MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>"); |
| 527 | MODULE_DESCRIPTION("Texas Instruments ADS8688 driver"); | 527 | MODULE_DESCRIPTION("Texas Instruments ADS8688 driver"); |
| 528 | MODULE_LICENSE("GPL v2"); | 528 | MODULE_LICENSE("GPL v2"); |
| @@ -36,7 +36,8 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) · 35 unmodified lines | |||
| 36 | static void iio_buffer_cb_release(struct iio_buffer *buffer) | 36 | static void iio_buffer_cb_release(struct iio_buffer *buffer) |
| 37 | { | 37 | { |
| 38 | struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); | 38 | struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); |
| 39 | kfree(cb_buff->buffer.scan_mask); | 39 | |
| 40 | bitmap_free(cb_buff->buffer.scan_mask); | ||
| 40 | kfree(cb_buff); | 41 | kfree(cb_buff); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| @@ -74,9 +75,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, · 31 unmodified lines | |||
| 74 | } | 75 | } |
| 75 | 76 | ||
| 76 | cb_buff->indio_dev = cb_buff->channels[0].indio_dev; | 77 | cb_buff->indio_dev = cb_buff->channels[0].indio_dev; |
| 77 | cb_buff->buffer.scan_mask | 78 | cb_buff->buffer.scan_mask = bitmap_zalloc(cb_buff->indio_dev->masklength, |
| 78 | = kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength), | 79 | GFP_KERNEL); |
| 79 | sizeof(long), GFP_KERNEL); | ||
| 80 | if (cb_buff->buffer.scan_mask == NULL) { | 80 | if (cb_buff->buffer.scan_mask == NULL) { |
| 81 | ret = -ENOMEM; | 81 | ret = -ENOMEM; |
| 82 | goto error_release_channels; | 82 | goto error_release_channels; |
| @@ -95,7 +95,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, · 12 unmodified lines | |||
| 95 | return cb_buff; | 95 | return cb_buff; |
| 96 | 96 | ||
| 97 | error_free_scan_mask: | 97 | error_free_scan_mask: |
| 98 | kfree(cb_buff->buffer.scan_mask); | 98 | bitmap_free(cb_buff->buffer.scan_mask); |
| 99 | error_release_channels: | 99 | error_release_channels: |
| 100 | iio_channel_release_all(cb_buff->channels); | 100 | iio_channel_release_all(cb_buff->channels); |
| 101 | error_free_cb_buff: | 101 | error_free_cb_buff: |
| @@ -12,14 +12,14 @@ config ATLAS_PH_SENSOR · 11 unmodified lines | |||
| 12 | select IIO_TRIGGERED_BUFFER | 12 | select IIO_TRIGGERED_BUFFER |
| 13 | select IRQ_WORK | 13 | select IRQ_WORK |
| 14 | help | 14 | help |
| 15 | Say Y here to build I2C interface support for the following | 15 | Say Y here to build I2C interface support for the following |
| 16 | Atlas Scientific OEM SM sensors: | 16 | Atlas Scientific OEM SM sensors: |
| 17 | * pH SM sensor | 17 | * pH SM sensor |
| 18 | * EC SM sensor | 18 | * EC SM sensor |
| 19 | * ORP SM sensor | 19 | * ORP SM sensor |
| 20 | 20 | ||
| 21 | To compile this driver as module, choose M here: the | 21 | To compile this driver as module, choose M here: the |
| 22 | module will be called atlas-ph-sensor. | 22 | module will be called atlas-ph-sensor. |
| 23 | 23 | ||
| 24 | config BME680 | 24 | config BME680 |
| 25 | tristate "Bosch Sensortec BME680 sensor driver" | 25 | tristate "Bosch Sensortec BME680 sensor driver" |
| @@ -47,8 +47,8 @@ config BME680_SPI · 21 unmodified lines | |||
| 47 | config CCS811 | 47 | config CCS811 |
| 48 | tristate "AMS CCS811 VOC sensor" | 48 | tristate "AMS CCS811 VOC sensor" |
| 49 | depends on I2C | 49 | depends on I2C |
| 50 | select IIO_BUFFER | 50 | select IIO_BUFFER |
| 51 | select IIO_TRIGGERED_BUFFER | 51 | select IIO_TRIGGERED_BUFFER |
| 52 | help | 52 | help |
| 53 | Say Y here to build I2C interface support for the AMS | 53 | Say Y here to build I2C interface support for the AMS |
| 54 | CCS811 VOC (Volatile Organic Compounds) sensor | 54 | CCS811 VOC (Volatile Organic Compounds) sensor |
| @@ -321,7 +321,12 @@ static int pms7003_probe(struct serdev_device *serdev) · 320 unmodified lines | |||
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | static const struct of_device_id pms7003_of_match[] = { | 323 | static const struct of_device_id pms7003_of_match[] = { |
| 324 | { .compatible = "plantower,pms1003" }, | ||
| 325 | { .compatible = "plantower,pms3003" }, | ||
| 326 | { .compatible = "plantower,pms5003" }, | ||
| 327 | { .compatible = "plantower,pms6003" }, | ||
| 324 | { .compatible = "plantower,pms7003" }, | 328 | { .compatible = "plantower,pms7003" }, |
| 329 | { .compatible = "plantower,pmsa003" }, | ||
| 325 | { } | 330 | { } |
| 326 | }; | 331 | }; |
| 327 | MODULE_DEVICE_TABLE(of, pms7003_of_match); | 332 | MODULE_DEVICE_TABLE(of, pms7003_of_match); |
| @@ -1,22 +1,13 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors. | 3 | * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors. |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2016 Google, Inc | 5 | * Copyright (C) 2016 Google, Inc |
| 5 | * | 6 | * |
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the cros-ec interface to communicate with the Chrome OS | 7 | * This driver uses the cros-ec interface to communicate with the Chrome OS |
| 16 | * EC about sensors data. Data access is presented through iio sysfs. | 8 | * EC about sensors data. Data access is presented through iio sysfs. |
| 17 | */ | 9 | */ |
| 18 | 10 | ||
| 19 | #include <linux/delay.h> | ||
| 20 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 21 | #include <linux/iio/buffer.h> | 12 | #include <linux/iio/buffer.h> |
| 22 | #include <linux/iio/common/cros_ec_sensors_core.h> | 13 | #include <linux/iio/common/cros_ec_sensors_core.h> |
| @@ -30,7 +21,6 @@ · 7 unmodified lines | |||
| 30 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 31 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
| 32 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 33 | #include <linux/sysfs.h> | ||
| 34 | 24 | ||
| 35 | #define CROS_EC_SENSORS_MAX_CHANNELS 4 | 25 | #define CROS_EC_SENSORS_MAX_CHANNELS 4 |
| 36 | 26 | ||
| @@ -1,16 +1,8 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_sensors_core - Common function for Chrome OS EC sensor driver. | 3 | * cros_ec_sensors_core - Common function for Chrome OS EC sensor driver. |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2016 Google, Inc | 5 | * Copyright (C) 2016 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | 6 | */ |
| 15 | 7 | ||
| 16 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
| @@ -25,7 +17,6 @@ · 8 unmodified lines | |||
| 25 | #include <linux/mfd/cros_ec_commands.h> | 17 | #include <linux/mfd/cros_ec_commands.h> |
| 26 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 27 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 28 | #include <linux/sysfs.h> | ||
| 29 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 30 | 21 | ||
| 31 | static char *cros_ec_loc[] = { | 22 | static char *cros_ec_loc[] = { |
| @@ -269,6 +260,17 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, · 237 unmodified lines | |||
| 269 | return 0; | 260 | return 0; |
| 270 | } | 261 | } |
| 271 | 262 | ||
| 263 | /** | ||
| 264 | * cros_ec_sensors_read_lpc() - read acceleration data from EC shared memory. | ||
| 265 | * @indio_dev: pointer to IIO device. | ||
| 266 | * @scan_mask: bitmap of the sensor indices to scan. | ||
| 267 | * @data: location to store data. | ||
| 268 | * | ||
| 269 | * Note: this is the safe function for reading the EC data. It guarantees | ||
| 270 | * that the data sampled was not modified by the EC while being read. | ||
| 271 | * | ||
| 272 | * Return: 0 on success, -errno on failure. | ||
| 273 | */ | ||
| 272 | int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, | 274 | int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, |
| 273 | unsigned long scan_mask, s16 *data) | 275 | unsigned long scan_mask, s16 *data) |
| 274 | { | 276 | { |
| @@ -3,4 +3,4 @@ · 2 unmodified lines | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | config IIO_MS_SENSORS_I2C | 5 | config IIO_MS_SENSORS_I2C |
| 6 | tristate | 6 | tristate |
| @@ -81,7 +81,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, · 80 unmodified lines | |||
| 81 | unsigned int len, int64_t timestamp) | 81 | unsigned int len, int64_t timestamp) |
| 82 | { | 82 | { |
| 83 | __le32 time; | 83 | __le32 time; |
| 84 | int64_t calculated_time; | 84 | int64_t calculated_time = 0; |
| 85 | struct ssp_sensor_data *spd = iio_priv(indio_dev); | 85 | struct ssp_sensor_data *spd = iio_priv(indio_dev); |
| 86 | 86 | ||
| 87 | if (indio_dev->scan_bytes == 0) | 87 | if (indio_dev->scan_bytes == 0) |
| @@ -1,631 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * IIO driver for the ACCES 104-QUAD-8 | ||
| 3 | * Copyright (C) 2016 William Breathitt Gray | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License, version 2, as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, but | ||
| 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * General Public License for more details. | ||
| 13 | * | ||
| 14 | * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. | ||
| 15 | */ | ||
| 16 | #include <linux/bitops.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/iio/iio.h> | ||
| 20 | #include <linux/iio/types.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/ioport.h> | ||
| 23 | #include <linux/isa.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/types.h> | ||
| 28 | |||
| 29 | #define QUAD8_EXTENT 32 | ||
| 30 | |||
| 31 | static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; | ||
| 32 | static unsigned int num_quad8; | ||
| 33 | module_param_array(base, uint, &num_quad8, 0); | ||
| 34 | MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); | ||
| 35 | |||
| 36 | #define QUAD8_NUM_COUNTERS 8 | ||
| 37 | |||
| 38 | /** | ||
| 39 | * struct quad8_iio - IIO device private data structure | ||
| 40 | * @preset: array of preset values | ||
| 41 | * @count_mode: array of count mode configurations | ||
| 42 | * @quadrature_mode: array of quadrature mode configurations | ||
| 43 | * @quadrature_scale: array of quadrature mode scale configurations | ||
| 44 | * @ab_enable: array of A and B inputs enable configurations | ||
| 45 | * @preset_enable: array of set_to_preset_on_index attribute configurations | ||
| 46 | * @synchronous_mode: array of index function synchronous mode configurations | ||
| 47 | * @index_polarity: array of index function polarity configurations | ||
| 48 | * @base: base port address of the IIO device | ||
| 49 | */ | ||
| 50 | struct quad8_iio { | ||
| 51 | unsigned int preset[QUAD8_NUM_COUNTERS]; | ||
| 52 | unsigned int count_mode[QUAD8_NUM_COUNTERS]; | ||
| 53 | unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; | ||
| 54 | unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; | ||
| 55 | unsigned int ab_enable[QUAD8_NUM_COUNTERS]; | ||
| 56 | unsigned int preset_enable[QUAD8_NUM_COUNTERS]; | ||
| 57 | unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; | ||
| 58 | unsigned int index_polarity[QUAD8_NUM_COUNTERS]; | ||
| 59 | unsigned int base; | ||
| 60 | }; | ||
| 61 | |||
| 62 | #define QUAD8_REG_CHAN_OP 0x11 | ||
| 63 | #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 | ||
| 64 | /* Borrow Toggle flip-flop */ | ||
| 65 | #define QUAD8_FLAG_BT BIT(0) | ||
| 66 | /* Carry Toggle flip-flop */ | ||
| 67 | #define QUAD8_FLAG_CT BIT(1) | ||
| 68 | /* Error flag */ | ||
| 69 | #define QUAD8_FLAG_E BIT(4) | ||
| 70 | /* Up/Down flag */ | ||
| 71 | #define QUAD8_FLAG_UD BIT(5) | ||
| 72 | /* Reset and Load Signal Decoders */ | ||
| 73 | #define QUAD8_CTR_RLD 0x00 | ||
| 74 | /* Counter Mode Register */ | ||
| 75 | #define QUAD8_CTR_CMR 0x20 | ||
| 76 | /* Input / Output Control Register */ | ||
| 77 | #define QUAD8_CTR_IOR 0x40 | ||
| 78 | /* Index Control Register */ | ||
| 79 | #define QUAD8_CTR_IDR 0x60 | ||
| 80 | /* Reset Byte Pointer (three byte data pointer) */ | ||
| 81 | #define QUAD8_RLD_RESET_BP 0x01 | ||
| 82 | /* Reset Counter */ | ||
| 83 | #define QUAD8_RLD_RESET_CNTR 0x02 | ||
| 84 | /* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */ | ||
| 85 | #define QUAD8_RLD_RESET_FLAGS 0x04 | ||
| 86 | /* Reset Error flag */ | ||
| 87 | #define QUAD8_RLD_RESET_E 0x06 | ||
| 88 | /* Preset Register to Counter */ | ||
| 89 | #define QUAD8_RLD_PRESET_CNTR 0x08 | ||
| 90 | /* Transfer Counter to Output Latch */ | ||
| 91 | #define QUAD8_RLD_CNTR_OUT 0x10 | ||
| 92 | #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00 | ||
| 93 | #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 | ||
| 94 | |||
| 95 | static int quad8_read_raw(struct iio_dev *indio_dev, | ||
| 96 | struct iio_chan_spec const *chan, int *val, int *val2, long mask) | ||
| 97 | { | ||
| 98 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 99 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 100 | unsigned int flags; | ||
| 101 | unsigned int borrow; | ||
| 102 | unsigned int carry; | ||
| 103 | int i; | ||
| 104 | |||
| 105 | switch (mask) { | ||
| 106 | case IIO_CHAN_INFO_RAW: | ||
| 107 | if (chan->type == IIO_INDEX) { | ||
| 108 | *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) | ||
| 109 | & BIT(chan->channel)); | ||
| 110 | return IIO_VAL_INT; | ||
| 111 | } | ||
| 112 | |||
| 113 | flags = inb(base_offset + 1); | ||
| 114 | borrow = flags & QUAD8_FLAG_BT; | ||
| 115 | carry = !!(flags & QUAD8_FLAG_CT); | ||
| 116 | |||
| 117 | /* Borrow XOR Carry effectively doubles count range */ | ||
| 118 | *val = (borrow ^ carry) << 24; | ||
| 119 | |||
| 120 | /* Reset Byte Pointer; transfer Counter to Output Latch */ | ||
| 121 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, | ||
| 122 | base_offset + 1); | ||
| 123 | |||
| 124 | for (i = 0; i < 3; i++) | ||
| 125 | *val |= (unsigned int)inb(base_offset) << (8 * i); | ||
| 126 | |||
| 127 | return IIO_VAL_INT; | ||
| 128 | case IIO_CHAN_INFO_ENABLE: | ||
| 129 | *val = priv->ab_enable[chan->channel]; | ||
| 130 | return IIO_VAL_INT; | ||
| 131 | case IIO_CHAN_INFO_SCALE: | ||
| 132 | *val = 1; | ||
| 133 | *val2 = priv->quadrature_scale[chan->channel]; | ||
| 134 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 135 | } | ||
| 136 | |||
| 137 | return -EINVAL; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int quad8_write_raw(struct iio_dev *indio_dev, | ||
| 141 | struct iio_chan_spec const *chan, int val, int val2, long mask) | ||
| 142 | { | ||
| 143 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 144 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 145 | int i; | ||
| 146 | unsigned int ior_cfg; | ||
| 147 | |||
| 148 | switch (mask) { | ||
| 149 | case IIO_CHAN_INFO_RAW: | ||
| 150 | if (chan->type == IIO_INDEX) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | /* Only 24-bit values are supported */ | ||
| 154 | if ((unsigned int)val > 0xFFFFFF) | ||
| 155 | return -EINVAL; | ||
| 156 | |||
| 157 | /* Reset Byte Pointer */ | ||
| 158 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 159 | |||
| 160 | /* Counter can only be set via Preset Register */ | ||
| 161 | for (i = 0; i < 3; i++) | ||
| 162 | outb(val >> (8 * i), base_offset); | ||
| 163 | |||
| 164 | /* Transfer Preset Register to Counter */ | ||
| 165 | outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); | ||
| 166 | |||
| 167 | /* Reset Byte Pointer */ | ||
| 168 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 169 | |||
| 170 | /* Set Preset Register back to original value */ | ||
| 171 | val = priv->preset[chan->channel]; | ||
| 172 | for (i = 0; i < 3; i++) | ||
| 173 | outb(val >> (8 * i), base_offset); | ||
| 174 | |||
| 175 | /* Reset Borrow, Carry, Compare, and Sign flags */ | ||
| 176 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); | ||
| 177 | /* Reset Error flag */ | ||
| 178 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); | ||
| 179 | |||
| 180 | return 0; | ||
| 181 | case IIO_CHAN_INFO_ENABLE: | ||
| 182 | /* only boolean values accepted */ | ||
| 183 | if (val < 0 || val > 1) | ||
| 184 | return -EINVAL; | ||
| 185 | |||
| 186 | priv->ab_enable[chan->channel] = val; | ||
| 187 | |||
| 188 | ior_cfg = val | priv->preset_enable[chan->channel] << 1; | ||
| 189 | |||
| 190 | /* Load I/O control configuration */ | ||
| 191 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | case IIO_CHAN_INFO_SCALE: | ||
| 195 | /* Quadrature scaling only available in quadrature mode */ | ||
| 196 | if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) | ||
| 197 | return -EINVAL; | ||
| 198 | |||
| 199 | /* Only three gain states (1, 0.5, 0.25) */ | ||
| 200 | if (val == 1 && !val2) | ||
| 201 | priv->quadrature_scale[chan->channel] = 0; | ||
| 202 | else if (!val) | ||
| 203 | switch (val2) { | ||
| 204 | case 500000: | ||
| 205 | priv->quadrature_scale[chan->channel] = 1; | ||
| 206 | break; | ||
| 207 | case 250000: | ||
| 208 | priv->quadrature_scale[chan->channel] = 2; | ||
| 209 | break; | ||
| 210 | default: | ||
| 211 | return -EINVAL; | ||
| 212 | } | ||
| 213 | else | ||
| 214 | return -EINVAL; | ||
| 215 | |||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | |||
| 219 | return -EINVAL; | ||
| 220 | } | ||
| 221 | |||
| 222 | static const struct iio_info quad8_info = { | ||
| 223 | .read_raw = quad8_read_raw, | ||
| 224 | .write_raw = quad8_write_raw | ||
| 225 | }; | ||
| 226 | |||
| 227 | static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, | ||
| 228 | const struct iio_chan_spec *chan, char *buf) | ||
| 229 | { | ||
| 230 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 231 | |||
| 232 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); | ||
| 233 | } | ||
| 234 | |||
| 235 | static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, | ||
| 236 | const struct iio_chan_spec *chan, const char *buf, size_t len) | ||
| 237 | { | ||
| 238 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 239 | const int base_offset = priv->base + 2 * chan->channel; | ||
| 240 | unsigned int preset; | ||
| 241 | int ret; | ||
| 242 | int i; | ||
| 243 | |||
| 244 | ret = kstrtouint(buf, 0, &preset); | ||
| 245 | if (ret) | ||
| 246 | return ret; | ||
| 247 | |||
| 248 | /* Only 24-bit values are supported */ | ||
| 249 | if (preset > 0xFFFFFF) | ||
| 250 | return -EINVAL; | ||
| 251 | |||
| 252 | priv->preset[chan->channel] = preset; | ||
| 253 | |||
| 254 | /* Reset Byte Pointer */ | ||
| 255 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 256 | |||
| 257 | /* Set Preset Register */ | ||
| 258 | for (i = 0; i < 3; i++) | ||
| 259 | outb(preset >> (8 * i), base_offset); | ||
| 260 | |||
| 261 | return len; | ||
| 262 | } | ||
| 263 | |||
| 264 | static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, | ||
| 265 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) | ||
| 266 | { | ||
| 267 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 268 | |||
| 269 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
| 270 | !priv->preset_enable[chan->channel]); | ||
| 271 | } | ||
| 272 | |||
| 273 | static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, | ||
| 274 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, | ||
| 275 | size_t len) | ||
| 276 | { | ||
| 277 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 278 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 279 | bool preset_enable; | ||
| 280 | int ret; | ||
| 281 | unsigned int ior_cfg; | ||
| 282 | |||
| 283 | ret = kstrtobool(buf, &preset_enable); | ||
| 284 | if (ret) | ||
| 285 | return ret; | ||
| 286 | |||
| 287 | /* Preset enable is active low in Input/Output Control register */ | ||
| 288 | preset_enable = !preset_enable; | ||
| 289 | |||
| 290 | priv->preset_enable[chan->channel] = preset_enable; | ||
| 291 | |||
| 292 | ior_cfg = priv->ab_enable[chan->channel] | | ||
| 293 | (unsigned int)preset_enable << 1; | ||
| 294 | |||
| 295 | /* Load I/O control configuration to Input / Output Control Register */ | ||
| 296 | outb(QUAD8_CTR_IOR | ior_cfg, base_offset); | ||
| 297 | |||
| 298 | return len; | ||
| 299 | } | ||
| 300 | |||
| 301 | static const char *const quad8_noise_error_states[] = { | ||
| 302 | "No excessive noise is present at the count inputs", | ||
| 303 | "Excessive noise is present at the count inputs" | ||
| 304 | }; | ||
| 305 | |||
| 306 | static int quad8_get_noise_error(struct iio_dev *indio_dev, | ||
| 307 | const struct iio_chan_spec *chan) | ||
| 308 | { | ||
| 309 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 310 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 311 | |||
| 312 | return !!(inb(base_offset) & QUAD8_FLAG_E); | ||
| 313 | } | ||
| 314 | |||
| 315 | static const struct iio_enum quad8_noise_error_enum = { | ||
| 316 | .items = quad8_noise_error_states, | ||
| 317 | .num_items = ARRAY_SIZE(quad8_noise_error_states), | ||
| 318 | .get = quad8_get_noise_error | ||
| 319 | }; | ||
| 320 | |||
| 321 | static const char *const quad8_count_direction_states[] = { | ||
| 322 | "down", | ||
| 323 | "up" | ||
| 324 | }; | ||
| 325 | |||
| 326 | static int quad8_get_count_direction(struct iio_dev *indio_dev, | ||
| 327 | const struct iio_chan_spec *chan) | ||
| 328 | { | ||
| 329 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 330 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 331 | |||
| 332 | return !!(inb(base_offset) & QUAD8_FLAG_UD); | ||
| 333 | } | ||
| 334 | |||
| 335 | static const struct iio_enum quad8_count_direction_enum = { | ||
| 336 | .items = quad8_count_direction_states, | ||
| 337 | .num_items = ARRAY_SIZE(quad8_count_direction_states), | ||
| 338 | .get = quad8_get_count_direction | ||
| 339 | }; | ||
| 340 | |||
| 341 | static const char *const quad8_count_modes[] = { | ||
| 342 | "normal", | ||
| 343 | "range limit", | ||
| 344 | "non-recycle", | ||
| 345 | "modulo-n" | ||
| 346 | }; | ||
| 347 | |||
| 348 | static int quad8_set_count_mode(struct iio_dev *indio_dev, | ||
| 349 | const struct iio_chan_spec *chan, unsigned int count_mode) | ||
| 350 | { | ||
| 351 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 352 | unsigned int mode_cfg = count_mode << 1; | ||
| 353 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 354 | |||
| 355 | priv->count_mode[chan->channel] = count_mode; | ||
| 356 | |||
| 357 | /* Add quadrature mode configuration */ | ||
| 358 | if (priv->quadrature_mode[chan->channel]) | ||
| 359 | mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; | ||
| 360 | |||
| 361 | /* Load mode configuration to Counter Mode Register */ | ||
| 362 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 363 | |||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 367 | static int quad8_get_count_mode(struct iio_dev *indio_dev, | ||
| 368 | const struct iio_chan_spec *chan) | ||
| 369 | { | ||
| 370 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 371 | |||
| 372 | return priv->count_mode[chan->channel]; | ||
| 373 | } | ||
| 374 | |||
| 375 | static const struct iio_enum quad8_count_mode_enum = { | ||
| 376 | .items = quad8_count_modes, | ||
| 377 | .num_items = ARRAY_SIZE(quad8_count_modes), | ||
| 378 | .set = quad8_set_count_mode, | ||
| 379 | .get = quad8_get_count_mode | ||
| 380 | }; | ||
| 381 | |||
| 382 | static const char *const quad8_synchronous_modes[] = { | ||
| 383 | "non-synchronous", | ||
| 384 | "synchronous" | ||
| 385 | }; | ||
| 386 | |||
| 387 | static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, | ||
| 388 | const struct iio_chan_spec *chan, unsigned int synchronous_mode) | ||
| 389 | { | ||
| 390 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 391 | const unsigned int idr_cfg = synchronous_mode | | ||
| 392 | priv->index_polarity[chan->channel] << 1; | ||
| 393 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 394 | |||
| 395 | /* Index function must be non-synchronous in non-quadrature mode */ | ||
| 396 | if (synchronous_mode && !priv->quadrature_mode[chan->channel]) | ||
| 397 | return -EINVAL; | ||
| 398 | |||
| 399 | priv->synchronous_mode[chan->channel] = synchronous_mode; | ||
| 400 | |||
| 401 | /* Load Index Control configuration to Index Control Register */ | ||
| 402 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, | ||
| 408 | const struct iio_chan_spec *chan) | ||
| 409 | { | ||
| 410 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 411 | |||
| 412 | return priv->synchronous_mode[chan->channel]; | ||
| 413 | } | ||
| 414 | |||
| 415 | static const struct iio_enum quad8_synchronous_mode_enum = { | ||
| 416 | .items = quad8_synchronous_modes, | ||
| 417 | .num_items = ARRAY_SIZE(quad8_synchronous_modes), | ||
| 418 | .set = quad8_set_synchronous_mode, | ||
| 419 | .get = quad8_get_synchronous_mode | ||
| 420 | }; | ||
| 421 | |||
| 422 | static const char *const quad8_quadrature_modes[] = { | ||
| 423 | "non-quadrature", | ||
| 424 | "quadrature" | ||
| 425 | }; | ||
| 426 | |||
| 427 | static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, | ||
| 428 | const struct iio_chan_spec *chan, unsigned int quadrature_mode) | ||
| 429 | { | ||
| 430 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 431 | unsigned int mode_cfg = priv->count_mode[chan->channel] << 1; | ||
| 432 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 433 | |||
| 434 | if (quadrature_mode) | ||
| 435 | mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; | ||
| 436 | else { | ||
| 437 | /* Quadrature scaling only available in quadrature mode */ | ||
| 438 | priv->quadrature_scale[chan->channel] = 0; | ||
| 439 | |||
| 440 | /* Synchronous function not supported in non-quadrature mode */ | ||
| 441 | if (priv->synchronous_mode[chan->channel]) | ||
| 442 | quad8_set_synchronous_mode(indio_dev, chan, 0); | ||
| 443 | } | ||
| 444 | |||
| 445 | priv->quadrature_mode[chan->channel] = quadrature_mode; | ||
| 446 | |||
| 447 | /* Load mode configuration to Counter Mode Register */ | ||
| 448 | outb(QUAD8_CTR_CMR | mode_cfg, base_offset); | ||
| 449 | |||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, | ||
| 454 | const struct iio_chan_spec *chan) | ||
| 455 | { | ||
| 456 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 457 | |||
| 458 | return priv->quadrature_mode[chan->channel]; | ||
| 459 | } | ||
| 460 | |||
| 461 | static const struct iio_enum quad8_quadrature_mode_enum = { | ||
| 462 | .items = quad8_quadrature_modes, | ||
| 463 | .num_items = ARRAY_SIZE(quad8_quadrature_modes), | ||
| 464 | .set = quad8_set_quadrature_mode, | ||
| 465 | .get = quad8_get_quadrature_mode | ||
| 466 | }; | ||
| 467 | |||
| 468 | static const char *const quad8_index_polarity_modes[] = { | ||
| 469 | "negative", | ||
| 470 | "positive" | ||
| 471 | }; | ||
| 472 | |||
| 473 | static int quad8_set_index_polarity(struct iio_dev *indio_dev, | ||
| 474 | const struct iio_chan_spec *chan, unsigned int index_polarity) | ||
| 475 | { | ||
| 476 | struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 477 | const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | | ||
| 478 | index_polarity << 1; | ||
| 479 | const int base_offset = priv->base + 2 * chan->channel + 1; | ||
| 480 | |||
| 481 | priv->index_polarity[chan->channel] = index_polarity; | ||
| 482 | |||
| 483 | /* Load Index Control configuration to Index Control Register */ | ||
| 484 | outb(QUAD8_CTR_IDR | idr_cfg, base_offset); | ||
| 485 | |||
| 486 | return 0; | ||
| 487 | } | ||
| 488 | |||
| 489 | static int quad8_get_index_polarity(struct iio_dev *indio_dev, | ||
| 490 | const struct iio_chan_spec *chan) | ||
| 491 | { | ||
| 492 | const struct quad8_iio *const priv = iio_priv(indio_dev); | ||
| 493 | |||
| 494 | return priv->index_polarity[chan->channel]; | ||
| 495 | } | ||
| 496 | |||
| 497 | static const struct iio_enum quad8_index_polarity_enum = { | ||
| 498 | .items = quad8_index_polarity_modes, | ||
| 499 | .num_items = ARRAY_SIZE(quad8_index_polarity_modes), | ||
| 500 | .set = quad8_set_index_polarity, | ||
| 501 | .get = quad8_get_index_polarity | ||
| 502 | }; | ||
| 503 | |||
| 504 | static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { | ||
| 505 | { | ||
| 506 | .name = "preset", | ||
| 507 | .shared = IIO_SEPARATE, | ||
| 508 | .read = quad8_read_preset, | ||
| 509 | .write = quad8_write_preset | ||
| 510 | }, | ||
| 511 | { | ||
| 512 | .name = "set_to_preset_on_index", | ||
| 513 | .shared = IIO_SEPARATE, | ||
| 514 | .read = quad8_read_set_to_preset_on_index, | ||
| 515 | .write = quad8_write_set_to_preset_on_index | ||
| 516 | }, | ||
| 517 | IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), | ||
| 518 | IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), | ||
| 519 | IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), | ||
| 520 | IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), | ||
| 521 | IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), | ||
| 522 | IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), | ||
| 523 | IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), | ||
| 524 | IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), | ||
| 525 | {} | ||
| 526 | }; | ||
| 527 | |||
| 528 | static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { | ||
| 529 | IIO_ENUM("synchronous_mode", IIO_SEPARATE, | ||
| 530 | &quad8_synchronous_mode_enum), | ||
| 531 | IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), | ||
| 532 | IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), | ||
| 533 | IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), | ||
| 534 | {} | ||
| 535 | }; | ||
| 536 | |||
| 537 | #define QUAD8_COUNT_CHAN(_chan) { \ | ||
| 538 | .type = IIO_COUNT, \ | ||
| 539 | .channel = (_chan), \ | ||
| 540 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 541 | BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 542 | .ext_info = quad8_count_ext_info, \ | ||
| 543 | .indexed = 1 \ | ||
| 544 | } | ||
| 545 | |||
| 546 | #define QUAD8_INDEX_CHAN(_chan) { \ | ||
| 547 | .type = IIO_INDEX, \ | ||
| 548 | .channel = (_chan), \ | ||
| 549 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 550 | .ext_info = quad8_index_ext_info, \ | ||
| 551 | .indexed = 1 \ | ||
| 552 | } | ||
| 553 | |||
| 554 | static const struct iio_chan_spec quad8_channels[] = { | ||
| 555 | QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), | ||
| 556 | QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), | ||
| 557 | QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), | ||
| 558 | QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), | ||
| 559 | QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), | ||
| 560 | QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), | ||
| 561 | QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), | ||
| 562 | QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) | ||
| 563 | }; | ||
| 564 | |||
| 565 | static int quad8_probe(struct device *dev, unsigned int id) | ||
| 566 | { | ||
| 567 | struct iio_dev *indio_dev; | ||
| 568 | struct quad8_iio *priv; | ||
| 569 | int i, j; | ||
| 570 | unsigned int base_offset; | ||
| 571 | |||
| 572 | indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); | ||
| 573 | if (!indio_dev) | ||
| 574 | return -ENOMEM; | ||
| 575 | |||
| 576 | if (!devm_request_region(dev, base[id], QUAD8_EXTENT, | ||
| 577 | dev_name(dev))) { | ||
| 578 | dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", | ||
| 579 | base[id], base[id] + QUAD8_EXTENT); | ||
| 580 | return -EBUSY; | ||
| 581 | } | ||
| 582 | |||
| 583 | indio_dev->info = &quad8_info; | ||
| 584 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 585 | indio_dev->num_channels = ARRAY_SIZE(quad8_channels); | ||
| 586 | indio_dev->channels = quad8_channels; | ||
| 587 | indio_dev->name = dev_name(dev); | ||
| 588 | indio_dev->dev.parent = dev; | ||
| 589 | |||
| 590 | priv = iio_priv(indio_dev); | ||
| 591 | priv->base = base[id]; | ||
| 592 | |||
| 593 | /* Reset all counters and disable interrupt function */ | ||
| 594 | outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); | ||
| 595 | /* Set initial configuration for all counters */ | ||
| 596 | for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { | ||
| 597 | base_offset = base[id] + 2 * i; | ||
| 598 | /* Reset Byte Pointer */ | ||
| 599 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); | ||
| 600 | /* Reset Preset Register */ | ||
| 601 | for (j = 0; j < 3; j++) | ||
| 602 | outb(0x00, base_offset); | ||
| 603 | /* Reset Borrow, Carry, Compare, and Sign flags */ | ||
| 604 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); | ||
| 605 | /* Reset Error flag */ | ||
| 606 | outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); | ||
| 607 | /* Binary encoding; Normal count; non-quadrature mode */ | ||
| 608 | outb(QUAD8_CTR_CMR, base_offset + 1); | ||
| 609 | /* Disable A and B inputs; preset on index; FLG1 as Carry */ | ||
| 610 | outb(QUAD8_CTR_IOR, base_offset + 1); | ||
| 611 | /* Disable index function; negative index polarity */ | ||
| 612 | outb(QUAD8_CTR_IDR, base_offset + 1); | ||
| 613 | } | ||
| 614 | /* Enable all counters */ | ||
| 615 | outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); | ||
| 616 | |||
| 617 | return devm_iio_device_register(dev, indio_dev); | ||
| 618 | } | ||
| 619 | |||
| 620 | static struct isa_driver quad8_driver = { | ||
| 621 | .probe = quad8_probe, | ||
| 622 | .driver = { | ||
| 623 | .name = "104-quad-8" | ||
| 624 | } | ||
| 625 | }; | ||
| 626 | |||
| 627 | module_isa_driver(quad8_driver, num_quad8); | ||
| 628 | |||
| 629 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); | ||
| 630 | MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); | ||
| 631 | MODULE_LICENSE("GPL v2"); | ||
| @@ -1,34 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Counter devices | ||
| 3 | # | ||
| 4 | # When adding new entries keep the list in alphabetical order | ||
| 5 | |||
| 6 | menu "Counters" | ||
| 7 | |||
| 8 | config 104_QUAD_8 | ||
| 9 | tristate "ACCES 104-QUAD-8 driver" | ||
| 10 | depends on PC104 && X86 | ||
| 11 | select ISA_BUS_API | ||
| 12 | help | ||
| 13 | Say yes here to build support for the ACCES 104-QUAD-8 quadrature | ||
| 14 | encoder counter/interface device family (104-QUAD-8, 104-QUAD-4). | ||
| 15 | |||
| 16 | Performing a write to a counter's IIO_CHAN_INFO_RAW sets the counter and | ||
| 17 | also clears the counter's respective error flag. Although the counters | ||
| 18 | have a 25-bit range, only the lower 24 bits may be set, either directly | ||
| 19 | or via a counter's preset attribute. Interrupts are not supported by | ||
| 20 | this driver. | ||
| 21 | |||
| 22 | The base port addresses for the devices may be configured via the base | ||
| 23 | array module parameter. | ||
| 24 | |||
| 25 | config STM32_LPTIMER_CNT | ||
| 26 | tristate "STM32 LP Timer encoder counter driver" | ||
| 27 | depends on MFD_STM32_LPTIMER || COMPILE_TEST | ||
| 28 | help | ||
| 29 | Select this option to enable STM32 Low-Power Timer quadrature encoder | ||
| 30 | and counter driver. | ||
| 31 | |||
| 32 | To compile this driver as a module, choose M here: the | ||
| 33 | module will be called stm32-lptimer-cnt. | ||
| 34 | endmenu | ||
| @@ -1,8 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Makefile for IIO counter devices | ||
| 3 | # | ||
| 4 | |||
| 5 | # When adding new entries keep the list in alphabetical order | ||
| 6 | |||
| 7 | obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o | ||
| 8 | obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o | ||
| @@ -1,382 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * STM32 Low-Power Timer Encoder and Counter driver | ||
| 4 | * | ||
| 5 | * Copyright (C) STMicroelectronics 2017 | ||
| 6 | * | ||
| 7 | * Author: Fabrice Gasnier <fabrice.gasnier@st.com> | ||
| 8 | * | ||
| 9 | * Inspired by 104-quad-8 and stm32-timer-trigger drivers. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/bitfield.h> | ||
| 14 | #include <linux/iio/iio.h> | ||
| 15 | #include <linux/mfd/stm32-lptimer.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | |||
| 19 | struct stm32_lptim_cnt { | ||
| 20 | struct device *dev; | ||
| 21 | struct regmap *regmap; | ||
| 22 | struct clk *clk; | ||
| 23 | u32 preset; | ||
| 24 | u32 polarity; | ||
| 25 | u32 quadrature_mode; | ||
| 26 | }; | ||
| 27 | |||
| 28 | static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) | ||
| 29 | { | ||
| 30 | u32 val; | ||
| 31 | int ret; | ||
| 32 | |||
| 33 | ret = regmap_read(priv->regmap, STM32_LPTIM_CR, &val); | ||
| 34 | if (ret) | ||
| 35 | return ret; | ||
| 36 | |||
| 37 | return FIELD_GET(STM32_LPTIM_ENABLE, val); | ||
| 38 | } | ||
| 39 | |||
| 40 | static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, | ||
| 41 | int enable) | ||
| 42 | { | ||
| 43 | int ret; | ||
| 44 | u32 val; | ||
| 45 | |||
| 46 | val = FIELD_PREP(STM32_LPTIM_ENABLE, enable); | ||
| 47 | ret = regmap_write(priv->regmap, STM32_LPTIM_CR, val); | ||
| 48 | if (ret) | ||
| 49 | return ret; | ||
| 50 | |||
| 51 | if (!enable) { | ||
| 52 | clk_disable(priv->clk); | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* LP timer must be enabled before writing CMP & ARR */ | ||
| 57 | ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, priv->preset); | ||
| 58 | if (ret) | ||
| 59 | return ret; | ||
| 60 | |||
| 61 | ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, 0); | ||
| 62 | if (ret) | ||
| 63 | return ret; | ||
| 64 | |||
| 65 | /* ensure CMP & ARR registers are properly written */ | ||
| 66 | ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, | ||
| 67 | (val & STM32_LPTIM_CMPOK_ARROK), | ||
| 68 | 100, 1000); | ||
| 69 | if (ret) | ||
| 70 | return ret; | ||
| 71 | |||
| 72 | ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, | ||
| 73 | STM32_LPTIM_CMPOKCF_ARROKCF); | ||
| 74 | if (ret) | ||
| 75 | return ret; | ||
| 76 | |||
| 77 | ret = clk_enable(priv->clk); | ||
| 78 | if (ret) { | ||
| 79 | regmap_write(priv->regmap, STM32_LPTIM_CR, 0); | ||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Start LP timer in continuous mode */ | ||
| 84 | return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, | ||
| 85 | STM32_LPTIM_CNTSTRT, STM32_LPTIM_CNTSTRT); | ||
| 86 | } | ||
| 87 | |||
| 88 | static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable) | ||
| 89 | { | ||
| 90 | u32 mask = STM32_LPTIM_ENC | STM32_LPTIM_COUNTMODE | | ||
| 91 | STM32_LPTIM_CKPOL | STM32_LPTIM_PRESC; | ||
| 92 | u32 val; | ||
| 93 | |||
| 94 | /* Setup LP timer encoder/counter and polarity, without prescaler */ | ||
| 95 | if (priv->quadrature_mode) | ||
| 96 | val = enable ? STM32_LPTIM_ENC : 0; | ||
| 97 | else | ||
| 98 | val = enable ? STM32_LPTIM_COUNTMODE : 0; | ||
| 99 | val |= FIELD_PREP(STM32_LPTIM_CKPOL, enable ? priv->polarity : 0); | ||
| 100 | |||
| 101 | return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val); | ||
| 102 | } | ||
| 103 | |||
| 104 | static int stm32_lptim_write_raw(struct iio_dev *indio_dev, | ||
| 105 | struct iio_chan_spec const *chan, | ||
| 106 | int val, int val2, long mask) | ||
| 107 | { | ||
| 108 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | switch (mask) { | ||
| 112 | case IIO_CHAN_INFO_ENABLE: | ||
| 113 | if (val < 0 || val > 1) | ||
| 114 | return -EINVAL; | ||
| 115 | |||
| 116 | /* Check nobody uses the timer, or already disabled/enabled */ | ||
| 117 | ret = stm32_lptim_is_enabled(priv); | ||
| 118 | if ((ret < 0) || (!ret && !val)) | ||
| 119 | return ret; | ||
| 120 | if (val && ret) | ||
| 121 | return -EBUSY; | ||
| 122 | |||
| 123 | ret = stm32_lptim_setup(priv, val); | ||
| 124 | if (ret) | ||
| 125 | return ret; | ||
| 126 | return stm32_lptim_set_enable_state(priv, val); | ||
| 127 | |||
| 128 | default: | ||
| 129 | return -EINVAL; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | static int stm32_lptim_read_raw(struct iio_dev *indio_dev, | ||
| 134 | struct iio_chan_spec const *chan, | ||
| 135 | int *val, int *val2, long mask) | ||
| 136 | { | ||
| 137 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 138 | u32 dat; | ||
| 139 | int ret; | ||
| 140 | |||
| 141 | switch (mask) { | ||
| 142 | case IIO_CHAN_INFO_RAW: | ||
| 143 | ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat); | ||
| 144 | if (ret) | ||
| 145 | return ret; | ||
| 146 | *val = dat; | ||
| 147 | return IIO_VAL_INT; | ||
| 148 | |||
| 149 | case IIO_CHAN_INFO_ENABLE: | ||
| 150 | ret = stm32_lptim_is_enabled(priv); | ||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | *val = ret; | ||
| 154 | return IIO_VAL_INT; | ||
| 155 | |||
| 156 | case IIO_CHAN_INFO_SCALE: | ||
| 157 | /* Non-quadrature mode: scale = 1 */ | ||
| 158 | *val = 1; | ||
| 159 | *val2 = 0; | ||
| 160 | if (priv->quadrature_mode) { | ||
| 161 | /* | ||
| 162 | * Quadrature encoder mode: | ||
| 163 | * - both edges, quarter cycle, scale is 0.25 | ||
| 164 | * - either rising/falling edge scale is 0.5 | ||
| 165 | */ | ||
| 166 | if (priv->polarity > 1) | ||
| 167 | *val2 = 2; | ||
| 168 | else | ||
| 169 | *val2 = 1; | ||
| 170 | } | ||
| 171 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 172 | |||
| 173 | default: | ||
| 174 | return -EINVAL; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | static const struct iio_info stm32_lptim_cnt_iio_info = { | ||
| 179 | .read_raw = stm32_lptim_read_raw, | ||
| 180 | .write_raw = stm32_lptim_write_raw, | ||
| 181 | }; | ||
| 182 | |||
| 183 | static const char *const stm32_lptim_quadrature_modes[] = { | ||
| 184 | "non-quadrature", | ||
| 185 | "quadrature", | ||
| 186 | }; | ||
| 187 | |||
| 188 | static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev, | ||
| 189 | const struct iio_chan_spec *chan) | ||
| 190 | { | ||
| 191 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 192 | |||
| 193 | return priv->quadrature_mode; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev, | ||
| 197 | const struct iio_chan_spec *chan, | ||
| 198 | unsigned int type) | ||
| 199 | { | ||
| 200 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 201 | |||
| 202 | if (stm32_lptim_is_enabled(priv)) | ||
| 203 | return -EBUSY; | ||
| 204 | |||
| 205 | priv->quadrature_mode = type; | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static const struct iio_enum stm32_lptim_quadrature_mode_en = { | ||
| 211 | .items = stm32_lptim_quadrature_modes, | ||
| 212 | .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes), | ||
| 213 | .get = stm32_lptim_get_quadrature_mode, | ||
| 214 | .set = stm32_lptim_set_quadrature_mode, | ||
| 215 | }; | ||
| 216 | |||
| 217 | static const char * const stm32_lptim_cnt_polarity[] = { | ||
| 218 | "rising-edge", "falling-edge", "both-edges", | ||
| 219 | }; | ||
| 220 | |||
| 221 | static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev, | ||
| 222 | const struct iio_chan_spec *chan) | ||
| 223 | { | ||
| 224 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 225 | |||
| 226 | return priv->polarity; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev, | ||
| 230 | const struct iio_chan_spec *chan, | ||
| 231 | unsigned int type) | ||
| 232 | { | ||
| 233 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 234 | |||
| 235 | if (stm32_lptim_is_enabled(priv)) | ||
| 236 | return -EBUSY; | ||
| 237 | |||
| 238 | priv->polarity = type; | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static const struct iio_enum stm32_lptim_cnt_polarity_en = { | ||
| 244 | .items = stm32_lptim_cnt_polarity, | ||
| 245 | .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity), | ||
| 246 | .get = stm32_lptim_cnt_get_polarity, | ||
| 247 | .set = stm32_lptim_cnt_set_polarity, | ||
| 248 | }; | ||
| 249 | |||
| 250 | static ssize_t stm32_lptim_cnt_get_preset(struct iio_dev *indio_dev, | ||
| 251 | uintptr_t private, | ||
| 252 | const struct iio_chan_spec *chan, | ||
| 253 | char *buf) | ||
| 254 | { | ||
| 255 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 256 | |||
| 257 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset); | ||
| 258 | } | ||
| 259 | |||
| 260 | static ssize_t stm32_lptim_cnt_set_preset(struct iio_dev *indio_dev, | ||
| 261 | uintptr_t private, | ||
| 262 | const struct iio_chan_spec *chan, | ||
| 263 | const char *buf, size_t len) | ||
| 264 | { | ||
| 265 | struct stm32_lptim_cnt *priv = iio_priv(indio_dev); | ||
| 266 | int ret; | ||
| 267 | |||
| 268 | if (stm32_lptim_is_enabled(priv)) | ||
| 269 | return -EBUSY; | ||
| 270 | |||
| 271 | ret = kstrtouint(buf, 0, &priv->preset); | ||
| 272 | if (ret) | ||
| 273 | return ret; | ||
| 274 | |||
| 275 | if (priv->preset > STM32_LPTIM_MAX_ARR) | ||
| 276 | return -EINVAL; | ||
| 277 | |||
| 278 | return len; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* LP timer with encoder */ | ||
| 282 | static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = { | ||
| 283 | { | ||
| 284 | .name = "preset", | ||
| 285 | .shared = IIO_SEPARATE, | ||
| 286 | .read = stm32_lptim_cnt_get_preset, | ||
| 287 | .write = stm32_lptim_cnt_set_preset, | ||
| 288 | }, | ||
| 289 | IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), | ||
| 290 | IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), | ||
| 291 | IIO_ENUM("quadrature_mode", IIO_SEPARATE, | ||
| 292 | &stm32_lptim_quadrature_mode_en), | ||
| 293 | IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en), | ||
| 294 | {} | ||
| 295 | }; | ||
| 296 | |||
| 297 | static const struct iio_chan_spec stm32_lptim_enc_channels = { | ||
| 298 | .type = IIO_COUNT, | ||
| 299 | .channel = 0, | ||
| 300 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 301 | BIT(IIO_CHAN_INFO_ENABLE) | | ||
| 302 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 303 | .ext_info = stm32_lptim_enc_ext_info, | ||
| 304 | .indexed = 1, | ||
| 305 | }; | ||
| 306 | |||
| 307 | /* LP timer without encoder (counter only) */ | ||
| 308 | static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = { | ||
| 309 | { | ||
| 310 | .name = "preset", | ||
| 311 | .shared = IIO_SEPARATE, | ||
| 312 | .read = stm32_lptim_cnt_get_preset, | ||
| 313 | .write = stm32_lptim_cnt_set_preset, | ||
| 314 | }, | ||
| 315 | IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en), | ||
| 316 | IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en), | ||
| 317 | {} | ||
| 318 | }; | ||
| 319 | |||
| 320 | static const struct iio_chan_spec stm32_lptim_cnt_channels = { | ||
| 321 | .type = IIO_COUNT, | ||
| 322 | .channel = 0, | ||
| 323 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 324 | BIT(IIO_CHAN_INFO_ENABLE) | | ||
| 325 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 326 | .ext_info = stm32_lptim_cnt_ext_info, | ||
| 327 | .indexed = 1, | ||
| 328 | }; | ||
| 329 | |||
| 330 | static int stm32_lptim_cnt_probe(struct platform_device *pdev) | ||
| 331 | { | ||
| 332 | struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); | ||
| 333 | struct stm32_lptim_cnt *priv; | ||
| 334 | struct iio_dev *indio_dev; | ||
| 335 | |||
| 336 | if (IS_ERR_OR_NULL(ddata)) | ||
| 337 | return -EINVAL; | ||
| 338 | |||
| 339 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); | ||
| 340 | if (!indio_dev) | ||
| 341 | return -ENOMEM; | ||
| 342 | |||
| 343 | priv = iio_priv(indio_dev); | ||
| 344 | priv->dev = &pdev->dev; | ||
| 345 | priv->regmap = ddata->regmap; | ||
| 346 | priv->clk = ddata->clk; | ||
| 347 | priv->preset = STM32_LPTIM_MAX_ARR; | ||
| 348 | |||
| 349 | indio_dev->name = dev_name(&pdev->dev); | ||
| 350 | indio_dev->dev.parent = &pdev->dev; | ||
| 351 | indio_dev->dev.of_node = pdev->dev.of_node; | ||
| 352 | indio_dev->info = &stm32_lptim_cnt_iio_info; | ||
| 353 | if (ddata->has_encoder) | ||
| 354 | indio_dev->channels = &stm32_lptim_enc_channels; | ||
| 355 | else | ||
| 356 | indio_dev->channels = &stm32_lptim_cnt_channels; | ||
| 357 | indio_dev->num_channels = 1; | ||
| 358 | |||
| 359 | platform_set_drvdata(pdev, priv); | ||
| 360 | |||
| 361 | return devm_iio_device_register(&pdev->dev, indio_dev); | ||
| 362 | } | ||
| 363 | |||
| 364 | static const struct of_device_id stm32_lptim_cnt_of_match[] = { | ||
| 365 | { .compatible = "st,stm32-lptimer-counter", }, | ||
| 366 | {}, | ||
| 367 | }; | ||
| 368 | MODULE_DEVICE_TABLE(of, stm32_lptim_cnt_of_match); | ||
| 369 | |||
| 370 | static struct platform_driver stm32_lptim_cnt_driver = { | ||
| 371 | .probe = stm32_lptim_cnt_probe, | ||
| 372 | .driver = { | ||
| 373 | .name = "stm32-lptimer-counter", | ||
| 374 | .of_match_table = stm32_lptim_cnt_of_match, | ||
| 375 | }, | ||
| 376 | }; | ||
| 377 | module_platform_driver(stm32_lptim_cnt_driver); | ||
| 378 | |||
| 379 | MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); | ||
| 380 | MODULE_ALIAS("platform:stm32-lptimer-counter"); | ||
| 381 | MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver"); | ||
| 382 | MODULE_LICENSE("GPL v2"); | ||
| @@ -112,6 +112,8 @@ struct ad5064_state { · 111 unmodified lines | |||
| 112 | bool use_internal_vref; | 112 | bool use_internal_vref; |
| 113 | 113 | ||
| 114 | ad5064_write_func write; | 114 | ad5064_write_func write; |
| 115 | /* Lock used to maintain consistency between cached and dev state */ | ||
| 116 | struct mutex lock; | ||
| 115 | 117 | ||
| 116 | /* | 118 | /* |
| 117 | * DMA (thus cache coherency maintenance) requires the | 119 | * DMA (thus cache coherency maintenance) requires the |
| @@ -248,11 +250,11 @@ static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, · 130 unmodified lines | |||
| 248 | struct ad5064_state *st = iio_priv(indio_dev); | 250 | struct ad5064_state *st = iio_priv(indio_dev); |
| 249 | int ret; | 251 | int ret; |
| 250 | 252 | ||
| 251 | mutex_lock(&indio_dev->mlock); | 253 | mutex_lock(&st->lock); |
| 252 | st->pwr_down_mode[chan->channel] = mode + 1; | 254 | st->pwr_down_mode[chan->channel] = mode + 1; |
| 253 | 255 | ||
| 254 | ret = ad5064_sync_powerdown_mode(st, chan); | 256 | ret = ad5064_sync_powerdown_mode(st, chan); |
| 255 | mutex_unlock(&indio_dev->mlock); | 257 | mutex_unlock(&st->lock); |
| 256 | 258 | ||
| 257 | return ret; | 259 | return ret; |
| 258 | } | 260 | } |
| @@ -291,11 +293,11 @@ static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, · 32 unmodified lines | |||
| 291 | if (ret) | 293 | if (ret) |
| 292 | return ret; | 294 | return ret; |
| 293 | 295 | ||
| 294 | mutex_lock(&indio_dev->mlock); | 296 | mutex_lock(&st->lock); |
| 295 | st->pwr_down[chan->channel] = pwr_down; | 297 | st->pwr_down[chan->channel] = pwr_down; |
| 296 | 298 | ||
| 297 | ret = ad5064_sync_powerdown_mode(st, chan); | 299 | ret = ad5064_sync_powerdown_mode(st, chan); |
| 298 | mutex_unlock(&indio_dev->mlock); | 300 | mutex_unlock(&st->lock); |
| 299 | return ret ? ret : len; | 301 | return ret ? ret : len; |
| 300 | } | 302 | } |
| 301 | 303 | ||
| @@ -349,12 +351,12 @@ static int ad5064_write_raw(struct iio_dev *indio_dev, · 47 unmodified lines | |||
| 349 | if (val >= (1 << chan->scan_type.realbits) || val < 0) | 351 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
| 350 | return -EINVAL; | 352 | return -EINVAL; |
| 351 | 353 | ||
| 352 | mutex_lock(&indio_dev->mlock); | 354 | mutex_lock(&st->lock); |
| 353 | ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, | 355 | ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, |
| 354 | chan->address, val, chan->scan_type.shift); | 356 | chan->address, val, chan->scan_type.shift); |
| 355 | if (ret == 0) | 357 | if (ret == 0) |
| 356 | st->dac_cache[chan->channel] = val; | 358 | st->dac_cache[chan->channel] = val; |
| 357 | mutex_unlock(&indio_dev->mlock); | 359 | mutex_unlock(&st->lock); |
| 358 | break; | 360 | break; |
| 359 | default: | 361 | default: |
| 360 | ret = -EINVAL; | 362 | ret = -EINVAL; |
| @@ -856,6 +858,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, · 495 unmodified lines | |||
| 856 | return -ENOMEM; | 858 | return -ENOMEM; |
| 857 | 859 | ||
| 858 | st = iio_priv(indio_dev); | 860 | st = iio_priv(indio_dev); |
| 861 | mutex_init(&st->lock); | ||
| 859 | dev_set_drvdata(dev, indio_dev); | 862 | dev_set_drvdata(dev, indio_dev); |
| 860 | 863 | ||
| 861 | st->chip_info = &ad5064_chip_info_tbl[type]; | 864 | st->chip_info = &ad5064_chip_info_tbl[type]; |
| @@ -72,8 +72,6 @@ · 71 unmodified lines | |||
| 72 | #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) | 72 | #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) |
| 73 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) | 73 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) |
| 74 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) | 74 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) |
| 75 | #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7) | ||
| 76 | #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7) | ||
| 77 | 75 | ||
| 78 | /* AD5758_DCDC_CONFIG2 */ | 76 | /* AD5758_DCDC_CONFIG2 */ |
| 79 | #define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) | 77 | #define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) |
| @@ -84,6 +82,10 @@ · 4 unmodified lines | |||
| 84 | /* AD5758_DIGITAL_DIAG_RESULTS */ | 82 | /* AD5758_DIGITAL_DIAG_RESULTS */ |
| 85 | #define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) | 83 | #define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) |
| 86 | 84 | ||
| 85 | /* AD5758_ADC_CONFIG */ | ||
| 86 | #define AD5758_ADC_CONFIG_PPC_BUF_EN(x) (((x) & 0x1) << 11) | ||
| 87 | #define AD5758_ADC_CONFIG_PPC_BUF_MSK BIT(11) | ||
| 88 | |||
| 87 | #define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) | 89 | #define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) |
| 88 | 90 | ||
| 89 | #define AD5758_FULL_SCALE_MICRO 65535000000ULL | 91 | #define AD5758_FULL_SCALE_MICRO 65535000000ULL |
| @@ -315,6 +317,18 @@ static int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st, · 225 unmodified lines | |||
| 315 | { | 317 | { |
| 316 | int ret; | 318 | int ret; |
| 317 | 319 | ||
| 320 | /* | ||
| 321 | * The ENABLE_PPC_BUFFERS bit must be set prior to enabling PPC current | ||
| 322 | * mode. | ||
| 323 | */ | ||
| 324 | if (mode == AD5758_DCDC_MODE_PPC_CURRENT) { | ||
| 325 | ret = ad5758_spi_write_mask(st, AD5758_ADC_CONFIG, | ||
| 326 | AD5758_ADC_CONFIG_PPC_BUF_MSK, | ||
| 327 | AD5758_ADC_CONFIG_PPC_BUF_EN(1)); | ||
| 328 | if (ret < 0) | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 318 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | 332 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, |
| 319 | AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, | 333 | AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, |
| 320 | AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); | 334 | AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); |
| @@ -444,23 +458,6 @@ static int ad5758_set_out_range(struct ad5758_state *st, int range) · 123 unmodified lines | |||
| 444 | AD5758_CAL_MEM_UNREFRESHED_MSK); | 458 | AD5758_CAL_MEM_UNREFRESHED_MSK); |
| 445 | } | 459 | } |
| 446 | 460 | ||
| 447 | static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable) | ||
| 448 | { | ||
| 449 | int ret; | ||
| 450 | |||
| 451 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | ||
| 452 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK, | ||
| 453 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable)); | ||
| 454 | if (ret < 0) | ||
| 455 | return ret; | ||
| 456 | /* | ||
| 457 | * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. | ||
| 458 | * This allows the 3-wire interface communication to complete. | ||
| 459 | */ | ||
| 460 | return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, | ||
| 461 | AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); | ||
| 462 | } | ||
| 463 | |||
| 464 | static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) | 461 | static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) |
| 465 | { | 462 | { |
| 466 | int ret; | 463 | int ret; |
| @@ -585,8 +582,8 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, · 118 unmodified lines | |||
| 585 | { | 582 | { |
| 586 | struct ad5758_state *st = iio_priv(indio_dev); | 583 | struct ad5758_state *st = iio_priv(indio_dev); |
| 587 | bool pwr_down; | 584 | bool pwr_down; |
| 588 | unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val; | 585 | unsigned int dc_dc_mode, dac_config_mode, val; |
| 589 | unsigned long int dcdc_config1_msk, dac_config_msk; | 586 | unsigned long int dac_config_msk; |
| 590 | int ret; | 587 | int ret; |
| 591 | 588 | ||
| 592 | ret = kstrtobool(buf, &pwr_down); | 589 | ret = kstrtobool(buf, &pwr_down); |
| @@ -602,17 +599,6 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, · 9 unmodified lines | |||
| 602 | val = 1; | 599 | val = 1; |
| 603 | } | 600 | } |
| 604 | 601 | ||
| 605 | dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) | | ||
| 606 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val); | ||
| 607 | dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK | | ||
| 608 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK; | ||
| 609 | |||
| 610 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | ||
| 611 | dcdc_config1_msk, | ||
| 612 | dcdc_config1_mode); | ||
| 613 | if (ret < 0) | ||
| 614 | goto err_unlock; | ||
| 615 | |||
| 616 | dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | | 602 | dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | |
| 617 | AD5758_DAC_CONFIG_INT_EN_MODE(val); | 603 | AD5758_DAC_CONFIG_INT_EN_MODE(val); |
| 618 | dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK | | 604 | dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK | |
| @@ -841,11 +827,6 @@ static int ad5758_init(struct ad5758_state *st) · 222 unmodified lines | |||
| 841 | return ret; | 827 | return ret; |
| 842 | } | 828 | } |
| 843 | 829 | ||
| 844 | /* Enable the VIOUT fault protection switch (FPS is closed) */ | ||
| 845 | ret = ad5758_fault_prot_switch_en(st, 1); | ||
| 846 | if (ret < 0) | ||
| 847 | return ret; | ||
| 848 | |||
| 849 | /* Power up the DAC and internal (INT) amplifiers */ | 830 | /* Power up the DAC and internal (INT) amplifiers */ |
| 850 | ret = ad5758_internal_buffers_en(st, 1); | 831 | ret = ad5758_internal_buffers_en(st, 1); |
| 851 | if (ret < 0) | 832 | if (ret < 0) |
| @@ -429,6 +429,6 @@ static struct i2c_driver dac5571_driver = { · 428 unmodified lines | |||
| 429 | }; | 429 | }; |
| 430 | module_i2c_driver(dac5571_driver); | 430 | module_i2c_driver(dac5571_driver); |
| 431 | 431 | ||
| 432 | MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); | 432 | MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>"); |
| 433 | MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); | 433 | MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); |
| 434 | MODULE_LICENSE("GPL v2"); | 434 | MODULE_LICENSE("GPL v2"); |
| @@ -196,7 +196,10 @@ static __init int iio_dummy_evgen_init(void) · 195 unmodified lines | |||
| 196 | return ret; | 196 | return ret; |
| 197 | device_initialize(&iio_evgen_dev); | 197 | device_initialize(&iio_evgen_dev); |
| 198 | dev_set_name(&iio_evgen_dev, "iio_evgen"); | 198 | dev_set_name(&iio_evgen_dev, "iio_evgen"); |
| 199 | return device_add(&iio_evgen_dev); | 199 | ret = device_add(&iio_evgen_dev); |
| 200 | if (ret) | ||
| 201 | put_device(&iio_evgen_dev); | ||
| 202 | return ret; | ||
| 200 | } | 203 | } |
| 201 | module_init(iio_dummy_evgen_init); | 204 | module_init(iio_dummy_evgen_init); |
| 202 | 205 | ||
| @@ -872,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev) · 871 unmodified lines | |||
| 872 | return ret; | 872 | return ret; |
| 873 | 873 | ||
| 874 | ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER, | 874 | ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER, |
| 875 | AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) | | 875 | AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_div_m1) | |
| 876 | AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) | | 876 | AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_div_m2) | |
| 877 | AD_IFE(pll2_vco_diff_m1, 0, | 877 | AD_IFE(pll2_vco_div_m1, 0, |
| 878 | AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) | | 878 | AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) | |
| 879 | AD_IFE(pll2_vco_diff_m2, 0, | 879 | AD_IFE(pll2_vco_div_m2, 0, |
| 880 | AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN)); | 880 | AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN)); |
| 881 | if (ret < 0) | 881 | if (ret < 0) |
| 882 | return ret; | 882 | return ret; |
| 883 | 883 | ||
| 884 | if (pdata->pll2_vco_diff_m1) | 884 | if (pdata->pll2_vco_div_m1) |
| 885 | st->vco_out_freq[AD9523_VCO1] = | 885 | st->vco_out_freq[AD9523_VCO1] = |
| 886 | st->vco_freq / pdata->pll2_vco_diff_m1; | 886 | st->vco_freq / pdata->pll2_vco_div_m1; |
| 887 | 887 | ||
| 888 | if (pdata->pll2_vco_diff_m2) | 888 | if (pdata->pll2_vco_div_m2) |
| 889 | st->vco_out_freq[AD9523_VCO2] = | 889 | st->vco_out_freq[AD9523_VCO2] = |
| 890 | st->vco_freq / pdata->pll2_vco_diff_m2; | 890 | st->vco_freq / pdata->pll2_vco_div_m2; |
| 891 | 891 | ||
| 892 | st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq; | 892 | st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq; |
| 893 | 893 | ||
| @@ -73,6 +73,28 @@ config BMG160_SPI · 72 unmodified lines | |||
| 73 | tristate | 73 | tristate |
| 74 | select REGMAP_SPI | 74 | select REGMAP_SPI |
| 75 | 75 | ||
| 76 | config FXAS21002C | ||
| 77 | tristate "NXP FXAS21002C Gyro Sensor" | ||
| 78 | select IIO_BUFFER | ||
| 79 | select IIO_TRIGGERED_BUFFER | ||
| 80 | select FXAS21002C_I2C if (I2C) | ||
| 81 | select FXAS21002C_SPI if (SPI) | ||
| 82 | depends on (I2C || SPI_MASTER) | ||
| 83 | help | ||
| 84 | Say yes here to build support for NXP FXAS21002C Tri-axis Gyro | ||
| 85 | Sensor driver connected via I2C or SPI. | ||
| 86 | |||
| 87 | This driver can also be built as a module. If so, the module | ||
| 88 | will be called fxas21002c_i2c or fxas21002c_spi. | ||
| 89 | |||
| 90 | config FXAS21002C_I2C | ||
| 91 | tristate | ||
| 92 | select REGMAP_I2C | ||
| 93 | |||
| 94 | config FXAS21002C_SPI | ||
| 95 | tristate | ||
| 96 | select REGMAP_SPI | ||
| 97 | |||
| 76 | config HID_SENSOR_GYRO_3D | 98 | config HID_SENSOR_GYRO_3D |
| 77 | depends on HID_SENSOR_HUB | 99 | depends on HID_SENSOR_HUB |
| 78 | select IIO_BUFFER | 100 | select IIO_BUFFER |
| @@ -12,6 +12,9 @@ obj-$(CONFIG_ADXRS450) += adxrs450.o · 11 unmodified lines | |||
| 12 | obj-$(CONFIG_BMG160) += bmg160_core.o | 12 | obj-$(CONFIG_BMG160) += bmg160_core.o |
| 13 | obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o | 13 | obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o |
| 14 | obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o | 14 | obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o |
| 15 | obj-$(CONFIG_FXAS21002C) += fxas21002c_core.o | ||
| 16 | obj-$(CONFIG_FXAS21002C_I2C) += fxas21002c_i2c.o | ||
| 17 | obj-$(CONFIG_FXAS21002C_SPI) += fxas21002c_spi.o | ||
| 15 | 18 | ||
| 16 | obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o | 19 | obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o |
| 17 | 20 | ||
| @@ -102,6 +102,7 @@ struct bmg160_data { · 101 unmodified lines | |||
| 102 | struct regmap *regmap; | 102 | struct regmap *regmap; |
| 103 | struct iio_trigger *dready_trig; | 103 | struct iio_trigger *dready_trig; |
| 104 | struct iio_trigger *motion_trig; | 104 | struct iio_trigger *motion_trig; |
| 105 | struct iio_mount_matrix orientation; | ||
| 105 | struct mutex mutex; | 106 | struct mutex mutex; |
| 106 | s16 buffer[8]; | 107 | s16 buffer[8]; |
| 107 | u32 dps_range; | 108 | u32 dps_range; |
| @@ -794,6 +795,20 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev, · 686 unmodified lines | |||
| 794 | return 0; | 795 | return 0; |
| 795 | } | 796 | } |
| 796 | 797 | ||
| 798 | static const struct iio_mount_matrix * | ||
| 799 | bmg160_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 800 | const struct iio_chan_spec *chan) | ||
| 801 | { | ||
| 802 | struct bmg160_data *data = iio_priv(indio_dev); | ||
| 803 | |||
| 804 | return &data->orientation; | ||
| 805 | } | ||
| 806 | |||
| 807 | static const struct iio_chan_spec_ext_info bmg160_ext_info[] = { | ||
| 808 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmg160_get_mount_matrix), | ||
| 809 | { } | ||
| 810 | }; | ||
| 811 | |||
| 797 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000"); | 812 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000"); |
| 798 | 813 | ||
| 799 | static IIO_CONST_ATTR(in_anglvel_scale_available, | 814 | static IIO_CONST_ATTR(in_anglvel_scale_available, |
| @@ -831,6 +846,7 @@ static const struct iio_event_spec bmg160_event = { · 31 unmodified lines | |||
| 831 | .storagebits = 16, \ | 846 | .storagebits = 16, \ |
| 832 | .endianness = IIO_LE, \ | 847 | .endianness = IIO_LE, \ |
| 833 | }, \ | 848 | }, \ |
| 849 | .ext_info = bmg160_ext_info, \ | ||
| 834 | .event_spec = &bmg160_event, \ | 850 | .event_spec = &bmg160_event, \ |
| 835 | .num_event_specs = 1 \ | 851 | .num_event_specs = 1 \ |
| 836 | } | 852 | } |
| @@ -1075,6 +1091,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, · 238 unmodified lines | |||
| 1075 | data->irq = irq; | 1091 | data->irq = irq; |
| 1076 | data->regmap = regmap; | 1092 | data->regmap = regmap; |
| 1077 | 1093 | ||
| 1094 | ret = iio_read_mount_matrix(dev, "mount-matrix", | ||
| 1095 | &data->orientation); | ||
| 1096 | if (ret) | ||
| 1097 | return ret; | ||
| 1098 | |||
| 1078 | ret = bmg160_chip_init(data); | 1099 | ret = bmg160_chip_init(data); |
| 1079 | if (ret < 0) | 1100 | if (ret < 0) |
| 1080 | return ret; | 1101 | return ret; |
| @@ -54,10 +54,19 @@ static const struct i2c_device_id bmg160_i2c_id[] = { · 53 unmodified lines | |||
| 54 | 54 | ||
| 55 | MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); | 55 | MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); |
| 56 | 56 | ||
| 57 | static const struct of_device_id bmg160_of_match[] = { | ||
| 58 | { .compatible = "bosch,bmg160" }, | ||
| 59 | { .compatible = "bosch,bmi055_gyro" }, | ||
| 60 | { } | ||
| 61 | }; | ||
| 62 | |||
| 63 | MODULE_DEVICE_TABLE(of, bmg160_of_match); | ||
| 64 | |||
| 57 | static struct i2c_driver bmg160_i2c_driver = { | 65 | static struct i2c_driver bmg160_i2c_driver = { |
| 58 | .driver = { | 66 | .driver = { |
| 59 | .name = "bmg160_i2c", | 67 | .name = "bmg160_i2c", |
| 60 | .acpi_match_table = ACPI_PTR(bmg160_acpi_match), | 68 | .acpi_match_table = ACPI_PTR(bmg160_acpi_match), |
| 69 | .of_match_table = bmg160_of_match, | ||
| 61 | .pm = &bmg160_pm_ops, | 70 | .pm = &bmg160_pm_ops, |
| 62 | }, | 71 | }, |
| 63 | .probe = bmg160_i2c_probe, | 72 | .probe = bmg160_i2c_probe, |
| @@ -0,0 +1,150 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Driver for NXP FXAS21002C Gyroscope - Header | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 Linaro Ltd. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef FXAS21002C_H_ | ||
| 9 | #define FXAS21002C_H_ | ||
| 10 | |||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #define FXAS21002C_REG_STATUS 0x00 | ||
| 14 | #define FXAS21002C_REG_OUT_X_MSB 0x01 | ||
| 15 | #define FXAS21002C_REG_OUT_X_LSB 0x02 | ||
| 16 | #define FXAS21002C_REG_OUT_Y_MSB 0x03 | ||
| 17 | #define FXAS21002C_REG_OUT_Y_LSB 0x04 | ||
| 18 | #define FXAS21002C_REG_OUT_Z_MSB 0x05 | ||
| 19 | #define FXAS21002C_REG_OUT_Z_LSB 0x06 | ||
| 20 | #define FXAS21002C_REG_DR_STATUS 0x07 | ||
| 21 | #define FXAS21002C_REG_F_STATUS 0x08 | ||
| 22 | #define FXAS21002C_REG_F_SETUP 0x09 | ||
| 23 | #define FXAS21002C_REG_F_EVENT 0x0A | ||
| 24 | #define FXAS21002C_REG_INT_SRC_FLAG 0x0B | ||
| 25 | #define FXAS21002C_REG_WHO_AM_I 0x0C | ||
| 26 | #define FXAS21002C_REG_CTRL0 0x0D | ||
| 27 | #define FXAS21002C_REG_RT_CFG 0x0E | ||
| 28 | #define FXAS21002C_REG_RT_SRC 0x0F | ||
| 29 | #define FXAS21002C_REG_RT_THS 0x10 | ||
| 30 | #define FXAS21002C_REG_RT_COUNT 0x11 | ||
| 31 | #define FXAS21002C_REG_TEMP 0x12 | ||
| 32 | #define FXAS21002C_REG_CTRL1 0x13 | ||
| 33 | #define FXAS21002C_REG_CTRL2 0x14 | ||
| 34 | #define FXAS21002C_REG_CTRL3 0x15 | ||
| 35 | |||
| 36 | enum fxas21002c_fields { | ||
| 37 | F_DR_STATUS, | ||
| 38 | F_OUT_X_MSB, | ||
| 39 | F_OUT_X_LSB, | ||
| 40 | F_OUT_Y_MSB, | ||
| 41 | F_OUT_Y_LSB, | ||
| 42 | F_OUT_Z_MSB, | ||
| 43 | F_OUT_Z_LSB, | ||
| 44 | /* DR_STATUS */ | ||
| 45 | F_ZYX_OW, F_Z_OW, F_Y_OW, F_X_OW, F_ZYX_DR, F_Z_DR, F_Y_DR, F_X_DR, | ||
| 46 | /* F_STATUS */ | ||
| 47 | F_OVF, F_WMKF, F_CNT, | ||
| 48 | /* F_SETUP */ | ||
| 49 | F_MODE, F_WMRK, | ||
| 50 | /* F_EVENT */ | ||
| 51 | F_EVENT, FE_TIME, | ||
| 52 | /* INT_SOURCE_FLAG */ | ||
| 53 | F_BOOTEND, F_SRC_FIFO, F_SRC_RT, F_SRC_DRDY, | ||
| 54 | /* WHO_AM_I */ | ||
| 55 | F_WHO_AM_I, | ||
| 56 | /* CTRL_REG0 */ | ||
| 57 | F_BW, F_SPIW, F_SEL, F_HPF_EN, F_FS, | ||
| 58 | /* RT_CFG */ | ||
| 59 | F_ELE, F_ZTEFE, F_YTEFE, F_XTEFE, | ||
| 60 | /* RT_SRC */ | ||
| 61 | F_EA, F_ZRT, F_ZRT_POL, F_YRT, F_YRT_POL, F_XRT, F_XRT_POL, | ||
| 62 | /* RT_THS */ | ||
| 63 | F_DBCNTM, F_THS, | ||
| 64 | /* RT_COUNT */ | ||
| 65 | F_RT_COUNT, | ||
| 66 | /* TEMP */ | ||
| 67 | F_TEMP, | ||
| 68 | /* CTRL_REG1 */ | ||
| 69 | F_RST, F_ST, F_DR, F_ACTIVE, F_READY, | ||
| 70 | /* CTRL_REG2 */ | ||
| 71 | F_INT_CFG_FIFO, F_INT_EN_FIFO, F_INT_CFG_RT, F_INT_EN_RT, | ||
| 72 | F_INT_CFG_DRDY, F_INT_EN_DRDY, F_IPOL, F_PP_OD, | ||
| 73 | /* CTRL_REG3 */ | ||
| 74 | F_WRAPTOONE, F_EXTCTRLEN, F_FS_DOUBLE, | ||
| 75 | /* MAX FIELDS */ | ||
| 76 | F_MAX_FIELDS, | ||
| 77 | }; | ||
| 78 | |||
| 79 | static const struct reg_field fxas21002c_reg_fields[] = { | ||
| 80 | [F_DR_STATUS] = REG_FIELD(FXAS21002C_REG_STATUS, 0, 7), | ||
| 81 | [F_OUT_X_MSB] = REG_FIELD(FXAS21002C_REG_OUT_X_MSB, 0, 7), | ||
| 82 | [F_OUT_X_LSB] = REG_FIELD(FXAS21002C_REG_OUT_X_LSB, 0, 7), | ||
| 83 | [F_OUT_Y_MSB] = REG_FIELD(FXAS21002C_REG_OUT_Y_MSB, 0, 7), | ||
| 84 | [F_OUT_Y_LSB] = REG_FIELD(FXAS21002C_REG_OUT_Y_LSB, 0, 7), | ||
| 85 | [F_OUT_Z_MSB] = REG_FIELD(FXAS21002C_REG_OUT_Z_MSB, 0, 7), | ||
| 86 | [F_OUT_Z_LSB] = REG_FIELD(FXAS21002C_REG_OUT_Z_LSB, 0, 7), | ||
| 87 | [F_ZYX_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 7, 7), | ||
| 88 | [F_Z_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 6, 6), | ||
| 89 | [F_Y_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 5, 5), | ||
| 90 | [F_X_OW] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 4, 4), | ||
| 91 | [F_ZYX_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 3, 3), | ||
| 92 | [F_Z_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 2, 2), | ||
| 93 | [F_Y_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 1, 1), | ||
| 94 | [F_X_DR] = REG_FIELD(FXAS21002C_REG_DR_STATUS, 0, 0), | ||
| 95 | [F_OVF] = REG_FIELD(FXAS21002C_REG_F_STATUS, 7, 7), | ||
| 96 | [F_WMKF] = REG_FIELD(FXAS21002C_REG_F_STATUS, 6, 6), | ||
| 97 | [F_CNT] = REG_FIELD(FXAS21002C_REG_F_STATUS, 0, 5), | ||
| 98 | [F_MODE] = REG_FIELD(FXAS21002C_REG_F_SETUP, 6, 7), | ||
| 99 | [F_WMRK] = REG_FIELD(FXAS21002C_REG_F_SETUP, 0, 5), | ||
| 100 | [F_EVENT] = REG_FIELD(FXAS21002C_REG_F_EVENT, 5, 5), | ||
| 101 | [FE_TIME] = REG_FIELD(FXAS21002C_REG_F_EVENT, 0, 4), | ||
| 102 | [F_BOOTEND] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 3, 3), | ||
| 103 | [F_SRC_FIFO] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 2, 2), | ||
| 104 | [F_SRC_RT] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 1, 1), | ||
| 105 | [F_SRC_DRDY] = REG_FIELD(FXAS21002C_REG_INT_SRC_FLAG, 0, 0), | ||
| 106 | [F_WHO_AM_I] = REG_FIELD(FXAS21002C_REG_WHO_AM_I, 0, 7), | ||
| 107 | [F_BW] = REG_FIELD(FXAS21002C_REG_CTRL0, 6, 7), | ||
| 108 | [F_SPIW] = REG_FIELD(FXAS21002C_REG_CTRL0, 5, 5), | ||
| 109 | [F_SEL] = REG_FIELD(FXAS21002C_REG_CTRL0, 3, 4), | ||
| 110 | [F_HPF_EN] = REG_FIELD(FXAS21002C_REG_CTRL0, 2, 2), | ||
| 111 | [F_FS] = REG_FIELD(FXAS21002C_REG_CTRL0, 0, 1), | ||
| 112 | [F_ELE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 3, 3), | ||
| 113 | [F_ZTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 2, 2), | ||
| 114 | [F_YTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 1, 1), | ||
| 115 | [F_XTEFE] = REG_FIELD(FXAS21002C_REG_RT_CFG, 0, 0), | ||
| 116 | [F_EA] = REG_FIELD(FXAS21002C_REG_RT_SRC, 6, 6), | ||
| 117 | [F_ZRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 5, 5), | ||
| 118 | [F_ZRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 4, 4), | ||
| 119 | [F_YRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 3, 3), | ||
| 120 | [F_YRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 2, 2), | ||
| 121 | [F_XRT] = REG_FIELD(FXAS21002C_REG_RT_SRC, 1, 1), | ||
| 122 | [F_XRT_POL] = REG_FIELD(FXAS21002C_REG_RT_SRC, 0, 0), | ||
| 123 | [F_DBCNTM] = REG_FIELD(FXAS21002C_REG_RT_THS, 7, 7), | ||
| 124 | [F_THS] = REG_FIELD(FXAS21002C_REG_RT_SRC, 0, 6), | ||
| 125 | [F_RT_COUNT] = REG_FIELD(FXAS21002C_REG_RT_COUNT, 0, 7), | ||
| 126 | [F_TEMP] = REG_FIELD(FXAS21002C_REG_TEMP, 0, 7), | ||
| 127 | [F_RST] = REG_FIELD(FXAS21002C_REG_CTRL1, 6, 6), | ||
| 128 | [F_ST] = REG_FIELD(FXAS21002C_REG_CTRL1, 5, 5), | ||
| 129 | [F_DR] = REG_FIELD(FXAS21002C_REG_CTRL1, 2, 4), | ||
| 130 | [F_ACTIVE] = REG_FIELD(FXAS21002C_REG_CTRL1, 1, 1), | ||
| 131 | [F_READY] = REG_FIELD(FXAS21002C_REG_CTRL1, 0, 0), | ||
| 132 | [F_INT_CFG_FIFO] = REG_FIELD(FXAS21002C_REG_CTRL2, 7, 7), | ||
| 133 | [F_INT_EN_FIFO] = REG_FIELD(FXAS21002C_REG_CTRL2, 6, 6), | ||
| 134 | [F_INT_CFG_RT] = REG_FIELD(FXAS21002C_REG_CTRL2, 5, 5), | ||
| 135 | [F_INT_EN_RT] = REG_FIELD(FXAS21002C_REG_CTRL2, 4, 4), | ||
| 136 | [F_INT_CFG_DRDY] = REG_FIELD(FXAS21002C_REG_CTRL2, 3, 3), | ||
| 137 | [F_INT_EN_DRDY] = REG_FIELD(FXAS21002C_REG_CTRL2, 2, 2), | ||
| 138 | [F_IPOL] = REG_FIELD(FXAS21002C_REG_CTRL2, 1, 1), | ||
| 139 | [F_PP_OD] = REG_FIELD(FXAS21002C_REG_CTRL2, 0, 0), | ||
| 140 | [F_WRAPTOONE] = REG_FIELD(FXAS21002C_REG_CTRL3, 3, 3), | ||
| 141 | [F_EXTCTRLEN] = REG_FIELD(FXAS21002C_REG_CTRL3, 2, 2), | ||
| 142 | [F_FS_DOUBLE] = REG_FIELD(FXAS21002C_REG_CTRL3, 0, 0), | ||
| 143 | }; | ||
| 144 | |||
| 145 | extern const struct dev_pm_ops fxas21002c_pm_ops; | ||
| 146 | |||
| 147 | int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq, | ||
| 148 | const char *name); | ||
| 149 | void fxas21002c_core_remove(struct device *dev); | ||
| 150 | #endif | ||
| @@ -0,0 +1,1004 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for NXP FXAS21002C Gyroscope - Core | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 Linaro Ltd. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/interrupt.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/of_irq.h> | ||
| 11 | #include <linux/pm.h> | ||
| 12 | #include <linux/pm_runtime.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | |||
| 16 | #include <linux/iio/events.h> | ||
| 17 | #include <linux/iio/iio.h> | ||
| 18 | #include <linux/iio/buffer.h> | ||
| 19 | #include <linux/iio/sysfs.h> | ||
| 20 | #include <linux/iio/trigger.h> | ||
| 21 | #include <linux/iio/trigger_consumer.h> | ||
| 22 | #include <linux/iio/triggered_buffer.h> | ||
| 23 | |||
| 24 | #include "fxas21002c.h" | ||
| 25 | |||
| 26 | #define FXAS21002C_CHIP_ID_1 0xD6 | ||
| 27 | #define FXAS21002C_CHIP_ID_2 0xD7 | ||
| 28 | |||
| 29 | enum fxas21002c_mode_state { | ||
| 30 | FXAS21002C_MODE_STANDBY, | ||
| 31 | FXAS21002C_MODE_READY, | ||
| 32 | FXAS21002C_MODE_ACTIVE, | ||
| 33 | }; | ||
| 34 | |||
| 35 | #define FXAS21002C_STANDBY_ACTIVE_TIME_MS 62 | ||
| 36 | #define FXAS21002C_READY_ACTIVE_TIME_MS 7 | ||
| 37 | |||
| 38 | #define FXAS21002C_ODR_LIST_MAX 10 | ||
| 39 | |||
| 40 | #define FXAS21002C_SCALE_FRACTIONAL 32 | ||
| 41 | #define FXAS21002C_RANGE_LIMIT_DOUBLE 2000 | ||
| 42 | |||
| 43 | #define FXAS21002C_AXIS_TO_REG(axis) (FXAS21002C_REG_OUT_X_MSB + ((axis) * 2)) | ||
| 44 | |||
| 45 | static const int fxas21002c_odr_values[] = { | ||
| 46 | 800, 400, 200, 100, 50, 25, 12, 12 | ||
| 47 | }; | ||
| 48 | |||
| 49 | /* | ||
| 50 | * These values are taken from the low-pass filter cutoff frequency calculated | ||
| 51 | * ODR * 0.lpf_values. So, for ODR = 800Hz with a lpf value = 0.32 | ||
| 52 | * => LPF cutoff frequency = 800 * 0.32 = 256 Hz | ||
| 53 | */ | ||
| 54 | static const int fxas21002c_lpf_values[] = { | ||
| 55 | 32, 16, 8 | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* | ||
| 59 | * These values are taken from the high-pass filter cutoff frequency calculated | ||
| 60 | * ODR * 0.0hpf_values. So, for ODR = 800Hz with a hpf value = 0.018750 | ||
| 61 | * => HPF cutoff frequency = 800 * 0.018750 = 15 Hz | ||
| 62 | */ | ||
| 63 | static const int fxas21002c_hpf_values[] = { | ||
| 64 | 18750, 9625, 4875, 2475 | ||
| 65 | }; | ||
| 66 | |||
| 67 | static const int fxas21002c_range_values[] = { | ||
| 68 | 4000, 2000, 1000, 500, 250 | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct fxas21002c_data { | ||
| 72 | u8 chip_id; | ||
| 73 | enum fxas21002c_mode_state mode; | ||
| 74 | enum fxas21002c_mode_state prev_mode; | ||
| 75 | |||
| 76 | struct mutex lock; /* serialize data access */ | ||
| 77 | struct regmap *regmap; | ||
| 78 | struct regmap_field *regmap_fields[F_MAX_FIELDS]; | ||
| 79 | struct iio_trigger *dready_trig; | ||
| 80 | s64 timestamp; | ||
| 81 | int irq; | ||
| 82 | |||
| 83 | struct regulator *vdd; | ||
| 84 | struct regulator *vddio; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * DMA (thus cache coherency maintenance) requires the | ||
| 88 | * transfer buffers to live in their own cache lines. | ||
| 89 | */ | ||
| 90 | s16 buffer[8] ____cacheline_aligned; | ||
| 91 | }; | ||
| 92 | |||
| 93 | enum fxas21002c_channel_index { | ||
| 94 | CHANNEL_SCAN_INDEX_X, | ||
| 95 | CHANNEL_SCAN_INDEX_Y, | ||
| 96 | CHANNEL_SCAN_INDEX_Z, | ||
| 97 | CHANNEL_SCAN_MAX, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int fxas21002c_odr_hz_from_value(struct fxas21002c_data *data, u8 value) | ||
| 101 | { | ||
| 102 | int odr_value_max = ARRAY_SIZE(fxas21002c_odr_values) - 1; | ||
| 103 | |||
| 104 | value = min_t(u8, value, odr_value_max); | ||
| 105 | |||
| 106 | return fxas21002c_odr_values[value]; | ||
| 107 | } | ||
| 108 | |||
| 109 | static int fxas21002c_odr_value_from_hz(struct fxas21002c_data *data, | ||
| 110 | unsigned int hz) | ||
| 111 | { | ||
| 112 | int odr_table_size = ARRAY_SIZE(fxas21002c_odr_values); | ||
| 113 | int i; | ||
| 114 | |||
| 115 | for (i = 0; i < odr_table_size; i++) | ||
| 116 | if (fxas21002c_odr_values[i] == hz) | ||
| 117 | return i; | ||
| 118 | |||
| 119 | return -EINVAL; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int fxas21002c_lpf_bw_from_value(struct fxas21002c_data *data, u8 value) | ||
| 123 | { | ||
| 124 | int lpf_value_max = ARRAY_SIZE(fxas21002c_lpf_values) - 1; | ||
| 125 | |||
| 126 | value = min_t(u8, value, lpf_value_max); | ||
| 127 | |||
| 128 | return fxas21002c_lpf_values[value]; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int fxas21002c_lpf_value_from_bw(struct fxas21002c_data *data, | ||
| 132 | unsigned int hz) | ||
| 133 | { | ||
| 134 | int lpf_table_size = ARRAY_SIZE(fxas21002c_lpf_values); | ||
| 135 | int i; | ||
| 136 | |||
| 137 | for (i = 0; i < lpf_table_size; i++) | ||
| 138 | if (fxas21002c_lpf_values[i] == hz) | ||
| 139 | return i; | ||
| 140 | |||
| 141 | return -EINVAL; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int fxas21002c_hpf_sel_from_value(struct fxas21002c_data *data, u8 value) | ||
| 145 | { | ||
| 146 | int hpf_value_max = ARRAY_SIZE(fxas21002c_hpf_values) - 1; | ||
| 147 | |||
| 148 | value = min_t(u8, value, hpf_value_max); | ||
| 149 | |||
| 150 | return fxas21002c_hpf_values[value]; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int fxas21002c_hpf_value_from_sel(struct fxas21002c_data *data, | ||
| 154 | unsigned int hz) | ||
| 155 | { | ||
| 156 | int hpf_table_size = ARRAY_SIZE(fxas21002c_hpf_values); | ||
| 157 | int i; | ||
| 158 | |||
| 159 | for (i = 0; i < hpf_table_size; i++) | ||
| 160 | if (fxas21002c_hpf_values[i] == hz) | ||
| 161 | return i; | ||
| 162 | |||
| 163 | return -EINVAL; | ||
| 164 | } | ||
| 165 | |||
| 166 | static int fxas21002c_range_fs_from_value(struct fxas21002c_data *data, | ||
| 167 | u8 value) | ||
| 168 | { | ||
| 169 | int range_value_max = ARRAY_SIZE(fxas21002c_range_values) - 1; | ||
| 170 | unsigned int fs_double; | ||
| 171 | int ret; | ||
| 172 | |||
| 173 | /* We need to check if FS_DOUBLE is enabled to offset the value */ | ||
| 174 | ret = regmap_field_read(data->regmap_fields[F_FS_DOUBLE], &fs_double); | ||
| 175 | if (ret < 0) | ||
| 176 | return ret; | ||
| 177 | |||
| 178 | if (!fs_double) | ||
| 179 | value += 1; | ||
| 180 | |||
| 181 | value = min_t(u8, value, range_value_max); | ||
| 182 | |||
| 183 | return fxas21002c_range_values[value]; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int fxas21002c_range_value_from_fs(struct fxas21002c_data *data, | ||
| 187 | unsigned int range) | ||
| 188 | { | ||
| 189 | int range_table_size = ARRAY_SIZE(fxas21002c_range_values); | ||
| 190 | bool found = false; | ||
| 191 | int fs_double = 0; | ||
| 192 | int ret; | ||
| 193 | int i; | ||
| 194 | |||
| 195 | for (i = 0; i < range_table_size; i++) | ||
| 196 | if (fxas21002c_range_values[i] == range) { | ||
| 197 | found = true; | ||
| 198 | break; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (!found) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | if (range > FXAS21002C_RANGE_LIMIT_DOUBLE) | ||
| 205 | fs_double = 1; | ||
| 206 | |||
| 207 | ret = regmap_field_write(data->regmap_fields[F_FS_DOUBLE], fs_double); | ||
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 210 | |||
| 211 | return i; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int fxas21002c_mode_get(struct fxas21002c_data *data) | ||
| 215 | { | ||
| 216 | unsigned int active; | ||
| 217 | unsigned int ready; | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | ret = regmap_field_read(data->regmap_fields[F_ACTIVE], &active); | ||
| 221 | if (ret < 0) | ||
| 222 | return ret; | ||
| 223 | if (active) | ||
| 224 | return FXAS21002C_MODE_ACTIVE; | ||
| 225 | |||
| 226 | ret = regmap_field_read(data->regmap_fields[F_READY], &ready); | ||
| 227 | if (ret < 0) | ||
| 228 | return ret; | ||
| 229 | if (ready) | ||
| 230 | return FXAS21002C_MODE_READY; | ||
| 231 | |||
| 232 | return FXAS21002C_MODE_STANDBY; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int fxas21002c_mode_set(struct fxas21002c_data *data, | ||
| 236 | enum fxas21002c_mode_state mode) | ||
| 237 | { | ||
| 238 | int ret; | ||
| 239 | |||
| 240 | if (mode == data->mode) | ||
| 241 | return 0; | ||
| 242 | |||
| 243 | if (mode == FXAS21002C_MODE_READY) | ||
| 244 | ret = regmap_field_write(data->regmap_fields[F_READY], 1); | ||
| 245 | else | ||
| 246 | ret = regmap_field_write(data->regmap_fields[F_READY], 0); | ||
| 247 | if (ret < 0) | ||
| 248 | return ret; | ||
| 249 | |||
| 250 | if (mode == FXAS21002C_MODE_ACTIVE) | ||
| 251 | ret = regmap_field_write(data->regmap_fields[F_ACTIVE], 1); | ||
| 252 | else | ||
| 253 | ret = regmap_field_write(data->regmap_fields[F_ACTIVE], 0); | ||
| 254 | if (ret < 0) | ||
| 255 | return ret; | ||
| 256 | |||
| 257 | /* if going to active wait the setup times */ | ||
| 258 | if (mode == FXAS21002C_MODE_ACTIVE && | ||
| 259 | data->mode == FXAS21002C_MODE_STANDBY) | ||
| 260 | msleep_interruptible(FXAS21002C_STANDBY_ACTIVE_TIME_MS); | ||
| 261 | |||
| 262 | if (data->mode == FXAS21002C_MODE_READY) | ||
| 263 | msleep_interruptible(FXAS21002C_READY_ACTIVE_TIME_MS); | ||
| 264 | |||
| 265 | data->prev_mode = data->mode; | ||
| 266 | data->mode = mode; | ||
| 267 | |||
| 268 | return ret; | ||
| 269 | } | ||
| 270 | |||
| 271 | static int fxas21002c_write(struct fxas21002c_data *data, | ||
| 272 | enum fxas21002c_fields field, int bits) | ||
| 273 | { | ||
| 274 | int actual_mode; | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | mutex_lock(&data->lock); | ||
| 278 | |||
| 279 | actual_mode = fxas21002c_mode_get(data); | ||
| 280 | if (actual_mode < 0) { | ||
| 281 | ret = actual_mode; | ||
| 282 | goto out_unlock; | ||
| 283 | } | ||
| 284 | |||
| 285 | ret = fxas21002c_mode_set(data, FXAS21002C_MODE_READY); | ||
| 286 | if (ret < 0) | ||
| 287 | goto out_unlock; | ||
| 288 | |||
| 289 | ret = regmap_field_write(data->regmap_fields[field], bits); | ||
| 290 | if (ret < 0) | ||
| 291 | goto out_unlock; | ||
| 292 | |||
| 293 | ret = fxas21002c_mode_set(data, data->prev_mode); | ||
| 294 | |||
| 295 | out_unlock: | ||
| 296 | mutex_unlock(&data->lock); | ||
| 297 | |||
| 298 | return ret; | ||
| 299 | } | ||
| 300 | |||
| 301 | static int fxas21002c_pm_get(struct fxas21002c_data *data) | ||
| 302 | { | ||
| 303 | struct device *dev = regmap_get_device(data->regmap); | ||
| 304 | int ret; | ||
| 305 | |||
| 306 | ret = pm_runtime_get_sync(dev); | ||
| 307 | if (ret < 0) | ||
| 308 | pm_runtime_put_noidle(dev); | ||
| 309 | |||
| 310 | return ret; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int fxas21002c_pm_put(struct fxas21002c_data *data) | ||
| 314 | { | ||
| 315 | struct device *dev = regmap_get_device(data->regmap); | ||
| 316 | |||
| 317 | pm_runtime_mark_last_busy(dev); | ||
| 318 | |||
| 319 | return pm_runtime_put_autosuspend(dev); | ||
| 320 | } | ||
| 321 | |||
| 322 | static int fxas21002c_temp_get(struct fxas21002c_data *data, int *val) | ||
| 323 | { | ||
| 324 | struct device *dev = regmap_get_device(data->regmap); | ||
| 325 | unsigned int temp; | ||
| 326 | int ret; | ||
| 327 | |||
| 328 | mutex_lock(&data->lock); | ||
| 329 | ret = fxas21002c_pm_get(data); | ||
| 330 | if (ret < 0) | ||
| 331 | goto data_unlock; | ||
| 332 | |||
| 333 | ret = regmap_field_read(data->regmap_fields[F_TEMP], &temp); | ||
| 334 | if (ret < 0) { | ||
| 335 | dev_err(dev, "failed to read temp: %d\n", ret); | ||
| 336 | goto data_unlock; | ||
| 337 | } | ||
| 338 | |||
| 339 | *val = sign_extend32(temp, 7); | ||
| 340 | |||
| 341 | ret = fxas21002c_pm_put(data); | ||
| 342 | if (ret < 0) | ||
| 343 | goto data_unlock; | ||
| 344 | |||
| 345 | ret = IIO_VAL_INT; | ||
| 346 | |||
| 347 | data_unlock: | ||
| 348 | mutex_unlock(&data->lock); | ||
| 349 | |||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int fxas21002c_axis_get(struct fxas21002c_data *data, | ||
| 354 | int index, int *val) | ||
| 355 | { | ||
| 356 | struct device *dev = regmap_get_device(data->regmap); | ||
| 357 | __be16 axis_be; | ||
| 358 | int ret; | ||
| 359 | |||
| 360 | mutex_lock(&data->lock); | ||
| 361 | ret = fxas21002c_pm_get(data); | ||
| 362 | if (ret < 0) | ||
| 363 | goto data_unlock; | ||
| 364 | |||
| 365 | ret = regmap_bulk_read(data->regmap, FXAS21002C_AXIS_TO_REG(index), | ||
| 366 | &axis_be, sizeof(axis_be)); | ||
| 367 | if (ret < 0) { | ||
| 368 | dev_err(dev, "failed to read axis: %d: %d\n", index, ret); | ||
| 369 | goto data_unlock; | ||
| 370 | } | ||
| 371 | |||
| 372 | *val = sign_extend32(be16_to_cpu(axis_be), 15); | ||
| 373 | |||
| 374 | ret = fxas21002c_pm_put(data); | ||
| 375 | if (ret < 0) | ||
| 376 | goto data_unlock; | ||
| 377 | |||
| 378 | ret = IIO_VAL_INT; | ||
| 379 | |||
| 380 | data_unlock: | ||
| 381 | mutex_unlock(&data->lock); | ||
| 382 | |||
| 383 | return ret; | ||
| 384 | } | ||
| 385 | |||
| 386 | static int fxas21002c_odr_get(struct fxas21002c_data *data, int *odr) | ||
| 387 | { | ||
| 388 | unsigned int odr_bits; | ||
| 389 | int ret; | ||
| 390 | |||
| 391 | mutex_lock(&data->lock); | ||
| 392 | ret = regmap_field_read(data->regmap_fields[F_DR], &odr_bits); | ||
| 393 | if (ret < 0) | ||
| 394 | goto data_unlock; | ||
| 395 | |||
| 396 | *odr = fxas21002c_odr_hz_from_value(data, odr_bits); | ||
| 397 | |||
| 398 | ret = IIO_VAL_INT; | ||
| 399 | |||
| 400 | data_unlock: | ||
| 401 | mutex_unlock(&data->lock); | ||
| 402 | |||
| 403 | return ret; | ||
| 404 | } | ||
| 405 | |||
| 406 | static int fxas21002c_odr_set(struct fxas21002c_data *data, int odr) | ||
| 407 | { | ||
| 408 | int odr_bits; | ||
| 409 | |||
| 410 | odr_bits = fxas21002c_odr_value_from_hz(data, odr); | ||
| 411 | if (odr_bits < 0) | ||
| 412 | return odr_bits; | ||
| 413 | |||
| 414 | return fxas21002c_write(data, F_DR, odr_bits); | ||
| 415 | } | ||
| 416 | |||
| 417 | static int fxas21002c_lpf_get(struct fxas21002c_data *data, int *val2) | ||
| 418 | { | ||
| 419 | unsigned int bw_bits; | ||
| 420 | int ret; | ||
| 421 | |||
| 422 | mutex_lock(&data->lock); | ||
| 423 | ret = regmap_field_read(data->regmap_fields[F_BW], &bw_bits); | ||
| 424 | if (ret < 0) | ||
| 425 | goto data_unlock; | ||
| 426 | |||
| 427 | *val2 = fxas21002c_lpf_bw_from_value(data, bw_bits) * 10000; | ||
| 428 | |||
| 429 | ret = IIO_VAL_INT_PLUS_MICRO; | ||
| 430 | |||
| 431 | data_unlock: | ||
| 432 | mutex_unlock(&data->lock); | ||
| 433 | |||
| 434 | return ret; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int fxas21002c_lpf_set(struct fxas21002c_data *data, int bw) | ||
| 438 | { | ||
| 439 | int bw_bits; | ||
| 440 | int odr; | ||
| 441 | int ret; | ||
| 442 | |||
| 443 | bw_bits = fxas21002c_lpf_value_from_bw(data, bw); | ||
| 444 | if (bw_bits < 0) | ||
| 445 | return bw_bits; | ||
| 446 | |||
| 447 | /* | ||
| 448 | * From table 33 of the device spec, for ODR = 25Hz and 12.5 value 0.08 | ||
| 449 | * is not allowed and for ODR = 12.5 value 0.16 is also not allowed | ||
| 450 | */ | ||
| 451 | ret = fxas21002c_odr_get(data, &odr); | ||
| 452 | if (ret < 0) | ||
| 453 | return -EINVAL; | ||
| 454 | |||
| 455 | if ((odr == 25 && bw_bits > 0x01) || (odr == 12 && bw_bits > 0)) | ||
| 456 | return -EINVAL; | ||
| 457 | |||
| 458 | return fxas21002c_write(data, F_BW, bw_bits); | ||
| 459 | } | ||
| 460 | |||
| 461 | static int fxas21002c_hpf_get(struct fxas21002c_data *data, int *val2) | ||
| 462 | { | ||
| 463 | unsigned int sel_bits; | ||
| 464 | int ret; | ||
| 465 | |||
| 466 | mutex_lock(&data->lock); | ||
| 467 | ret = regmap_field_read(data->regmap_fields[F_SEL], &sel_bits); | ||
| 468 | if (ret < 0) | ||
| 469 | goto data_unlock; | ||
| 470 | |||
| 471 | *val2 = fxas21002c_hpf_sel_from_value(data, sel_bits); | ||
| 472 | |||
| 473 | ret = IIO_VAL_INT_PLUS_MICRO; | ||
| 474 | |||
| 475 | data_unlock: | ||
| 476 | mutex_unlock(&data->lock); | ||
| 477 | |||
| 478 | return ret; | ||
| 479 | } | ||
| 480 | |||
| 481 | static int fxas21002c_hpf_set(struct fxas21002c_data *data, int sel) | ||
| 482 | { | ||
| 483 | int sel_bits; | ||
| 484 | |||
| 485 | sel_bits = fxas21002c_hpf_value_from_sel(data, sel); | ||
| 486 | if (sel_bits < 0) | ||
| 487 | return sel_bits; | ||
| 488 | |||
| 489 | return fxas21002c_write(data, F_SEL, sel_bits); | ||
| 490 | } | ||
| 491 | |||
| 492 | static int fxas21002c_scale_get(struct fxas21002c_data *data, int *val) | ||
| 493 | { | ||
| 494 | int fs_bits; | ||
| 495 | int scale; | ||
| 496 | int ret; | ||
| 497 | |||
| 498 | mutex_lock(&data->lock); | ||
| 499 | ret = regmap_field_read(data->regmap_fields[F_FS], &fs_bits); | ||
| 500 | if (ret < 0) | ||
| 501 | goto data_unlock; | ||
| 502 | |||
| 503 | scale = fxas21002c_range_fs_from_value(data, fs_bits); | ||
| 504 | if (scale < 0) { | ||
| 505 | ret = scale; | ||
| 506 | goto data_unlock; | ||
| 507 | } | ||
| 508 | |||
| 509 | *val = scale; | ||
| 510 | |||
| 511 | data_unlock: | ||
| 512 | mutex_unlock(&data->lock); | ||
| 513 | |||
| 514 | return ret; | ||
| 515 | } | ||
| 516 | |||
| 517 | static int fxas21002c_scale_set(struct fxas21002c_data *data, int range) | ||
| 518 | { | ||
| 519 | int fs_bits; | ||
| 520 | |||
| 521 | fs_bits = fxas21002c_range_value_from_fs(data, range); | ||
| 522 | if (fs_bits < 0) | ||
| 523 | return fs_bits; | ||
| 524 | |||
| 525 | return fxas21002c_write(data, F_FS, fs_bits); | ||
| 526 | } | ||
| 527 | |||
| 528 | static int fxas21002c_read_raw(struct iio_dev *indio_dev, | ||
| 529 | struct iio_chan_spec const *chan, int *val, | ||
| 530 | int *val2, long mask) | ||
| 531 | { | ||
| 532 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 533 | int ret; | ||
| 534 | |||
| 535 | switch (mask) { | ||
| 536 | case IIO_CHAN_INFO_RAW: | ||
| 537 | switch (chan->type) { | ||
| 538 | case IIO_TEMP: | ||
| 539 | return fxas21002c_temp_get(data, val); | ||
| 540 | case IIO_ANGL_VEL: | ||
| 541 | return fxas21002c_axis_get(data, chan->scan_index, val); | ||
| 542 | default: | ||
| 543 | return -EINVAL; | ||
| 544 | } | ||
| 545 | case IIO_CHAN_INFO_SCALE: | ||
| 546 | switch (chan->type) { | ||
| 547 | case IIO_ANGL_VEL: | ||
| 548 | *val2 = FXAS21002C_SCALE_FRACTIONAL; | ||
| 549 | ret = fxas21002c_scale_get(data, val); | ||
| 550 | if (ret < 0) | ||
| 551 | return ret; | ||
| 552 | |||
| 553 | return IIO_VAL_FRACTIONAL; | ||
| 554 | default: | ||
| 555 | return -EINVAL; | ||
| 556 | } | ||
| 557 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | ||
| 558 | *val = 0; | ||
| 559 | return fxas21002c_lpf_get(data, val2); | ||
| 560 | case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: | ||
| 561 | *val = 0; | ||
| 562 | return fxas21002c_hpf_get(data, val2); | ||
| 563 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 564 | *val2 = 0; | ||
| 565 | return fxas21002c_odr_get(data, val); | ||
| 566 | default: | ||
| 567 | return -EINVAL; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | static int fxas21002c_write_raw(struct iio_dev *indio_dev, | ||
| 572 | struct iio_chan_spec const *chan, int val, | ||
| 573 | int val2, long mask) | ||
| 574 | { | ||
| 575 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 576 | int range; | ||
| 577 | |||
| 578 | switch (mask) { | ||
| 579 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 580 | if (val2) | ||
| 581 | return -EINVAL; | ||
| 582 | |||
| 583 | return fxas21002c_odr_set(data, val); | ||
| 584 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | ||
| 585 | if (val) | ||
| 586 | return -EINVAL; | ||
| 587 | |||
| 588 | val2 = val2 / 10000; | ||
| 589 | return fxas21002c_lpf_set(data, val2); | ||
| 590 | case IIO_CHAN_INFO_SCALE: | ||
| 591 | switch (chan->type) { | ||
| 592 | case IIO_ANGL_VEL: | ||
| 593 | range = (((val * 1000 + val2 / 1000) * | ||
| 594 | FXAS21002C_SCALE_FRACTIONAL) / 1000); | ||
| 595 | return fxas21002c_scale_set(data, range); | ||
| 596 | default: | ||
| 597 | return -EINVAL; | ||
| 598 | } | ||
| 599 | case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: | ||
| 600 | return fxas21002c_hpf_set(data, val2); | ||
| 601 | default: | ||
| 602 | return -EINVAL; | ||
| 603 | } | ||
| 604 | } | ||
| 605 | |||
| 606 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("12.5 25 50 100 200 400 800"); | ||
| 607 | |||
| 608 | static IIO_CONST_ATTR(in_anglvel_filter_low_pass_3db_frequency_available, | ||
| 609 | "0.32 0.16 0.08"); | ||
| 610 | |||
| 611 | static IIO_CONST_ATTR(in_anglvel_filter_high_pass_3db_frequency_available, | ||
| 612 | "0.018750 0.009625 0.004875 0.002475"); | ||
| 613 | |||
| 614 | static IIO_CONST_ATTR(in_anglvel_scale_available, | ||
| 615 | "125.0 62.5 31.25 15.625 7.8125"); | ||
| 616 | |||
| 617 | static struct attribute *fxas21002c_attributes[] = { | ||
| 618 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
| 619 | &iio_const_attr_in_anglvel_filter_low_pass_3db_frequency_available.dev_attr.attr, | ||
| 620 | &iio_const_attr_in_anglvel_filter_high_pass_3db_frequency_available.dev_attr.attr, | ||
| 621 | &iio_const_attr_in_anglvel_scale_available.dev_attr.attr, | ||
| 622 | NULL, | ||
| 623 | }; | ||
| 624 | |||
| 625 | static const struct attribute_group fxas21002c_attrs_group = { | ||
| 626 | .attrs = fxas21002c_attributes, | ||
| 627 | }; | ||
| 628 | |||
| 629 | #define FXAS21002C_CHANNEL(_axis) { \ | ||
| 630 | .type = IIO_ANGL_VEL, \ | ||
| 631 | .modified = 1, \ | ||
| 632 | .channel2 = IIO_MOD_##_axis, \ | ||
| 633 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 634 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | ||
| 635 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ | ||
| 636 | BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \ | ||
| 637 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 638 | .scan_index = CHANNEL_SCAN_INDEX_##_axis, \ | ||
| 639 | .scan_type = { \ | ||
| 640 | .sign = 's', \ | ||
| 641 | .realbits = 16, \ | ||
| 642 | .storagebits = 16, \ | ||
| 643 | .endianness = IIO_BE, \ | ||
| 644 | }, \ | ||
| 645 | } | ||
| 646 | |||
| 647 | static const struct iio_chan_spec fxas21002c_channels[] = { | ||
| 648 | { | ||
| 649 | .type = IIO_TEMP, | ||
| 650 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | ||
| 651 | .scan_index = -1, | ||
| 652 | }, | ||
| 653 | FXAS21002C_CHANNEL(X), | ||
| 654 | FXAS21002C_CHANNEL(Y), | ||
| 655 | FXAS21002C_CHANNEL(Z), | ||
| 656 | }; | ||
| 657 | |||
| 658 | static const struct iio_info fxas21002c_info = { | ||
| 659 | .attrs = &fxas21002c_attrs_group, | ||
| 660 | .read_raw = &fxas21002c_read_raw, | ||
| 661 | .write_raw = &fxas21002c_write_raw, | ||
| 662 | }; | ||
| 663 | |||
| 664 | static irqreturn_t fxas21002c_trigger_handler(int irq, void *p) | ||
| 665 | { | ||
| 666 | struct iio_poll_func *pf = p; | ||
| 667 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 668 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 669 | int ret; | ||
| 670 | |||
| 671 | mutex_lock(&data->lock); | ||
| 672 | ret = regmap_bulk_read(data->regmap, FXAS21002C_REG_OUT_X_MSB, | ||
| 673 | data->buffer, CHANNEL_SCAN_MAX * sizeof(s16)); | ||
| 674 | if (ret < 0) | ||
| 675 | goto out_unlock; | ||
| 676 | |||
| 677 | iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | ||
| 678 | data->timestamp); | ||
| 679 | |||
| 680 | out_unlock: | ||
| 681 | mutex_unlock(&data->lock); | ||
| 682 | |||
| 683 | iio_trigger_notify_done(indio_dev->trig); | ||
| 684 | |||
| 685 | return IRQ_HANDLED; | ||
| 686 | } | ||
| 687 | |||
| 688 | static int fxas21002c_chip_init(struct fxas21002c_data *data) | ||
| 689 | { | ||
| 690 | struct device *dev = regmap_get_device(data->regmap); | ||
| 691 | unsigned int chip_id; | ||
| 692 | int ret; | ||
| 693 | |||
| 694 | ret = regmap_field_read(data->regmap_fields[F_WHO_AM_I], &chip_id); | ||
| 695 | if (ret < 0) | ||
| 696 | return ret; | ||
| 697 | |||
| 698 | if (chip_id != FXAS21002C_CHIP_ID_1 && | ||
| 699 | chip_id != FXAS21002C_CHIP_ID_2) { | ||
| 700 | dev_err(dev, "chip id 0x%02x is not supported\n", chip_id); | ||
| 701 | return -EINVAL; | ||
| 702 | } | ||
| 703 | |||
| 704 | data->chip_id = chip_id; | ||
| 705 | |||
| 706 | ret = fxas21002c_mode_set(data, FXAS21002C_MODE_STANDBY); | ||
| 707 | if (ret < 0) | ||
| 708 | return ret; | ||
| 709 | |||
| 710 | /* Set ODR to 200HZ as default */ | ||
| 711 | ret = fxas21002c_odr_set(data, 200); | ||
| 712 | if (ret < 0) | ||
| 713 | dev_err(dev, "failed to set ODR: %d\n", ret); | ||
| 714 | |||
| 715 | return ret; | ||
| 716 | } | ||
| 717 | |||
| 718 | static int fxas21002c_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 719 | bool state) | ||
| 720 | { | ||
| 721 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | ||
| 722 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 723 | |||
| 724 | return regmap_field_write(data->regmap_fields[F_INT_EN_DRDY], state); | ||
| 725 | } | ||
| 726 | |||
| 727 | static const struct iio_trigger_ops fxas21002c_trigger_ops = { | ||
| 728 | .set_trigger_state = &fxas21002c_data_rdy_trigger_set_state, | ||
| 729 | }; | ||
| 730 | |||
| 731 | static irqreturn_t fxas21002c_data_rdy_handler(int irq, void *private) | ||
| 732 | { | ||
| 733 | struct iio_dev *indio_dev = private; | ||
| 734 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 735 | |||
| 736 | data->timestamp = iio_get_time_ns(indio_dev); | ||
| 737 | |||
| 738 | return IRQ_WAKE_THREAD; | ||
| 739 | } | ||
| 740 | |||
| 741 | static irqreturn_t fxas21002c_data_rdy_thread(int irq, void *private) | ||
| 742 | { | ||
| 743 | struct iio_dev *indio_dev = private; | ||
| 744 | struct fxas21002c_data *data = iio_priv(indio_dev); | ||
| 745 | unsigned int data_ready; | ||
| 746 | int ret; | ||
| 747 | |||
| 748 | ret = regmap_field_read(data->regmap_fields[F_SRC_DRDY], &data_ready); | ||
| 749 | if (ret < 0) | ||
| 750 | return IRQ_NONE; | ||
| 751 | |||
| 752 | if (!data_ready) | ||
| 753 | return IRQ_NONE; | ||
| 754 | |||
| 755 | iio_trigger_poll_chained(data->dready_trig); | ||
| 756 | |||
| 757 | return IRQ_HANDLED; | ||
| 758 | } | ||
| 759 | |||
| 760 | static int fxas21002c_trigger_probe(struct fxas21002c_data *data) | ||
| 761 | { | ||
| 762 | struct device *dev = regmap_get_device(data->regmap); | ||
| 763 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 764 | struct device_node *np = indio_dev->dev.of_node; | ||
| 765 | unsigned long irq_trig; | ||
| 766 | bool irq_open_drain; | ||
| 767 | int irq1; | ||
| 768 | int ret; | ||
| 769 | |||
| 770 | if (!data->irq) | ||
| 771 | return 0; | ||
| 772 | |||
| 773 | irq1 = of_irq_get_byname(np, "INT1"); | ||
| 774 | |||
| 775 | if (irq1 == data->irq) { | ||
| 776 | dev_info(dev, "using interrupt line INT1\n"); | ||
| 777 | ret = regmap_field_write(data->regmap_fields[F_INT_CFG_DRDY], | ||
| 778 | 1); | ||
| 779 | if (ret < 0) | ||
| 780 | return ret; | ||
| 781 | } | ||
| 782 | |||
| 783 | dev_info(dev, "using interrupt line INT2\n"); | ||
| 784 | |||
| 785 | irq_open_drain = of_property_read_bool(np, "drive-open-drain"); | ||
| 786 | |||
| 787 | data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", | ||
| 788 | indio_dev->name, | ||
| 789 | indio_dev->id); | ||
| 790 | if (!data->dready_trig) | ||
| 791 | return -ENOMEM; | ||
| 792 | |||
| 793 | irq_trig = irqd_get_trigger_type(irq_get_irq_data(data->irq)); | ||
| 794 | |||
| 795 | if (irq_trig == IRQF_TRIGGER_RISING) { | ||
| 796 | ret = regmap_field_write(data->regmap_fields[F_IPOL], 1); | ||
| 797 | if (ret < 0) | ||
| 798 | return ret; | ||
| 799 | } | ||
| 800 | |||
| 801 | if (irq_open_drain) | ||
| 802 | irq_trig |= IRQF_SHARED; | ||
| 803 | |||
| 804 | ret = devm_request_threaded_irq(dev, data->irq, | ||
| 805 | fxas21002c_data_rdy_handler, | ||
| 806 | fxas21002c_data_rdy_thread, | ||
| 807 | irq_trig, "fxas21002c_data_ready", | ||
| 808 | indio_dev); | ||
| 809 | if (ret < 0) | ||
| 810 | return ret; | ||
| 811 | |||
| 812 | data->dready_trig->dev.parent = dev; | ||
| 813 | data->dready_trig->ops = &fxas21002c_trigger_ops; | ||
| 814 | iio_trigger_set_drvdata(data->dready_trig, indio_dev); | ||
| 815 | |||
| 816 | return devm_iio_trigger_register(dev, data->dready_trig); | ||
| 817 | } | ||
| 818 | |||
| 819 | static int fxas21002c_power_enable(struct fxas21002c_data *data) | ||
| 820 | { | ||
| 821 | int ret; | ||
| 822 | |||
| 823 | ret = regulator_enable(data->vdd); | ||
| 824 | if (ret < 0) | ||
| 825 | return ret; | ||
| 826 | |||
| 827 | ret = regulator_enable(data->vddio); | ||
| 828 | if (ret < 0) { | ||
| 829 | regulator_disable(data->vdd); | ||
| 830 | return ret; | ||
| 831 | } | ||
| 832 | |||
| 833 | return 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | static void fxas21002c_power_disable(struct fxas21002c_data *data) | ||
| 837 | { | ||
| 838 | regulator_disable(data->vdd); | ||
| 839 | regulator_disable(data->vddio); | ||
| 840 | } | ||
| 841 | |||
| 842 | static void fxas21002c_power_disable_action(void *_data) | ||
| 843 | { | ||
| 844 | struct fxas21002c_data *data = _data; | ||
| 845 | |||
| 846 | fxas21002c_power_disable(data); | ||
| 847 | } | ||
| 848 | |||
| 849 | static int fxas21002c_regulators_get(struct fxas21002c_data *data) | ||
| 850 | { | ||
| 851 | struct device *dev = regmap_get_device(data->regmap); | ||
| 852 | |||
| 853 | data->vdd = devm_regulator_get(dev->parent, "vdd"); | ||
| 854 | if (IS_ERR(data->vdd)) | ||
| 855 | return PTR_ERR(data->vdd); | ||
| 856 | |||
| 857 | data->vddio = devm_regulator_get(dev->parent, "vddio"); | ||
| 858 | |||
| 859 | return PTR_ERR_OR_ZERO(data->vddio); | ||
| 860 | } | ||
| 861 | |||
| 862 | int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq, | ||
| 863 | const char *name) | ||
| 864 | { | ||
| 865 | struct fxas21002c_data *data; | ||
| 866 | struct iio_dev *indio_dev; | ||
| 867 | struct regmap_field *f; | ||
| 868 | int i; | ||
| 869 | int ret; | ||
| 870 | |||
| 871 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | ||
| 872 | if (!indio_dev) | ||
| 873 | return -ENOMEM; | ||
| 874 | |||
| 875 | data = iio_priv(indio_dev); | ||
| 876 | dev_set_drvdata(dev, indio_dev); | ||
| 877 | data->irq = irq; | ||
| 878 | data->regmap = regmap; | ||
| 879 | |||
| 880 | for (i = 0; i < F_MAX_FIELDS; i++) { | ||
| 881 | f = devm_regmap_field_alloc(dev, data->regmap, | ||
| 882 | fxas21002c_reg_fields[i]); | ||
| 883 | if (IS_ERR(f)) | ||
| 884 | return PTR_ERR(f); | ||
| 885 | |||
| 886 | data->regmap_fields[i] = f; | ||
| 887 | } | ||
| 888 | |||
| 889 | mutex_init(&data->lock); | ||
| 890 | |||
| 891 | ret = fxas21002c_regulators_get(data); | ||
| 892 | if (ret < 0) | ||
| 893 | return ret; | ||
| 894 | |||
| 895 | ret = fxas21002c_power_enable(data); | ||
| 896 | if (ret < 0) | ||
| 897 | return ret; | ||
| 898 | |||
| 899 | ret = devm_add_action_or_reset(dev, fxas21002c_power_disable_action, | ||
| 900 | data); | ||
| 901 | if (ret < 0) | ||
| 902 | return ret; | ||
| 903 | |||
| 904 | ret = fxas21002c_chip_init(data); | ||
| 905 | if (ret < 0) | ||
| 906 | return ret; | ||
| 907 | |||
| 908 | indio_dev->dev.parent = dev; | ||
| 909 | indio_dev->channels = fxas21002c_channels; | ||
| 910 | indio_dev->num_channels = ARRAY_SIZE(fxas21002c_channels); | ||
| 911 | indio_dev->name = name; | ||
| 912 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 913 | indio_dev->info = &fxas21002c_info; | ||
| 914 | |||
| 915 | ret = fxas21002c_trigger_probe(data); | ||
| 916 | if (ret < 0) | ||
| 917 | return ret; | ||
| 918 | |||
| 919 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, | ||
| 920 | fxas21002c_trigger_handler, NULL); | ||
| 921 | if (ret < 0) | ||
| 922 | return ret; | ||
| 923 | |||
| 924 | ret = pm_runtime_set_active(dev); | ||
| 925 | if (ret) | ||
| 926 | return ret; | ||
| 927 | |||
| 928 | pm_runtime_enable(dev); | ||
| 929 | pm_runtime_set_autosuspend_delay(dev, 2000); | ||
| 930 | pm_runtime_use_autosuspend(dev); | ||
| 931 | |||
| 932 | ret = iio_device_register(indio_dev); | ||
| 933 | if (ret < 0) | ||
| 934 | goto pm_disable; | ||
| 935 | |||
| 936 | return 0; | ||
| 937 | |||
| 938 | pm_disable: | ||
| 939 | pm_runtime_disable(dev); | ||
| 940 | pm_runtime_set_suspended(dev); | ||
| 941 | pm_runtime_put_noidle(dev); | ||
| 942 | |||
| 943 | return ret; | ||
| 944 | } | ||
| 945 | EXPORT_SYMBOL_GPL(fxas21002c_core_probe); | ||
| 946 | |||
| 947 | void fxas21002c_core_remove(struct device *dev) | ||
| 948 | { | ||
| 949 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 950 | |||
| 951 | iio_device_unregister(indio_dev); | ||
| 952 | |||
| 953 | pm_runtime_disable(dev); | ||
| 954 | pm_runtime_set_suspended(dev); | ||
| 955 | pm_runtime_put_noidle(dev); | ||
| 956 | } | ||
| 957 | EXPORT_SYMBOL_GPL(fxas21002c_core_remove); | ||
| 958 | |||
| 959 | static int __maybe_unused fxas21002c_suspend(struct device *dev) | ||
| 960 | { | ||
| 961 | struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev)); | ||
| 962 | |||
| 963 | fxas21002c_mode_set(data, FXAS21002C_MODE_STANDBY); | ||
| 964 | fxas21002c_power_disable(data); | ||
| 965 | |||
| 966 | return 0; | ||
| 967 | } | ||
| 968 | |||
| 969 | static int __maybe_unused fxas21002c_resume(struct device *dev) | ||
| 970 | { | ||
| 971 | struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev)); | ||
| 972 | int ret; | ||
| 973 | |||
| 974 | ret = fxas21002c_power_enable(data); | ||
| 975 | if (ret < 0) | ||
| 976 | return ret; | ||
| 977 | |||
| 978 | return fxas21002c_mode_set(data, data->prev_mode); | ||
| 979 | } | ||
| 980 | |||
| 981 | static int __maybe_unused fxas21002c_runtime_suspend(struct device *dev) | ||
| 982 | { | ||
| 983 | struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev)); | ||
| 984 | |||
| 985 | return fxas21002c_mode_set(data, FXAS21002C_MODE_READY); | ||
| 986 | } | ||
| 987 | |||
| 988 | static int __maybe_unused fxas21002c_runtime_resume(struct device *dev) | ||
| 989 | { | ||
| 990 | struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev)); | ||
| 991 | |||
| 992 | return fxas21002c_mode_set(data, FXAS21002C_MODE_ACTIVE); | ||
| 993 | } | ||
| 994 | |||
| 995 | const struct dev_pm_ops fxas21002c_pm_ops = { | ||
| 996 | SET_SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume) | ||
| 997 | SET_RUNTIME_PM_OPS(fxas21002c_runtime_suspend, | ||
| 998 | fxas21002c_runtime_resume, NULL) | ||
| 999 | }; | ||
| 1000 | EXPORT_SYMBOL_GPL(fxas21002c_pm_ops); | ||
| 1001 | |||
| 1002 | MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>"); | ||
| 1003 | MODULE_LICENSE("GPL v2"); | ||
| 1004 | MODULE_DESCRIPTION("FXAS21002C Gyro driver"); | ||
| @@ -0,0 +1,69 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for NXP FXAS21002C Gyroscope - I2C | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018 Linaro Ltd. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/err.h> | ||
| 9 | #include <linux/i2c.h> | ||
| 10 | #include <linux/mod_devicetable.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | |||
| 14 | #include "fxas21002c.h" | ||
| 15 | |||
| 16 | static const struct regmap_config fxas21002c_regmap_i2c_conf = { | ||
| 17 | .reg_bits = 8, | ||
| 18 | .val_bits = 8, | ||
| 19 | .max_register = FXAS21002C_REG_CTRL3, | ||
| 20 | }; | ||
| 21 | |||
| 22 | static int fxas21002c_i2c_probe(struct i2c_client *i2c) | ||
| 23 | { | ||
| 24 | struct regmap *regmap; | ||
| 25 | |||
| 26 | regmap = devm_regmap_init_i2c(i2c, &fxas21002c_regmap_i2c_conf); | ||
| 27 | if (IS_ERR(regmap)) { | ||
| 28 | dev_err(&i2c->dev, "Failed to register i2c regmap: %ld\n", | ||
| 29 | PTR_ERR(regmap)); | ||
| 30 | return PTR_ERR(regmap); | ||
| 31 | } | ||
| 32 | |||
| 33 | return fxas21002c_core_probe(&i2c->dev, regmap, i2c->irq, i2c->name); | ||
| 34 | } | ||
| 35 | |||
| 36 | static int fxas21002c_i2c_remove(struct i2c_client *i2c) | ||
| 37 | { | ||
| 38 | fxas21002c_core_remove(&i2c->dev); | ||
| 39 | |||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | static const struct i2c_device_id fxas21002c_i2c_id[] = { | ||
| 44 | { "fxas21002c", 0 }, | ||
| 45 | { } | ||
| 46 | }; | ||
| 47 | MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id); | ||
| 48 | |||
| 49 | static const struct of_device_id fxas21002c_i2c_of_match[] = { | ||
| 50 | { .compatible = "nxp,fxas21002c", }, | ||
| 51 | { } | ||
| 52 | }; | ||
| 53 | MODULE_DEVICE_TABLE(of, fxas21002c_i2c_of_match); | ||
| 54 | |||
| 55 | static struct i2c_driver fxas21002c_i2c_driver = { | ||
| 56 | .driver = { | ||
| 57 | .name = "fxas21002c_i2c", | ||
| 58 | .pm = &fxas21002c_pm_ops, | ||
| 59 | .of_match_table = fxas21002c_i2c_of_match, | ||
| 60 | }, | ||
| 61 | .probe_new = fxas21002c_i2c_probe, | ||
| 62 | .remove = fxas21002c_i2c_remove, | ||
| 63 | .id_table = fxas21002c_i2c_id, | ||
| 64 | }; | ||
| 65 | module_i2c_driver(fxas21002c_i2c_driver); | ||
| 66 | |||
| 67 | MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>"); | ||
| 68 | MODULE_LICENSE("GPL v2"); | ||
| 69 | MODULE_DESCRIPTION("FXAS21002C I2C Gyro driver"); | ||
| @@ -0,0 +1,70 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for NXP Fxas21002c Gyroscope - SPI | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 Linaro Ltd. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/err.h> | ||
| 9 | #include <linux/mod_devicetable.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | #include <linux/spi/spi.h> | ||
| 13 | |||
| 14 | #include "fxas21002c.h" | ||
| 15 | |||
| 16 | static const struct regmap_config fxas21002c_regmap_spi_conf = { | ||
| 17 | .reg_bits = 8, | ||
| 18 | .val_bits = 8, | ||
| 19 | .max_register = FXAS21002C_REG_CTRL3, | ||
| 20 | }; | ||
| 21 | |||
| 22 | static int fxas21002c_spi_probe(struct spi_device *spi) | ||
| 23 | { | ||
| 24 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
| 25 | struct regmap *regmap; | ||
| 26 | |||
| 27 | regmap = devm_regmap_init_spi(spi, &fxas21002c_regmap_spi_conf); | ||
| 28 | if (IS_ERR(regmap)) { | ||
| 29 | dev_err(&spi->dev, "Failed to register spi regmap: %ld\n", | ||
| 30 | PTR_ERR(regmap)); | ||
| 31 | return PTR_ERR(regmap); | ||
| 32 | } | ||
| 33 | |||
| 34 | return fxas21002c_core_probe(&spi->dev, regmap, spi->irq, id->name); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int fxas21002c_spi_remove(struct spi_device *spi) | ||
| 38 | { | ||
| 39 | fxas21002c_core_remove(&spi->dev); | ||
| 40 | |||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | static const struct spi_device_id fxas21002c_spi_id[] = { | ||
| 45 | { "fxas21002c", 0 }, | ||
| 46 | { } | ||
| 47 | }; | ||
| 48 | MODULE_DEVICE_TABLE(spi, fxas21002c_spi_id); | ||
| 49 | |||
| 50 | static const struct of_device_id fxas21002c_spi_of_match[] = { | ||
| 51 | { .compatible = "nxp,fxas21002c", }, | ||
| 52 | { } | ||
| 53 | }; | ||
| 54 | MODULE_DEVICE_TABLE(of, fxas21002c_spi_of_match); | ||
| 55 | |||
| 56 | static struct spi_driver fxas21002c_spi_driver = { | ||
| 57 | .driver = { | ||
| 58 | .name = "fxas21002c_spi", | ||
| 59 | .pm = &fxas21002c_pm_ops, | ||
| 60 | .of_match_table = fxas21002c_spi_of_match, | ||
| 61 | }, | ||
| 62 | .probe = fxas21002c_spi_probe, | ||
| 63 | .remove = fxas21002c_spi_remove, | ||
| 64 | .id_table = fxas21002c_spi_id, | ||
| 65 | }; | ||
| 66 | module_spi_driver(fxas21002c_spi_driver); | ||
| 67 | |||
| 68 | MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>"); | ||
| 69 | MODULE_LICENSE("GPL v2"); | ||
| 70 | MODULE_DESCRIPTION("FXAS21002C SPI Gyro driver"); | ||
| @@ -242,6 +242,20 @@ err_ret: · 241 unmodified lines | |||
| 242 | return ret; | 242 | return ret; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static const struct iio_mount_matrix * | ||
| 246 | itg3200_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 247 | const struct iio_chan_spec *chan) | ||
| 248 | { | ||
| 249 | struct itg3200 *data = iio_priv(indio_dev); | ||
| 250 | |||
| 251 | return &data->orientation; | ||
| 252 | } | ||
| 253 | |||
| 254 | static const struct iio_chan_spec_ext_info itg3200_ext_info[] = { | ||
| 255 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, itg3200_get_mount_matrix), | ||
| 256 | { } | ||
| 257 | }; | ||
| 258 | |||
| 245 | #define ITG3200_ST \ | 259 | #define ITG3200_ST \ |
| 246 | { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE } | 260 | { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE } |
| 247 | 261 | ||
| @@ -255,6 +269,7 @@ err_ret: · 7 unmodified lines | |||
| 255 | .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ | 269 | .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ |
| 256 | .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ | 270 | .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ |
| 257 | .scan_type = ITG3200_ST, \ | 271 | .scan_type = ITG3200_ST, \ |
| 272 | .ext_info = itg3200_ext_info, \ | ||
| 258 | } | 273 | } |
| 259 | 274 | ||
| 260 | static const struct iio_chan_spec itg3200_channels[] = { | 275 | static const struct iio_chan_spec itg3200_channels[] = { |
| @@ -297,6 +312,11 @@ static int itg3200_probe(struct i2c_client *client, · 36 unmodified lines | |||
| 297 | 312 | ||
| 298 | st = iio_priv(indio_dev); | 313 | st = iio_priv(indio_dev); |
| 299 | 314 | ||
| 315 | ret = iio_read_mount_matrix(&client->dev, "mount-matrix", | ||
| 316 | &st->orientation); | ||
| 317 | if (ret) | ||
| 318 | return ret; | ||
| 319 | |||
| 300 | i2c_set_clientdata(client, indio_dev); | 320 | i2c_set_clientdata(client, indio_dev); |
| 301 | st->i2c = client; | 321 | st->i2c = client; |
| 302 | 322 | ||
| @@ -865,7 +865,7 @@ static int mpu3050_power_up(struct mpu3050 *mpu3050) · 864 unmodified lines | |||
| 865 | dev_err(mpu3050->dev, "error setting power mode\n"); | 865 | dev_err(mpu3050->dev, "error setting power mode\n"); |
| 866 | return ret; | 866 | return ret; |
| 867 | } | 867 | } |
| 868 | msleep(10); | 868 | usleep_range(10000, 20000); |
| 869 | 869 | ||
| 870 | return 0; | 870 | return 0; |
| 871 | } | 871 | } |
| @@ -1150,8 +1150,7 @@ int mpu3050_common_probe(struct device *dev, · 278 unmodified lines | |||
| 1150 | mpu3050->divisor = 99; | 1150 | mpu3050->divisor = 99; |
| 1151 | 1151 | ||
| 1152 | /* Read the mounting matrix, if present */ | 1152 | /* Read the mounting matrix, if present */ |
| 1153 | ret = of_iio_read_mount_matrix(dev, "mount-matrix", | 1153 | ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation); |
| 1154 | &mpu3050->orientation); | ||
| 1155 | if (ret) | 1154 | if (ret) |
| 1156 | return ret; | 1155 | return ret; |
| 1157 | 1156 | ||
| @@ -4,16 +4,16 @@ · 3 unmodified lines | |||
| 4 | menu "Humidity sensors" | 4 | menu "Humidity sensors" |
| 5 | 5 | ||
| 6 | config AM2315 | 6 | config AM2315 |
| 7 | tristate "Aosong AM2315 relative humidity and temperature sensor" | 7 | tristate "Aosong AM2315 relative humidity and temperature sensor" |
| 8 | depends on I2C | 8 | depends on I2C |
| 9 | select IIO_BUFFER | 9 | select IIO_BUFFER |
| 10 | select IIO_TRIGGERED_BUFFER | 10 | select IIO_TRIGGERED_BUFFER |
| 11 | help | 11 | help |
| 12 | If you say yes here you get support for the Aosong AM2315 | 12 | If you say yes here you get support for the Aosong AM2315 |
| 13 | relative humidity and ambient temperature sensor. | 13 | relative humidity and ambient temperature sensor. |
| 14 | 14 | ||
| 15 | This driver can also be built as a module. If so, the module will | 15 | This driver can also be built as a module. If so, the module will |
| 16 | be called am2315. | 16 | be called am2315. |
| 17 | 17 | ||
| 18 | config DHT11 | 18 | config DHT11 |
| 19 | tristate "DHT11 (and compatible sensors) driver" | 19 | tristate "DHT11 (and compatible sensors) driver" |
| @@ -78,7 +78,7 @@ config HTS221_SPI · 58 unmodified lines | |||
| 78 | config HTU21 | 78 | config HTU21 |
| 79 | tristate "Measurement Specialties HTU21 humidity & temperature sensor" | 79 | tristate "Measurement Specialties HTU21 humidity & temperature sensor" |
| 80 | depends on I2C | 80 | depends on I2C |
| 81 | select IIO_MS_SENSORS_I2C | 81 | select IIO_MS_SENSORS_I2C |
| 82 | help | 82 | help |
| 83 | If you say yes here you get support for the Measurement Specialties | 83 | If you say yes here you get support for the Measurement Specialties |
| 84 | HTU21 humidity and temperature sensor. | 84 | HTU21 humidity and temperature sensor. |
| @@ -4,8 +4,6 @@ · 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 | adis16400-y := adis16400_core.o | ||
| 8 | adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o | ||
| 9 | obj-$(CONFIG_ADIS16400) += adis16400.o | 7 | obj-$(CONFIG_ADIS16400) += adis16400.o |
| 10 | obj-$(CONFIG_ADIS16480) += adis16480.o | 8 | obj-$(CONFIG_ADIS16480) += adis16480.o |
| 11 | 9 | ||
| @@ -31,8 +31,183 @@ · 30 unmodified lines | |||
| 31 | #include <linux/iio/iio.h> | 31 | #include <linux/iio/iio.h> |
| 32 | #include <linux/iio/sysfs.h> | 32 | #include <linux/iio/sysfs.h> |
| 33 | #include <linux/iio/buffer.h> | 33 | #include <linux/iio/buffer.h> |
| 34 | #include <linux/iio/trigger_consumer.h> | ||
| 35 | #include <linux/iio/imu/adis.h> | ||
| 36 | |||
| 37 | #define ADIS16400_STARTUP_DELAY 290 /* ms */ | ||
| 38 | #define ADIS16400_MTEST_DELAY 90 /* ms */ | ||
| 39 | |||
| 40 | #define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ | ||
| 41 | #define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ | ||
| 42 | #define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ | ||
| 43 | #define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ | ||
| 44 | #define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ | ||
| 45 | #define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ | ||
| 46 | #define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ | ||
| 47 | #define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ | ||
| 48 | #define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ | ||
| 49 | #define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ | ||
| 50 | #define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ | ||
| 51 | #define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ | ||
| 52 | #define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ | ||
| 53 | |||
| 54 | #define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ | ||
| 55 | #define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ | ||
| 56 | #define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ | ||
| 57 | |||
| 58 | #define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ | ||
| 59 | #define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ | ||
| 60 | #define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ | ||
| 61 | |||
| 62 | #define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ | ||
| 63 | #define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ | ||
| 64 | |||
| 65 | /* Calibration parameters */ | ||
| 66 | #define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ | ||
| 67 | #define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ | ||
| 68 | #define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ | ||
| 69 | #define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ | ||
| 70 | #define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ | ||
| 71 | #define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ | ||
| 72 | #define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ | ||
| 73 | #define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ | ||
| 74 | #define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ | ||
| 75 | #define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ | ||
| 76 | #define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ | ||
| 77 | #define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ | ||
| 78 | |||
| 79 | #define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ | ||
| 80 | #define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ | ||
| 81 | #define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ | ||
| 82 | #define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ | ||
| 83 | #define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ | ||
| 84 | #define ADIS16400_DIAG_STAT 0x3C /* System status */ | ||
| 85 | |||
| 86 | /* Alarm functions */ | ||
| 87 | #define ADIS16400_GLOB_CMD 0x3E /* System command */ | ||
| 88 | #define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ | ||
| 89 | #define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ | ||
| 90 | #define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ | ||
| 91 | #define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ | ||
| 92 | #define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ | ||
| 93 | #define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ | ||
| 94 | |||
| 95 | #define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ | ||
| 96 | #define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ | ||
| 97 | #define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ | ||
| 98 | #define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ | ||
| 99 | |||
| 100 | #define ADIS16400_ERROR_ACTIVE (1<<14) | ||
| 101 | #define ADIS16400_NEW_DATA (1<<14) | ||
| 102 | |||
| 103 | /* MSC_CTRL */ | ||
| 104 | #define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) | ||
| 105 | #define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) | ||
| 106 | #define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) | ||
| 107 | #define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) | ||
| 108 | #define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) | ||
| 109 | #define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) | ||
| 110 | #define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) | ||
| 111 | #define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) | ||
| 112 | #define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) | ||
| 113 | |||
| 114 | /* SMPL_PRD */ | ||
| 115 | #define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) | ||
| 116 | #define ADIS16400_SMPL_PRD_DIV_MASK 0x7F | ||
| 117 | |||
| 118 | /* DIAG_STAT */ | ||
| 119 | #define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 | ||
| 120 | #define ADIS16400_DIAG_STAT_YACCL_FAIL 14 | ||
| 121 | #define ADIS16400_DIAG_STAT_XACCL_FAIL 13 | ||
| 122 | #define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 | ||
| 123 | #define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 | ||
| 124 | #define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 | ||
| 125 | #define ADIS16400_DIAG_STAT_ALARM2 9 | ||
| 126 | #define ADIS16400_DIAG_STAT_ALARM1 8 | ||
| 127 | #define ADIS16400_DIAG_STAT_FLASH_CHK 6 | ||
| 128 | #define ADIS16400_DIAG_STAT_SELF_TEST 5 | ||
| 129 | #define ADIS16400_DIAG_STAT_OVERFLOW 4 | ||
| 130 | #define ADIS16400_DIAG_STAT_SPI_FAIL 3 | ||
| 131 | #define ADIS16400_DIAG_STAT_FLASH_UPT 2 | ||
| 132 | #define ADIS16400_DIAG_STAT_POWER_HIGH 1 | ||
| 133 | #define ADIS16400_DIAG_STAT_POWER_LOW 0 | ||
| 134 | |||
| 135 | /* GLOB_CMD */ | ||
| 136 | #define ADIS16400_GLOB_CMD_SW_RESET (1<<7) | ||
| 137 | #define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) | ||
| 138 | #define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) | ||
| 139 | #define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) | ||
| 140 | #define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) | ||
| 141 | #define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) | ||
| 142 | |||
| 143 | /* SLP_CNT */ | ||
| 144 | #define ADIS16400_SLP_CNT_POWER_OFF (1<<8) | ||
| 145 | |||
| 146 | #define ADIS16334_RATE_DIV_SHIFT 8 | ||
| 147 | #define ADIS16334_RATE_INT_CLK BIT(0) | ||
| 148 | |||
| 149 | #define ADIS16400_SPI_SLOW (u32)(300 * 1000) | ||
| 150 | #define ADIS16400_SPI_BURST (u32)(1000 * 1000) | ||
| 151 | #define ADIS16400_SPI_FAST (u32)(2000 * 1000) | ||
| 152 | |||
| 153 | #define ADIS16400_HAS_PROD_ID BIT(0) | ||
| 154 | #define ADIS16400_NO_BURST BIT(1) | ||
| 155 | #define ADIS16400_HAS_SLOW_MODE BIT(2) | ||
| 156 | #define ADIS16400_HAS_SERIAL_NUMBER BIT(3) | ||
| 157 | #define ADIS16400_BURST_DIAG_STAT BIT(4) | ||
| 158 | |||
| 159 | struct adis16400_state; | ||
| 160 | |||
| 161 | struct adis16400_chip_info { | ||
| 162 | const struct iio_chan_spec *channels; | ||
| 163 | const int num_channels; | ||
| 164 | const long flags; | ||
| 165 | unsigned int gyro_scale_micro; | ||
| 166 | unsigned int accel_scale_micro; | ||
| 167 | int temp_scale_nano; | ||
| 168 | int temp_offset; | ||
| 169 | int (*set_freq)(struct adis16400_state *st, unsigned int freq); | ||
| 170 | int (*get_freq)(struct adis16400_state *st); | ||
| 171 | }; | ||
| 172 | |||
| 173 | /** | ||
| 174 | * struct adis16400_state - device instance specific data | ||
| 175 | * @variant: chip variant info | ||
| 176 | * @filt_int: integer part of requested filter frequency | ||
| 177 | * @adis: adis device | ||
| 178 | **/ | ||
| 179 | struct adis16400_state { | ||
| 180 | struct adis16400_chip_info *variant; | ||
| 181 | int filt_int; | ||
| 182 | |||
| 183 | struct adis adis; | ||
| 184 | unsigned long avail_scan_mask[2]; | ||
| 185 | }; | ||
| 34 | 186 | ||
| 35 | #include "adis16400.h" | 187 | /* At the moment triggers are only used for ring buffer |
| 188 | * filling. This may change! | ||
| 189 | */ | ||
| 190 | |||
| 191 | enum { | ||
| 192 | ADIS16400_SCAN_SUPPLY, | ||
| 193 | ADIS16400_SCAN_GYRO_X, | ||
| 194 | ADIS16400_SCAN_GYRO_Y, | ||
| 195 | ADIS16400_SCAN_GYRO_Z, | ||
| 196 | ADIS16400_SCAN_ACC_X, | ||
| 197 | ADIS16400_SCAN_ACC_Y, | ||
| 198 | ADIS16400_SCAN_ACC_Z, | ||
| 199 | ADIS16400_SCAN_MAGN_X, | ||
| 200 | ADIS16400_SCAN_MAGN_Y, | ||
| 201 | ADIS16400_SCAN_MAGN_Z, | ||
| 202 | ADIS16400_SCAN_BARO, | ||
| 203 | ADIS16350_SCAN_TEMP_X, | ||
| 204 | ADIS16350_SCAN_TEMP_Y, | ||
| 205 | ADIS16350_SCAN_TEMP_Z, | ||
| 206 | ADIS16300_SCAN_INCLI_X, | ||
| 207 | ADIS16300_SCAN_INCLI_Y, | ||
| 208 | ADIS16400_SCAN_ADC, | ||
| 209 | ADIS16400_SCAN_TIMESTAMP, | ||
| 210 | }; | ||
| 36 | 211 | ||
| 37 | #ifdef CONFIG_DEBUG_FS | 212 | #ifdef CONFIG_DEBUG_FS |
| 38 | 213 | ||
| @@ -145,6 +320,11 @@ enum adis16400_chip_variant { · 106 unmodified lines | |||
| 145 | ADIS16448, | 320 | ADIS16448, |
| 146 | }; | 321 | }; |
| 147 | 322 | ||
| 323 | static struct adis_burst adis16400_burst = { | ||
| 324 | .en = true, | ||
| 325 | .reg_cmd = ADIS16400_GLOB_CMD, | ||
| 326 | }; | ||
| 327 | |||
| 148 | static int adis16334_get_freq(struct adis16400_state *st) | 328 | static int adis16334_get_freq(struct adis16400_state *st) |
| 149 | { | 329 | { |
| 150 | int ret; | 330 | int ret; |
| @@ -465,6 +645,51 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, · 314 unmodified lines | |||
| 465 | } | 645 | } |
| 466 | } | 646 | } |
| 467 | 647 | ||
| 648 | #if IS_ENABLED(CONFIG_IIO_BUFFER) | ||
| 649 | static irqreturn_t adis16400_trigger_handler(int irq, void *p) | ||
| 650 | { | ||
| 651 | struct iio_poll_func *pf = p; | ||
| 652 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 653 | struct adis16400_state *st = iio_priv(indio_dev); | ||
| 654 | struct adis *adis = &st->adis; | ||
| 655 | u32 old_speed_hz = st->adis.spi->max_speed_hz; | ||
| 656 | void *buffer; | ||
| 657 | int ret; | ||
| 658 | |||
| 659 | if (!adis->buffer) | ||
| 660 | return -ENOMEM; | ||
| 661 | |||
| 662 | if (!(st->variant->flags & ADIS16400_NO_BURST) && | ||
| 663 | st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { | ||
| 664 | st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; | ||
| 665 | spi_setup(st->adis.spi); | ||
| 666 | } | ||
| 667 | |||
| 668 | ret = spi_sync(adis->spi, &adis->msg); | ||
| 669 | if (ret) | ||
| 670 | dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); | ||
| 671 | |||
| 672 | if (!(st->variant->flags & ADIS16400_NO_BURST)) { | ||
| 673 | st->adis.spi->max_speed_hz = old_speed_hz; | ||
| 674 | spi_setup(st->adis.spi); | ||
| 675 | } | ||
| 676 | |||
| 677 | if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) | ||
| 678 | buffer = adis->buffer + sizeof(u16); | ||
| 679 | else | ||
| 680 | buffer = adis->buffer; | ||
| 681 | |||
| 682 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, | ||
| 683 | pf->timestamp); | ||
| 684 | |||
| 685 | iio_trigger_notify_done(indio_dev->trig); | ||
| 686 | |||
| 687 | return IRQ_HANDLED; | ||
| 688 | } | ||
| 689 | #else | ||
| 690 | #define adis16400_trigger_handler NULL | ||
| 691 | #endif /* IS_ENABLED(CONFIG_IIO_BUFFER) */ | ||
| 692 | |||
| 468 | #define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ | 693 | #define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ |
| 469 | .type = IIO_VOLTAGE, \ | 694 | .type = IIO_VOLTAGE, \ |
| 470 | .indexed = 1, \ | 695 | .indexed = 1, \ |
| @@ -835,7 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = { · 364 unmodified lines | |||
| 835 | static const struct iio_info adis16400_info = { | 1060 | static const struct iio_info adis16400_info = { |
| 836 | .read_raw = &adis16400_read_raw, | 1061 | .read_raw = &adis16400_read_raw, |
| 837 | .write_raw = &adis16400_write_raw, | 1062 | .write_raw = &adis16400_write_raw, |
| 838 | .update_scan_mode = adis16400_update_scan_mode, | 1063 | .update_scan_mode = adis_update_scan_mode, |
| 839 | .debugfs_reg_access = adis_debugfs_reg_access, | 1064 | .debugfs_reg_access = adis_debugfs_reg_access, |
| 840 | }; | 1065 | }; |
| 841 | 1066 | ||
| @@ -926,6 +1151,9 @@ static int adis16400_probe(struct spi_device *spi) · 84 unmodified lines | |||
| 926 | if (!(st->variant->flags & ADIS16400_NO_BURST)) { | 1151 | if (!(st->variant->flags & ADIS16400_NO_BURST)) { |
| 927 | adis16400_setup_chan_mask(st); | 1152 | adis16400_setup_chan_mask(st); |
| 928 | indio_dev->available_scan_masks = st->avail_scan_mask; | 1153 | indio_dev->available_scan_masks = st->avail_scan_mask; |
| 1154 | st->adis.burst = &adis16400_burst; | ||
| 1155 | if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) | ||
| 1156 | st->adis.burst->extra_len = sizeof(u16); | ||
| 929 | } | 1157 | } |
| 930 | 1158 | ||
| 931 | ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); | 1159 | ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); |
| @@ -1,215 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * adis16400.h support Analog Devices ADIS16400 | ||
| 3 | * 3d 18g accelerometers, | ||
| 4 | * 3d gyroscopes, | ||
| 5 | * 3d 2.5gauss magnetometers via SPI | ||
| 6 | * | ||
| 7 | * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | ||
| 8 | * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> | ||
| 9 | * | ||
| 10 | * Loosely based upon lis3l02dq.h | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef SPI_ADIS16400_H_ | ||
| 18 | #define SPI_ADIS16400_H_ | ||
| 19 | |||
| 20 | #include <linux/iio/imu/adis.h> | ||
| 21 | |||
| 22 | #define ADIS16400_STARTUP_DELAY 290 /* ms */ | ||
| 23 | #define ADIS16400_MTEST_DELAY 90 /* ms */ | ||
| 24 | |||
| 25 | #define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ | ||
| 26 | #define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ | ||
| 27 | #define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ | ||
| 28 | #define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ | ||
| 29 | #define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ | ||
| 30 | #define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ | ||
| 31 | #define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ | ||
| 32 | #define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ | ||
| 33 | #define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ | ||
| 34 | #define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ | ||
| 35 | #define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ | ||
| 36 | #define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ | ||
| 37 | #define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ | ||
| 38 | |||
| 39 | #define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ | ||
| 40 | #define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ | ||
| 41 | #define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ | ||
| 42 | |||
| 43 | #define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ | ||
| 44 | #define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ | ||
| 45 | #define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ | ||
| 46 | |||
| 47 | #define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ | ||
| 48 | #define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ | ||
| 49 | |||
| 50 | /* Calibration parameters */ | ||
| 51 | #define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ | ||
| 52 | #define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ | ||
| 53 | #define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ | ||
| 54 | #define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ | ||
| 55 | #define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ | ||
| 56 | #define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ | ||
| 57 | #define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ | ||
| 58 | #define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ | ||
| 59 | #define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ | ||
| 60 | #define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ | ||
| 61 | #define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ | ||
| 62 | #define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ | ||
| 63 | |||
| 64 | #define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ | ||
| 65 | #define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ | ||
| 66 | #define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ | ||
| 67 | #define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ | ||
| 68 | #define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ | ||
| 69 | #define ADIS16400_DIAG_STAT 0x3C /* System status */ | ||
| 70 | |||
| 71 | /* Alarm functions */ | ||
| 72 | #define ADIS16400_GLOB_CMD 0x3E /* System command */ | ||
| 73 | #define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ | ||
| 74 | #define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ | ||
| 75 | #define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ | ||
| 76 | #define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ | ||
| 77 | #define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ | ||
| 78 | #define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ | ||
| 79 | |||
| 80 | #define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ | ||
| 81 | #define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ | ||
| 82 | #define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ | ||
| 83 | #define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ | ||
| 84 | |||
| 85 | #define ADIS16400_ERROR_ACTIVE (1<<14) | ||
| 86 | #define ADIS16400_NEW_DATA (1<<14) | ||
| 87 | |||
| 88 | /* MSC_CTRL */ | ||
| 89 | #define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) | ||
| 90 | #define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) | ||
| 91 | #define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) | ||
| 92 | #define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) | ||
| 93 | #define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) | ||
| 94 | #define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) | ||
| 95 | #define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) | ||
| 96 | #define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) | ||
| 97 | #define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) | ||
| 98 | |||
| 99 | /* SMPL_PRD */ | ||
| 100 | #define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) | ||
| 101 | #define ADIS16400_SMPL_PRD_DIV_MASK 0x7F | ||
| 102 | |||
| 103 | /* DIAG_STAT */ | ||
| 104 | #define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 | ||
| 105 | #define ADIS16400_DIAG_STAT_YACCL_FAIL 14 | ||
| 106 | #define ADIS16400_DIAG_STAT_XACCL_FAIL 13 | ||
| 107 | #define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 | ||
| 108 | #define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 | ||
| 109 | #define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 | ||
| 110 | #define ADIS16400_DIAG_STAT_ALARM2 9 | ||
| 111 | #define ADIS16400_DIAG_STAT_ALARM1 8 | ||
| 112 | #define ADIS16400_DIAG_STAT_FLASH_CHK 6 | ||
| 113 | #define ADIS16400_DIAG_STAT_SELF_TEST 5 | ||
| 114 | #define ADIS16400_DIAG_STAT_OVERFLOW 4 | ||
| 115 | #define ADIS16400_DIAG_STAT_SPI_FAIL 3 | ||
| 116 | #define ADIS16400_DIAG_STAT_FLASH_UPT 2 | ||
| 117 | #define ADIS16400_DIAG_STAT_POWER_HIGH 1 | ||
| 118 | #define ADIS16400_DIAG_STAT_POWER_LOW 0 | ||
| 119 | |||
| 120 | /* GLOB_CMD */ | ||
| 121 | #define ADIS16400_GLOB_CMD_SW_RESET (1<<7) | ||
| 122 | #define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) | ||
| 123 | #define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) | ||
| 124 | #define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) | ||
| 125 | #define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) | ||
| 126 | #define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) | ||
| 127 | |||
| 128 | /* SLP_CNT */ | ||
| 129 | #define ADIS16400_SLP_CNT_POWER_OFF (1<<8) | ||
| 130 | |||
| 131 | #define ADIS16334_RATE_DIV_SHIFT 8 | ||
| 132 | #define ADIS16334_RATE_INT_CLK BIT(0) | ||
| 133 | |||
| 134 | #define ADIS16400_SPI_SLOW (u32)(300 * 1000) | ||
| 135 | #define ADIS16400_SPI_BURST (u32)(1000 * 1000) | ||
| 136 | #define ADIS16400_SPI_FAST (u32)(2000 * 1000) | ||
| 137 | |||
| 138 | #define ADIS16400_HAS_PROD_ID BIT(0) | ||
| 139 | #define ADIS16400_NO_BURST BIT(1) | ||
| 140 | #define ADIS16400_HAS_SLOW_MODE BIT(2) | ||
| 141 | #define ADIS16400_HAS_SERIAL_NUMBER BIT(3) | ||
| 142 | #define ADIS16400_BURST_DIAG_STAT BIT(4) | ||
| 143 | |||
| 144 | struct adis16400_state; | ||
| 145 | |||
| 146 | struct adis16400_chip_info { | ||
| 147 | const struct iio_chan_spec *channels; | ||
| 148 | const int num_channels; | ||
| 149 | const long flags; | ||
| 150 | unsigned int gyro_scale_micro; | ||
| 151 | unsigned int accel_scale_micro; | ||
| 152 | int temp_scale_nano; | ||
| 153 | int temp_offset; | ||
| 154 | int (*set_freq)(struct adis16400_state *st, unsigned int freq); | ||
| 155 | int (*get_freq)(struct adis16400_state *st); | ||
| 156 | }; | ||
| 157 | |||
| 158 | /** | ||
| 159 | * struct adis16400_state - device instance specific data | ||
| 160 | * @variant: chip variant info | ||
| 161 | * @filt_int: integer part of requested filter frequency | ||
| 162 | * @adis: adis device | ||
| 163 | **/ | ||
| 164 | struct adis16400_state { | ||
| 165 | struct adis16400_chip_info *variant; | ||
| 166 | int filt_int; | ||
| 167 | |||
| 168 | struct adis adis; | ||
| 169 | unsigned long avail_scan_mask[2]; | ||
| 170 | }; | ||
| 171 | |||
| 172 | /* At the moment triggers are only used for ring buffer | ||
| 173 | * filling. This may change! | ||
| 174 | */ | ||
| 175 | |||
| 176 | enum { | ||
| 177 | ADIS16400_SCAN_SUPPLY, | ||
| 178 | ADIS16400_SCAN_GYRO_X, | ||
| 179 | ADIS16400_SCAN_GYRO_Y, | ||
| 180 | ADIS16400_SCAN_GYRO_Z, | ||
| 181 | ADIS16400_SCAN_ACC_X, | ||
| 182 | ADIS16400_SCAN_ACC_Y, | ||
| 183 | ADIS16400_SCAN_ACC_Z, | ||
| 184 | ADIS16400_SCAN_MAGN_X, | ||
| 185 | ADIS16400_SCAN_MAGN_Y, | ||
| 186 | ADIS16400_SCAN_MAGN_Z, | ||
| 187 | ADIS16400_SCAN_BARO, | ||
| 188 | ADIS16350_SCAN_TEMP_X, | ||
| 189 | ADIS16350_SCAN_TEMP_Y, | ||
| 190 | ADIS16350_SCAN_TEMP_Z, | ||
| 191 | ADIS16300_SCAN_INCLI_X, | ||
| 192 | ADIS16300_SCAN_INCLI_Y, | ||
| 193 | ADIS16400_SCAN_ADC, | ||
| 194 | ADIS16400_SCAN_TIMESTAMP, | ||
| 195 | }; | ||
| 196 | |||
| 197 | #ifdef CONFIG_IIO_BUFFER | ||
| 198 | |||
| 199 | ssize_t adis16400_read_data_from_ring(struct device *dev, | ||
| 200 | struct device_attribute *attr, | ||
| 201 | char *buf); | ||
| 202 | |||
| 203 | |||
| 204 | int adis16400_update_scan_mode(struct iio_dev *indio_dev, | ||
| 205 | const unsigned long *scan_mask); | ||
| 206 | irqreturn_t adis16400_trigger_handler(int irq, void *p); | ||
| 207 | |||
| 208 | #else /* CONFIG_IIO_BUFFER */ | ||
| 209 | |||
| 210 | #define adis16400_update_scan_mode NULL | ||
| 211 | #define adis16400_trigger_handler NULL | ||
| 212 | |||
| 213 | #endif /* CONFIG_IIO_BUFFER */ | ||
| 214 | |||
| 215 | #endif /* SPI_ADIS16400_H_ */ | ||
| @@ -1,101 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <linux/interrupt.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/kernel.h> | ||
| 5 | #include <linux/spi/spi.h> | ||
| 6 | #include <linux/slab.h> | ||
| 7 | #include <linux/bitops.h> | ||
| 8 | #include <linux/export.h> | ||
| 9 | |||
| 10 | #include <linux/iio/iio.h> | ||
| 11 | #include <linux/iio/buffer.h> | ||
| 12 | #include <linux/iio/triggered_buffer.h> | ||
| 13 | #include <linux/iio/trigger_consumer.h> | ||
| 14 | |||
| 15 | #include "adis16400.h" | ||
| 16 | |||
| 17 | int adis16400_update_scan_mode(struct iio_dev *indio_dev, | ||
| 18 | const unsigned long *scan_mask) | ||
| 19 | { | ||
| 20 | struct adis16400_state *st = iio_priv(indio_dev); | ||
| 21 | struct adis *adis = &st->adis; | ||
| 22 | unsigned int burst_length; | ||
| 23 | u8 *tx; | ||
| 24 | |||
| 25 | if (st->variant->flags & ADIS16400_NO_BURST) | ||
| 26 | return adis_update_scan_mode(indio_dev, scan_mask); | ||
| 27 | |||
| 28 | kfree(adis->xfer); | ||
| 29 | kfree(adis->buffer); | ||
| 30 | |||
| 31 | /* All but the timestamp channel */ | ||
| 32 | burst_length = (indio_dev->num_channels - 1) * sizeof(u16); | ||
| 33 | if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) | ||
| 34 | burst_length += sizeof(u16); | ||
| 35 | |||
| 36 | adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); | ||
| 37 | if (!adis->xfer) | ||
| 38 | return -ENOMEM; | ||
| 39 | |||
| 40 | adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); | ||
| 41 | if (!adis->buffer) | ||
| 42 | return -ENOMEM; | ||
| 43 | |||
| 44 | tx = adis->buffer + burst_length; | ||
| 45 | tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); | ||
| 46 | tx[1] = 0; | ||
| 47 | |||
| 48 | adis->xfer[0].tx_buf = tx; | ||
| 49 | adis->xfer[0].bits_per_word = 8; | ||
| 50 | adis->xfer[0].len = 2; | ||
| 51 | adis->xfer[1].rx_buf = adis->buffer; | ||
| 52 | adis->xfer[1].bits_per_word = 8; | ||
| 53 | adis->xfer[1].len = burst_length; | ||
| 54 | |||
| 55 | spi_message_init(&adis->msg); | ||
| 56 | spi_message_add_tail(&adis->xfer[0], &adis->msg); | ||
| 57 | spi_message_add_tail(&adis->xfer[1], &adis->msg); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | irqreturn_t adis16400_trigger_handler(int irq, void *p) | ||
| 63 | { | ||
| 64 | struct iio_poll_func *pf = p; | ||
| 65 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 66 | struct adis16400_state *st = iio_priv(indio_dev); | ||
| 67 | struct adis *adis = &st->adis; | ||
| 68 | u32 old_speed_hz = st->adis.spi->max_speed_hz; | ||
| 69 | void *buffer; | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | if (!adis->buffer) | ||
| 73 | return -ENOMEM; | ||
| 74 | |||
| 75 | if (!(st->variant->flags & ADIS16400_NO_BURST) && | ||
| 76 | st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { | ||
| 77 | st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; | ||
| 78 | spi_setup(st->adis.spi); | ||
| 79 | } | ||
| 80 | |||
| 81 | ret = spi_sync(adis->spi, &adis->msg); | ||
| 82 | if (ret) | ||
| 83 | dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); | ||
| 84 | |||
| 85 | if (!(st->variant->flags & ADIS16400_NO_BURST)) { | ||
| 86 | st->adis.spi->max_speed_hz = old_speed_hz; | ||
| 87 | spi_setup(st->adis.spi); | ||
| 88 | } | ||
| 89 | |||
| 90 | if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) | ||
| 91 | buffer = adis->buffer + sizeof(u16); | ||
| 92 | else | ||
| 93 | buffer = adis->buffer; | ||
| 94 | |||
| 95 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, | ||
| 96 | pf->timestamp); | ||
| 97 | |||
| 98 | iio_trigger_notify_done(indio_dev->trig); | ||
| 99 | |||
| 100 | return IRQ_HANDLED; | ||
| 101 | } | ||
| @@ -9,6 +9,9 @@ · 8 unmodified lines | |||
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/clk.h> | ||
| 13 | #include <linux/bitfield.h> | ||
| 14 | #include <linux/of_irq.h> | ||
| 12 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 13 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 14 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
| @@ -97,6 +100,12 @@ · 82 unmodified lines | |||
| 97 | #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) | 100 | #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) |
| 98 | #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) | 101 | #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) |
| 99 | 102 | ||
| 103 | /* | ||
| 104 | * External clock scaling in PPS mode. | ||
| 105 | * Available only for ADIS1649x devices | ||
| 106 | */ | ||
| 107 | #define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) | ||
| 108 | |||
| 100 | #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) | 109 | #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) |
| 101 | 110 | ||
| 102 | /* Each filter coefficent bank spans two pages */ | 111 | /* Each filter coefficent bank spans two pages */ |
| @@ -107,6 +116,20 @@ · 4 unmodified lines | |||
| 107 | #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) | 116 | #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) |
| 108 | #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) | 117 | #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) |
| 109 | 118 | ||
| 119 | /* ADIS16480_REG_FNCTIO_CTRL */ | ||
| 120 | #define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0) | ||
| 121 | #define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x) | ||
| 122 | #define ADIS16480_DRDY_POL_MSK BIT(2) | ||
| 123 | #define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x) | ||
| 124 | #define ADIS16480_DRDY_EN_MSK BIT(3) | ||
| 125 | #define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x) | ||
| 126 | #define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4) | ||
| 127 | #define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x) | ||
| 128 | #define ADIS16480_SYNC_EN_MSK BIT(7) | ||
| 129 | #define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x) | ||
| 130 | #define ADIS16480_SYNC_MODE_MSK BIT(8) | ||
| 131 | #define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) | ||
| 132 | |||
| 110 | struct adis16480_chip_info { | 133 | struct adis16480_chip_info { |
| 111 | unsigned int num_channels; | 134 | unsigned int num_channels; |
| 112 | const struct iio_chan_spec *channels; | 135 | const struct iio_chan_spec *channels; |
| @@ -114,12 +137,40 @@ struct adis16480_chip_info { · 1 unmodified line | |||
| 114 | unsigned int gyro_max_scale; | 137 | unsigned int gyro_max_scale; |
| 115 | unsigned int accel_max_val; | 138 | unsigned int accel_max_val; |
| 116 | unsigned int accel_max_scale; | 139 | unsigned int accel_max_scale; |
| 140 | unsigned int temp_scale; | ||
| 141 | unsigned int int_clk; | ||
| 142 | unsigned int max_dec_rate; | ||
| 143 | const unsigned int *filter_freqs; | ||
| 144 | bool has_pps_clk_mode; | ||
| 145 | }; | ||
| 146 | |||
| 147 | enum adis16480_int_pin { | ||
| 148 | ADIS16480_PIN_DIO1, | ||
| 149 | ADIS16480_PIN_DIO2, | ||
| 150 | ADIS16480_PIN_DIO3, | ||
| 151 | ADIS16480_PIN_DIO4 | ||
| 152 | }; | ||
| 153 | |||
| 154 | enum adis16480_clock_mode { | ||
| 155 | ADIS16480_CLK_SYNC, | ||
| 156 | ADIS16480_CLK_PPS, | ||
| 157 | ADIS16480_CLK_INT | ||
| 117 | }; | 158 | }; |
| 118 | 159 | ||
| 119 | struct adis16480 { | 160 | struct adis16480 { |
| 120 | const struct adis16480_chip_info *chip_info; | 161 | const struct adis16480_chip_info *chip_info; |
| 121 | 162 | ||
| 122 | struct adis adis; | 163 | struct adis adis; |
| 164 | struct clk *ext_clk; | ||
| 165 | enum adis16480_clock_mode clk_mode; | ||
| 166 | unsigned int clk_freq; | ||
| 167 | }; | ||
| 168 | |||
| 169 | static const char * const adis16480_int_pin_names[4] = { | ||
| 170 | [ADIS16480_PIN_DIO1] = "DIO1", | ||
| 171 | [ADIS16480_PIN_DIO2] = "DIO2", | ||
| 172 | [ADIS16480_PIN_DIO3] = "DIO3", | ||
| 173 | [ADIS16480_PIN_DIO4] = "DIO4", | ||
| 123 | }; | 174 | }; |
| 124 | 175 | ||
| 125 | #ifdef CONFIG_DEBUG_FS | 176 | #ifdef CONFIG_DEBUG_FS |
| @@ -268,20 +319,34 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev) · 142 unmodified lines | |||
| 268 | static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) | 319 | static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) |
| 269 | { | 320 | { |
| 270 | struct adis16480 *st = iio_priv(indio_dev); | 321 | struct adis16480 *st = iio_priv(indio_dev); |
| 271 | unsigned int t; | 322 | unsigned int t, reg; |
| 272 | 323 | ||
| 273 | t = val * 1000 + val2 / 1000; | 324 | t = val * 1000 + val2 / 1000; |
| 274 | if (t <= 0) | 325 | if (t <= 0) |
| 275 | return -EINVAL; | 326 | return -EINVAL; |
| 276 | 327 | ||
| 277 | t = 2460000 / t; | 328 | /* |
| 278 | if (t > 2048) | 329 | * When using PPS mode, the rate of data collection is equal to the |
| 279 | t = 2048; | 330 | * product of the external clock frequency and the scale factor in the |
| 331 | * SYNC_SCALE register. | ||
| 332 | * When using sync mode, or internal clock, the output data rate is | ||
| 333 | * equal with the clock frequency divided by DEC_RATE + 1. | ||
| 334 | */ | ||
| 335 | if (st->clk_mode == ADIS16480_CLK_PPS) { | ||
| 336 | t = t / st->clk_freq; | ||
| 337 | reg = ADIS16495_REG_SYNC_SCALE; | ||
| 338 | } else { | ||
| 339 | t = st->clk_freq / t; | ||
| 340 | reg = ADIS16480_REG_DEC_RATE; | ||
| 341 | } | ||
| 342 | |||
| 343 | if (t > st->chip_info->max_dec_rate) | ||
| 344 | t = st->chip_info->max_dec_rate; | ||
| 280 | 345 | ||
| 281 | if (t != 0) | 346 | if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS)) |
| 282 | t--; | 347 | t--; |
| 283 | 348 | ||
| 284 | return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); | 349 | return adis_write_reg_16(&st->adis, reg, t); |
| 285 | } | 350 | } |
| 286 | 351 | ||
| 287 | static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) | 352 | static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) |
| @@ -290,12 +355,29 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) · 2 unmodified lines | |||
| 290 | uint16_t t; | 355 | uint16_t t; |
| 291 | int ret; | 356 | int ret; |
| 292 | unsigned freq; | 357 | unsigned freq; |
| 358 | unsigned int reg; | ||
| 293 | 359 | ||
| 294 | ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); | 360 | if (st->clk_mode == ADIS16480_CLK_PPS) |
| 361 | reg = ADIS16495_REG_SYNC_SCALE; | ||
| 362 | else | ||
| 363 | reg = ADIS16480_REG_DEC_RATE; | ||
| 364 | |||
| 365 | ret = adis_read_reg_16(&st->adis, reg, &t); | ||
| 295 | if (ret < 0) | 366 | if (ret < 0) |
| 296 | return ret; | 367 | return ret; |
| 297 | 368 | ||
| 298 | freq = 2460000 / (t + 1); | 369 | /* |
| 370 | * When using PPS mode, the rate of data collection is equal to the | ||
| 371 | * product of the external clock frequency and the scale factor in the | ||
| 372 | * SYNC_SCALE register. | ||
| 373 | * When using sync mode, or internal clock, the output data rate is | ||
| 374 | * equal with the clock frequency divided by DEC_RATE + 1. | ||
| 375 | */ | ||
| 376 | if (st->clk_mode == ADIS16480_CLK_PPS) | ||
| 377 | freq = st->clk_freq * t; | ||
| 378 | else | ||
| 379 | freq = st->clk_freq / (t + 1); | ||
| 380 | |||
| 299 | *val = freq / 1000; | 381 | *val = freq / 1000; |
| 300 | *val2 = (freq % 1000) * 1000; | 382 | *val2 = (freq % 1000) * 1000; |
| 301 | 383 | ||
| @@ -425,6 +507,13 @@ static const unsigned int adis16480_def_filter_freqs[] = { · 123 unmodified lines | |||
| 425 | 63, | 507 | 63, |
| 426 | }; | 508 | }; |
| 427 | 509 | ||
| 510 | static const unsigned int adis16495_def_filter_freqs[] = { | ||
| 511 | 300, | ||
| 512 | 100, | ||
| 513 | 300, | ||
| 514 | 100, | ||
| 515 | }; | ||
| 516 | |||
| 428 | static const unsigned int ad16480_filter_data[][2] = { | 517 | static const unsigned int ad16480_filter_data[][2] = { |
| 429 | [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, | 518 | [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, |
| 430 | [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, | 519 | [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, |
| @@ -456,7 +545,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev, · 25 unmodified lines | |||
| 456 | if (!(val & enable_mask)) | 545 | if (!(val & enable_mask)) |
| 457 | *freq = 0; | 546 | *freq = 0; |
| 458 | else | 547 | else |
| 459 | *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3]; | 548 | *freq = st->chip_info->filter_freqs[(val >> offset) & 0x3]; |
| 460 | 549 | ||
| 461 | return IIO_VAL_INT; | 550 | return IIO_VAL_INT; |
| 462 | } | 551 | } |
| @@ -483,10 +572,10 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, · 20 unmodified lines | |||
| 483 | val &= ~enable_mask; | 572 | val &= ~enable_mask; |
| 484 | } else { | 573 | } else { |
| 485 | best_freq = 0; | 574 | best_freq = 0; |
| 486 | best_diff = 310; | 575 | best_diff = st->chip_info->filter_freqs[0]; |
| 487 | for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { | 576 | for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { |
| 488 | if (adis16480_def_filter_freqs[i] >= freq) { | 577 | if (st->chip_info->filter_freqs[i] >= freq) { |
| 489 | diff = adis16480_def_filter_freqs[i] - freq; | 578 | diff = st->chip_info->filter_freqs[i] - freq; |
| 490 | if (diff < best_diff) { | 579 | if (diff < best_diff) { |
| 491 | best_diff = diff; | 580 | best_diff = diff; |
| 492 | best_freq = i; | 581 | best_freq = i; |
| @@ -506,6 +595,7 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, · 13 unmodified lines | |||
| 506 | const struct iio_chan_spec *chan, int *val, int *val2, long info) | 595 | const struct iio_chan_spec *chan, int *val, int *val2, long info) |
| 507 | { | 596 | { |
| 508 | struct adis16480 *st = iio_priv(indio_dev); | 597 | struct adis16480 *st = iio_priv(indio_dev); |
| 598 | unsigned int temp; | ||
| 509 | 599 | ||
| 510 | switch (info) { | 600 | switch (info) { |
| 511 | case IIO_CHAN_INFO_RAW: | 601 | case IIO_CHAN_INFO_RAW: |
| @@ -525,8 +615,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, · 13 unmodified lines | |||
| 525 | *val2 = 100; /* 0.0001 gauss */ | 615 | *val2 = 100; /* 0.0001 gauss */ |
| 526 | return IIO_VAL_INT_PLUS_MICRO; | 616 | return IIO_VAL_INT_PLUS_MICRO; |
| 527 | case IIO_TEMP: | 617 | case IIO_TEMP: |
| 528 | *val = 5; | 618 | /* |
| 529 | *val2 = 650000; /* 5.65 milli degree Celsius */ | 619 | * +85 degrees Celsius = temp_max_scale |
| 620 | * +25 degrees Celsius = 0 | ||
| 621 | * LSB, 25 degrees Celsius = 60 / temp_max_scale | ||
| 622 | */ | ||
| 623 | *val = st->chip_info->temp_scale / 1000; | ||
| 624 | *val2 = (st->chip_info->temp_scale % 1000) * 1000; | ||
| 530 | return IIO_VAL_INT_PLUS_MICRO; | 625 | return IIO_VAL_INT_PLUS_MICRO; |
| 531 | case IIO_PRESSURE: | 626 | case IIO_PRESSURE: |
| 532 | *val = 0; | 627 | *val = 0; |
| @@ -537,7 +632,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev, · 4 unmodified lines | |||
| 537 | } | 632 | } |
| 538 | case IIO_CHAN_INFO_OFFSET: | 633 | case IIO_CHAN_INFO_OFFSET: |
| 539 | /* Only the temperature channel has a offset */ | 634 | /* Only the temperature channel has a offset */ |
| 540 | *val = 4425; /* 25 degree Celsius = 0x0000 */ | 635 | temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */ |
| 636 | *val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale); | ||
| 541 | return IIO_VAL_INT; | 637 | return IIO_VAL_INT; |
| 542 | case IIO_CHAN_INFO_CALIBBIAS: | 638 | case IIO_CHAN_INFO_CALIBBIAS: |
| 543 | return adis16480_get_calibbias(indio_dev, chan, val); | 639 | return adis16480_get_calibbias(indio_dev, chan, val); |
| @@ -678,6 +774,12 @@ enum adis16480_variant { · 134 unmodified lines | |||
| 678 | ADIS16480, | 774 | ADIS16480, |
| 679 | ADIS16485, | 775 | ADIS16485, |
| 680 | ADIS16488, | 776 | ADIS16488, |
| 777 | ADIS16495_1, | ||
| 778 | ADIS16495_2, | ||
| 779 | ADIS16495_3, | ||
| 780 | ADIS16497_1, | ||
| 781 | ADIS16497_2, | ||
| 782 | ADIS16497_3, | ||
| 681 | }; | 783 | }; |
| 682 | 784 | ||
| 683 | static const struct adis16480_chip_info adis16480_chip_info[] = { | 785 | static const struct adis16480_chip_info adis16480_chip_info[] = { |
| @@ -693,6 +795,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 9 unmodified lines | |||
| 693 | .gyro_max_scale = 300, | 795 | .gyro_max_scale = 300, |
| 694 | .accel_max_val = IIO_M_S_2_TO_G(21973), | 796 | .accel_max_val = IIO_M_S_2_TO_G(21973), |
| 695 | .accel_max_scale = 18, | 797 | .accel_max_scale = 18, |
| 798 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 799 | .int_clk = 2460000, | ||
| 800 | .max_dec_rate = 2048, | ||
| 801 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 696 | }, | 802 | }, |
| 697 | [ADIS16480] = { | 803 | [ADIS16480] = { |
| 698 | .channels = adis16480_channels, | 804 | .channels = adis16480_channels, |
| @@ -701,6 +807,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 2 unmodified lines | |||
| 701 | .gyro_max_scale = 450, | 807 | .gyro_max_scale = 450, |
| 702 | .accel_max_val = IIO_M_S_2_TO_G(12500), | 808 | .accel_max_val = IIO_M_S_2_TO_G(12500), |
| 703 | .accel_max_scale = 10, | 809 | .accel_max_scale = 10, |
| 810 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 811 | .int_clk = 2460000, | ||
| 812 | .max_dec_rate = 2048, | ||
| 813 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 704 | }, | 814 | }, |
| 705 | [ADIS16485] = { | 815 | [ADIS16485] = { |
| 706 | .channels = adis16485_channels, | 816 | .channels = adis16485_channels, |
| @@ -709,6 +819,10 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 2 unmodified lines | |||
| 709 | .gyro_max_scale = 450, | 819 | .gyro_max_scale = 450, |
| 710 | .accel_max_val = IIO_M_S_2_TO_G(20000), | 820 | .accel_max_val = IIO_M_S_2_TO_G(20000), |
| 711 | .accel_max_scale = 5, | 821 | .accel_max_scale = 5, |
| 822 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 823 | .int_clk = 2460000, | ||
| 824 | .max_dec_rate = 2048, | ||
| 825 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 712 | }, | 826 | }, |
| 713 | [ADIS16488] = { | 827 | [ADIS16488] = { |
| 714 | .channels = adis16480_channels, | 828 | .channels = adis16480_channels, |
| @@ -717,6 +831,88 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 2 unmodified lines | |||
| 717 | .gyro_max_scale = 450, | 831 | .gyro_max_scale = 450, |
| 718 | .accel_max_val = IIO_M_S_2_TO_G(22500), | 832 | .accel_max_val = IIO_M_S_2_TO_G(22500), |
| 719 | .accel_max_scale = 18, | 833 | .accel_max_scale = 18, |
| 834 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 835 | .int_clk = 2460000, | ||
| 836 | .max_dec_rate = 2048, | ||
| 837 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 838 | }, | ||
| 839 | [ADIS16495_1] = { | ||
| 840 | .channels = adis16485_channels, | ||
| 841 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 842 | .gyro_max_val = IIO_RAD_TO_DEGREE(20000), | ||
| 843 | .gyro_max_scale = 125, | ||
| 844 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 845 | .accel_max_scale = 8, | ||
| 846 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 847 | .int_clk = 4250000, | ||
| 848 | .max_dec_rate = 4250, | ||
| 849 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 850 | .has_pps_clk_mode = true, | ||
| 851 | }, | ||
| 852 | [ADIS16495_2] = { | ||
| 853 | .channels = adis16485_channels, | ||
| 854 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 855 | .gyro_max_val = IIO_RAD_TO_DEGREE(18000), | ||
| 856 | .gyro_max_scale = 450, | ||
| 857 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 858 | .accel_max_scale = 8, | ||
| 859 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 860 | .int_clk = 4250000, | ||
| 861 | .max_dec_rate = 4250, | ||
| 862 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 863 | .has_pps_clk_mode = true, | ||
| 864 | }, | ||
| 865 | [ADIS16495_3] = { | ||
| 866 | .channels = adis16485_channels, | ||
| 867 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 868 | .gyro_max_val = IIO_RAD_TO_DEGREE(20000), | ||
| 869 | .gyro_max_scale = 2000, | ||
| 870 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 871 | .accel_max_scale = 8, | ||
| 872 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 873 | .int_clk = 4250000, | ||
| 874 | .max_dec_rate = 4250, | ||
| 875 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 876 | .has_pps_clk_mode = true, | ||
| 877 | }, | ||
| 878 | [ADIS16497_1] = { | ||
| 879 | .channels = adis16485_channels, | ||
| 880 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 881 | .gyro_max_val = IIO_RAD_TO_DEGREE(20000), | ||
| 882 | .gyro_max_scale = 125, | ||
| 883 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 884 | .accel_max_scale = 40, | ||
| 885 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 886 | .int_clk = 4250000, | ||
| 887 | .max_dec_rate = 4250, | ||
| 888 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 889 | .has_pps_clk_mode = true, | ||
| 890 | }, | ||
| 891 | [ADIS16497_2] = { | ||
| 892 | .channels = adis16485_channels, | ||
| 893 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 894 | .gyro_max_val = IIO_RAD_TO_DEGREE(18000), | ||
| 895 | .gyro_max_scale = 450, | ||
| 896 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 897 | .accel_max_scale = 40, | ||
| 898 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 899 | .int_clk = 4250000, | ||
| 900 | .max_dec_rate = 4250, | ||
| 901 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 902 | .has_pps_clk_mode = true, | ||
| 903 | }, | ||
| 904 | [ADIS16497_3] = { | ||
| 905 | .channels = adis16485_channels, | ||
| 906 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 907 | .gyro_max_val = IIO_RAD_TO_DEGREE(20000), | ||
| 908 | .gyro_max_scale = 2000, | ||
| 909 | .accel_max_val = IIO_M_S_2_TO_G(32000), | ||
| 910 | .accel_max_scale = 40, | ||
| 911 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | ||
| 912 | .int_clk = 4250000, | ||
| 913 | .max_dec_rate = 4250, | ||
| 914 | .filter_freqs = adis16495_def_filter_freqs, | ||
| 915 | .has_pps_clk_mode = true, | ||
| 720 | }, | 916 | }, |
| 721 | }; | 917 | }; |
| 722 | 918 | ||
| @@ -741,8 +937,17 @@ static int adis16480_stop_device(struct iio_dev *indio_dev) · 18 unmodified lines | |||
| 741 | 937 | ||
| 742 | static int adis16480_enable_irq(struct adis *adis, bool enable) | 938 | static int adis16480_enable_irq(struct adis *adis, bool enable) |
| 743 | { | 939 | { |
| 744 | return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, | 940 | uint16_t val; |
| 745 | enable ? BIT(3) : 0); | 941 | int ret; |
| 942 | |||
| 943 | ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); | ||
| 944 | if (ret < 0) | ||
| 945 | return ret; | ||
| 946 | |||
| 947 | val &= ~ADIS16480_DRDY_EN_MSK; | ||
| 948 | val |= ADIS16480_DRDY_EN(enable); | ||
| 949 | |||
| 950 | return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); | ||
| 746 | } | 951 | } |
| 747 | 952 | ||
| 748 | static int adis16480_initial_setup(struct iio_dev *indio_dev) | 953 | static int adis16480_initial_setup(struct iio_dev *indio_dev) |
| @@ -826,6 +1031,156 @@ static const struct adis_data adis16480_data = { · 77 unmodified lines | |||
| 826 | .enable_irq = adis16480_enable_irq, | 1031 | .enable_irq = adis16480_enable_irq, |
| 827 | }; | 1032 | }; |
| 828 | 1033 | ||
| 1034 | static int adis16480_config_irq_pin(struct device_node *of_node, | ||
| 1035 | struct adis16480 *st) | ||
| 1036 | { | ||
| 1037 | struct irq_data *desc; | ||
| 1038 | enum adis16480_int_pin pin; | ||
| 1039 | unsigned int irq_type; | ||
| 1040 | uint16_t val; | ||
| 1041 | int i, irq = 0; | ||
| 1042 | |||
| 1043 | desc = irq_get_irq_data(st->adis.spi->irq); | ||
| 1044 | if (!desc) { | ||
| 1045 | dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq); | ||
| 1046 | return -EINVAL; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /* Disable data ready since the default after reset is on */ | ||
| 1050 | val = ADIS16480_DRDY_EN(0); | ||
| 1051 | |||
| 1052 | /* | ||
| 1053 | * Get the interrupt from the devicetre by reading the interrupt-names | ||
| 1054 | * property. If it is not specified, use DIO1 pin as default. | ||
| 1055 | * According to the datasheet, the factory default assigns DIO2 as data | ||
| 1056 | * ready signal. However, in the previous versions of the driver, DIO1 | ||
| 1057 | * pin was used. So, we should leave it as is since some devices might | ||
| 1058 | * be expecting the interrupt on the wrong physical pin. | ||
| 1059 | */ | ||
| 1060 | pin = ADIS16480_PIN_DIO1; | ||
| 1061 | for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { | ||
| 1062 | irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]); | ||
| 1063 | if (irq > 0) { | ||
| 1064 | pin = i; | ||
| 1065 | break; | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | val |= ADIS16480_DRDY_SEL(pin); | ||
| 1070 | |||
| 1071 | /* | ||
| 1072 | * Get the interrupt line behaviour. The data ready polarity can be | ||
| 1073 | * configured as positive or negative, corresponding to | ||
| 1074 | * IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING respectively. | ||
| 1075 | */ | ||
| 1076 | irq_type = irqd_get_trigger_type(desc); | ||
| 1077 | if (irq_type == IRQF_TRIGGER_RISING) { /* Default */ | ||
| 1078 | val |= ADIS16480_DRDY_POL(1); | ||
| 1079 | } else if (irq_type == IRQF_TRIGGER_FALLING) { | ||
| 1080 | val |= ADIS16480_DRDY_POL(0); | ||
| 1081 | } else { | ||
| 1082 | dev_err(&st->adis.spi->dev, | ||
| 1083 | "Invalid interrupt type 0x%x specified\n", irq_type); | ||
| 1084 | return -EINVAL; | ||
| 1085 | } | ||
| 1086 | /* Write the data ready configuration to the FNCTIO_CTRL register */ | ||
| 1087 | return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static int adis16480_of_get_ext_clk_pin(struct adis16480 *st, | ||
| 1091 | struct device_node *of_node) | ||
| 1092 | { | ||
| 1093 | const char *ext_clk_pin; | ||
| 1094 | enum adis16480_int_pin pin; | ||
| 1095 | int i; | ||
| 1096 | |||
| 1097 | pin = ADIS16480_PIN_DIO2; | ||
| 1098 | if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin)) | ||
| 1099 | goto clk_input_not_found; | ||
| 1100 | |||
| 1101 | for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { | ||
| 1102 | if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0) | ||
| 1103 | return i; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | clk_input_not_found: | ||
| 1107 | dev_info(&st->adis.spi->dev, | ||
| 1108 | "clk input line not specified, using DIO2\n"); | ||
| 1109 | return pin; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | static int adis16480_ext_clk_config(struct adis16480 *st, | ||
| 1113 | struct device_node *of_node, | ||
| 1114 | bool enable) | ||
| 1115 | { | ||
| 1116 | unsigned int mode, mask; | ||
| 1117 | enum adis16480_int_pin pin; | ||
| 1118 | uint16_t val; | ||
| 1119 | int ret; | ||
| 1120 | |||
| 1121 | ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); | ||
| 1122 | if (ret < 0) | ||
| 1123 | return ret; | ||
| 1124 | |||
| 1125 | pin = adis16480_of_get_ext_clk_pin(st, of_node); | ||
| 1126 | /* | ||
| 1127 | * Each DIOx pin supports only one function at a time. When a single pin | ||
| 1128 | * has two assignments, the enable bit for a lower priority function | ||
| 1129 | * automatically resets to zero (disabling the lower priority function). | ||
| 1130 | */ | ||
| 1131 | if (pin == ADIS16480_DRDY_SEL(val)) | ||
| 1132 | dev_warn(&st->adis.spi->dev, | ||
| 1133 | "DIO%x pin supports only one function at a time\n", | ||
| 1134 | pin + 1); | ||
| 1135 | |||
| 1136 | mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin); | ||
| 1137 | mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK; | ||
| 1138 | /* Only ADIS1649x devices support pps ext clock mode */ | ||
| 1139 | if (st->chip_info->has_pps_clk_mode) { | ||
| 1140 | mode |= ADIS16480_SYNC_MODE(st->clk_mode); | ||
| 1141 | mask |= ADIS16480_SYNC_MODE_MSK; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | val &= ~mask; | ||
| 1145 | val |= mode; | ||
| 1146 | |||
| 1147 | ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); | ||
| 1148 | if (ret < 0) | ||
| 1149 | return ret; | ||
| 1150 | |||
| 1151 | return clk_prepare_enable(st->ext_clk); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | static int adis16480_get_ext_clocks(struct adis16480 *st) | ||
| 1155 | { | ||
| 1156 | st->clk_mode = ADIS16480_CLK_INT; | ||
| 1157 | st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync"); | ||
| 1158 | if (!IS_ERR_OR_NULL(st->ext_clk)) { | ||
| 1159 | st->clk_mode = ADIS16480_CLK_SYNC; | ||
| 1160 | return 0; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | if (PTR_ERR(st->ext_clk) != -ENOENT) { | ||
| 1164 | dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); | ||
| 1165 | return PTR_ERR(st->ext_clk); | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | if (st->chip_info->has_pps_clk_mode) { | ||
| 1169 | st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps"); | ||
| 1170 | if (!IS_ERR_OR_NULL(st->ext_clk)) { | ||
| 1171 | st->clk_mode = ADIS16480_CLK_PPS; | ||
| 1172 | return 0; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | if (PTR_ERR(st->ext_clk) != -ENOENT) { | ||
| 1176 | dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); | ||
| 1177 | return PTR_ERR(st->ext_clk); | ||
| 1178 | } | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | return 0; | ||
| 1182 | } | ||
| 1183 | |||
| 829 | static int adis16480_probe(struct spi_device *spi) | 1184 | static int adis16480_probe(struct spi_device *spi) |
| 830 | { | 1185 | { |
| 831 | const struct spi_device_id *id = spi_get_device_id(spi); | 1186 | const struct spi_device_id *id = spi_get_device_id(spi); |
| @@ -853,10 +1208,29 @@ static int adis16480_probe(struct spi_device *spi) · 21 unmodified lines | |||
| 853 | if (ret) | 1208 | if (ret) |
| 854 | return ret; | 1209 | return ret; |
| 855 | 1210 | ||
| 856 | ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); | 1211 | ret = adis16480_config_irq_pin(spi->dev.of_node, st); |
| 1212 | if (ret) | ||
| 1213 | return ret; | ||
| 1214 | |||
| 1215 | ret = adis16480_get_ext_clocks(st); | ||
| 857 | if (ret) | 1216 | if (ret) |
| 858 | return ret; | 1217 | return ret; |
| 859 | 1218 | ||
| 1219 | if (!IS_ERR_OR_NULL(st->ext_clk)) { | ||
| 1220 | ret = adis16480_ext_clk_config(st, spi->dev.of_node, true); | ||
| 1221 | if (ret) | ||
| 1222 | return ret; | ||
| 1223 | |||
| 1224 | st->clk_freq = clk_get_rate(st->ext_clk); | ||
| 1225 | st->clk_freq *= 1000; /* micro */ | ||
| 1226 | } else { | ||
| 1227 | st->clk_freq = st->chip_info->int_clk; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); | ||
| 1231 | if (ret) | ||
| 1232 | goto error_clk_disable_unprepare; | ||
| 1233 | |||
| 860 | ret = adis16480_initial_setup(indio_dev); | 1234 | ret = adis16480_initial_setup(indio_dev); |
| 861 | if (ret) | 1235 | if (ret) |
| 862 | goto error_cleanup_buffer; | 1236 | goto error_cleanup_buffer; |
| @@ -873,6 +1247,8 @@ error_stop_device: · 10 unmodified lines | |||
| 873 | adis16480_stop_device(indio_dev); | 1247 | adis16480_stop_device(indio_dev); |
| 874 | error_cleanup_buffer: | 1248 | error_cleanup_buffer: |
| 875 | adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | 1249 | adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); |
| 1250 | error_clk_disable_unprepare: | ||
| 1251 | clk_disable_unprepare(st->ext_clk); | ||
| 876 | return ret; | 1252 | return ret; |
| 877 | } | 1253 | } |
| 878 | 1254 | ||
| @@ -885,6 +1261,7 @@ static int adis16480_remove(struct spi_device *spi) · 6 unmodified lines | |||
| 885 | adis16480_stop_device(indio_dev); | 1261 | adis16480_stop_device(indio_dev); |
| 886 | 1262 | ||
| 887 | adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | 1263 | adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); |
| 1264 | clk_disable_unprepare(st->ext_clk); | ||
| 888 | 1265 | ||
| 889 | return 0; | 1266 | return 0; |
| 890 | } | 1267 | } |
| @@ -894,13 +1271,35 @@ static const struct spi_device_id adis16480_ids[] = { · 3 unmodified lines | |||
| 894 | { "adis16480", ADIS16480 }, | 1271 | { "adis16480", ADIS16480 }, |
| 895 | { "adis16485", ADIS16485 }, | 1272 | { "adis16485", ADIS16485 }, |
| 896 | { "adis16488", ADIS16488 }, | 1273 | { "adis16488", ADIS16488 }, |
| 1274 | { "adis16495-1", ADIS16495_1 }, | ||
| 1275 | { "adis16495-2", ADIS16495_2 }, | ||
| 1276 | { "adis16495-3", ADIS16495_3 }, | ||
| 1277 | { "adis16497-1", ADIS16497_1 }, | ||
| 1278 | { "adis16497-2", ADIS16497_2 }, | ||
| 1279 | { "adis16497-3", ADIS16497_3 }, | ||
| 897 | { } | 1280 | { } |
| 898 | }; | 1281 | }; |
| 899 | MODULE_DEVICE_TABLE(spi, adis16480_ids); | 1282 | MODULE_DEVICE_TABLE(spi, adis16480_ids); |
| 900 | 1283 | ||
| 1284 | static const struct of_device_id adis16480_of_match[] = { | ||
| 1285 | { .compatible = "adi,adis16375" }, | ||
| 1286 | { .compatible = "adi,adis16480" }, | ||
| 1287 | { .compatible = "adi,adis16485" }, | ||
| 1288 | { .compatible = "adi,adis16488" }, | ||
| 1289 | { .compatible = "adi,adis16495-1" }, | ||
| 1290 | { .compatible = "adi,adis16495-2" }, | ||
| 1291 | { .compatible = "adi,adis16495-3" }, | ||
| 1292 | { .compatible = "adi,adis16497-1" }, | ||
| 1293 | { .compatible = "adi,adis16497-2" }, | ||
| 1294 | { .compatible = "adi,adis16497-3" }, | ||
| 1295 | { }, | ||
| 1296 | }; | ||
| 1297 | MODULE_DEVICE_TABLE(of, adis16480_of_match); | ||
| 1298 | |||
| 901 | static struct spi_driver adis16480_driver = { | 1299 | static struct spi_driver adis16480_driver = { |
| 902 | .driver = { | 1300 | .driver = { |
| 903 | .name = "adis16480", | 1301 | .name = "adis16480", |
| 1302 | .of_match_table = adis16480_of_match, | ||
| 904 | }, | 1303 | }, |
| 905 | .id_table = adis16480_ids, | 1304 | .id_table = adis16480_ids, |
| 906 | .probe = adis16480_probe, | 1305 | .probe = adis16480_probe, |
| @@ -20,6 +20,43 @@ · 19 unmodified lines | |||
| 20 | #include <linux/iio/triggered_buffer.h> | 20 | #include <linux/iio/triggered_buffer.h> |
| 21 | #include <linux/iio/imu/adis.h> | 21 | #include <linux/iio/imu/adis.h> |
| 22 | 22 | ||
| 23 | static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, | ||
| 24 | const unsigned long *scan_mask) | ||
| 25 | { | ||
| 26 | struct adis *adis = iio_device_get_drvdata(indio_dev); | ||
| 27 | unsigned int burst_length; | ||
| 28 | u8 *tx; | ||
| 29 | |||
| 30 | /* All but the timestamp channel */ | ||
| 31 | burst_length = (indio_dev->num_channels - 1) * sizeof(u16); | ||
| 32 | burst_length += adis->burst->extra_len; | ||
| 33 | |||
| 34 | adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); | ||
| 35 | if (!adis->xfer) | ||
| 36 | return -ENOMEM; | ||
| 37 | |||
| 38 | adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL); | ||
| 39 | if (!adis->buffer) | ||
| 40 | return -ENOMEM; | ||
| 41 | |||
| 42 | tx = adis->buffer + burst_length; | ||
| 43 | tx[0] = ADIS_READ_REG(adis->burst->reg_cmd); | ||
| 44 | tx[1] = 0; | ||
| 45 | |||
| 46 | adis->xfer[0].tx_buf = tx; | ||
| 47 | adis->xfer[0].bits_per_word = 8; | ||
| 48 | adis->xfer[0].len = 2; | ||
| 49 | adis->xfer[1].rx_buf = adis->buffer; | ||
| 50 | adis->xfer[1].bits_per_word = 8; | ||
| 51 | adis->xfer[1].len = burst_length; | ||
| 52 | |||
| 53 | spi_message_init(&adis->msg); | ||
| 54 | spi_message_add_tail(&adis->xfer[0], &adis->msg); | ||
| 55 | spi_message_add_tail(&adis->xfer[1], &adis->msg); | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 23 | int adis_update_scan_mode(struct iio_dev *indio_dev, | 60 | int adis_update_scan_mode(struct iio_dev *indio_dev, |
| 24 | const unsigned long *scan_mask) | 61 | const unsigned long *scan_mask) |
| 25 | { | 62 | { |
| @@ -32,6 +69,9 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 32 | kfree(adis->xfer); | 69 | kfree(adis->xfer); |
| 33 | kfree(adis->buffer); | 70 | kfree(adis->buffer); |
| 34 | 71 | ||
| 72 | if (adis->burst && adis->burst->en) | ||
| 73 | return adis_update_scan_mode_burst(indio_dev, scan_mask); | ||
| 74 | |||
| 35 | scan_count = indio_dev->scan_bytes / 2; | 75 | scan_count = indio_dev->scan_bytes / 2; |
| 36 | 76 | ||
| 37 | adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL); | 77 | adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL); |
| @@ -796,12 +796,14 @@ static const struct iio_mount_matrix * · 795 unmodified lines | |||
| 796 | inv_get_mount_matrix(const struct iio_dev *indio_dev, | 796 | inv_get_mount_matrix(const struct iio_dev *indio_dev, |
| 797 | const struct iio_chan_spec *chan) | 797 | const struct iio_chan_spec *chan) |
| 798 | { | 798 | { |
| 799 | return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation; | 799 | struct inv_mpu6050_state *data = iio_priv(indio_dev); |
| 800 | |||
| 801 | return &data->orientation; | ||
| 800 | } | 802 | } |
| 801 | 803 | ||
| 802 | static const struct iio_chan_spec_ext_info inv_ext_info[] = { | 804 | static const struct iio_chan_spec_ext_info inv_ext_info[] = { |
| 803 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix), | 805 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix), |
| 804 | { }, | 806 | { } |
| 805 | }; | 807 | }; |
| 806 | 808 | ||
| 807 | #define INV_MPU6050_CHAN(_type, _channel2, _index) \ | 809 | #define INV_MPU6050_CHAN(_type, _channel2, _index) \ |
| @@ -1021,8 +1023,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, · 213 unmodified lines | |||
| 1021 | 1023 | ||
| 1022 | pdata = dev_get_platdata(dev); | 1024 | pdata = dev_get_platdata(dev); |
| 1023 | if (!pdata) { | 1025 | if (!pdata) { |
| 1024 | result = of_iio_read_mount_matrix(dev, "mount-matrix", | 1026 | result = iio_read_mount_matrix(dev, "mount-matrix", |
| 1025 | &st->orientation); | 1027 | &st->orientation); |
| 1026 | if (result) { | 1028 | if (result) { |
| 1027 | dev_err(dev, "Failed to retrieve mounting matrix %d\n", | 1029 | dev_err(dev, "Failed to retrieve mounting matrix %d\n", |
| 1028 | result); | 1030 | result); |
| @@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX · 8 unmodified lines | |||
| 9 | help | 9 | help |
| 10 | Say yes here to build support for STMicroelectronics LSM6DSx imu | 10 | Say yes here to build support for STMicroelectronics LSM6DSx imu |
| 11 | sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, | 11 | sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, |
| 12 | ism330dlc, lsm6dso | 12 | ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr |
| 13 | 13 | ||
| 14 | To compile this driver as a module, choose M here: the module | 14 | To compile this driver as a module, choose M here: the module |
| 15 | will be called st_lsm6dsx. | 15 | will be called st_lsm6dsx. |
| @@ -20,6 +20,9 @@ · 19 unmodified lines | |||
| 20 | #define ST_LSM6DSM_DEV_NAME "lsm6dsm" | 20 | #define ST_LSM6DSM_DEV_NAME "lsm6dsm" |
| 21 | #define ST_ISM330DLC_DEV_NAME "ism330dlc" | 21 | #define ST_ISM330DLC_DEV_NAME "ism330dlc" |
| 22 | #define ST_LSM6DSO_DEV_NAME "lsm6dso" | 22 | #define ST_LSM6DSO_DEV_NAME "lsm6dso" |
| 23 | #define ST_ASM330LHH_DEV_NAME "asm330lhh" | ||
| 24 | #define ST_LSM6DSOX_DEV_NAME "lsm6dsox" | ||
| 25 | #define ST_LSM6DSR_DEV_NAME "lsm6dsr" | ||
| 23 | 26 | ||
| 24 | enum st_lsm6dsx_hw_id { | 27 | enum st_lsm6dsx_hw_id { |
| 25 | ST_LSM6DS3_ID, | 28 | ST_LSM6DS3_ID, |
| @@ -28,6 +31,9 @@ enum st_lsm6dsx_hw_id { · 2 unmodified lines | |||
| 28 | ST_LSM6DSM_ID, | 31 | ST_LSM6DSM_ID, |
| 29 | ST_ISM330DLC_ID, | 32 | ST_ISM330DLC_ID, |
| 30 | ST_LSM6DSO_ID, | 33 | ST_LSM6DSO_ID, |
| 34 | ST_ASM330LHH_ID, | ||
| 35 | ST_LSM6DSOX_ID, | ||
| 36 | ST_LSM6DSR_ID, | ||
| 31 | ST_LSM6DSX_MAX_ID, | 37 | ST_LSM6DSX_MAX_ID, |
| 32 | }; | 38 | }; |
| 33 | 39 | ||
| @@ -13,9 +13,9 @@ · 12 unmodified lines | |||
| 13 | * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the | 13 | * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the |
| 14 | * value of the decimation factor and ODR set for each FIFO data set. | 14 | * value of the decimation factor and ODR set for each FIFO data set. |
| 15 | * | 15 | * |
| 16 | * LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and | 16 | * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR: The FIFO buffer can be configured to |
| 17 | * accelerometer. Each sample is queued with a tag (1B) indicating data source | 17 | * store data from gyroscope and accelerometer. Each sample is queued with |
| 18 | * (gyroscope, accelerometer, hw timer). | 18 | * a tag (1B) indicating data source (gyroscope, accelerometer, hw timer). |
| 19 | * | 19 | * |
| 20 | * FIFO supported modes: | 20 | * FIFO supported modes: |
| 21 | * - BYPASS: FIFO disabled | 21 | * - BYPASS: FIFO disabled |
| @@ -506,7 +506,7 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, · 484 unmodified lines | |||
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | /** | 508 | /** |
| 509 | * st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine | 509 | * st_lsm6dsx_read_tagged_fifo() - tagged hw FIFO read routine |
| 510 | * @hw: Pointer to instance of struct st_lsm6dsx_hw. | 510 | * @hw: Pointer to instance of struct st_lsm6dsx_hw. |
| 511 | * | 511 | * |
| 512 | * Read samples from the hw FIFO and push them to IIO buffers. | 512 | * Read samples from the hw FIFO and push them to IIO buffers. |
| @@ -517,7 +517,6 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) · 4 unmodified lines | |||
| 517 | { | 517 | { |
| 518 | u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE; | 518 | u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE; |
| 519 | u16 fifo_len, fifo_diff_mask; | 519 | u16 fifo_len, fifo_diff_mask; |
| 520 | struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor; | ||
| 521 | u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag; | 520 | u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag; |
| 522 | bool reset_ts = false; | 521 | bool reset_ts = false; |
| 523 | int i, err, read_len; | 522 | int i, err, read_len; |
| @@ -539,9 +538,6 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) · 15 unmodified lines | |||
| 539 | if (!fifo_len) | 538 | if (!fifo_len) |
| 540 | return 0; | 539 | return 0; |
| 541 | 540 | ||
| 542 | acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); | ||
| 543 | gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]); | ||
| 544 | |||
| 545 | for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { | 541 | for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { |
| 546 | err = st_lsm6dsx_read_block(hw, | 542 | err = st_lsm6dsx_read_block(hw, |
| 547 | ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR, | 543 | ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR, |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 | 23 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 |
| 24 | * - FIFO size: 4KB | 24 | * - FIFO size: 4KB |
| 25 | * | 25 | * |
| 26 | * - LSM6DSO | 26 | * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR |
| 27 | * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 | 27 | * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 |
| 28 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 | 28 | * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 |
| 29 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 | 29 | * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 |
| @@ -62,37 +62,19 @@ · 32 unmodified lines | |||
| 62 | #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 | 62 | #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 |
| 63 | #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) | 63 | #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) |
| 64 | 64 | ||
| 65 | #define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10 | ||
| 66 | #define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4) | ||
| 67 | #define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10 | ||
| 68 | #define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2) | ||
| 69 | #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 | 65 | #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 |
| 70 | #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a | 66 | #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a |
| 71 | #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c | 67 | #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c |
| 72 | 68 | ||
| 73 | #define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11 | ||
| 74 | #define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4) | ||
| 75 | #define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11 | ||
| 76 | #define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2) | ||
| 77 | #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 | 69 | #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 |
| 78 | #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 | 70 | #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 |
| 79 | #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 | 71 | #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 |
| 80 | 72 | ||
| 81 | #define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) | ||
| 82 | #define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) | ||
| 83 | #define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) | ||
| 84 | #define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488) | ||
| 85 | |||
| 86 | #define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(8750) | ||
| 87 | #define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500) | ||
| 88 | #define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000) | ||
| 89 | #define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000) | ||
| 90 | |||
| 91 | static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { | 73 | static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { |
| 92 | [ST_LSM6DSX_ID_ACC] = { | 74 | [ST_LSM6DSX_ID_ACC] = { |
| 93 | .reg = { | 75 | .reg = { |
| 94 | .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR, | 76 | .addr = 0x10, |
| 95 | .mask = ST_LSM6DSX_REG_ACC_ODR_MASK, | 77 | .mask = GENMASK(7, 4), |
| 96 | }, | 78 | }, |
| 97 | .odr_avl[0] = { 13, 0x01 }, | 79 | .odr_avl[0] = { 13, 0x01 }, |
| 98 | .odr_avl[1] = { 26, 0x02 }, | 80 | .odr_avl[1] = { 26, 0x02 }, |
| @@ -103,8 +85,8 @@ static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { · 4 unmodified lines | |||
| 103 | }, | 85 | }, |
| 104 | [ST_LSM6DSX_ID_GYRO] = { | 86 | [ST_LSM6DSX_ID_GYRO] = { |
| 105 | .reg = { | 87 | .reg = { |
| 106 | .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR, | 88 | .addr = 0x11, |
| 107 | .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK, | 89 | .mask = GENMASK(7, 4), |
| 108 | }, | 90 | }, |
| 109 | .odr_avl[0] = { 13, 0x01 }, | 91 | .odr_avl[0] = { 13, 0x01 }, |
| 110 | .odr_avl[1] = { 26, 0x02 }, | 92 | .odr_avl[1] = { 26, 0x02 }, |
| @@ -118,23 +100,23 @@ static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { · 7 unmodified lines | |||
| 118 | static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { | 100 | static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { |
| 119 | [ST_LSM6DSX_ID_ACC] = { | 101 | [ST_LSM6DSX_ID_ACC] = { |
| 120 | .reg = { | 102 | .reg = { |
| 121 | .addr = ST_LSM6DSX_REG_ACC_FS_ADDR, | 103 | .addr = 0x10, |
| 122 | .mask = ST_LSM6DSX_REG_ACC_FS_MASK, | 104 | .mask = GENMASK(3, 2), |
| 123 | }, | 105 | }, |
| 124 | .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 }, | 106 | .fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 }, |
| 125 | .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 }, | 107 | .fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 }, |
| 126 | .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 }, | 108 | .fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 }, |
| 127 | .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 }, | 109 | .fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 }, |
| 128 | }, | 110 | }, |
| 129 | [ST_LSM6DSX_ID_GYRO] = { | 111 | [ST_LSM6DSX_ID_GYRO] = { |
| 130 | .reg = { | 112 | .reg = { |
| 131 | .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR, | 113 | .addr = 0x11, |
| 132 | .mask = ST_LSM6DSX_REG_GYRO_FS_MASK, | 114 | .mask = GENMASK(3, 2), |
| 133 | }, | 115 | }, |
| 134 | .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 }, | 116 | .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, |
| 135 | .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 }, | 117 | .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, |
| 136 | .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 }, | 118 | .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 }, |
| 137 | .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 }, | 119 | .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, |
| 138 | } | 120 | } |
| 139 | }; | 121 | }; |
| 140 | 122 | ||
| @@ -287,6 +269,111 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { · 146 unmodified lines | |||
| 287 | .max_fifo_size = 512, | 269 | .max_fifo_size = 512, |
| 288 | .id = { | 270 | .id = { |
| 289 | [0] = ST_LSM6DSO_ID, | 271 | [0] = ST_LSM6DSO_ID, |
| 272 | [1] = ST_LSM6DSOX_ID, | ||
| 273 | }, | ||
| 274 | .batch = { | ||
| 275 | [ST_LSM6DSX_ID_ACC] = { | ||
| 276 | .addr = 0x09, | ||
| 277 | .mask = GENMASK(3, 0), | ||
| 278 | }, | ||
| 279 | [ST_LSM6DSX_ID_GYRO] = { | ||
| 280 | .addr = 0x09, | ||
| 281 | .mask = GENMASK(7, 4), | ||
| 282 | }, | ||
| 283 | }, | ||
| 284 | .fifo_ops = { | ||
| 285 | .read_fifo = st_lsm6dsx_read_tagged_fifo, | ||
| 286 | .fifo_th = { | ||
| 287 | .addr = 0x07, | ||
| 288 | .mask = GENMASK(8, 0), | ||
| 289 | }, | ||
| 290 | .fifo_diff = { | ||
| 291 | .addr = 0x3a, | ||
| 292 | .mask = GENMASK(8, 0), | ||
| 293 | }, | ||
| 294 | .th_wl = 1, | ||
| 295 | }, | ||
| 296 | .ts_settings = { | ||
| 297 | .timer_en = { | ||
| 298 | .addr = 0x19, | ||
| 299 | .mask = BIT(5), | ||
| 300 | }, | ||
| 301 | .decimator = { | ||
| 302 | .addr = 0x0a, | ||
| 303 | .mask = GENMASK(7, 6), | ||
| 304 | }, | ||
| 305 | }, | ||
| 306 | .shub_settings = { | ||
| 307 | .page_mux = { | ||
| 308 | .addr = 0x01, | ||
| 309 | .mask = BIT(6), | ||
| 310 | }, | ||
| 311 | .master_en = { | ||
| 312 | .addr = 0x14, | ||
| 313 | .mask = BIT(2), | ||
| 314 | }, | ||
| 315 | .pullup_en = { | ||
| 316 | .addr = 0x14, | ||
| 317 | .mask = BIT(3), | ||
| 318 | }, | ||
| 319 | .aux_sens = { | ||
| 320 | .addr = 0x14, | ||
| 321 | .mask = GENMASK(1, 0), | ||
| 322 | }, | ||
| 323 | .wr_once = { | ||
| 324 | .addr = 0x14, | ||
| 325 | .mask = BIT(6), | ||
| 326 | }, | ||
| 327 | .shub_out = 0x02, | ||
| 328 | .slv0_addr = 0x15, | ||
| 329 | .dw_slv0_addr = 0x21, | ||
| 330 | .batch_en = BIT(3), | ||
| 331 | } | ||
| 332 | }, | ||
| 333 | { | ||
| 334 | .wai = 0x6b, | ||
| 335 | .max_fifo_size = 512, | ||
| 336 | .id = { | ||
| 337 | [0] = ST_ASM330LHH_ID, | ||
| 338 | }, | ||
| 339 | .batch = { | ||
| 340 | [ST_LSM6DSX_ID_ACC] = { | ||
| 341 | .addr = 0x09, | ||
| 342 | .mask = GENMASK(3, 0), | ||
| 343 | }, | ||
| 344 | [ST_LSM6DSX_ID_GYRO] = { | ||
| 345 | .addr = 0x09, | ||
| 346 | .mask = GENMASK(7, 4), | ||
| 347 | }, | ||
| 348 | }, | ||
| 349 | .fifo_ops = { | ||
| 350 | .read_fifo = st_lsm6dsx_read_tagged_fifo, | ||
| 351 | .fifo_th = { | ||
| 352 | .addr = 0x07, | ||
| 353 | .mask = GENMASK(8, 0), | ||
| 354 | }, | ||
| 355 | .fifo_diff = { | ||
| 356 | .addr = 0x3a, | ||
| 357 | .mask = GENMASK(8, 0), | ||
| 358 | }, | ||
| 359 | .th_wl = 1, | ||
| 360 | }, | ||
| 361 | .ts_settings = { | ||
| 362 | .timer_en = { | ||
| 363 | .addr = 0x19, | ||
| 364 | .mask = BIT(5), | ||
| 365 | }, | ||
| 366 | .decimator = { | ||
| 367 | .addr = 0x0a, | ||
| 368 | .mask = GENMASK(7, 6), | ||
| 369 | }, | ||
| 370 | }, | ||
| 371 | }, | ||
| 372 | { | ||
| 373 | .wai = 0x6b, | ||
| 374 | .max_fifo_size = 512, | ||
| 375 | .id = { | ||
| 376 | [0] = ST_LSM6DSR_ID, | ||
| 290 | }, | 377 | }, |
| 291 | .batch = { | 378 | .batch = { |
| 292 | [ST_LSM6DSX_ID_ACC] = { | 379 | [ST_LSM6DSX_ID_ACC] = { |
| @@ -65,6 +65,18 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { · 64 unmodified lines | |||
| 65 | .compatible = "st,lsm6dso", | 65 | .compatible = "st,lsm6dso", |
| 66 | .data = (void *)ST_LSM6DSO_ID, | 66 | .data = (void *)ST_LSM6DSO_ID, |
| 67 | }, | 67 | }, |
| 68 | { | ||
| 69 | .compatible = "st,asm330lhh", | ||
| 70 | .data = (void *)ST_ASM330LHH_ID, | ||
| 71 | }, | ||
| 72 | { | ||
| 73 | .compatible = "st,lsm6dsox", | ||
| 74 | .data = (void *)ST_LSM6DSOX_ID, | ||
| 75 | }, | ||
| 76 | { | ||
| 77 | .compatible = "st,lsm6dsr", | ||
| 78 | .data = (void *)ST_LSM6DSR_ID, | ||
| 79 | }, | ||
| 68 | {}, | 80 | {}, |
| 69 | }; | 81 | }; |
| 70 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); | 82 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); |
| @@ -76,6 +88,9 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { · 5 unmodified lines | |||
| 76 | { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, | 88 | { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, |
| 77 | { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, | 89 | { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, |
| 78 | { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, | 90 | { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, |
| 91 | { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, | ||
| 92 | { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, | ||
| 93 | { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, | ||
| 79 | {}, | 94 | {}, |
| 80 | }; | 95 | }; |
| 81 | MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); | 96 | MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); |
| @@ -65,6 +65,18 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { · 64 unmodified lines | |||
| 65 | .compatible = "st,lsm6dso", | 65 | .compatible = "st,lsm6dso", |
| 66 | .data = (void *)ST_LSM6DSO_ID, | 66 | .data = (void *)ST_LSM6DSO_ID, |
| 67 | }, | 67 | }, |
| 68 | { | ||
| 69 | .compatible = "st,asm330lhh", | ||
| 70 | .data = (void *)ST_ASM330LHH_ID, | ||
| 71 | }, | ||
| 72 | { | ||
| 73 | .compatible = "st,lsm6dsox", | ||
| 74 | .data = (void *)ST_LSM6DSOX_ID, | ||
| 75 | }, | ||
| 76 | { | ||
| 77 | .compatible = "st,lsm6dsr", | ||
| 78 | .data = (void *)ST_LSM6DSR_ID, | ||
| 79 | }, | ||
| 68 | {}, | 80 | {}, |
| 69 | }; | 81 | }; |
| 70 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); | 82 | MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); |
| @@ -76,6 +88,9 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { · 5 unmodified lines | |||
| 76 | { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, | 88 | { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, |
| 77 | { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, | 89 | { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, |
| 78 | { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, | 90 | { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, |
| 91 | { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, | ||
| 92 | { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, | ||
| 93 | { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, | ||
| 79 | {}, | 94 | {}, |
| 80 | }; | 95 | }; |
| 81 | MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); | 96 | MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); |
| @@ -343,12 +343,12 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, · 342 unmodified lines | |||
| 343 | } | 343 | } |
| 344 | bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); | 344 | bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); |
| 345 | 345 | ||
| 346 | kfree(trialmask); | 346 | bitmap_free(trialmask); |
| 347 | 347 | ||
| 348 | return 0; | 348 | return 0; |
| 349 | 349 | ||
| 350 | err_invalid_mask: | 350 | err_invalid_mask: |
| 351 | kfree(trialmask); | 351 | bitmap_free(trialmask); |
| 352 | return -EINVAL; | 352 | return -EINVAL; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| @@ -665,7 +665,7 @@ static void iio_free_scan_mask(struct iio_dev *indio_dev, · 310 unmodified lines | |||
| 665 | { | 665 | { |
| 666 | /* If the mask is dynamically allocated free it, otherwise do nothing */ | 666 | /* If the mask is dynamically allocated free it, otherwise do nothing */ |
| 667 | if (!indio_dev->available_scan_masks) | 667 | if (!indio_dev->available_scan_masks) |
| 668 | kfree(mask); | 668 | bitmap_free(mask); |
| 669 | } | 669 | } |
| 670 | 670 | ||
| 671 | struct iio_device_config { | 671 | struct iio_device_config { |
| @@ -735,8 +735,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, · 63 unmodified lines | |||
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | /* What scan mask do we actually have? */ | 737 | /* What scan mask do we actually have? */ |
| 738 | compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), | 738 | compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); |
| 739 | sizeof(long), GFP_KERNEL); | ||
| 740 | if (compound_mask == NULL) | 739 | if (compound_mask == NULL) |
| 741 | return -ENOMEM; | 740 | return -ENOMEM; |
| 742 | 741 | ||
| @@ -761,7 +760,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, · 18 unmodified lines | |||
| 761 | indio_dev->masklength, | 760 | indio_dev->masklength, |
| 762 | compound_mask, | 761 | compound_mask, |
| 763 | strict_scanmask); | 762 | strict_scanmask); |
| 764 | kfree(compound_mask); | 763 | bitmap_free(compound_mask); |
| 765 | if (scan_mask == NULL) | 764 | if (scan_mask == NULL) |
| 766 | return -EINVAL; | 765 | return -EINVAL; |
| 767 | } else { | 766 | } else { |
| @@ -1302,9 +1301,8 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) · 534 unmodified lines | |||
| 1302 | channels[i].scan_index; | 1301 | channels[i].scan_index; |
| 1303 | } | 1302 | } |
| 1304 | if (indio_dev->masklength && buffer->scan_mask == NULL) { | 1303 | if (indio_dev->masklength && buffer->scan_mask == NULL) { |
| 1305 | buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), | 1304 | buffer->scan_mask = bitmap_zalloc(indio_dev->masklength, |
| 1306 | sizeof(*buffer->scan_mask), | 1305 | GFP_KERNEL); |
| 1307 | GFP_KERNEL); | ||
| 1308 | if (buffer->scan_mask == NULL) { | 1306 | if (buffer->scan_mask == NULL) { |
| 1309 | ret = -ENOMEM; | 1307 | ret = -ENOMEM; |
| 1310 | goto error_cleanup_dynamic; | 1308 | goto error_cleanup_dynamic; |
| @@ -1333,7 +1331,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) · 22 unmodified lines | |||
| 1333 | return 0; | 1331 | return 0; |
| 1334 | 1332 | ||
| 1335 | error_free_scan_mask: | 1333 | error_free_scan_mask: |
| 1336 | kfree(buffer->scan_mask); | 1334 | bitmap_free(buffer->scan_mask); |
| 1337 | error_cleanup_dynamic: | 1335 | error_cleanup_dynamic: |
| 1338 | iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); | 1336 | iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); |
| 1339 | kfree(indio_dev->buffer->buffer_group.attrs); | 1337 | kfree(indio_dev->buffer->buffer_group.attrs); |
| @@ -1346,7 +1344,7 @@ void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) · 6 unmodified lines | |||
| 1346 | if (!indio_dev->buffer) | 1344 | if (!indio_dev->buffer) |
| 1347 | return; | 1345 | return; |
| 1348 | 1346 | ||
| 1349 | kfree(indio_dev->buffer->scan_mask); | 1347 | bitmap_free(indio_dev->buffer->scan_mask); |
| 1350 | kfree(indio_dev->buffer->buffer_group.attrs); | 1348 | kfree(indio_dev->buffer->buffer_group.attrs); |
| 1351 | kfree(indio_dev->buffer->scan_el_group.attrs); | 1349 | kfree(indio_dev->buffer->scan_el_group.attrs); |
| 1352 | iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list); | 1350 | iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list); |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
| 20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
| 21 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
| 22 | #include <linux/property.h> | ||
| 22 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
| 23 | #include <linux/wait.h> | 24 | #include <linux/wait.h> |
| 24 | #include <linux/cdev.h> | 25 | #include <linux/cdev.h> |
| @@ -530,8 +531,8 @@ ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, · 505 unmodified lines | |||
| 530 | EXPORT_SYMBOL_GPL(iio_show_mount_matrix); | 531 | EXPORT_SYMBOL_GPL(iio_show_mount_matrix); |
| 531 | 532 | ||
| 532 | /** | 533 | /** |
| 533 | * of_iio_read_mount_matrix() - retrieve iio device mounting matrix from | 534 | * iio_read_mount_matrix() - retrieve iio device mounting matrix from |
| 534 | * device-tree "mount-matrix" property | 535 | * device "mount-matrix" property |
| 535 | * @dev: device the mounting matrix property is assigned to | 536 | * @dev: device the mounting matrix property is assigned to |
| 536 | * @propname: device specific mounting matrix property name | 537 | * @propname: device specific mounting matrix property name |
| 537 | * @matrix: where to store retrieved matrix | 538 | * @matrix: where to store retrieved matrix |
| @@ -541,40 +542,29 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix); · 3 unmodified lines | |||
| 541 | * | 542 | * |
| 542 | * Return: 0 if success, or a negative error code on failure. | 543 | * Return: 0 if success, or a negative error code on failure. |
| 543 | */ | 544 | */ |
| 544 | #ifdef CONFIG_OF | 545 | int iio_read_mount_matrix(struct device *dev, const char *propname, |
| 545 | int of_iio_read_mount_matrix(const struct device *dev, | 546 | struct iio_mount_matrix *matrix) |
| 546 | const char *propname, | ||
| 547 | struct iio_mount_matrix *matrix) | ||
| 548 | { | 547 | { |
| 549 | if (dev->of_node) { | 548 | size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation); |
| 550 | int err = of_property_read_string_array(dev->of_node, | 549 | int err; |
| 551 | propname, matrix->rotation, | ||
| 552 | ARRAY_SIZE(iio_mount_idmatrix.rotation)); | ||
| 553 | 550 | ||
| 554 | if (err == ARRAY_SIZE(iio_mount_idmatrix.rotation)) | 551 | err = device_property_read_string_array(dev, propname, |
| 555 | return 0; | 552 | matrix->rotation, len); |
| 553 | if (err == len) | ||
| 554 | return 0; | ||
| 556 | 555 | ||
| 557 | if (err >= 0) | 556 | if (err >= 0) |
| 558 | /* Invalid number of matrix entries. */ | 557 | /* Invalid number of matrix entries. */ |
| 559 | return -EINVAL; | 558 | return -EINVAL; |
| 560 | 559 | ||
| 561 | if (err != -EINVAL) | 560 | if (err != -EINVAL) |
| 562 | /* Invalid matrix declaration format. */ | 561 | /* Invalid matrix declaration format. */ |
| 563 | return err; | 562 | return err; |
| 564 | } | ||
| 565 | 563 | ||
| 566 | /* Matrix was not declared at all: fallback to identity. */ | 564 | /* Matrix was not declared at all: fallback to identity. */ |
| 567 | return iio_setup_mount_idmatrix(dev, matrix); | 565 | return iio_setup_mount_idmatrix(dev, matrix); |
| 568 | } | 566 | } |
| 569 | #else | 567 | EXPORT_SYMBOL(iio_read_mount_matrix); |
| 570 | int of_iio_read_mount_matrix(const struct device *dev, | ||
| 571 | const char *propname, | ||
| 572 | struct iio_mount_matrix *matrix) | ||
| 573 | { | ||
| 574 | return iio_setup_mount_idmatrix(dev, matrix); | ||
| 575 | } | ||
| 576 | #endif | ||
| 577 | EXPORT_SYMBOL(of_iio_read_mount_matrix); | ||
| 578 | 568 | ||
| 579 | static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, | 569 | static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, |
| 580 | int size, const int *vals) | 570 | int size, const int *vals) |
| @@ -254,8 +254,11 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, · 253 unmodified lines | |||
| 254 | 254 | ||
| 255 | /* Get irq number */ | 255 | /* Get irq number */ |
| 256 | pf->irq = iio_trigger_get_irq(trig); | 256 | pf->irq = iio_trigger_get_irq(trig); |
| 257 | if (pf->irq < 0) | 257 | if (pf->irq < 0) { |
| 258 | pr_err("Could not find an available irq for trigger %s, CONFIG_IIO_CONSUMERS_PER_TRIGGER=%d limit might be exceeded\n", | ||
| 259 | trig->name, CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
| 258 | goto out_put_module; | 260 | goto out_put_module; |
| 261 | } | ||
| 259 | 262 | ||
| 260 | /* Request irq */ | 263 | /* Request irq */ |
| 261 | ret = request_threaded_irq(pf->irq, pf->h, pf->thread, | 264 | ret = request_threaded_irq(pf->irq, pf->h, pf->thread, |
| @@ -13,11 +13,11 @@ config ACPI_ALS · 12 unmodified lines | |||
| 13 | select IIO_TRIGGERED_BUFFER | 13 | select IIO_TRIGGERED_BUFFER |
| 14 | select IIO_KFIFO_BUF | 14 | select IIO_KFIFO_BUF |
| 15 | help | 15 | help |
| 16 | Say Y here if you want to build a driver for the ACPI0008 | 16 | Say Y here if you want to build a driver for the ACPI0008 |
| 17 | Ambient Light Sensor. | 17 | Ambient Light Sensor. |
| 18 | 18 | ||
| 19 | To compile this driver as a module, choose M here: the module will | 19 | To compile this driver as a module, choose M here: the module will |
| 20 | be called acpi-als. | 20 | be called acpi-als. |
| 21 | 21 | ||
| 22 | config ADJD_S311 | 22 | config ADJD_S311 |
| 23 | tristate "ADJD-S311-CR999 digital color sensor" | 23 | tristate "ADJD-S311-CR999 digital color sensor" |
| @@ -25,31 +25,31 @@ config ADJD_S311 · 1 unmodified line | |||
| 25 | select IIO_TRIGGERED_BUFFER | 25 | select IIO_TRIGGERED_BUFFER |
| 26 | depends on I2C | 26 | depends on I2C |
| 27 | help | 27 | help |
| 28 | If you say yes here you get support for the Avago ADJD-S311-CR999 | 28 | If you say yes here you get support for the Avago ADJD-S311-CR999 |
| 29 | digital color light sensor. | 29 | digital color light sensor. |
| 30 | 30 | ||
| 31 | This driver can also be built as a module. If so, the module | 31 | This driver can also be built as a module. If so, the module |
| 32 | will be called adjd_s311. | 32 | will be called adjd_s311. |
| 33 | 33 | ||
| 34 | config AL3320A | 34 | config AL3320A |
| 35 | tristate "AL3320A ambient light sensor" | 35 | tristate "AL3320A ambient light sensor" |
| 36 | depends on I2C | 36 | depends on I2C |
| 37 | help | 37 | help |
| 38 | Say Y here if you want to build a driver for the Dyna Image AL3320A | 38 | Say Y here if you want to build a driver for the Dyna Image AL3320A |
| 39 | ambient light sensor. | 39 | ambient light sensor. |
| 40 | 40 | ||
| 41 | To compile this driver as a module, choose M here: the | 41 | To compile this driver as a module, choose M here: the |
| 42 | module will be called al3320a. | 42 | module will be called al3320a. |
| 43 | 43 | ||
| 44 | config APDS9300 | 44 | config APDS9300 |
| 45 | tristate "APDS9300 ambient light sensor" | 45 | tristate "APDS9300 ambient light sensor" |
| 46 | depends on I2C | 46 | depends on I2C |
| 47 | help | 47 | help |
| 48 | Say Y here if you want to build a driver for the Avago APDS9300 | 48 | Say Y here if you want to build a driver for the Avago APDS9300 |
| 49 | ambient light sensor. | 49 | ambient light sensor. |
| 50 | 50 | ||
| 51 | To compile this driver as a module, choose M here: the | 51 | To compile this driver as a module, choose M here: the |
| 52 | module will be called apds9300. | 52 | module will be called apds9300. |
| 53 | 53 | ||
| 54 | config APDS9960 | 54 | config APDS9960 |
| 55 | tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" | 55 | tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" |
| @@ -68,74 +68,74 @@ config BH1750 · 12 unmodified lines | |||
| 68 | tristate "ROHM BH1750 ambient light sensor" | 68 | tristate "ROHM BH1750 ambient light sensor" |
| 69 | depends on I2C | 69 | depends on I2C |
| 70 | help | 70 | help |
| 71 | Say Y here to build support for the ROHM BH1710, BH1715, BH1721, | 71 | Say Y here to build support for the ROHM BH1710, BH1715, BH1721, |
| 72 | BH1750, BH1751 ambient light sensors. | 72 | BH1750, BH1751 ambient light sensors. |
| 73 | 73 | ||
| 74 | To compile this driver as a module, choose M here: the module will | 74 | To compile this driver as a module, choose M here: the module will |
| 75 | be called bh1750. | 75 | be called bh1750. |
| 76 | 76 | ||
| 77 | config BH1780 | 77 | config BH1780 |
| 78 | tristate "ROHM BH1780 ambient light sensor" | 78 | tristate "ROHM BH1780 ambient light sensor" |
| 79 | depends on I2C | 79 | depends on I2C |
| 80 | help | 80 | help |
| 81 | Say Y here to build support for the ROHM BH1780GLI ambient | 81 | Say Y here to build support for the ROHM BH1780GLI ambient |
| 82 | light sensor. | 82 | light sensor. |
| 83 | 83 | ||
| 84 | To compile this driver as a module, choose M here: the module will | 84 | To compile this driver as a module, choose M here: the module will |
| 85 | be called bh1780. | 85 | be called bh1780. |
| 86 | 86 | ||
| 87 | config CM32181 | 87 | config CM32181 |
| 88 | depends on I2C | 88 | depends on I2C |
| 89 | tristate "CM32181 driver" | 89 | tristate "CM32181 driver" |
| 90 | help | 90 | help |
| 91 | Say Y here if you use cm32181. | 91 | Say Y here if you use cm32181. |
| 92 | This option enables ambient light sensor using | 92 | This option enables ambient light sensor using |
| 93 | Capella cm32181 device driver. | 93 | Capella cm32181 device driver. |
| 94 | 94 | ||
| 95 | To compile this driver as a module, choose M here: | 95 | To compile this driver as a module, choose M here: |
| 96 | the module will be called cm32181. | 96 | the module will be called cm32181. |
| 97 | 97 | ||
| 98 | config CM3232 | 98 | config CM3232 |
| 99 | depends on I2C | 99 | depends on I2C |
| 100 | tristate "CM3232 ambient light sensor" | 100 | tristate "CM3232 ambient light sensor" |
| 101 | help | 101 | help |
| 102 | Say Y here if you use cm3232. | 102 | Say Y here if you use cm3232. |
| 103 | This option enables ambient light sensor using | 103 | This option enables ambient light sensor using |
| 104 | Capella Microsystems cm3232 device driver. | 104 | Capella Microsystems cm3232 device driver. |
| 105 | 105 | ||
| 106 | To compile this driver as a module, choose M here: | 106 | To compile this driver as a module, choose M here: |
| 107 | the module will be called cm3232. | 107 | the module will be called cm3232. |
| 108 | 108 | ||
| 109 | config CM3323 | 109 | config CM3323 |
| 110 | depends on I2C | 110 | depends on I2C |
| 111 | tristate "Capella CM3323 color light sensor" | 111 | tristate "Capella CM3323 color light sensor" |
| 112 | help | 112 | help |
| 113 | Say Y here if you want to build a driver for Capella CM3323 | 113 | Say Y here if you want to build a driver for Capella CM3323 |
| 114 | color sensor. | 114 | color sensor. |
| 115 | 115 | ||
| 116 | To compile this driver as a module, choose M here: the module will | 116 | To compile this driver as a module, choose M here: the module will |
| 117 | be called cm3323. | 117 | be called cm3323. |
| 118 | 118 | ||
| 119 | config CM3605 | 119 | config CM3605 |
| 120 | tristate "Capella CM3605 ambient light and proximity sensor" | 120 | tristate "Capella CM3605 ambient light and proximity sensor" |
| 121 | depends on OF | 121 | depends on OF |
| 122 | help | 122 | help |
| 123 | Say Y here if you want to build a driver for Capella CM3605 | 123 | Say Y here if you want to build a driver for Capella CM3605 |
| 124 | ambient light and short range proximity sensor. | 124 | ambient light and short range proximity sensor. |
| 125 | 125 | ||
| 126 | To compile this driver as a module, choose M here: the module will | 126 | To compile this driver as a module, choose M here: the module will |
| 127 | be called cm3605. | 127 | be called cm3605. |
| 128 | 128 | ||
| 129 | config CM36651 | 129 | config CM36651 |
| 130 | depends on I2C | 130 | depends on I2C |
| 131 | tristate "CM36651 driver" | 131 | tristate "CM36651 driver" |
| 132 | help | 132 | help |
| 133 | Say Y here if you use cm36651. | 133 | Say Y here if you use cm36651. |
| 134 | This option enables proximity & RGB sensor using | 134 | This option enables proximity & RGB sensor using |
| 135 | Capella cm36651 device driver. | 135 | Capella cm36651 device driver. |
| 136 | 136 | ||
| 137 | To compile this driver as a module, choose M here: | 137 | To compile this driver as a module, choose M here: |
| 138 | the module will be called cm36651. | 138 | the module will be called cm36651. |
| 139 | 139 | ||
| 140 | config IIO_CROS_EC_LIGHT_PROX | 140 | config IIO_CROS_EC_LIGHT_PROX |
| 141 | tristate "ChromeOS EC Light and Proximity Sensors" | 141 | tristate "ChromeOS EC Light and Proximity Sensors" |
| @@ -167,21 +167,21 @@ config SENSORS_ISL29018 · 25 unmodified lines | |||
| 167 | select REGMAP_I2C | 167 | select REGMAP_I2C |
| 168 | default n | 168 | default n |
| 169 | help | 169 | help |
| 170 | If you say yes here you get support for ambient light sensing and | 170 | If you say yes here you get support for ambient light sensing and |
| 171 | proximity infrared sensing from Intersil ISL29018. | 171 | proximity infrared sensing from Intersil ISL29018. |
| 172 | This driver will provide the measurements of ambient light intensity | 172 | This driver will provide the measurements of ambient light intensity |
| 173 | in lux, proximity infrared sensing and normal infrared sensing. | 173 | in lux, proximity infrared sensing and normal infrared sensing. |
| 174 | Data from sensor is accessible via sysfs. | 174 | Data from sensor is accessible via sysfs. |
| 175 | 175 | ||
| 176 | config SENSORS_ISL29028 | 176 | config SENSORS_ISL29028 |
| 177 | tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" | 177 | tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" |
| 178 | depends on I2C | 178 | depends on I2C |
| 179 | select REGMAP_I2C | 179 | select REGMAP_I2C |
| 180 | help | 180 | help |
| 181 | Provides driver for the Intersil's ISL29028 device. | 181 | Provides driver for the Intersil's ISL29028 device. |
| 182 | This driver supports the sysfs interface to get the ALS, IR intensity, | 182 | This driver supports the sysfs interface to get the ALS, IR intensity, |
| 183 | Proximity value via iio. The ISL29028 provides the concurrent sensing | 183 | Proximity value via iio. The ISL29028 provides the concurrent sensing |
| 184 | of ambient light and proximity. | 184 | of ambient light and proximity. |
| 185 | 185 | ||
| 186 | config ISL29125 | 186 | config ISL29125 |
| 187 | tristate "Intersil ISL29125 digital color light sensor" | 187 | tristate "Intersil ISL29125 digital color light sensor" |
| @@ -228,22 +228,22 @@ config JSA1212 · 40 unmodified lines | |||
| 228 | depends on I2C | 228 | depends on I2C |
| 229 | select REGMAP_I2C | 229 | select REGMAP_I2C |
| 230 | help | 230 | help |
| 231 | Say Y here if you want to build a IIO driver for JSA1212 | 231 | Say Y here if you want to build a IIO driver for JSA1212 |
| 232 | proximity & ALS sensor device. | 232 | proximity & ALS sensor device. |
| 233 | 233 | ||
| 234 | To compile this driver as a module, choose M here: | 234 | To compile this driver as a module, choose M here: |
| 235 | the module will be called jsa1212. | 235 | the module will be called jsa1212. |
| 236 | 236 | ||
| 237 | config RPR0521 | 237 | config RPR0521 |
| 238 | tristate "ROHM RPR0521 ALS and proximity sensor driver" | 238 | tristate "ROHM RPR0521 ALS and proximity sensor driver" |
| 239 | depends on I2C | 239 | depends on I2C |
| 240 | select REGMAP_I2C | 240 | select REGMAP_I2C |
| 241 | help | 241 | help |
| 242 | Say Y here if you want to build support for ROHM's RPR0521 | 242 | Say Y here if you want to build support for ROHM's RPR0521 |
| 243 | ambient light and proximity sensor device. | 243 | ambient light and proximity sensor device. |
| 244 | 244 | ||
| 245 | To compile this driver as a module, choose M here: | 245 | To compile this driver as a module, choose M here: |
| 246 | the module will be called rpr0521. | 246 | the module will be called rpr0521. |
| 247 | 247 | ||
| 248 | config SENSORS_LM3533 | 248 | config SENSORS_LM3533 |
| 249 | tristate "LM3533 ambient light sensor" | 249 | tristate "LM3533 ambient light sensor" |
| @@ -269,22 +269,22 @@ config LTR501 · 19 unmodified lines | |||
| 269 | select IIO_BUFFER | 269 | select IIO_BUFFER |
| 270 | select IIO_TRIGGERED_BUFFER | 270 | select IIO_TRIGGERED_BUFFER |
| 271 | help | 271 | help |
| 272 | If you say yes here you get support for the Lite-On LTR-501ALS-01 | 272 | If you say yes here you get support for the Lite-On LTR-501ALS-01 |
| 273 | ambient light and proximity sensor. This driver also supports LTR-559 | 273 | ambient light and proximity sensor. This driver also supports LTR-559 |
| 274 | ALS/PS or LTR-301 ALS sensors. | 274 | ALS/PS or LTR-301 ALS sensors. |
| 275 | 275 | ||
| 276 | This driver can also be built as a module. If so, the module | 276 | This driver can also be built as a module. If so, the module |
| 277 | will be called ltr501. | 277 | will be called ltr501. |
| 278 | 278 | ||
| 279 | config LV0104CS | 279 | config LV0104CS |
| 280 | tristate "LV0104CS Ambient Light Sensor" | 280 | tristate "LV0104CS Ambient Light Sensor" |
| 281 | depends on I2C | 281 | depends on I2C |
| 282 | help | 282 | help |
| 283 | Say Y here if you want to build support for the On Semiconductor | 283 | Say Y here if you want to build support for the On Semiconductor |
| 284 | LV0104CS ambient light sensor. | 284 | LV0104CS ambient light sensor. |
| 285 | 285 | ||
| 286 | To compile this driver as a module, choose M here: | 286 | To compile this driver as a module, choose M here: |
| 287 | the module will be called lv0104cs. | 287 | the module will be called lv0104cs. |
| 288 | 288 | ||
| 289 | config MAX44000 | 289 | config MAX44000 |
| 290 | tristate "MAX44000 Ambient and Infrared Proximity Sensor" | 290 | tristate "MAX44000 Ambient and Infrared Proximity Sensor" |
| @@ -293,11 +293,11 @@ config MAX44000 · 2 unmodified lines | |||
| 293 | select IIO_BUFFER | 293 | select IIO_BUFFER |
| 294 | select IIO_TRIGGERED_BUFFER | 294 | select IIO_TRIGGERED_BUFFER |
| 295 | help | 295 | help |
| 296 | Say Y here if you want to build support for Maxim Integrated's | 296 | Say Y here if you want to build support for Maxim Integrated's |
| 297 | MAX44000 ambient and infrared proximity sensor device. | 297 | MAX44000 ambient and infrared proximity sensor device. |
| 298 | 298 | ||
| 299 | To compile this driver as a module, choose M here: | 299 | To compile this driver as a module, choose M here: |
| 300 | the module will be called max44000. | 300 | the module will be called max44000. |
| 301 | 301 | ||
| 302 | config MAX44009 | 302 | config MAX44009 |
| 303 | tristate "MAX44009 Ambient Light Sensor" | 303 | tristate "MAX44009 Ambient Light Sensor" |
| @@ -320,15 +320,15 @@ config OPT3001 · 16 unmodified lines | |||
| 320 | opt3001. | 320 | opt3001. |
| 321 | 321 | ||
| 322 | config PA12203001 | 322 | config PA12203001 |
| 323 | tristate "TXC PA12203001 light and proximity sensor" | 323 | tristate "TXC PA12203001 light and proximity sensor" |
| 324 | depends on I2C | 324 | depends on I2C |
| 325 | select REGMAP_I2C | 325 | select REGMAP_I2C |
| 326 | help | 326 | help |
| 327 | If you say yes here you get support for the TXC PA12203001 | 327 | If you say yes here you get support for the TXC PA12203001 |
| 328 | ambient light and proximity sensor. | 328 | ambient light and proximity sensor. |
| 329 | 329 | ||
| 330 | This driver can also be built as a module. If so, the module | 330 | This driver can also be built as a module. If so, the module |
| 331 | will be called pa12203001. | 331 | will be called pa12203001. |
| 332 | 332 | ||
| 333 | config SI1133 | 333 | config SI1133 |
| 334 | tristate "SI1133 UV Index Sensor and Ambient Light Sensor" | 334 | tristate "SI1133 UV Index Sensor and Ambient Light Sensor" |
| @@ -359,12 +359,12 @@ config STK3310 · 24 unmodified lines | |||
| 359 | depends on I2C | 359 | depends on I2C |
| 360 | select REGMAP_I2C | 360 | select REGMAP_I2C |
| 361 | help | 361 | help |
| 362 | Say yes here to get support for the Sensortek STK3310 ambient light | 362 | Say yes here to get support for the Sensortek STK3310 ambient light |
| 363 | and proximity sensor. The STK3311 model is also supported by this | 363 | and proximity sensor. The STK3311 model is also supported by this |
| 364 | driver. | 364 | driver. |
| 365 | 365 | ||
| 366 | Choosing M will build the driver as a module. If so, the module | 366 | Choosing M will build the driver as a module. If so, the module |
| 367 | will be called stk3310. | 367 | will be called stk3310. |
| 368 | 368 | ||
| 369 | config ST_UVIS25 | 369 | config ST_UVIS25 |
| 370 | tristate "STMicroelectronics UVIS25 sensor driver" | 370 | tristate "STMicroelectronics UVIS25 sensor driver" |
| @@ -396,11 +396,11 @@ config TCS3414 · 25 unmodified lines | |||
| 396 | select IIO_BUFFER | 396 | select IIO_BUFFER |
| 397 | select IIO_TRIGGERED_BUFFER | 397 | select IIO_TRIGGERED_BUFFER |
| 398 | help | 398 | help |
| 399 | If you say yes here you get support for the TAOS TCS3414 | 399 | If you say yes here you get support for the TAOS TCS3414 |
| 400 | family of digital color sensors. | 400 | family of digital color sensors. |
| 401 | 401 | ||
| 402 | This driver can also be built as a module. If so, the module | 402 | This driver can also be built as a module. If so, the module |
| 403 | will be called tcs3414. | 403 | will be called tcs3414. |
| 404 | 404 | ||
| 405 | config TCS3472 | 405 | config TCS3472 |
| 406 | tristate "TAOS TCS3472 color light-to-digital converter" | 406 | tristate "TAOS TCS3472 color light-to-digital converter" |
| @@ -408,67 +408,67 @@ config TCS3472 · 1 unmodified line | |||
| 408 | select IIO_BUFFER | 408 | select IIO_BUFFER |
| 409 | select IIO_TRIGGERED_BUFFER | 409 | select IIO_TRIGGERED_BUFFER |
| 410 | help | 410 | help |
| 411 | If you say yes here you get support for the TAOS TCS3472 | 411 | If you say yes here you get support for the TAOS TCS3472 |
| 412 | family of color light-to-digital converters with IR filter. | 412 | family of color light-to-digital converters with IR filter. |
| 413 | 413 | ||
| 414 | This driver can also be built as a module. If so, the module | 414 | This driver can also be built as a module. If so, the module |
| 415 | will be called tcs3472. | 415 | will be called tcs3472. |
| 416 | 416 | ||
| 417 | config SENSORS_TSL2563 | 417 | config SENSORS_TSL2563 |
| 418 | tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" | 418 | tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" |
| 419 | depends on I2C | 419 | depends on I2C |
| 420 | help | 420 | help |
| 421 | If you say yes here you get support for the Taos TSL2560, | 421 | If you say yes here you get support for the Taos TSL2560, |
| 422 | TSL2561, TSL2562 and TSL2563 ambient light sensors. | 422 | TSL2561, TSL2562 and TSL2563 ambient light sensors. |
| 423 | 423 | ||
| 424 | This driver can also be built as a module. If so, the module | 424 | This driver can also be built as a module. If so, the module |
| 425 | will be called tsl2563. | 425 | will be called tsl2563. |
| 426 | 426 | ||
| 427 | config TSL2583 | 427 | config TSL2583 |
| 428 | tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters" | 428 | tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters" |
| 429 | depends on I2C | 429 | depends on I2C |
| 430 | help | 430 | help |
| 431 | Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. | 431 | Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. |
| 432 | Access ALS data via iio, sysfs. | 432 | Access ALS data via iio, sysfs. |
| 433 | 433 | ||
| 434 | config TSL2772 | 434 | config TSL2772 |
| 435 | tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" | 435 | tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" |
| 436 | depends on I2C | 436 | depends on I2C |
| 437 | help | 437 | help |
| 438 | Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, | 438 | Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, |
| 439 | tmd2672, tsl2772, tmd2772 devices. | 439 | tmd2672, tsl2772, tmd2772 devices. |
| 440 | Provides iio_events and direct access via sysfs. | 440 | Provides iio_events and direct access via sysfs. |
| 441 | 441 | ||
| 442 | config TSL4531 | 442 | config TSL4531 |
| 443 | tristate "TAOS TSL4531 ambient light sensors" | 443 | tristate "TAOS TSL4531 ambient light sensors" |
| 444 | depends on I2C | 444 | depends on I2C |
| 445 | help | 445 | help |
| 446 | Say Y here if you want to build a driver for the TAOS TSL4531 family | 446 | Say Y here if you want to build a driver for the TAOS TSL4531 family |
| 447 | of ambient light sensors with direct lux output. | 447 | of ambient light sensors with direct lux output. |
| 448 | 448 | ||
| 449 | To compile this driver as a module, choose M here: the | 449 | To compile this driver as a module, choose M here: the |
| 450 | module will be called tsl4531. | 450 | module will be called tsl4531. |
| 451 | 451 | ||
| 452 | config US5182D | 452 | config US5182D |
| 453 | tristate "UPISEMI light and proximity sensor" | 453 | tristate "UPISEMI light and proximity sensor" |
| 454 | depends on I2C | 454 | depends on I2C |
| 455 | help | 455 | help |
| 456 | If you say yes here you get support for the UPISEMI US5182D | 456 | If you say yes here you get support for the UPISEMI US5182D |
| 457 | ambient light and proximity sensor. | 457 | ambient light and proximity sensor. |
| 458 | 458 | ||
| 459 | This driver can also be built as a module. If so, the module | 459 | This driver can also be built as a module. If so, the module |
| 460 | will be called us5182d. | 460 | will be called us5182d. |
| 461 | 461 | ||
| 462 | config VCNL4000 | 462 | config VCNL4000 |
| 463 | tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor" | 463 | tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor" |
| 464 | depends on I2C | 464 | depends on I2C |
| 465 | help | 465 | help |
| 466 | Say Y here if you want to build a driver for the Vishay VCNL4000, | 466 | Say Y here if you want to build a driver for the Vishay VCNL4000, |
| 467 | VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity | 467 | VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity |
| 468 | sensor. | 468 | sensor. |
| 469 | 469 | ||
| 470 | To compile this driver as a module, choose M here: the | 470 | To compile this driver as a module, choose M here: the |
| 471 | module will be called vcnl4000. | 471 | module will be called vcnl4000. |
| 472 | 472 | ||
| 473 | config VCNL4035 | 473 | config VCNL4035 |
| 474 | tristate "VCNL4035 combined ALS and proximity sensor" | 474 | tristate "VCNL4035 combined ALS and proximity sensor" |
| @@ -476,41 +476,41 @@ config VCNL4035 · 1 unmodified line | |||
| 476 | select REGMAP_I2C | 476 | select REGMAP_I2C |
| 477 | depends on I2C | 477 | depends on I2C |
| 478 | help | 478 | help |
| 479 | Say Y here if you want to build a driver for the Vishay VCNL4035, | 479 | Say Y here if you want to build a driver for the Vishay VCNL4035, |
| 480 | combined ambient light (ALS) and proximity sensor. Currently only ALS | 480 | combined ambient light (ALS) and proximity sensor. Currently only ALS |
| 481 | function is available. | 481 | function is available. |
| 482 | 482 | ||
| 483 | To compile this driver as a module, choose M here: the | 483 | To compile this driver as a module, choose M here: the |
| 484 | module will be called vcnl4035. | 484 | module will be called vcnl4035. |
| 485 | 485 | ||
| 486 | config VEML6070 | 486 | config VEML6070 |
| 487 | tristate "VEML6070 UV A light sensor" | 487 | tristate "VEML6070 UV A light sensor" |
| 488 | depends on I2C | 488 | depends on I2C |
| 489 | help | 489 | help |
| 490 | Say Y here if you want to build a driver for the Vishay VEML6070 UV A | 490 | Say Y here if you want to build a driver for the Vishay VEML6070 UV A |
| 491 | light sensor. | 491 | light sensor. |
| 492 | 492 | ||
| 493 | To compile this driver as a module, choose M here: the | 493 | To compile this driver as a module, choose M here: the |
| 494 | module will be called veml6070. | 494 | module will be called veml6070. |
| 495 | 495 | ||
| 496 | config VL6180 | 496 | config VL6180 |
| 497 | tristate "VL6180 ALS, range and proximity sensor" | 497 | tristate "VL6180 ALS, range and proximity sensor" |
| 498 | depends on I2C | 498 | depends on I2C |
| 499 | help | 499 | help |
| 500 | Say Y here if you want to build a driver for the STMicroelectronics | 500 | Say Y here if you want to build a driver for the STMicroelectronics |
| 501 | VL6180 combined ambient light, range and proximity sensor. | 501 | VL6180 combined ambient light, range and proximity sensor. |
| 502 | 502 | ||
| 503 | To compile this driver as a module, choose M here: the | 503 | To compile this driver as a module, choose M here: the |
| 504 | module will be called vl6180. | 504 | module will be called vl6180. |
| 505 | 505 | ||
| 506 | config ZOPT2201 | 506 | config ZOPT2201 |
| 507 | tristate "ZOPT2201 ALS and UV B sensor" | 507 | tristate "ZOPT2201 ALS and UV B sensor" |
| 508 | depends on I2C | 508 | depends on I2C |
| 509 | help | 509 | help |
| 510 | Say Y here if you want to build a driver for the IDT | 510 | Say Y here if you want to build a driver for the IDT |
| 511 | ZOPT2201 ambient light and UV B sensor. | 511 | ZOPT2201 ambient light and UV B sensor. |
| 512 | 512 | ||
| 513 | To compile this driver as a module, choose M here: the | 513 | To compile this driver as a module, choose M here: the |
| 514 | module will be called zopt2201. | 514 | module will be called zopt2201. |
| 515 | 515 | ||
| 516 | endmenu | 516 | endmenu |
| @@ -1,19 +1,10 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC. | 3 | * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC. |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2017 Google, Inc | 5 | * Copyright (C) 2017 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | 6 | */ |
| 15 | 7 | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 18 | #include <linux/iio/buffer.h> | 9 | #include <linux/iio/buffer.h> |
| 19 | #include <linux/iio/common/cros_ec_sensors_core.h> | 10 | #include <linux/iio/common/cros_ec_sensors_core.h> |
| @@ -28,7 +19,6 @@ · 8 unmodified lines | |||
| 28 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 29 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 30 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 31 | #include <linux/sysfs.h> | ||
| 32 | 22 | ||
| 33 | /* | 23 | /* |
| 34 | * We only represent one entry for light or proximity. EC is merging different | 24 | * We only represent one entry for light or proximity. EC is merging different |
| @@ -1,8 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient | 2 | * vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4040/4200 combined ambient |
| 3 | * light and proximity sensor | 3 | * light and proximity sensor |
| 4 | * | 4 | * |
| 5 | * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net> | 5 | * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net> |
| 6 | * Copyright 2019 Pursim SPC | ||
| 6 | * | 7 | * |
| 7 | * This file is subject to the terms and conditions of version 2 of | 8 | * This file is subject to the terms and conditions of version 2 of |
| 8 | * the GNU General Public License. See the file COPYING in the main | 9 | * the GNU General Public License. See the file COPYING in the main |
| @@ -10,13 +11,14 @@ · 1 unmodified line | |||
| 10 | * | 11 | * |
| 11 | * IIO driver for: | 12 | * IIO driver for: |
| 12 | * VCNL4000/10/20 (7-bit I2C slave address 0x13) | 13 | * VCNL4000/10/20 (7-bit I2C slave address 0x13) |
| 14 | * VCNL4040 (7-bit I2C slave address 0x60) | ||
| 13 | * VCNL4200 (7-bit I2C slave address 0x51) | 15 | * VCNL4200 (7-bit I2C slave address 0x51) |
| 14 | * | 16 | * |
| 15 | * TODO: | 17 | * TODO: |
| 16 | * allow to adjust IR current | 18 | * allow to adjust IR current |
| 17 | * proximity threshold and event handling | 19 | * proximity threshold and event handling |
| 18 | * periodic ALS/proximity measurement (VCNL4010/20) | 20 | * periodic ALS/proximity measurement (VCNL4010/20) |
| 19 | * interrupts (VCNL4010/20, VCNL4200) | 21 | * interrupts (VCNL4010/20/40, VCNL4200) |
| 20 | */ | 22 | */ |
| 21 | 23 | ||
| 22 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -30,6 +32,7 @@ · 7 unmodified lines | |||
| 30 | #define VCNL4000_DRV_NAME "vcnl4000" | 32 | #define VCNL4000_DRV_NAME "vcnl4000" |
| 31 | #define VCNL4000_PROD_ID 0x01 | 33 | #define VCNL4000_PROD_ID 0x01 |
| 32 | #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */ | 34 | #define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */ |
| 35 | #define VCNL4040_PROD_ID 0x86 | ||
| 33 | #define VCNL4200_PROD_ID 0x58 | 36 | #define VCNL4200_PROD_ID 0x58 |
| 34 | 37 | ||
| 35 | #define VCNL4000_COMMAND 0x80 /* Command register */ | 38 | #define VCNL4000_COMMAND 0x80 /* Command register */ |
| @@ -49,6 +52,8 @@ · 13 unmodified lines | |||
| 49 | #define VCNL4200_AL_DATA 0x09 /* Ambient light data */ | 52 | #define VCNL4200_AL_DATA 0x09 /* Ambient light data */ |
| 50 | #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */ | 53 | #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */ |
| 51 | 54 | ||
| 55 | #define VCNL4040_DEV_ID 0x0c /* Device ID and version */ | ||
| 56 | |||
| 52 | /* Bit masks for COMMAND register */ | 57 | /* Bit masks for COMMAND register */ |
| 53 | #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */ | 58 | #define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */ |
| 54 | #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */ | 59 | #define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */ |
| @@ -58,6 +63,7 @@ · 3 unmodified lines | |||
| 58 | enum vcnl4000_device_ids { | 63 | enum vcnl4000_device_ids { |
| 59 | VCNL4000, | 64 | VCNL4000, |
| 60 | VCNL4010, | 65 | VCNL4010, |
| 66 | VCNL4040, | ||
| 61 | VCNL4200, | 67 | VCNL4200, |
| 62 | }; | 68 | }; |
| 63 | 69 | ||
| @@ -90,6 +96,7 @@ static const struct i2c_device_id vcnl4000_id[] = { · 26 unmodified lines | |||
| 90 | { "vcnl4000", VCNL4000 }, | 96 | { "vcnl4000", VCNL4000 }, |
| 91 | { "vcnl4010", VCNL4010 }, | 97 | { "vcnl4010", VCNL4010 }, |
| 92 | { "vcnl4020", VCNL4010 }, | 98 | { "vcnl4020", VCNL4010 }, |
| 99 | { "vcnl4040", VCNL4040 }, | ||
| 93 | { "vcnl4200", VCNL4200 }, | 100 | { "vcnl4200", VCNL4200 }, |
| 94 | { } | 101 | { } |
| 95 | }; | 102 | }; |
| @@ -128,31 +135,53 @@ static int vcnl4000_init(struct vcnl4000_data *data) · 32 unmodified lines | |||
| 128 | 135 | ||
| 129 | static int vcnl4200_init(struct vcnl4000_data *data) | 136 | static int vcnl4200_init(struct vcnl4000_data *data) |
| 130 | { | 137 | { |
| 131 | int ret; | 138 | int ret, id; |
| 132 | 139 | ||
| 133 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); | 140 | ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); |
| 134 | if (ret < 0) | 141 | if (ret < 0) |
| 135 | return ret; | 142 | return ret; |
| 136 | 143 | ||
| 137 | if ((ret & 0xff) != VCNL4200_PROD_ID) | 144 | id = ret & 0xff; |
| 138 | return -ENODEV; | 145 | |
| 146 | if (id != VCNL4200_PROD_ID) { | ||
| 147 | ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID); | ||
| 148 | if (ret < 0) | ||
| 149 | return ret; | ||
| 150 | |||
| 151 | id = ret & 0xff; | ||
| 152 | |||
| 153 | if (id != VCNL4040_PROD_ID) | ||
| 154 | return -ENODEV; | ||
| 155 | } | ||
| 156 | |||
| 157 | dev_dbg(&data->client->dev, "device id 0x%x", id); | ||
| 139 | 158 | ||
| 140 | data->rev = (ret >> 8) & 0xf; | 159 | data->rev = (ret >> 8) & 0xf; |
| 141 | 160 | ||
| 142 | /* Set defaults and enable both channels */ | 161 | /* Set defaults and enable both channels */ |
| 143 | ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00); | 162 | ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0); |
| 144 | if (ret < 0) | 163 | if (ret < 0) |
| 145 | return ret; | 164 | return ret; |
| 146 | ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00); | 165 | ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0); |
| 147 | if (ret < 0) | 166 | if (ret < 0) |
| 148 | return ret; | 167 | return ret; |
| 149 | 168 | ||
| 150 | data->al_scale = 24000; | 169 | data->al_scale = 24000; |
| 151 | data->vcnl4200_al.reg = VCNL4200_AL_DATA; | 170 | data->vcnl4200_al.reg = VCNL4200_AL_DATA; |
| 152 | data->vcnl4200_ps.reg = VCNL4200_PS_DATA; | 171 | data->vcnl4200_ps.reg = VCNL4200_PS_DATA; |
| 153 | /* Integration time is 50ms, but the experiments show 54ms in total. */ | 172 | switch (id) { |
| 154 | data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000); | 173 | case VCNL4200_PROD_ID: |
| 155 | data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000); | 174 | /* Integration time is 50ms, but the experiments */ |
| 175 | /* show 54ms in total. */ | ||
| 176 | data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000); | ||
| 177 | data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000); | ||
| 178 | break; | ||
| 179 | case VCNL4040_PROD_ID: | ||
| 180 | /* Integration time is 80ms, add 10ms. */ | ||
| 181 | data->vcnl4200_al.sampling_rate = ktime_set(0, 100000 * 1000); | ||
| 182 | data->vcnl4200_ps.sampling_rate = ktime_set(0, 100000 * 1000); | ||
| 183 | break; | ||
| 184 | } | ||
| 156 | data->vcnl4200_al.last_measurement = ktime_set(0, 0); | 185 | data->vcnl4200_al.last_measurement = ktime_set(0, 0); |
| 157 | data->vcnl4200_ps.last_measurement = ktime_set(0, 0); | 186 | data->vcnl4200_ps.last_measurement = ktime_set(0, 0); |
| 158 | mutex_init(&data->vcnl4200_al.lock); | 187 | mutex_init(&data->vcnl4200_al.lock); |
| @@ -271,6 +300,12 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { · 112 unmodified lines | |||
| 271 | .measure_light = vcnl4000_measure_light, | 300 | .measure_light = vcnl4000_measure_light, |
| 272 | .measure_proximity = vcnl4000_measure_proximity, | 301 | .measure_proximity = vcnl4000_measure_proximity, |
| 273 | }, | 302 | }, |
| 303 | [VCNL4040] = { | ||
| 304 | .prod = "VCNL4040", | ||
| 305 | .init = vcnl4200_init, | ||
| 306 | .measure_light = vcnl4200_measure_light, | ||
| 307 | .measure_proximity = vcnl4200_measure_proximity, | ||
| 308 | }, | ||
| 274 | [VCNL4200] = { | 309 | [VCNL4200] = { |
| 275 | .prod = "VCNL4200", | 310 | .prod = "VCNL4200", |
| 276 | .init = vcnl4200_init, | 311 | .init = vcnl4200_init, |
| @@ -363,9 +398,31 @@ static int vcnl4000_probe(struct i2c_client *client, · 86 unmodified lines | |||
| 363 | return devm_iio_device_register(&client->dev, indio_dev); | 398 | return devm_iio_device_register(&client->dev, indio_dev); |
| 364 | } | 399 | } |
| 365 | 400 | ||
| 401 | static const struct of_device_id vcnl_4000_of_match[] = { | ||
| 402 | { | ||
| 403 | .compatible = "vishay,vcnl4000", | ||
| 404 | .data = "VCNL4000", | ||
| 405 | }, | ||
| 406 | { | ||
| 407 | .compatible = "vishay,vcnl4010", | ||
| 408 | .data = "VCNL4010", | ||
| 409 | }, | ||
| 410 | { | ||
| 411 | .compatible = "vishay,vcnl4010", | ||
| 412 | .data = "VCNL4020", | ||
| 413 | }, | ||
| 414 | { | ||
| 415 | .compatible = "vishay,vcnl4200", | ||
| 416 | .data = "VCNL4200", | ||
| 417 | }, | ||
| 418 | {}, | ||
| 419 | }; | ||
| 420 | MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); | ||
| 421 | |||
| 366 | static struct i2c_driver vcnl4000_driver = { | 422 | static struct i2c_driver vcnl4000_driver = { |
| 367 | .driver = { | 423 | .driver = { |
| 368 | .name = VCNL4000_DRV_NAME, | 424 | .name = VCNL4000_DRV_NAME, |
| 425 | .of_match_table = vcnl_4000_of_match, | ||
| 369 | }, | 426 | }, |
| 370 | .probe = vcnl4000_probe, | 427 | .probe = vcnl4000_probe, |
| 371 | .id_table = vcnl4000_id, | 428 | .id_table = vcnl4000_id, |
| @@ -733,9 +733,8 @@ static int ak8974_probe(struct i2c_client *i2c, · 732 unmodified lines | |||
| 733 | ak8974->i2c = i2c; | 733 | ak8974->i2c = i2c; |
| 734 | mutex_init(&ak8974->lock); | 734 | mutex_init(&ak8974->lock); |
| 735 | 735 | ||
| 736 | ret = of_iio_read_mount_matrix(&i2c->dev, | 736 | ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix", |
| 737 | "mount-matrix", | 737 | &ak8974->orientation); |
| 738 | &ak8974->orientation); | ||
| 739 | if (ret) | 738 | if (ret) |
| 740 | return ret; | 739 | return ret; |
| 741 | 740 | ||
| @@ -746,12 +746,14 @@ static const struct iio_mount_matrix * · 745 unmodified lines | |||
| 746 | ak8975_get_mount_matrix(const struct iio_dev *indio_dev, | 746 | ak8975_get_mount_matrix(const struct iio_dev *indio_dev, |
| 747 | const struct iio_chan_spec *chan) | 747 | const struct iio_chan_spec *chan) |
| 748 | { | 748 | { |
| 749 | return &((struct ak8975_data *)iio_priv(indio_dev))->orientation; | 749 | struct ak8975_data *data = iio_priv(indio_dev); |
| 750 | |||
| 751 | return &data->orientation; | ||
| 750 | } | 752 | } |
| 751 | 753 | ||
| 752 | static const struct iio_chan_spec_ext_info ak8975_ext_info[] = { | 754 | static const struct iio_chan_spec_ext_info ak8975_ext_info[] = { |
| 753 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix), | 755 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix), |
| 754 | { }, | 756 | { } |
| 755 | }; | 757 | }; |
| 756 | 758 | ||
| 757 | #define AK8975_CHANNEL(axis, index) \ | 759 | #define AK8975_CHANNEL(axis, index) \ |
| @@ -792,7 +794,7 @@ static const struct acpi_device_id ak_acpi_match[] = { · 34 unmodified lines | |||
| 792 | {"AK09911", AK09911}, | 794 | {"AK09911", AK09911}, |
| 793 | {"AKM9911", AK09911}, | 795 | {"AKM9911", AK09911}, |
| 794 | {"AK09912", AK09912}, | 796 | {"AK09912", AK09912}, |
| 795 | { }, | 797 | { } |
| 796 | }; | 798 | }; |
| 797 | MODULE_DEVICE_TABLE(acpi, ak_acpi_match); | 799 | MODULE_DEVICE_TABLE(acpi, ak_acpi_match); |
| 798 | #endif | 800 | #endif |
| @@ -911,9 +913,8 @@ static int ak8975_probe(struct i2c_client *client, · 112 unmodified lines | |||
| 911 | data->eoc_irq = 0; | 913 | data->eoc_irq = 0; |
| 912 | 914 | ||
| 913 | if (!pdata) { | 915 | if (!pdata) { |
| 914 | err = of_iio_read_mount_matrix(&client->dev, | 916 | err = iio_read_mount_matrix(&client->dev, "mount-matrix", |
| 915 | "mount-matrix", | 917 | &data->orientation); |
| 916 | &data->orientation); | ||
| 917 | if (err) | 918 | if (err) |
| 918 | return err; | 919 | return err; |
| 919 | } else | 920 | } else |
| @@ -143,6 +143,7 @@ struct bmc150_magn_data { · 142 unmodified lines | |||
| 143 | */ | 143 | */ |
| 144 | struct mutex mutex; | 144 | struct mutex mutex; |
| 145 | struct regmap *regmap; | 145 | struct regmap *regmap; |
| 146 | struct iio_mount_matrix orientation; | ||
| 146 | /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */ | 147 | /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */ |
| 147 | s32 buffer[6]; | 148 | s32 buffer[6]; |
| 148 | struct iio_trigger *dready_trig; | 149 | struct iio_trigger *dready_trig; |
| @@ -612,6 +613,20 @@ static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev, · 463 unmodified lines | |||
| 612 | return len; | 613 | return len; |
| 613 | } | 614 | } |
| 614 | 615 | ||
| 616 | static const struct iio_mount_matrix * | ||
| 617 | bmc150_magn_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 618 | const struct iio_chan_spec *chan) | ||
| 619 | { | ||
| 620 | struct bmc150_magn_data *data = iio_priv(indio_dev); | ||
| 621 | |||
| 622 | return &data->orientation; | ||
| 623 | } | ||
| 624 | |||
| 625 | static const struct iio_chan_spec_ext_info bmc150_magn_ext_info[] = { | ||
| 626 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_magn_get_mount_matrix), | ||
| 627 | { } | ||
| 628 | }; | ||
| 629 | |||
| 615 | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail); | 630 | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail); |
| 616 | 631 | ||
| 617 | static struct attribute *bmc150_magn_attributes[] = { | 632 | static struct attribute *bmc150_magn_attributes[] = { |
| @@ -638,6 +653,7 @@ static const struct attribute_group bmc150_magn_attrs_group = { · 20 unmodified lines | |||
| 638 | .storagebits = 32, \ | 653 | .storagebits = 32, \ |
| 639 | .endianness = IIO_LE \ | 654 | .endianness = IIO_LE \ |
| 640 | }, \ | 655 | }, \ |
| 656 | .ext_info = bmc150_magn_ext_info, \ | ||
| 641 | } | 657 | } |
| 642 | 658 | ||
| 643 | static const struct iio_chan_spec bmc150_magn_channels[] = { | 659 | static const struct iio_chan_spec bmc150_magn_channels[] = { |
| @@ -861,6 +877,11 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, · 217 unmodified lines | |||
| 861 | data->irq = irq; | 877 | data->irq = irq; |
| 862 | data->dev = dev; | 878 | data->dev = dev; |
| 863 | 879 | ||
| 880 | ret = iio_read_mount_matrix(dev, "mount-matrix", | ||
| 881 | &data->orientation); | ||
| 882 | if (ret) | ||
| 883 | return ret; | ||
| 884 | |||
| 864 | if (!name && ACPI_HANDLE(dev)) | 885 | if (!name && ACPI_HANDLE(dev)) |
| 865 | name = bmc150_magn_match_acpi_device(dev); | 886 | name = bmc150_magn_match_acpi_device(dev); |
| 866 | 887 | ||
| @@ -43,6 +43,7 @@ struct hmc5843_data { · 42 unmodified lines | |||
| 43 | struct mutex lock; | 43 | struct mutex lock; |
| 44 | struct regmap *regmap; | 44 | struct regmap *regmap; |
| 45 | const struct hmc5843_chip_info *variant; | 45 | const struct hmc5843_chip_info *variant; |
| 46 | struct iio_mount_matrix orientation; | ||
| 46 | __be16 buffer[8]; | 47 | __be16 buffer[8]; |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| @@ -237,6 +237,15 @@ int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, · 236 unmodified lines | |||
| 237 | return hmc5843_set_meas_conf(data, meas_conf); | 237 | return hmc5843_set_meas_conf(data, meas_conf); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | static const struct iio_mount_matrix * | ||
| 241 | hmc5843_get_mount_matrix(const struct iio_dev *indio_dev, | ||
| 242 | const struct iio_chan_spec *chan) | ||
| 243 | { | ||
| 244 | struct hmc5843_data *data = iio_priv(indio_dev); | ||
| 245 | |||
| 246 | return &data->orientation; | ||
| 247 | } | ||
| 248 | |||
| 240 | static const struct iio_enum hmc5843_meas_conf_enum = { | 249 | static const struct iio_enum hmc5843_meas_conf_enum = { |
| 241 | .items = hmc5843_meas_conf_modes, | 250 | .items = hmc5843_meas_conf_modes, |
| 242 | .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), | 251 | .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), |
| @@ -247,7 +256,8 @@ static const struct iio_enum hmc5843_meas_conf_enum = { · 4 unmodified lines | |||
| 247 | static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { | 256 | static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { |
| 248 | IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), | 257 | IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), |
| 249 | IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), | 258 | IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), |
| 250 | { }, | 259 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), |
| 260 | { } | ||
| 251 | }; | 261 | }; |
| 252 | 262 | ||
| 253 | static const struct iio_enum hmc5983_meas_conf_enum = { | 263 | static const struct iio_enum hmc5983_meas_conf_enum = { |
| @@ -260,7 +270,8 @@ static const struct iio_enum hmc5983_meas_conf_enum = { · 6 unmodified lines | |||
| 260 | static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { | 270 | static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { |
| 261 | IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), | 271 | IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), |
| 262 | IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), | 272 | IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), |
| 263 | { }, | 273 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), |
| 274 | { } | ||
| 264 | }; | 275 | }; |
| 265 | 276 | ||
| 266 | static | 277 | static |
| @@ -635,6 +646,11 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, · 368 unmodified lines | |||
| 635 | data->variant = &hmc5843_chip_info_tbl[id]; | 646 | data->variant = &hmc5843_chip_info_tbl[id]; |
| 636 | mutex_init(&data->lock); | 647 | mutex_init(&data->lock); |
| 637 | 648 | ||
| 649 | ret = iio_read_mount_matrix(dev, "mount-matrix", | ||
| 650 | &data->orientation); | ||
| 651 | if (ret) | ||
| 652 | return ret; | ||
| 653 | |||
| 638 | indio_dev->dev.parent = dev; | 654 | indio_dev->dev.parent = dev; |
| 639 | indio_dev->name = name; | 655 | indio_dev->name = name; |
| 640 | indio_dev->info = &hmc5843_info; | 656 | indio_dev->info = &hmc5843_info; |
| @@ -58,8 +58,13 @@ static const struct regmap_config hmc5843_i2c_regmap_config = { · 57 unmodified lines | |||
| 58 | static int hmc5843_i2c_probe(struct i2c_client *cli, | 58 | static int hmc5843_i2c_probe(struct i2c_client *cli, |
| 59 | const struct i2c_device_id *id) | 59 | const struct i2c_device_id *id) |
| 60 | { | 60 | { |
| 61 | struct regmap *regmap = devm_regmap_init_i2c(cli, | ||
| 62 | &hmc5843_i2c_regmap_config); | ||
| 63 | if (IS_ERR(regmap)) | ||
| 64 | return PTR_ERR(regmap); | ||
| 65 | |||
| 61 | return hmc5843_common_probe(&cli->dev, | 66 | return hmc5843_common_probe(&cli->dev, |
| 62 | devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config), | 67 | regmap, |
| 63 | id->driver_data, id->name); | 68 | id->driver_data, id->name); |
| 64 | } | 69 | } |
| 65 | 70 | ||
| @@ -58,6 +58,7 @@ static const struct regmap_config hmc5843_spi_regmap_config = { · 57 unmodified lines | |||
| 58 | static int hmc5843_spi_probe(struct spi_device *spi) | 58 | static int hmc5843_spi_probe(struct spi_device *spi) |
| 59 | { | 59 | { |
| 60 | int ret; | 60 | int ret; |
| 61 | struct regmap *regmap; | ||
| 61 | const struct spi_device_id *id = spi_get_device_id(spi); | 62 | const struct spi_device_id *id = spi_get_device_id(spi); |
| 62 | 63 | ||
| 63 | spi->mode = SPI_MODE_3; | 64 | spi->mode = SPI_MODE_3; |
| @@ -67,8 +68,12 @@ static int hmc5843_spi_probe(struct spi_device *spi) · 3 unmodified lines | |||
| 67 | if (ret) | 68 | if (ret) |
| 68 | return ret; | 69 | return ret; |
| 69 | 70 | ||
| 71 | regmap = devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config); | ||
| 72 | if (IS_ERR(regmap)) | ||
| 73 | return PTR_ERR(regmap); | ||
| 74 | |||
| 70 | return hmc5843_common_probe(&spi->dev, | 75 | return hmc5843_common_probe(&spi->dev, |
| 71 | devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config), | 76 | regmap, |
| 72 | id->driver_data, id->name); | 77 | id->driver_data, id->name); |
| 73 | } | 78 | } |
| 74 | 79 | ||
| @@ -26,26 +26,26 @@ config DS1803 · 25 unmodified lines | |||
| 26 | module will be called ds1803. | 26 | module will be called ds1803. |
| 27 | 27 | ||
| 28 | config MAX5481 | 28 | config MAX5481 |
| 29 | tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" | 29 | tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" |
| 30 | depends on SPI | 30 | depends on SPI |
| 31 | help | 31 | help |
| 32 | Say yes here to build support for the Maxim | 32 | Say yes here to build support for the Maxim |
| 33 | MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer | 33 | MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer |
| 34 | chips. | 34 | chips. |
| 35 | 35 | ||
| 36 | To compile this driver as a module, choose M here: the | 36 | To compile this driver as a module, choose M here: the |
| 37 | module will be called max5481. | 37 | module will be called max5481. |
| 38 | 38 | ||
| 39 | config MAX5487 | 39 | config MAX5487 |
| 40 | tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" | 40 | tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" |
| 41 | depends on SPI | 41 | depends on SPI |
| 42 | help | 42 | help |
| 43 | Say yes here to build support for the Maxim | 43 | Say yes here to build support for the Maxim |
| 44 | MAX5487, MAX5488, MAX5489 digital potentiometer | 44 | MAX5487, MAX5488, MAX5489 digital potentiometer |
| 45 | chips. | 45 | chips. |
| 46 | 46 | ||
| 47 | To compile this driver as a module, choose M here: the | 47 | To compile this driver as a module, choose M here: the |
| 48 | module will be called max5487. | 48 | module will be called max5487. |
| 49 | 49 | ||
| 50 | config MCP4018 | 50 | config MCP4018 |
| 51 | tristate "Microchip MCP4017/18/19 Digital Potentiometer driver" | 51 | tristate "Microchip MCP4017/18/19 Digital Potentiometer driver" |
| @@ -113,7 +113,7 @@ static int lmp91000_read(struct lmp91000_data *data, int channel, int *val) · 112 unmodified lines | |||
| 113 | return -EINVAL; | 113 | return -EINVAL; |
| 114 | 114 | ||
| 115 | /* delay till first temperature reading is complete */ | 115 | /* delay till first temperature reading is complete */ |
| 116 | if ((state != channel) && (channel == LMP91000_REG_MODECN_TEMP)) | 116 | if (state != channel && channel == LMP91000_REG_MODECN_TEMP) |
| 117 | usleep_range(3000, 4000); | 117 | usleep_range(3000, 4000); |
| 118 | 118 | ||
| 119 | data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; | 119 | data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; |
| @@ -211,12 +211,11 @@ static int lmp91000_read_config(struct lmp91000_data *data) · 91 unmodified lines | |||
| 211 | 211 | ||
| 212 | ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val); | 212 | ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val); |
| 213 | if (ret) { | 213 | if (ret) { |
| 214 | if (of_property_read_bool(np, "ti,external-tia-resistor")) | 214 | if (!of_property_read_bool(np, "ti,external-tia-resistor")) { |
| 215 | val = 0; | 215 | dev_err(dev, "no ti,tia-gain-ohm defined and external resistor not specified\n"); |
| 216 | else { | ||
| 217 | dev_err(dev, "no ti,tia-gain-ohm defined"); | ||
| 218 | return ret; | 216 | return ret; |
| 219 | } | 217 | } |
| 218 | val = 0; | ||
| 220 | } | 219 | } |
| 221 | 220 | ||
| 222 | ret = -EINVAL; | 221 | ret = -EINVAL; |
| @@ -255,8 +254,8 @@ static int lmp91000_read_config(struct lmp91000_data *data) · 32 unmodified lines | |||
| 255 | 254 | ||
| 256 | regmap_write(data->regmap, LMP91000_REG_LOCK, 0); | 255 | regmap_write(data->regmap, LMP91000_REG_LOCK, 0); |
| 257 | regmap_write(data->regmap, LMP91000_REG_TIACN, reg); | 256 | regmap_write(data->regmap, LMP91000_REG_TIACN, reg); |
| 258 | regmap_write(data->regmap, LMP91000_REG_REFCN, LMP91000_REG_REFCN_EXT_REF | 257 | regmap_write(data->regmap, LMP91000_REG_REFCN, |
| 259 | | LMP91000_REG_REFCN_50_ZERO); | 258 | LMP91000_REG_REFCN_EXT_REF | LMP91000_REG_REFCN_50_ZERO); |
| 260 | regmap_write(data->regmap, LMP91000_REG_LOCK, 1); | 259 | regmap_write(data->regmap, LMP91000_REG_LOCK, 1); |
| 261 | 260 | ||
| 262 | return 0; | 261 | return 0; |
| @@ -276,7 +275,6 @@ static int lmp91000_buffer_cb(const void *val, void *private) · 13 unmodified lines | |||
| 276 | static const struct iio_trigger_ops lmp91000_trigger_ops = { | 275 | static const struct iio_trigger_ops lmp91000_trigger_ops = { |
| 277 | }; | 276 | }; |
| 278 | 277 | ||
| 279 | |||
| 280 | static int lmp91000_buffer_preenable(struct iio_dev *indio_dev) | 278 | static int lmp91000_buffer_preenable(struct iio_dev *indio_dev) |
| 281 | { | 279 | { |
| 282 | struct lmp91000_data *data = iio_priv(indio_dev); | 280 | struct lmp91000_data *data = iio_priv(indio_dev); |
| @@ -164,6 +164,9 @@ static int bmp280_read_calib(struct bmp280_data *data, · 163 unmodified lines | |||
| 164 | return ret; | 164 | return ret; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | /* Toss the temperature calibration data into the entropy pool */ | ||
| 168 | add_device_randomness(t_buf, sizeof(t_buf)); | ||
| 169 | |||
| 167 | calib->T1 = le16_to_cpu(t_buf[T1]); | 170 | calib->T1 = le16_to_cpu(t_buf[T1]); |
| 168 | calib->T2 = le16_to_cpu(t_buf[T2]); | 171 | calib->T2 = le16_to_cpu(t_buf[T2]); |
| 169 | calib->T3 = le16_to_cpu(t_buf[T3]); | 172 | calib->T3 = le16_to_cpu(t_buf[T3]); |
| @@ -177,6 +180,9 @@ static int bmp280_read_calib(struct bmp280_data *data, · 7 unmodified lines | |||
| 177 | return ret; | 180 | return ret; |
| 178 | } | 181 | } |
| 179 | 182 | ||
| 183 | /* Toss the pressure calibration data into the entropy pool */ | ||
| 184 | add_device_randomness(p_buf, sizeof(p_buf)); | ||
| 185 | |||
| 180 | calib->P1 = le16_to_cpu(p_buf[P1]); | 186 | calib->P1 = le16_to_cpu(p_buf[P1]); |
| 181 | calib->P2 = le16_to_cpu(p_buf[P2]); | 187 | calib->P2 = le16_to_cpu(p_buf[P2]); |
| 182 | calib->P3 = le16_to_cpu(p_buf[P3]); | 188 | calib->P3 = le16_to_cpu(p_buf[P3]); |
| @@ -1,19 +1,10 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_baro - Driver for barometer sensor behind CrosEC. | 3 | * cros_ec_baro - Driver for barometer sensor behind CrosEC. |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2017 Google, Inc | 5 | * Copyright (C) 2017 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | 6 | */ |
| 15 | 7 | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 18 | #include <linux/iio/buffer.h> | 9 | #include <linux/iio/buffer.h> |
| 19 | #include <linux/iio/common/cros_ec_sensors_core.h> | 10 | #include <linux/iio/common/cros_ec_sensors_core.h> |
| @@ -45,6 +45,18 @@ config LIDAR_LITE_V2 · 44 unmodified lines | |||
| 45 | To compile this driver as a module, choose M here: the | 45 | To compile this driver as a module, choose M here: the |
| 46 | module will be called pulsedlight-lite-v2 | 46 | module will be called pulsedlight-lite-v2 |
| 47 | 47 | ||
| 48 | config MB1232 | ||
| 49 | tristate "MaxSonar I2CXL family ultrasonic sensors" | ||
| 50 | depends on I2C | ||
| 51 | help | ||
| 52 | Say Y to build a driver for the ultrasonic sensors I2CXL of | ||
| 53 | MaxBotix which have an i2c interface. It can be used to measure | ||
| 54 | the distance of objects. Supported types are mb1202, mb1212, | ||
| 55 | mb1222, mb1232, mb1242, mb7040, mb7137 | ||
| 56 | |||
| 57 | To compile this driver as a module, choose M here: the | ||
| 58 | module will be called mb1232. | ||
| 59 | |||
| 48 | config RFD77402 | 60 | config RFD77402 |
| 49 | tristate "RFD77402 ToF sensor" | 61 | tristate "RFD77402 ToF sensor" |
| 50 | depends on I2C | 62 | depends on I2C |
| @@ -56,12 +68,19 @@ config RFD77402 · 5 unmodified lines | |||
| 56 | module will be called rfd77402. | 68 | module will be called rfd77402. |
| 57 | 69 | ||
| 58 | config SRF04 | 70 | config SRF04 |
| 59 | tristate "Devantech SRF04 ultrasonic ranger sensor" | 71 | tristate "GPIO bitbanged ultrasonic ranger sensor (SRF04, MB1000)" |
| 60 | depends on GPIOLIB | 72 | depends on GPIOLIB |
| 61 | help | 73 | help |
| 62 | Say Y here to build a driver for Devantech SRF04 ultrasonic | 74 | Say Y here to build a driver for GPIO bitbanged ultrasonic |
| 63 | ranger sensor. This driver can be used to measure the distance | 75 | ranger sensor. This driver can be used to measure the distance |
| 64 | of objects. It is using two GPIOs. | 76 | of objects. It is using two GPIOs. |
| 77 | Actually Supported types are: | ||
| 78 | - Devantech SRF04 | ||
| 79 | - Maxbotix mb1000 | ||
| 80 | - Maxbotix mb1010 | ||
| 81 | - Maxbotix mb1020 | ||
| 82 | - Maxbotix mb1030 | ||
| 83 | - Maxbotix mb1040 | ||
| 65 | 84 | ||
| 66 | To compile this driver as a module, choose M here: the | 85 | To compile this driver as a module, choose M here: the |
| 67 | module will be called srf04. | 86 | module will be called srf04. |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | obj-$(CONFIG_AS3935) += as3935.o | 7 | obj-$(CONFIG_AS3935) += as3935.o |
| 8 | obj-$(CONFIG_ISL29501) += isl29501.o | 8 | obj-$(CONFIG_ISL29501) += isl29501.o |
| 9 | obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o | 9 | obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o |
| 10 | obj-$(CONFIG_MB1232) += mb1232.o | ||
| 10 | obj-$(CONFIG_RFD77402) += rfd77402.o | 11 | obj-$(CONFIG_RFD77402) += rfd77402.o |
| 11 | obj-$(CONFIG_SRF04) += srf04.o | 12 | obj-$(CONFIG_SRF04) += srf04.o |
| 12 | obj-$(CONFIG_SRF08) += srf08.o | 13 | obj-$(CONFIG_SRF08) += srf08.o |
| @@ -345,6 +345,14 @@ static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume); · 344 unmodified lines | |||
| 345 | #define AS3935_PM_OPS NULL | 345 | #define AS3935_PM_OPS NULL |
| 346 | #endif | 346 | #endif |
| 347 | 347 | ||
| 348 | static void as3935_stop_work(void *data) | ||
| 349 | { | ||
| 350 | struct iio_dev *indio_dev = data; | ||
| 351 | struct as3935_state *st = iio_priv(indio_dev); | ||
| 352 | |||
| 353 | cancel_delayed_work_sync(&st->work); | ||
| 354 | } | ||
| 355 | |||
| 348 | static int as3935_probe(struct spi_device *spi) | 356 | static int as3935_probe(struct spi_device *spi) |
| 349 | { | 357 | { |
| 350 | struct iio_dev *indio_dev; | 358 | struct iio_dev *indio_dev; |
| @@ -368,7 +376,6 @@ static int as3935_probe(struct spi_device *spi) · 17 unmodified lines | |||
| 368 | 376 | ||
| 369 | spi_set_drvdata(spi, indio_dev); | 377 | spi_set_drvdata(spi, indio_dev); |
| 370 | mutex_init(&st->lock); | 378 | mutex_init(&st->lock); |
| 371 | INIT_DELAYED_WORK(&st->work, as3935_event_work); | ||
| 372 | 379 | ||
| 373 | ret = of_property_read_u32(np, | 380 | ret = of_property_read_u32(np, |
| 374 | "ams,tuning-capacitor-pf", &st->tune_cap); | 381 | "ams,tuning-capacitor-pf", &st->tune_cap); |
| @@ -414,22 +421,28 @@ static int as3935_probe(struct spi_device *spi) · 39 unmodified lines | |||
| 414 | iio_trigger_set_drvdata(trig, indio_dev); | 421 | iio_trigger_set_drvdata(trig, indio_dev); |
| 415 | trig->ops = &iio_interrupt_trigger_ops; | 422 | trig->ops = &iio_interrupt_trigger_ops; |
| 416 | 423 | ||
| 417 | ret = iio_trigger_register(trig); | 424 | ret = devm_iio_trigger_register(&spi->dev, trig); |
| 418 | if (ret) { | 425 | if (ret) { |
| 419 | dev_err(&spi->dev, "failed to register trigger\n"); | 426 | dev_err(&spi->dev, "failed to register trigger\n"); |
| 420 | return ret; | 427 | return ret; |
| 421 | } | 428 | } |
| 422 | 429 | ||
| 423 | ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, | 430 | ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, |
| 424 | &as3935_trigger_handler, NULL); | 431 | iio_pollfunc_store_time, |
| 432 | as3935_trigger_handler, NULL); | ||
| 425 | 433 | ||
| 426 | if (ret) { | 434 | if (ret) { |
| 427 | dev_err(&spi->dev, "cannot setup iio trigger\n"); | 435 | dev_err(&spi->dev, "cannot setup iio trigger\n"); |
| 428 | goto unregister_trigger; | 436 | return ret; |
| 429 | } | 437 | } |
| 430 | 438 | ||
| 431 | calibrate_as3935(st); | 439 | calibrate_as3935(st); |
| 432 | 440 | ||
| 441 | INIT_DELAYED_WORK(&st->work, as3935_event_work); | ||
| 442 | ret = devm_add_action(&spi->dev, as3935_stop_work, indio_dev); | ||
| 443 | if (ret) | ||
| 444 | return ret; | ||
| 445 | |||
| 433 | ret = devm_request_irq(&spi->dev, spi->irq, | 446 | ret = devm_request_irq(&spi->dev, spi->irq, |
| 434 | &as3935_interrupt_handler, | 447 | &as3935_interrupt_handler, |
| 435 | IRQF_TRIGGER_RISING, | 448 | IRQF_TRIGGER_RISING, |
| @@ -438,35 +451,15 @@ static int as3935_probe(struct spi_device *spi) · 2 unmodified lines | |||
| 438 | 451 | ||
| 439 | if (ret) { | 452 | if (ret) { |
| 440 | dev_err(&spi->dev, "unable to request irq\n"); | 453 | dev_err(&spi->dev, "unable to request irq\n"); |
| 441 | goto unregister_buffer; | 454 | return ret; |
| 442 | } | 455 | } |
| 443 | 456 | ||
| 444 | ret = iio_device_register(indio_dev); | 457 | ret = devm_iio_device_register(&spi->dev, indio_dev); |
| 445 | if (ret < 0) { | 458 | if (ret < 0) { |
| 446 | dev_err(&spi->dev, "unable to register device\n"); | 459 | dev_err(&spi->dev, "unable to register device\n"); |
| 447 | goto unregister_buffer; | 460 | return ret; |
| 448 | } | 461 | } |
| 449 | return 0; | 462 | return 0; |
| 450 | |||
| 451 | unregister_buffer: | ||
| 452 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 453 | |||
| 454 | unregister_trigger: | ||
| 455 | iio_trigger_unregister(st->trig); | ||
| 456 | |||
| 457 | return ret; | ||
| 458 | } | ||
| 459 | |||
| 460 | static int as3935_remove(struct spi_device *spi) | ||
| 461 | { | ||
| 462 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 463 | struct as3935_state *st = iio_priv(indio_dev); | ||
| 464 | |||
| 465 | iio_device_unregister(indio_dev); | ||
| 466 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 467 | iio_trigger_unregister(st->trig); | ||
| 468 | |||
| 469 | return 0; | ||
| 470 | } | 463 | } |
| 471 | 464 | ||
| 472 | static const struct of_device_id as3935_of_match[] = { | 465 | static const struct of_device_id as3935_of_match[] = { |
| @@ -488,7 +481,6 @@ static struct spi_driver as3935_driver = { · 15 unmodified lines | |||
| 488 | .pm = AS3935_PM_OPS, | 481 | .pm = AS3935_PM_OPS, |
| 489 | }, | 482 | }, |
| 490 | .probe = as3935_probe, | 483 | .probe = as3935_probe, |
| 491 | .remove = as3935_remove, | ||
| 492 | .id_table = as3935_id, | 484 | .id_table = as3935_id, |
| 493 | }; | 485 | }; |
| 494 | module_spi_driver(as3935_driver); | 486 | module_spi_driver(as3935_driver); |
| @@ -0,0 +1,272 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * mb1232.c - Support for MaxBotix I2CXL-MaxSonar-EZ series ultrasonic | ||
| 4 | * ranger with i2c interface | ||
| 5 | * actually tested with mb1232 type | ||
| 6 | * | ||
| 7 | * Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de> | ||
| 8 | * | ||
| 9 | * For details about the device see: | ||
| 10 | * https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/i2c.h> | ||
| 15 | #include <linux/of_irq.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/bitops.h> | ||
| 19 | #include <linux/iio/iio.h> | ||
| 20 | #include <linux/iio/sysfs.h> | ||
| 21 | #include <linux/iio/buffer.h> | ||
| 22 | #include <linux/iio/trigger_consumer.h> | ||
| 23 | #include <linux/iio/triggered_buffer.h> | ||
| 24 | |||
| 25 | /* registers of MaxSonar device */ | ||
| 26 | #define MB1232_RANGE_COMMAND 0x51 /* Command for reading range */ | ||
| 27 | #define MB1232_ADDR_UNLOCK_1 0xAA /* Command 1 for changing address */ | ||
| 28 | #define MB1232_ADDR_UNLOCK_2 0xA5 /* Command 2 for changing address */ | ||
| 29 | |||
| 30 | struct mb1232_data { | ||
| 31 | struct i2c_client *client; | ||
| 32 | |||
| 33 | struct mutex lock; | ||
| 34 | |||
| 35 | /* | ||
| 36 | * optionally a gpio can be used to announce when ranging has | ||
| 37 | * finished | ||
| 38 | * since we are just using the falling trigger of it we request | ||
| 39 | * only the interrupt for announcing when data is ready to be read | ||
| 40 | */ | ||
| 41 | struct completion ranging; | ||
| 42 | int irqnr; | ||
| 43 | }; | ||
| 44 | |||
| 45 | static irqreturn_t mb1232_handle_irq(int irq, void *dev_id) | ||
| 46 | { | ||
| 47 | struct iio_dev *indio_dev = dev_id; | ||
| 48 | struct mb1232_data *data = iio_priv(indio_dev); | ||
| 49 | |||
| 50 | complete(&data->ranging); | ||
| 51 | |||
| 52 | return IRQ_HANDLED; | ||
| 53 | } | ||
| 54 | |||
| 55 | static s16 mb1232_read_distance(struct mb1232_data *data) | ||
| 56 | { | ||
| 57 | struct i2c_client *client = data->client; | ||
| 58 | int ret; | ||
| 59 | s16 distance; | ||
| 60 | __be16 buf; | ||
| 61 | |||
| 62 | mutex_lock(&data->lock); | ||
| 63 | |||
| 64 | reinit_completion(&data->ranging); | ||
| 65 | |||
| 66 | ret = i2c_smbus_write_byte(client, MB1232_RANGE_COMMAND); | ||
| 67 | if (ret < 0) { | ||
| 68 | dev_err(&client->dev, "write command - err: %d\n", ret); | ||
| 69 | goto error_unlock; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (data->irqnr >= 0) { | ||
| 73 | /* it cannot take more than 100 ms */ | ||
| 74 | ret = wait_for_completion_killable_timeout(&data->ranging, | ||
| 75 | HZ/10); | ||
| 76 | if (ret < 0) | ||
| 77 | goto error_unlock; | ||
| 78 | else if (ret == 0) { | ||
| 79 | ret = -ETIMEDOUT; | ||
| 80 | goto error_unlock; | ||
| 81 | } | ||
| 82 | } else { | ||
| 83 | /* use simple sleep if announce irq is not connected */ | ||
| 84 | msleep(15); | ||
| 85 | } | ||
| 86 | |||
| 87 | ret = i2c_master_recv(client, (char *)&buf, sizeof(buf)); | ||
| 88 | if (ret < 0) { | ||
| 89 | dev_err(&client->dev, "i2c_master_recv: ret=%d\n", ret); | ||
| 90 | goto error_unlock; | ||
| 91 | } | ||
| 92 | |||
| 93 | distance = __be16_to_cpu(buf); | ||
| 94 | /* check for not returning misleading error codes */ | ||
| 95 | if (distance < 0) { | ||
| 96 | dev_err(&client->dev, "distance=%d\n", distance); | ||
| 97 | ret = -EINVAL; | ||
| 98 | goto error_unlock; | ||
| 99 | } | ||
| 100 | |||
| 101 | mutex_unlock(&data->lock); | ||
| 102 | |||
| 103 | return distance; | ||
| 104 | |||
| 105 | error_unlock: | ||
| 106 | mutex_unlock(&data->lock); | ||
| 107 | |||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | |||
| 111 | static irqreturn_t mb1232_trigger_handler(int irq, void *p) | ||
| 112 | { | ||
| 113 | struct iio_poll_func *pf = p; | ||
| 114 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 115 | struct mb1232_data *data = iio_priv(indio_dev); | ||
| 116 | /* | ||
| 117 | * triggered buffer | ||
| 118 | * 16-bit channel + 48-bit padding + 64-bit timestamp | ||
| 119 | */ | ||
| 120 | s16 buffer[8] = { 0 }; | ||
| 121 | |||
| 122 | buffer[0] = mb1232_read_distance(data); | ||
| 123 | if (buffer[0] < 0) | ||
| 124 | goto err; | ||
| 125 | |||
| 126 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); | ||
| 127 | |||
| 128 | err: | ||
| 129 | iio_trigger_notify_done(indio_dev->trig); | ||
| 130 | return IRQ_HANDLED; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int mb1232_read_raw(struct iio_dev *indio_dev, | ||
| 134 | struct iio_chan_spec const *channel, int *val, | ||
| 135 | int *val2, long mask) | ||
| 136 | { | ||
| 137 | struct mb1232_data *data = iio_priv(indio_dev); | ||
| 138 | int ret; | ||
| 139 | |||
| 140 | if (channel->type != IIO_DISTANCE) | ||
| 141 | return -EINVAL; | ||
| 142 | |||
| 143 | switch (mask) { | ||
| 144 | case IIO_CHAN_INFO_RAW: | ||
| 145 | ret = mb1232_read_distance(data); | ||
| 146 | if (ret < 0) | ||
| 147 | return ret; | ||
| 148 | *val = ret; | ||
| 149 | return IIO_VAL_INT; | ||
| 150 | case IIO_CHAN_INFO_SCALE: | ||
| 151 | /* 1 LSB is 1 cm */ | ||
| 152 | *val = 0; | ||
| 153 | *val2 = 10000; | ||
| 154 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 155 | default: | ||
| 156 | return -EINVAL; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | static const struct iio_chan_spec mb1232_channels[] = { | ||
| 161 | { | ||
| 162 | .type = IIO_DISTANCE, | ||
| 163 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 164 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 165 | .scan_index = 0, | ||
| 166 | .scan_type = { | ||
| 167 | .sign = 's', | ||
| 168 | .realbits = 16, | ||
| 169 | .storagebits = 16, | ||
| 170 | .endianness = IIO_CPU, | ||
| 171 | }, | ||
| 172 | }, | ||
| 173 | IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 174 | }; | ||
| 175 | |||
| 176 | static const struct iio_info mb1232_info = { | ||
| 177 | .read_raw = mb1232_read_raw, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static int mb1232_probe(struct i2c_client *client, | ||
| 181 | const struct i2c_device_id *id) | ||
| 182 | { | ||
| 183 | struct iio_dev *indio_dev; | ||
| 184 | struct mb1232_data *data; | ||
| 185 | int ret; | ||
| 186 | struct device *dev = &client->dev; | ||
| 187 | |||
| 188 | if (!i2c_check_functionality(client->adapter, | ||
| 189 | I2C_FUNC_SMBUS_READ_BYTE | | ||
| 190 | I2C_FUNC_SMBUS_WRITE_BYTE)) | ||
| 191 | return -ENODEV; | ||
| 192 | |||
| 193 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | ||
| 194 | if (!indio_dev) | ||
| 195 | return -ENOMEM; | ||
| 196 | |||
| 197 | data = iio_priv(indio_dev); | ||
| 198 | i2c_set_clientdata(client, indio_dev); | ||
| 199 | data->client = client; | ||
| 200 | |||
| 201 | indio_dev->info = &mb1232_info; | ||
| 202 | indio_dev->name = id->name; | ||
| 203 | indio_dev->dev.parent = dev; | ||
| 204 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 205 | indio_dev->channels = mb1232_channels; | ||
| 206 | indio_dev->num_channels = ARRAY_SIZE(mb1232_channels); | ||
| 207 | |||
| 208 | mutex_init(&data->lock); | ||
| 209 | |||
| 210 | init_completion(&data->ranging); | ||
| 211 | |||
| 212 | data->irqnr = irq_of_parse_and_map(dev->of_node, 0); | ||
| 213 | if (data->irqnr <= 0) { | ||
| 214 | /* usage of interrupt is optional */ | ||
| 215 | data->irqnr = -1; | ||
| 216 | } else { | ||
| 217 | ret = devm_request_irq(dev, data->irqnr, mb1232_handle_irq, | ||
| 218 | IRQF_TRIGGER_FALLING, id->name, indio_dev); | ||
| 219 | if (ret < 0) { | ||
| 220 | dev_err(dev, "request_irq: %d\n", ret); | ||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, | ||
| 226 | iio_pollfunc_store_time, mb1232_trigger_handler, NULL); | ||
| 227 | if (ret < 0) { | ||
| 228 | dev_err(dev, "setup of iio triggered buffer failed\n"); | ||
| 229 | return ret; | ||
| 230 | } | ||
| 231 | |||
| 232 | return devm_iio_device_register(dev, indio_dev); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct of_device_id of_mb1232_match[] = { | ||
| 236 | { .compatible = "maxbotix,mb1202", }, | ||
| 237 | { .compatible = "maxbotix,mb1212", }, | ||
| 238 | { .compatible = "maxbotix,mb1222", }, | ||
| 239 | { .compatible = "maxbotix,mb1232", }, | ||
| 240 | { .compatible = "maxbotix,mb1242", }, | ||
| 241 | { .compatible = "maxbotix,mb7040", }, | ||
| 242 | { .compatible = "maxbotix,mb7137", }, | ||
| 243 | {}, | ||
| 244 | }; | ||
| 245 | |||
| 246 | MODULE_DEVICE_TABLE(of, of_mb1232_match); | ||
| 247 | |||
| 248 | static const struct i2c_device_id mb1232_id[] = { | ||
| 249 | { "maxbotix-mb1202", }, | ||
| 250 | { "maxbotix-mb1212", }, | ||
| 251 | { "maxbotix-mb1222", }, | ||
| 252 | { "maxbotix-mb1232", }, | ||
| 253 | { "maxbotix-mb1242", }, | ||
| 254 | { "maxbotix-mb7040", }, | ||
| 255 | { "maxbotix-mb7137", }, | ||
| 256 | { } | ||
| 257 | }; | ||
| 258 | MODULE_DEVICE_TABLE(i2c, mb1232_id); | ||
| 259 | |||
| 260 | static struct i2c_driver mb1232_driver = { | ||
| 261 | .driver = { | ||
| 262 | .name = "maxbotix-mb1232", | ||
| 263 | .of_match_table = of_mb1232_match, | ||
| 264 | }, | ||
| 265 | .probe = mb1232_probe, | ||
| 266 | .id_table = mb1232_id, | ||
| 267 | }; | ||
| 268 | module_i2c_driver(mb1232_driver); | ||
| 269 | |||
| 270 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); | ||
| 271 | MODULE_DESCRIPTION("Maxbotix I2CXL-MaxSonar i2c ultrasonic ranger driver"); | ||
| 272 | MODULE_LICENSE("GPL"); | ||
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | * trig: --+ +------------------------------------------------------ | 23 | * trig: --+ +------------------------------------------------------ |
| 24 | * ^ ^ | 24 | * ^ ^ |
| 25 | * |<->| | 25 | * |<->| |
| 26 | * udelay(10) | 26 | * udelay(trigger_pulse_us) |
| 27 | * | 27 | * |
| 28 | * ultra +-+ +-+ +-+ | 28 | * ultra +-+ +-+ +-+ |
| 29 | * sonic | | | | | | | 29 | * sonic | | | | | | |
| @@ -48,6 +48,7 @@ · 18 unmodified lines | |||
| 48 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
| 49 | #include <linux/module.h> | 49 | #include <linux/module.h> |
| 50 | #include <linux/of.h> | 50 | #include <linux/of.h> |
| 51 | #include <linux/of_device.h> | ||
| 51 | #include <linux/platform_device.h> | 52 | #include <linux/platform_device.h> |
| 52 | #include <linux/property.h> | 53 | #include <linux/property.h> |
| 53 | #include <linux/sched.h> | 54 | #include <linux/sched.h> |
| @@ -56,6 +57,10 @@ · 2 unmodified lines | |||
| 56 | #include <linux/iio/iio.h> | 57 | #include <linux/iio/iio.h> |
| 57 | #include <linux/iio/sysfs.h> | 58 | #include <linux/iio/sysfs.h> |
| 58 | 59 | ||
| 60 | struct srf04_cfg { | ||
| 61 | unsigned long trigger_pulse_us; | ||
| 62 | }; | ||
| 63 | |||
| 59 | struct srf04_data { | 64 | struct srf04_data { |
| 60 | struct device *dev; | 65 | struct device *dev; |
| 61 | struct gpio_desc *gpiod_trig; | 66 | struct gpio_desc *gpiod_trig; |
| @@ -66,6 +71,15 @@ struct srf04_data { · 4 unmodified lines | |||
| 66 | ktime_t ts_falling; | 71 | ktime_t ts_falling; |
| 67 | struct completion rising; | 72 | struct completion rising; |
| 68 | struct completion falling; | 73 | struct completion falling; |
| 74 | const struct srf04_cfg *cfg; | ||
| 75 | }; | ||
| 76 | |||
| 77 | static const struct srf04_cfg srf04_cfg = { | ||
| 78 | .trigger_pulse_us = 10, | ||
| 79 | }; | ||
| 80 | |||
| 81 | static const struct srf04_cfg mb_lv_cfg = { | ||
| 82 | .trigger_pulse_us = 20, | ||
| 69 | }; | 83 | }; |
| 70 | 84 | ||
| 71 | static irqreturn_t srf04_handle_irq(int irq, void *dev_id) | 85 | static irqreturn_t srf04_handle_irq(int irq, void *dev_id) |
| @@ -102,7 +116,7 @@ static int srf04_read(struct srf04_data *data) · 30 unmodified lines | |||
| 102 | reinit_completion(&data->falling); | 116 | reinit_completion(&data->falling); |
| 103 | 117 | ||
| 104 | gpiod_set_value(data->gpiod_trig, 1); | 118 | gpiod_set_value(data->gpiod_trig, 1); |
| 105 | udelay(10); | 119 | udelay(data->cfg->trigger_pulse_us); |
| 106 | gpiod_set_value(data->gpiod_trig, 0); | 120 | gpiod_set_value(data->gpiod_trig, 0); |
| 107 | 121 | ||
| 108 | /* it cannot take more than 20 ms */ | 122 | /* it cannot take more than 20 ms */ |
| @@ -215,6 +229,18 @@ static const struct iio_chan_spec srf04_chan_spec[] = { · 106 unmodified lines | |||
| 215 | }, | 229 | }, |
| 216 | }; | 230 | }; |
| 217 | 231 | ||
| 232 | static const struct of_device_id of_srf04_match[] = { | ||
| 233 | { .compatible = "devantech,srf04", .data = &srf04_cfg}, | ||
| 234 | { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg}, | ||
| 235 | { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg}, | ||
| 236 | { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg}, | ||
| 237 | { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg}, | ||
| 238 | { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg}, | ||
| 239 | {}, | ||
| 240 | }; | ||
| 241 | |||
| 242 | MODULE_DEVICE_TABLE(of, of_srf04_match); | ||
| 243 | |||
| 218 | static int srf04_probe(struct platform_device *pdev) | 244 | static int srf04_probe(struct platform_device *pdev) |
| 219 | { | 245 | { |
| 220 | struct device *dev = &pdev->dev; | 246 | struct device *dev = &pdev->dev; |
| @@ -230,6 +256,7 @@ static int srf04_probe(struct platform_device *pdev) · 9 unmodified lines | |||
| 230 | 256 | ||
| 231 | data = iio_priv(indio_dev); | 257 | data = iio_priv(indio_dev); |
| 232 | data->dev = dev; | 258 | data->dev = dev; |
| 259 | data->cfg = of_match_device(of_srf04_match, dev)->data; | ||
| 233 | 260 | ||
| 234 | mutex_init(&data->lock); | 261 | mutex_init(&data->lock); |
| 235 | init_completion(&data->rising); | 262 | init_completion(&data->rising); |
| @@ -280,13 +307,6 @@ static int srf04_probe(struct platform_device *pdev) · 44 unmodified lines | |||
| 280 | return devm_iio_device_register(dev, indio_dev); | 307 | return devm_iio_device_register(dev, indio_dev); |
| 281 | } | 308 | } |
| 282 | 309 | ||
| 283 | static const struct of_device_id of_srf04_match[] = { | ||
| 284 | { .compatible = "devantech,srf04", }, | ||
| 285 | {}, | ||
| 286 | }; | ||
| 287 | |||
| 288 | MODULE_DEVICE_TABLE(of, of_srf04_match); | ||
| 289 | |||
| 290 | static struct platform_driver srf04_driver = { | 310 | static struct platform_driver srf04_driver = { |
| 291 | .probe = srf04_probe, | 311 | .probe = srf04_probe, |
| 292 | .driver = { | 312 | .driver = { |
| @@ -66,14 +66,14 @@ config TMP006 · 65 unmodified lines | |||
| 66 | be called tmp006. | 66 | be called tmp006. |
| 67 | 67 | ||
| 68 | config TMP007 | 68 | config TMP007 |
| 69 | tristate "TMP007 infrared thermopile sensor with Integrated Math Engine" | 69 | tristate "TMP007 infrared thermopile sensor with Integrated Math Engine" |
| 70 | depends on I2C | 70 | depends on I2C |
| 71 | help | 71 | help |
| 72 | If you say yes here you get support for the Texas Instruments | 72 | If you say yes here you get support for the Texas Instruments |
| 73 | TMP007 infrared thermopile sensor with Integrated Math Engine. | 73 | TMP007 infrared thermopile sensor with Integrated Math Engine. |
| 74 | 74 | ||
| 75 | This driver can also be built as a module. If so, the module will | 75 | This driver can also be built as a module. If so, the module will |
| 76 | be called tmp007. | 76 | be called tmp007. |
| 77 | 77 | ||
| 78 | config TSYS01 | 78 | config TSYS01 |
| 79 | tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" | 79 | tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" |
| @@ -97,4 +97,14 @@ config TSYS02D · 17 unmodified lines | |||
| 97 | This driver can also be built as a module. If so, the module will | 97 | This driver can also be built as a module. If so, the module will |
| 98 | be called tsys02d. | 98 | be called tsys02d. |
| 99 | 99 | ||
| 100 | config MAX31856 | ||
| 101 | tristate "MAX31856 thermocouple sensor" | ||
| 102 | depends on SPI | ||
| 103 | help | ||
| 104 | If you say yes here you get support for MAX31856 | ||
| 105 | thermocouple sensor chip connected via SPI. | ||
| 106 | |||
| 107 | This driver can also be built as a module. If so, the module | ||
| 108 | will be called max31856. | ||
| 109 | |||
| 100 | endmenu | 110 | endmenu |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o | 6 | obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o |
| 7 | obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o | 7 | obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o |
| 8 | obj-$(CONFIG_MAX31856) += max31856.o | ||
| 8 | obj-$(CONFIG_MLX90614) += mlx90614.o | 9 | obj-$(CONFIG_MLX90614) += mlx90614.o |
| 9 | obj-$(CONFIG_MLX90632) += mlx90632.o | 10 | obj-$(CONFIG_MLX90632) += mlx90632.o |
| 10 | obj-$(CONFIG_TMP006) += tmp006.o | 11 | obj-$(CONFIG_TMP006) += tmp006.o |
| @@ -0,0 +1,356 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* max31856.c | ||
| 3 | * | ||
| 4 | * Maxim MAX31856 thermocouple sensor driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2018-2019 Rockwell Collins | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/err.h> | ||
| 12 | #include <linux/spi/spi.h> | ||
| 13 | #include <linux/iio/iio.h> | ||
| 14 | #include <linux/iio/sysfs.h> | ||
| 15 | #include <dt-bindings/iio/temperature/thermocouple.h> | ||
| 16 | /* | ||
| 17 | * The MSB of the register value determines whether the following byte will | ||
| 18 | * be written or read. If it is 0, one or more byte reads will follow. | ||
| 19 | */ | ||
| 20 | #define MAX31856_RD_WR_BIT BIT(7) | ||
| 21 | |||
| 22 | #define MAX31856_CR0_AUTOCONVERT BIT(7) | ||
| 23 | #define MAX31856_CR0_1SHOT BIT(6) | ||
| 24 | #define MAX31856_CR0_OCFAULT BIT(4) | ||
| 25 | #define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4) | ||
| 26 | #define MAX31856_TC_TYPE_MASK GENMASK(3, 0) | ||
| 27 | #define MAX31856_FAULT_OVUV BIT(1) | ||
| 28 | #define MAX31856_FAULT_OPEN BIT(0) | ||
| 29 | |||
| 30 | /* The MAX31856 registers */ | ||
| 31 | #define MAX31856_CR0_REG 0x00 | ||
| 32 | #define MAX31856_CR1_REG 0x01 | ||
| 33 | #define MAX31856_MASK_REG 0x02 | ||
| 34 | #define MAX31856_CJHF_REG 0x03 | ||
| 35 | #define MAX31856_CJLF_REG 0x04 | ||
| 36 | #define MAX31856_LTHFTH_REG 0x05 | ||
| 37 | #define MAX31856_LTHFTL_REG 0x06 | ||
| 38 | #define MAX31856_LTLFTH_REG 0x07 | ||
| 39 | #define MAX31856_LTLFTL_REG 0x08 | ||
| 40 | #define MAX31856_CJTO_REG 0x09 | ||
| 41 | #define MAX31856_CJTH_REG 0x0A | ||
| 42 | #define MAX31856_CJTL_REG 0x0B | ||
| 43 | #define MAX31856_LTCBH_REG 0x0C | ||
| 44 | #define MAX31856_LTCBM_REG 0x0D | ||
| 45 | #define MAX31856_LTCBL_REG 0x0E | ||
| 46 | #define MAX31856_SR_REG 0x0F | ||
| 47 | |||
| 48 | static const struct iio_chan_spec max31856_channels[] = { | ||
| 49 | { /* Thermocouple Temperature */ | ||
| 50 | .type = IIO_TEMP, | ||
| 51 | .info_mask_separate = | ||
| 52 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | ||
| 53 | }, | ||
| 54 | { /* Cold Junction Temperature */ | ||
| 55 | .type = IIO_TEMP, | ||
| 56 | .channel2 = IIO_MOD_TEMP_AMBIENT, | ||
| 57 | .modified = 1, | ||
| 58 | .info_mask_separate = | ||
| 59 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | ||
| 60 | }, | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct max31856_data { | ||
| 64 | struct spi_device *spi; | ||
| 65 | u32 thermocouple_type; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static int max31856_read(struct max31856_data *data, u8 reg, | ||
| 69 | u8 val[], unsigned int read_size) | ||
| 70 | { | ||
| 71 | return spi_write_then_read(data->spi, ®, 1, val, read_size); | ||
| 72 | } | ||
| 73 | |||
| 74 | static int max31856_write(struct max31856_data *data, u8 reg, | ||
| 75 | unsigned int val) | ||
| 76 | { | ||
| 77 | u8 buf[2]; | ||
| 78 | |||
| 79 | buf[0] = reg | (MAX31856_RD_WR_BIT); | ||
| 80 | buf[1] = val; | ||
| 81 | |||
| 82 | return spi_write(data->spi, buf, 2); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int max31856_init(struct max31856_data *data) | ||
| 86 | { | ||
| 87 | int ret; | ||
| 88 | u8 reg_cr0_val, reg_cr1_val; | ||
| 89 | |||
| 90 | /* Start by changing to Off mode before making changes as | ||
| 91 | * some settings are recommended to be set only when the device | ||
| 92 | * is off | ||
| 93 | */ | ||
| 94 | ret = max31856_read(data, MAX31856_CR0_REG, ®_cr0_val, 1); | ||
| 95 | if (ret) | ||
| 96 | return ret; | ||
| 97 | |||
| 98 | reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT; | ||
| 99 | ret = max31856_write(data, MAX31856_CR0_REG, reg_cr0_val); | ||
| 100 | if (ret) | ||
| 101 | return ret; | ||
| 102 | |||
| 103 | /* Set thermocouple type based on dts property */ | ||
| 104 | ret = max31856_read(data, MAX31856_CR1_REG, ®_cr1_val, 1); | ||
| 105 | if (ret) | ||
| 106 | return ret; | ||
| 107 | |||
| 108 | reg_cr1_val &= ~MAX31856_TC_TYPE_MASK; | ||
| 109 | reg_cr1_val |= data->thermocouple_type; | ||
| 110 | ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val); | ||
| 111 | if (ret) | ||
| 112 | return ret; | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Enable Open circuit fault detection | ||
| 116 | * Read datasheet for more information: Table 4. | ||
| 117 | * Value 01 means : Enabled (Once every 16 conversions) | ||
| 118 | */ | ||
| 119 | reg_cr0_val &= ~MAX31856_CR0_OCFAULT_MASK; | ||
| 120 | reg_cr0_val |= MAX31856_CR0_OCFAULT; | ||
| 121 | |||
| 122 | /* Set Auto Conversion Mode */ | ||
| 123 | reg_cr0_val &= ~MAX31856_CR0_1SHOT; | ||
| 124 | reg_cr0_val |= MAX31856_CR0_AUTOCONVERT; | ||
| 125 | |||
| 126 | return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val); | ||
| 127 | } | ||
| 128 | |||
| 129 | static int max31856_thermocouple_read(struct max31856_data *data, | ||
| 130 | struct iio_chan_spec const *chan, | ||
| 131 | int *val) | ||
| 132 | { | ||
| 133 | int ret, offset_cjto; | ||
| 134 | u8 reg_val[3]; | ||
| 135 | |||
| 136 | switch (chan->channel2) { | ||
| 137 | case IIO_NO_MOD: | ||
| 138 | /* | ||
| 139 | * Multibyte Read | ||
| 140 | * MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG | ||
| 141 | */ | ||
| 142 | ret = max31856_read(data, MAX31856_LTCBH_REG, reg_val, 3); | ||
| 143 | if (ret) | ||
| 144 | return ret; | ||
| 145 | /* Skip last 5 dead bits of LTCBL */ | ||
| 146 | *val = (reg_val[0] << 16 | reg_val[1] << 8 | reg_val[2]) >> 5; | ||
| 147 | /* Check 7th bit of LTCBH reg. value for sign*/ | ||
| 148 | if (reg_val[0] & 0x80) | ||
| 149 | *val -= 0x80000; | ||
| 150 | break; | ||
| 151 | |||
| 152 | case IIO_MOD_TEMP_AMBIENT: | ||
| 153 | /* | ||
| 154 | * Multibyte Read | ||
| 155 | * MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG | ||
| 156 | */ | ||
| 157 | ret = max31856_read(data, MAX31856_CJTO_REG, reg_val, 3); | ||
| 158 | if (ret) | ||
| 159 | return ret; | ||
| 160 | /* Get Cold Junction Temp. offset register value */ | ||
| 161 | offset_cjto = reg_val[0]; | ||
| 162 | /* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */ | ||
| 163 | *val = (reg_val[1] << 8 | reg_val[2]) >> 2; | ||
| 164 | /* As per datasheet add offset into CJTH and CJTL */ | ||
| 165 | *val += offset_cjto; | ||
| 166 | /* Check 7th bit of CJTH reg. value for sign */ | ||
| 167 | if (reg_val[1] & 0x80) | ||
| 168 | *val -= 0x4000; | ||
| 169 | break; | ||
| 170 | |||
| 171 | default: | ||
| 172 | return -EINVAL; | ||
| 173 | } | ||
| 174 | |||
| 175 | ret = max31856_read(data, MAX31856_SR_REG, reg_val, 1); | ||
| 176 | if (ret) | ||
| 177 | return ret; | ||
| 178 | /* Check for over/under voltage or open circuit fault */ | ||
| 179 | if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN)) | ||
| 180 | return -EIO; | ||
| 181 | |||
| 182 | return ret; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int max31856_read_raw(struct iio_dev *indio_dev, | ||
| 186 | struct iio_chan_spec const *chan, | ||
| 187 | int *val, int *val2, long mask) | ||
| 188 | { | ||
| 189 | struct max31856_data *data = iio_priv(indio_dev); | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | switch (mask) { | ||
| 193 | case IIO_CHAN_INFO_RAW: | ||
| 194 | ret = max31856_thermocouple_read(data, chan, val); | ||
| 195 | if (ret) | ||
| 196 | return ret; | ||
| 197 | return IIO_VAL_INT; | ||
| 198 | case IIO_CHAN_INFO_SCALE: | ||
| 199 | switch (chan->channel2) { | ||
| 200 | case IIO_MOD_TEMP_AMBIENT: | ||
| 201 | /* Cold junction Temp. Data resolution is 0.015625 */ | ||
| 202 | *val = 15; | ||
| 203 | *val2 = 625000; /* 1000 * 0.015625 */ | ||
| 204 | ret = IIO_VAL_INT_PLUS_MICRO; | ||
| 205 | break; | ||
| 206 | default: | ||
| 207 | /* Thermocouple Temp. Data resolution is 0.0078125 */ | ||
| 208 | *val = 7; | ||
| 209 | *val2 = 812500; /* 1000 * 0.0078125) */ | ||
| 210 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 211 | } | ||
| 212 | break; | ||
| 213 | default: | ||
| 214 | ret = -EINVAL; | ||
| 215 | break; | ||
| 216 | } | ||
| 217 | |||
| 218 | return ret; | ||
| 219 | } | ||
| 220 | |||
| 221 | static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf) | ||
| 222 | { | ||
| 223 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
| 224 | struct max31856_data *data = iio_priv(indio_dev); | ||
| 225 | u8 reg_val; | ||
| 226 | int ret; | ||
| 227 | bool fault; | ||
| 228 | |||
| 229 | ret = max31856_read(data, MAX31856_SR_REG, ®_val, 1); | ||
| 230 | if (ret) | ||
| 231 | return ret; | ||
| 232 | |||
| 233 | fault = reg_val & faultbit; | ||
| 234 | |||
| 235 | return sprintf(buf, "%d\n", fault); | ||
| 236 | } | ||
| 237 | |||
| 238 | static ssize_t show_fault_ovuv(struct device *dev, | ||
| 239 | struct device_attribute *attr, | ||
| 240 | char *buf) | ||
| 241 | { | ||
| 242 | return show_fault(dev, MAX31856_FAULT_OVUV, buf); | ||
| 243 | } | ||
| 244 | |||
| 245 | static ssize_t show_fault_oc(struct device *dev, | ||
| 246 | struct device_attribute *attr, | ||
| 247 | char *buf) | ||
| 248 | { | ||
| 249 | return show_fault(dev, MAX31856_FAULT_OPEN, buf); | ||
| 250 | } | ||
| 251 | |||
| 252 | static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0); | ||
| 253 | static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0); | ||
| 254 | |||
| 255 | static struct attribute *max31856_attributes[] = { | ||
| 256 | &iio_dev_attr_fault_ovuv.dev_attr.attr, | ||
| 257 | &iio_dev_attr_fault_oc.dev_attr.attr, | ||
| 258 | NULL, | ||
| 259 | }; | ||
| 260 | |||
| 261 | static const struct attribute_group max31856_group = { | ||
| 262 | .attrs = max31856_attributes, | ||
| 263 | }; | ||
| 264 | |||
| 265 | static const struct iio_info max31856_info = { | ||
| 266 | .read_raw = max31856_read_raw, | ||
| 267 | .attrs = &max31856_group, | ||
| 268 | }; | ||
| 269 | |||
| 270 | static int max31856_probe(struct spi_device *spi) | ||
| 271 | { | ||
| 272 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
| 273 | struct iio_dev *indio_dev; | ||
| 274 | struct max31856_data *data; | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); | ||
| 278 | if (!indio_dev) | ||
| 279 | return -ENOMEM; | ||
| 280 | |||
| 281 | data = iio_priv(indio_dev); | ||
| 282 | data->spi = spi; | ||
| 283 | |||
| 284 | spi_set_drvdata(spi, indio_dev); | ||
| 285 | |||
| 286 | indio_dev->info = &max31856_info; | ||
| 287 | indio_dev->name = id->name; | ||
| 288 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 289 | indio_dev->channels = max31856_channels; | ||
| 290 | indio_dev->num_channels = ARRAY_SIZE(max31856_channels); | ||
| 291 | |||
| 292 | ret = of_property_read_u32(spi->dev.of_node, "thermocouple-type", | ||
| 293 | &data->thermocouple_type); | ||
| 294 | |||
| 295 | if (ret) { | ||
| 296 | dev_info(&spi->dev, | ||
| 297 | "Could not read thermocouple type DT property, configuring as a K-Type\n"); | ||
| 298 | data->thermocouple_type = THERMOCOUPLE_TYPE_K; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * no need to translate values as the supported types | ||
| 303 | * have the same value as the #defines | ||
| 304 | */ | ||
| 305 | switch (data->thermocouple_type) { | ||
| 306 | case THERMOCOUPLE_TYPE_B: | ||
| 307 | case THERMOCOUPLE_TYPE_E: | ||
| 308 | case THERMOCOUPLE_TYPE_J: | ||
| 309 | case THERMOCOUPLE_TYPE_K: | ||
| 310 | case THERMOCOUPLE_TYPE_N: | ||
| 311 | case THERMOCOUPLE_TYPE_R: | ||
| 312 | case THERMOCOUPLE_TYPE_S: | ||
| 313 | case THERMOCOUPLE_TYPE_T: | ||
| 314 | break; | ||
| 315 | default: | ||
| 316 | dev_err(&spi->dev, | ||
| 317 | "error: thermocouple-type %u not supported by max31856\n" | ||
| 318 | , data->thermocouple_type); | ||
| 319 | return -EINVAL; | ||
| 320 | } | ||
| 321 | |||
| 322 | ret = max31856_init(data); | ||
| 323 | if (ret) { | ||
| 324 | dev_err(&spi->dev, "error: Failed to configure max31856\n"); | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | |||
| 328 | return devm_iio_device_register(&spi->dev, indio_dev); | ||
| 329 | } | ||
| 330 | |||
| 331 | static const struct spi_device_id max31856_id[] = { | ||
| 332 | { "max31856", 0 }, | ||
| 333 | { } | ||
| 334 | }; | ||
| 335 | MODULE_DEVICE_TABLE(spi, max31856_id); | ||
| 336 | |||
| 337 | static const struct of_device_id max31856_of_match[] = { | ||
| 338 | { .compatible = "maxim,max31856" }, | ||
| 339 | { } | ||
| 340 | }; | ||
| 341 | MODULE_DEVICE_TABLE(of, max31856_of_match); | ||
| 342 | |||
| 343 | static struct spi_driver max31856_driver = { | ||
| 344 | .driver = { | ||
| 345 | .name = "max31856", | ||
| 346 | .of_match_table = max31856_of_match, | ||
| 347 | }, | ||
| 348 | .probe = max31856_probe, | ||
| 349 | .id_table = max31856_id, | ||
| 350 | }; | ||
| 351 | module_spi_driver(max31856_driver); | ||
| 352 | |||
| 353 | MODULE_AUTHOR("Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>"); | ||
| 354 | MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>"); | ||
| 355 | MODULE_DESCRIPTION("Maxim MAX31856 thermocouple sensor driver"); | ||
| 356 | MODULE_LICENSE("GPL"); | ||
| @@ -60,7 +60,7 @@ static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state) · 59 unmodified lines | |||
| 60 | if (state) { | 60 | if (state) { |
| 61 | loop_trig->task = kthread_run(iio_loop_thread, | 61 | loop_trig->task = kthread_run(iio_loop_thread, |
| 62 | trig, trig->name); | 62 | trig, trig->name); |
| 63 | if (unlikely(IS_ERR(loop_trig->task))) { | 63 | if (IS_ERR(loop_trig->task)) { |
| 64 | dev_err(&trig->dev, | 64 | dev_err(&trig->dev, |
| 65 | "failed to create trigger loop thread\n"); | 65 | "failed to create trigger loop thread\n"); |
| 66 | return PTR_ERR(loop_trig->task); | 66 | return PTR_ERR(loop_trig->task); |
| @@ -22,51 +22,9 @@ · 21 unmodified lines | |||
| 22 | #include <linux/pwm.h> | 22 | #include <linux/pwm.h> |
| 23 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/fsl/ftm.h> | ||
| 25 | 26 | ||
| 26 | #define FTM_SC 0x00 | ||
| 27 | #define FTM_SC_CLK_MASK_SHIFT 3 | ||
| 28 | #define FTM_SC_CLK_MASK (3 << FTM_SC_CLK_MASK_SHIFT) | ||
| 29 | #define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_MASK_SHIFT) | 27 | #define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_MASK_SHIFT) |
| 30 | #define FTM_SC_PS_MASK 0x7 | ||
| 31 | |||
| 32 | #define FTM_CNT 0x04 | ||
| 33 | #define FTM_MOD 0x08 | ||
| 34 | |||
| 35 | #define FTM_CSC_BASE 0x0C | ||
| 36 | #define FTM_CSC_MSB BIT(5) | ||
| 37 | #define FTM_CSC_MSA BIT(4) | ||
| 38 | #define FTM_CSC_ELSB BIT(3) | ||
| 39 | #define FTM_CSC_ELSA BIT(2) | ||
| 40 | #define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8)) | ||
| 41 | |||
| 42 | #define FTM_CV_BASE 0x10 | ||
| 43 | #define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8)) | ||
| 44 | |||
| 45 | #define FTM_CNTIN 0x4C | ||
| 46 | #define FTM_STATUS 0x50 | ||
| 47 | |||
| 48 | #define FTM_MODE 0x54 | ||
| 49 | #define FTM_MODE_FTMEN BIT(0) | ||
| 50 | #define FTM_MODE_INIT BIT(2) | ||
| 51 | #define FTM_MODE_PWMSYNC BIT(3) | ||
| 52 | |||
| 53 | #define FTM_SYNC 0x58 | ||
| 54 | #define FTM_OUTINIT 0x5C | ||
| 55 | #define FTM_OUTMASK 0x60 | ||
| 56 | #define FTM_COMBINE 0x64 | ||
| 57 | #define FTM_DEADTIME 0x68 | ||
| 58 | #define FTM_EXTTRIG 0x6C | ||
| 59 | #define FTM_POL 0x70 | ||
| 60 | #define FTM_FMS 0x74 | ||
| 61 | #define FTM_FILTER 0x78 | ||
| 62 | #define FTM_FLTCTRL 0x7C | ||
| 63 | #define FTM_QDCTRL 0x80 | ||
| 64 | #define FTM_CONF 0x84 | ||
| 65 | #define FTM_FLTPOL 0x88 | ||
| 66 | #define FTM_SYNCONF 0x8C | ||
| 67 | #define FTM_INVCTRL 0x90 | ||
| 68 | #define FTM_SWOCTRL 0x94 | ||
| 69 | #define FTM_PWMLOAD 0x98 | ||
| 70 | 28 | ||
| 71 | enum fsl_pwm_clk { | 29 | enum fsl_pwm_clk { |
| 72 | FSL_PWM_CLK_SYS, | 30 | FSL_PWM_CLK_SYS, |
| @@ -57,8 +57,6 @@ struct mt7621_spi { · 56 unmodified lines | |||
| 57 | unsigned int speed; | 57 | unsigned int speed; |
| 58 | struct clk *clk; | 58 | struct clk *clk; |
| 59 | int pending_write; | 59 | int pending_write; |
| 60 | |||
| 61 | struct mt7621_spi_ops *ops; | ||
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| 64 | static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) | 62 | static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) |
| @@ -306,7 +304,7 @@ static int mt7621_spi_setup(struct spi_device *spi) · 241 unmodified lines | |||
| 306 | 304 | ||
| 307 | if ((spi->max_speed_hz == 0) || | 305 | if ((spi->max_speed_hz == 0) || |
| 308 | (spi->max_speed_hz > (rs->sys_freq / 2))) | 306 | (spi->max_speed_hz > (rs->sys_freq / 2))) |
| 309 | spi->max_speed_hz = (rs->sys_freq / 2); | 307 | spi->max_speed_hz = rs->sys_freq / 2; |
| 310 | 308 | ||
| 311 | if (spi->max_speed_hz < (rs->sys_freq / 4097)) { | 309 | if (spi->max_speed_hz < (rs->sys_freq / 4097)) { |
| 312 | dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", | 310 | dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", |
| @@ -332,13 +330,11 @@ static int mt7621_spi_probe(struct platform_device *pdev) · 19 unmodified lines | |||
| 332 | struct resource *r; | 330 | struct resource *r; |
| 333 | int status = 0; | 331 | int status = 0; |
| 334 | struct clk *clk; | 332 | struct clk *clk; |
| 335 | struct mt7621_spi_ops *ops; | ||
| 336 | int ret; | 333 | int ret; |
| 337 | 334 | ||
| 338 | match = of_match_device(mt7621_spi_match, &pdev->dev); | 335 | match = of_match_device(mt7621_spi_match, &pdev->dev); |
| 339 | if (!match) | 336 | if (!match) |
| 340 | return -EINVAL; | 337 | return -EINVAL; |
| 341 | ops = (struct mt7621_spi_ops *)match->data; | ||
| 342 | 338 | ||
| 343 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 339 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 344 | base = devm_ioremap_resource(&pdev->dev, r); | 340 | base = devm_ioremap_resource(&pdev->dev, r); |
| @@ -377,7 +373,6 @@ static int mt7621_spi_probe(struct platform_device *pdev) · 32 unmodified lines | |||
| 377 | rs->clk = clk; | 373 | rs->clk = clk; |
| 378 | rs->master = master; | 374 | rs->master = master; |
| 379 | rs->sys_freq = clk_get_rate(rs->clk); | 375 | rs->sys_freq = clk_get_rate(rs->clk); |
| 380 | rs->ops = ops; | ||
| 381 | rs->pending_write = 0; | 376 | rs->pending_write = 0; |
| 382 | dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); | 377 | dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); |
| 383 | 378 | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | menuconfig STAGING | 2 | menuconfig STAGING |
| 2 | bool "Staging drivers" | 3 | bool "Staging drivers" |
| 3 | default n | ||
| 4 | ---help--- | 4 | ---help--- |
| 5 | This option allows you to select a number of drivers that are | 5 | This option allows you to select a number of drivers that are |
| 6 | not of the "normal" Linux kernel quality level. These drivers | 6 | not of the "normal" Linux kernel quality level. These drivers |
| @@ -16,8 +16,8 @@ menuconfig STAGING · 9 unmodified lines | |||
| 16 | 16 | ||
| 17 | If you wish to work on these drivers, to help improve them, or | 17 | If you wish to work on these drivers, to help improve them, or |
| 18 | to report problems you have with them, please see the | 18 | to report problems you have with them, please see the |
| 19 | driver_name.README file in the drivers/staging/ directory to | 19 | drivers/staging/<driver_name>/TODO file to see what needs to be |
| 20 | see what needs to be worked on, and who to contact. | 20 | worked on, and who to contact. |
| 21 | 21 | ||
| 22 | If in doubt, say N here. | 22 | If in doubt, say N here. |
| 23 | 23 | ||
| @@ -40,8 +40,6 @@ source "drivers/staging/rtl8712/Kconfig" · 16 unmodified lines | |||
| 40 | 40 | ||
| 41 | source "drivers/staging/rtl8188eu/Kconfig" | 41 | source "drivers/staging/rtl8188eu/Kconfig" |
| 42 | 42 | ||
| 43 | source "drivers/staging/rtlwifi/Kconfig" | ||
| 44 | |||
| 45 | source "drivers/staging/rts5208/Kconfig" | 43 | source "drivers/staging/rts5208/Kconfig" |
| 46 | 44 | ||
| 47 | source "drivers/staging/octeon/Kconfig" | 45 | source "drivers/staging/octeon/Kconfig" |
| @@ -110,8 +108,6 @@ source "drivers/staging/mt7621-dma/Kconfig" · 62 unmodified lines | |||
| 110 | 108 | ||
| 111 | source "drivers/staging/ralink-gdma/Kconfig" | 109 | source "drivers/staging/ralink-gdma/Kconfig" |
| 112 | 110 | ||
| 113 | source "drivers/staging/mt7621-mmc/Kconfig" | ||
| 114 | |||
| 115 | source "drivers/staging/mt7621-dts/Kconfig" | 111 | source "drivers/staging/mt7621-dts/Kconfig" |
| 116 | 112 | ||
| 117 | source "drivers/staging/gasket/Kconfig" | 113 | source "drivers/staging/gasket/Kconfig" |
| @@ -120,4 +116,8 @@ source "drivers/staging/axis-fifo/Kconfig" · 2 unmodified lines | |||
| 120 | 116 | ||
| 121 | source "drivers/staging/erofs/Kconfig" | 117 | source "drivers/staging/erofs/Kconfig" |
| 122 | 118 | ||
| 119 | source "drivers/staging/fieldbus/Kconfig" | ||
| 120 | |||
| 121 | source "drivers/staging/kpc2000/Kconfig" | ||
| 122 | |||
| 123 | endif # STAGING | 123 | endif # STAGING |
| @@ -10,7 +10,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ · 9 unmodified lines | |||
| 10 | obj-$(CONFIG_RTL8723BS) += rtl8723bs/ | 10 | obj-$(CONFIG_RTL8723BS) += rtl8723bs/ |
| 11 | obj-$(CONFIG_R8712U) += rtl8712/ | 11 | obj-$(CONFIG_R8712U) += rtl8712/ |
| 12 | obj-$(CONFIG_R8188EU) += rtl8188eu/ | 12 | obj-$(CONFIG_R8188EU) += rtl8188eu/ |
| 13 | obj-$(CONFIG_R8822BE) += rtlwifi/ | ||
| 14 | obj-$(CONFIG_RTS5208) += rts5208/ | 13 | obj-$(CONFIG_RTS5208) += rts5208/ |
| 15 | obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ | 14 | obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ |
| 16 | obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ | 15 | obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ |
| @@ -45,8 +44,9 @@ obj-$(CONFIG_PCI_MT7621_PHY) += mt7621-pci-phy/ · 28 unmodified lines | |||
| 45 | obj-$(CONFIG_PINCTRL_RT2880) += mt7621-pinctrl/ | 44 | obj-$(CONFIG_PINCTRL_RT2880) += mt7621-pinctrl/ |
| 46 | obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ | 45 | obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ |
| 47 | obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ | 46 | obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ |
| 48 | obj-$(CONFIG_MTK_MMC) += mt7621-mmc/ | ||
| 49 | obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ | 47 | obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ |
| 50 | obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ | 48 | obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ |
| 51 | obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ | 49 | obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ |
| 52 | obj-$(CONFIG_EROFS_FS) += erofs/ | 50 | obj-$(CONFIG_EROFS_FS) += erofs/ |
| 51 | obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ | ||
| 52 | obj-$(CONFIG_KPC2000) += kpc2000/ | ||
| @@ -1,10 +1,10 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | menu "Android" | 2 | menu "Android" |
| 2 | 3 | ||
| 3 | if ANDROID | 4 | if ANDROID |
| 4 | 5 | ||
| 5 | config ASHMEM | 6 | config ASHMEM |
| 6 | bool "Enable the Anonymous Shared Memory Subsystem" | 7 | bool "Enable the Anonymous Shared Memory Subsystem" |
| 7 | default n | ||
| 8 | depends on SHMEM | 8 | depends on SHMEM |
| 9 | help | 9 | help |
| 10 | The ashmem subsystem is a new shared memory allocator, similar to | 10 | The ashmem subsystem is a new shared memory allocator, similar to |
| @@ -16,7 +16,6 @@ config ASHMEM · 5 unmodified lines | |||
| 16 | 16 | ||
| 17 | config ANDROID_VSOC | 17 | config ANDROID_VSOC |
| 18 | tristate "Android Virtual SoC support" | 18 | tristate "Android Virtual SoC support" |
| 19 | default n | ||
| 20 | depends on PCI_MSI | 19 | depends on PCI_MSI |
| 21 | help | 20 | help |
| 22 | This option adds support for the Virtual SoC driver needed to boot | 21 | This option adds support for the Virtual SoC driver needed to boot |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | ccflags-y += -I$(src) # needed for trace events | 2 | ccflags-y += -I$(src) # needed for trace events |
| 2 | 3 | ||
| 3 | obj-y += ion/ | 4 | obj-y += ion/ |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | menuconfig ION | 2 | menuconfig ION |
| 2 | bool "Ion Memory Manager" | 3 | bool "Ion Memory Manager" |
| 3 | depends on HAS_DMA && MMU | 4 | depends on HAS_DMA && MMU |
| @@ -259,7 +259,8 @@ do_create_fd_scoped_permission(struct vsoc_device_region *region_p, · 258 unmodified lines | |||
| 259 | atomic_t *owner_ptr = NULL; | 259 | atomic_t *owner_ptr = NULL; |
| 260 | struct vsoc_device_region *managed_region_p; | 260 | struct vsoc_device_region *managed_region_p; |
| 261 | 261 | ||
| 262 | if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) || | 262 | if (copy_from_user(&np->permission, |
| 263 | &arg->perm, sizeof(np->permission)) || | ||
| 263 | copy_from_user(&managed_fd, | 264 | copy_from_user(&managed_fd, |
| 264 | &arg->managed_region_fd, sizeof(managed_fd))) { | 265 | &arg->managed_region_fd, sizeof(managed_fd))) { |
| 265 | return -EFAULT; | 266 | return -EFAULT; |
| @@ -1,10 +1,12 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | # | 2 | # |
| 2 | # "Xilinx AXI-Stream FIFO IP core driver" | 3 | # "Xilinx AXI-Stream FIFO IP core driver" |
| 3 | # | 4 | # |
| 4 | config XIL_AXIS_FIFO | 5 | config XIL_AXIS_FIFO |
| 5 | tristate "Xilinx AXI-Stream FIFO IP core driver" | 6 | tristate "Xilinx AXI-Stream FIFO IP core driver" |
| 6 | depends on OF | 7 | depends on OF |
| 7 | default n | ||
| 8 | help | 8 | help |
| 9 | This adds support for the Xilinx AXI-Stream | 9 | This adds support for the Xilinx AXI-Stream FIFO IP core driver. |
| 10 | FIFO IP core driver. | 10 | The AXI Streaming FIFO allows memory mapped access to a AXI Streaming |
| 11 | interface. The Xilinx AXI-Stream FIFO IP core can be used to interface | ||
| 12 | to the AXI Ethernet without the need to use DMA. | ||
| @@ -1 +1,2 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo.o | 2 | obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo.o |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | config STAGING_BOARD | 2 | config STAGING_BOARD |
| 2 | bool "Staging Board Support" | 3 | bool "Staging Board Support" |
| 3 | depends on OF_ADDRESS && OF_IRQ && CLKDEV_LOOKUP | 4 | depends on OF_ADDRESS && OF_IRQ && CLKDEV_LOOKUP |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | obj-y := board.o | 2 | obj-y := board.o |
| 2 | obj-$(CONFIG_ARCH_EMEV2) += kzm9d.o | 3 | obj-$(CONFIG_ARCH_EMEV2) += kzm9d.o |
| 3 | obj-$(CONFIG_ARCH_R8A7740) += armadillo800eva.o | 4 | obj-$(CONFIG_ARCH_R8A7740) += armadillo800eva.o |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | # | 2 | # |
| 2 | # Xilinx Clocking Wizard Driver | 3 | # Xilinx Clocking Wizard Driver |
| 3 | # | 4 | # |
| @@ -1 +1,2 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o | 2 | obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o |
| @@ -1,6 +1,7 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | config COMEDI | 2 | config COMEDI |
| 2 | tristate "Data acquisition support (comedi)" | 3 | tristate "Data acquisition support (comedi)" |
| 3 | ---help--- | 4 | help |
| 4 | Enable support for a wide range of data acquisition devices | 5 | Enable support for a wide range of data acquisition devices |
| 5 | for Linux. | 6 | for Linux. |
| 6 | 7 | ||
| @@ -8,14 +9,14 @@ if COMEDI · 1 unmodified line | |||
| 8 | 9 | ||
| 9 | config COMEDI_DEBUG | 10 | config COMEDI_DEBUG |
| 10 | bool "Comedi debugging" | 11 | bool "Comedi debugging" |
| 11 | ---help--- | 12 | help |
| 12 | This is an option for use by developers; most people should | 13 | This is an option for use by developers; most people should |
| 13 | say N here. This enables comedi core and driver debugging. | 14 | say N here. This enables comedi core and driver debugging. |
| 14 | 15 | ||
| 15 | config COMEDI_DEFAULT_BUF_SIZE_KB | 16 | config COMEDI_DEFAULT_BUF_SIZE_KB |
| 16 | int "Comedi default initial asynchronous buffer size in KiB" | 17 | int "Comedi default initial asynchronous buffer size in KiB" |
| 17 | default "2048" | 18 | default "2048" |
| 18 | ---help--- | 19 | help |
| 19 | This is the default asynchronous buffer size which is used for | 20 | This is the default asynchronous buffer size which is used for |
| 20 | commands running in the background in kernel space. This | 21 | commands running in the background in kernel space. This |
| 21 | defaults to 2048 KiB of memory so that a 16 channel card | 22 | defaults to 2048 KiB of memory so that a 16 channel card |
| @@ -24,7 +25,7 @@ config COMEDI_DEFAULT_BUF_SIZE_KB · 2 unmodified lines | |||
| 24 | config COMEDI_DEFAULT_BUF_MAXSIZE_KB | 25 | config COMEDI_DEFAULT_BUF_MAXSIZE_KB |
| 25 | int "Comedi default maximum asynchronous buffer size in KiB" | 26 | int "Comedi default maximum asynchronous buffer size in KiB" |
| 26 | default "20480" | 27 | default "20480" |
| 27 | ---help--- | 28 | help |
| 28 | This is the default maximum asynchronous buffer size which can | 29 | This is the default maximum asynchronous buffer size which can |
| 29 | be requested by a userspace program without root privileges. | 30 | be requested by a userspace program without root privileges. |
| 30 | This is set to 20480 KiB so that a fast I/O card with 16 | 31 | This is set to 20480 KiB so that a fast I/O card with 16 |
| @@ -32,7 +33,7 @@ config COMEDI_DEFAULT_BUF_MAXSIZE_KB · 1 unmodified line | |||
| 32 | 33 | ||
| 33 | menuconfig COMEDI_MISC_DRIVERS | 34 | menuconfig COMEDI_MISC_DRIVERS |
| 34 | bool "Comedi misc drivers" | 35 | bool "Comedi misc drivers" |
| 35 | ---help--- | 36 | help |
| 36 | Enable comedi misc drivers to be built | 37 | Enable comedi misc drivers to be built |
| 37 | 38 | ||
| 38 | Note that the answer to this question won't directly affect the | 39 | Note that the answer to this question won't directly affect the |
| @@ -44,7 +45,7 @@ if COMEDI_MISC_DRIVERS · 5 unmodified lines | |||
| 44 | config COMEDI_BOND | 45 | config COMEDI_BOND |
| 45 | tristate "Comedi device bonding support" | 46 | tristate "Comedi device bonding support" |
| 46 | select COMEDI_KCOMEDILIB | 47 | select COMEDI_KCOMEDILIB |
| 47 | ---help--- | 48 | help |
| 48 | Enable support for a driver to 'bond' (merge) multiple subdevices | 49 | Enable support for a driver to 'bond' (merge) multiple subdevices |
| 49 | from multiple devices together as one. | 50 | from multiple devices together as one. |
| 50 | 51 | ||
| @@ -55,7 +56,7 @@ config COMEDI_BOND · 4 unmodified lines | |||
| 55 | 56 | ||
| 56 | config COMEDI_TEST | 57 | config COMEDI_TEST |
| 57 | tristate "Fake waveform generator support" | 58 | tristate "Fake waveform generator support" |
| 58 | ---help--- | 59 | help |
| 59 | Enable support for the fake waveform generator. | 60 | Enable support for the fake waveform generator. |
| 60 | This driver is mainly for testing purposes, but can also be used to | 61 | This driver is mainly for testing purposes, but can also be used to |
| 61 | generate sample waveforms on systems that don't have data acquisition | 62 | generate sample waveforms on systems that don't have data acquisition |
| @@ -66,7 +67,7 @@ config COMEDI_TEST · 4 unmodified lines | |||
| 66 | 67 | ||
| 67 | config COMEDI_PARPORT | 68 | config COMEDI_PARPORT |
| 68 | tristate "Parallel port support" | 69 | tristate "Parallel port support" |
| 69 | ---help--- | 70 | help |
| 70 | Enable support for the standard parallel port. | 71 | Enable support for the standard parallel port. |
| 71 | A cheap and easy way to get a few more digital I/O lines. Steal | 72 | A cheap and easy way to get a few more digital I/O lines. Steal |
| 72 | additional parallel ports from old computers or your neighbors' | 73 | additional parallel ports from old computers or your neighbors' |
| @@ -78,7 +79,7 @@ config COMEDI_PARPORT · 5 unmodified lines | |||
| 78 | config COMEDI_SSV_DNP | 79 | config COMEDI_SSV_DNP |
| 79 | tristate "SSV Embedded Systems DIL/Net-PC support" | 80 | tristate "SSV Embedded Systems DIL/Net-PC support" |
| 80 | depends on X86_32 || COMPILE_TEST | 81 | depends on X86_32 || COMPILE_TEST |
| 81 | ---help--- | 82 | help |
| 82 | Enable support for SSV Embedded Systems DIL/Net-PC | 83 | Enable support for SSV Embedded Systems DIL/Net-PC |
| 83 | 84 | ||
| 84 | To compile this driver as a module, choose M here: the module will be | 85 | To compile this driver as a module, choose M here: the module will be |
| @@ -88,7 +89,7 @@ endif # COMEDI_MISC_DRIVERS · 3 unmodified lines | |||
| 88 | 89 | ||
| 89 | menuconfig COMEDI_ISA_DRIVERS | 90 | menuconfig COMEDI_ISA_DRIVERS |
| 90 | bool "Comedi ISA and PC/104 drivers" | 91 | bool "Comedi ISA and PC/104 drivers" |
| 91 | ---help--- | 92 | help |
| 92 | Enable comedi ISA and PC/104 drivers to be built | 93 | Enable comedi ISA and PC/104 drivers to be built |
| 93 | 94 | ||
| 94 | Note that the answer to this question won't directly affect the | 95 | Note that the answer to this question won't directly affect the |
| @@ -100,7 +101,7 @@ if COMEDI_ISA_DRIVERS · 5 unmodified lines | |||
| 100 | config COMEDI_PCL711 | 101 | config COMEDI_PCL711 |
| 101 | tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" | 102 | tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" |
| 102 | select COMEDI_8254 | 103 | select COMEDI_8254 |
| 103 | ---help--- | 104 | help |
| 104 | Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 | 105 | Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 |
| 105 | 106 | ||
| 106 | To compile this driver as a module, choose M here: the module will be | 107 | To compile this driver as a module, choose M here: the module will be |
| @@ -109,7 +110,7 @@ config COMEDI_PCL711 · 2 unmodified lines | |||
| 109 | config COMEDI_PCL724 | 110 | config COMEDI_PCL724 |
| 110 | tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" | 111 | tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" |
| 111 | select COMEDI_8255 | 112 | select COMEDI_8255 |
| 112 | ---help--- | 113 | help |
| 113 | Enable support for ISA and PC/104 based 8255 digital i/o boards. This | 114 | Enable support for ISA and PC/104 based 8255 digital i/o boards. This |
| 114 | driver provides a legacy comedi driver wrapper for the generic 8255 | 115 | driver provides a legacy comedi driver wrapper for the generic 8255 |
| 115 | support driver. | 116 | support driver. |
| @@ -129,7 +130,7 @@ config COMEDI_PCL724 · 13 unmodified lines | |||
| 129 | 130 | ||
| 130 | config COMEDI_PCL726 | 131 | config COMEDI_PCL726 |
| 131 | tristate "Advantech PCL-726 and compatible ISA card support" | 132 | tristate "Advantech PCL-726 and compatible ISA card support" |
| 132 | ---help--- | 133 | help |
| 133 | Enable support for Advantech PCL-726 and compatible ISA cards. | 134 | Enable support for Advantech PCL-726 and compatible ISA cards. |
| 134 | 135 | ||
| 135 | To compile this driver as a module, choose M here: the module will be | 136 | To compile this driver as a module, choose M here: the module will be |
| @@ -137,7 +138,7 @@ config COMEDI_PCL726 · 1 unmodified line | |||
| 137 | 138 | ||
| 138 | config COMEDI_PCL730 | 139 | config COMEDI_PCL730 |
| 139 | tristate "Simple Digital I/O board support (8-bit ports)" | 140 | tristate "Simple Digital I/O board support (8-bit ports)" |
| 140 | ---help--- | 141 | help |
| 141 | Enable support for various simple ISA or PC/104 Digital I/O boards. | 142 | Enable support for various simple ISA or PC/104 Digital I/O boards. |
| 142 | These boards all use 8-bit I/O ports. | 143 | These boards all use 8-bit I/O ports. |
| 143 | 144 | ||
| @@ -162,7 +163,7 @@ config COMEDI_PCL812 · 18 unmodified lines | |||
| 162 | tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" | 163 | tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" |
| 163 | select COMEDI_ISADMA if ISA_DMA_API | 164 | select COMEDI_ISADMA if ISA_DMA_API |
| 164 | select COMEDI_8254 | 165 | select COMEDI_8254 |
| 165 | ---help--- | 166 | help |
| 166 | Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink | 167 | Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink |
| 167 | ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, | 168 | ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, |
| 168 | A-822PGH/PGL, A-823PGH/PGL, A-826PG and ICP DAS ISO-813 ISA cards | 169 | A-822PGH/PGL, A-823PGH/PGL, A-826PG and ICP DAS ISO-813 ISA cards |
| @@ -174,7 +175,7 @@ config COMEDI_PCL816 · 5 unmodified lines | |||
| 174 | tristate "Advantech PCL-814 and PCL-816 ISA card support" | 175 | tristate "Advantech PCL-814 and PCL-816 ISA card support" |
| 175 | select COMEDI_ISADMA if ISA_DMA_API | 176 | select COMEDI_ISADMA if ISA_DMA_API |
| 176 | select COMEDI_8254 | 177 | select COMEDI_8254 |
| 177 | ---help--- | 178 | help |
| 178 | Enable support for Advantech PCL-814 and PCL-816 ISA cards | 179 | Enable support for Advantech PCL-814 and PCL-816 ISA cards |
| 179 | 180 | ||
| 180 | To compile this driver as a module, choose M here: the module will be | 181 | To compile this driver as a module, choose M here: the module will be |
| @@ -184,7 +185,7 @@ config COMEDI_PCL818 · 3 unmodified lines | |||
| 184 | tristate "Advantech PCL-718 and PCL-818 ISA card support" | 185 | tristate "Advantech PCL-718 and PCL-818 ISA card support" |
| 185 | select COMEDI_ISADMA if ISA_DMA_API | 186 | select COMEDI_ISADMA if ISA_DMA_API |
| 186 | select COMEDI_8254 | 187 | select COMEDI_8254 |
| 187 | ---help--- | 188 | help |
| 188 | Enable support for Advantech PCL-818 ISA cards | 189 | Enable support for Advantech PCL-818 ISA cards |
| 189 | PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 | 190 | PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 |
| 190 | 191 | ||
| @@ -194,7 +195,7 @@ config COMEDI_PCL818 · 3 unmodified lines | |||
| 194 | config COMEDI_PCM3724 | 195 | config COMEDI_PCM3724 |
| 195 | tristate "Advantech PCM-3724 PC/104 card support" | 196 | tristate "Advantech PCM-3724 PC/104 card support" |
| 196 | select COMEDI_8255 | 197 | select COMEDI_8255 |
| 197 | ---help--- | 198 | help |
| 198 | Enable support for Advantech PCM-3724 PC/104 cards. | 199 | Enable support for Advantech PCM-3724 PC/104 cards. |
| 199 | 200 | ||
| 200 | To compile this driver as a module, choose M here: the module will be | 201 | To compile this driver as a module, choose M here: the module will be |
| @@ -203,7 +204,7 @@ config COMEDI_PCM3724 · 2 unmodified lines | |||
| 203 | config COMEDI_AMPLC_DIO200_ISA | 204 | config COMEDI_AMPLC_DIO200_ISA |
| 204 | tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" | 205 | tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" |
| 205 | select COMEDI_AMPLC_DIO200 | 206 | select COMEDI_AMPLC_DIO200 |
| 206 | ---help--- | 207 | help |
| 207 | Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and | 208 | Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and |
| 208 | PC272E ISA DIO boards | 209 | PC272E ISA DIO boards |
| 209 | 210 | ||
| @@ -213,7 +214,7 @@ config COMEDI_AMPLC_DIO200_ISA · 3 unmodified lines | |||
| 213 | config COMEDI_AMPLC_PC236_ISA | 214 | config COMEDI_AMPLC_PC236_ISA |
| 214 | tristate "Amplicon PC36AT DIO board support" | 215 | tristate "Amplicon PC36AT DIO board support" |
| 215 | select COMEDI_AMPLC_PC236 | 216 | select COMEDI_AMPLC_PC236 |
| 216 | ---help--- | 217 | help |
| 217 | Enable support for Amplicon PC36AT ISA DIO board. | 218 | Enable support for Amplicon PC36AT ISA DIO board. |
| 218 | 219 | ||
| 219 | To compile this driver as a module, choose M here: the module will be | 220 | To compile this driver as a module, choose M here: the module will be |
| @@ -221,7 +222,7 @@ config COMEDI_AMPLC_PC236_ISA · 1 unmodified line | |||
| 221 | 222 | ||
| 222 | config COMEDI_AMPLC_PC263_ISA | 223 | config COMEDI_AMPLC_PC263_ISA |
| 223 | tristate "Amplicon PC263 relay board support" | 224 | tristate "Amplicon PC263 relay board support" |
| 224 | ---help--- | 225 | help |
| 225 | Enable support for Amplicon PC263 ISA relay board. This board has | 226 | Enable support for Amplicon PC263 ISA relay board. This board has |
| 226 | 16 reed relay output channels. | 227 | 16 reed relay output channels. |
| 227 | 228 | ||
| @@ -230,7 +231,7 @@ config COMEDI_AMPLC_PC263_ISA · 2 unmodified lines | |||
| 230 | 231 | ||
| 231 | config COMEDI_RTI800 | 232 | config COMEDI_RTI800 |
| 232 | tristate "Analog Devices RTI-800/815 ISA card support" | 233 | tristate "Analog Devices RTI-800/815 ISA card support" |
| 233 | ---help--- | 234 | help |
| 234 | Enable support for Analog Devices RTI-800/815 ISA cards | 235 | Enable support for Analog Devices RTI-800/815 ISA cards |
| 235 | 236 | ||
| 236 | To compile this driver as a module, choose M here: the module will be | 237 | To compile this driver as a module, choose M here: the module will be |
| @@ -238,7 +239,7 @@ config COMEDI_RTI800 · 1 unmodified line | |||
| 238 | 239 | ||
| 239 | config COMEDI_RTI802 | 240 | config COMEDI_RTI802 |
| 240 | tristate "Analog Devices RTI-802 ISA card support" | 241 | tristate "Analog Devices RTI-802 ISA card support" |
| 241 | ---help--- | 242 | help |
| 242 | Enable support for Analog Devices RTI-802 ISA cards | 243 | Enable support for Analog Devices RTI-802 ISA cards |
| 243 | 244 | ||
| 244 | To compile this driver as a module, choose M here: the module will be | 245 | To compile this driver as a module, choose M here: the module will be |
| @@ -246,7 +247,7 @@ config COMEDI_RTI802 · 1 unmodified line | |||
| 246 | 247 | ||
| 247 | config COMEDI_DAC02 | 248 | config COMEDI_DAC02 |
| 248 | tristate "Keithley Metrabyte DAC02 compatible ISA card support" | 249 | tristate "Keithley Metrabyte DAC02 compatible ISA card support" |
| 249 | ---help--- | 250 | help |
| 250 | Enable support for Keithley Metrabyte DAC02 compatible ISA cards. | 251 | Enable support for Keithley Metrabyte DAC02 compatible ISA cards. |
| 251 | 252 | ||
| 252 | To compile this driver as a module, choose M here: the module will be | 253 | To compile this driver as a module, choose M here: the module will be |
| @@ -256,7 +257,7 @@ config COMEDI_DAS16M1 · 3 unmodified lines | |||
| 256 | tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" | 257 | tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" |
| 257 | select COMEDI_8254 | 258 | select COMEDI_8254 |
| 258 | select COMEDI_8255 | 259 | select COMEDI_8255 |
| 259 | ---help--- | 260 | help |
| 260 | Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. | 261 | Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. |
| 261 | 262 | ||
| 262 | To compile this driver as a module, choose M here: the module will be | 263 | To compile this driver as a module, choose M here: the module will be |
| @@ -265,7 +266,7 @@ config COMEDI_DAS16M1 · 2 unmodified lines | |||
| 265 | config COMEDI_DAS08_ISA | 266 | config COMEDI_DAS08_ISA |
| 266 | tristate "DAS-08 compatible ISA and PC/104 card support" | 267 | tristate "DAS-08 compatible ISA and PC/104 card support" |
| 267 | select COMEDI_DAS08 | 268 | select COMEDI_DAS08 |
| 268 | ---help--- | 269 | help |
| 269 | Enable support for Keithley Metrabyte/ComputerBoards DAS08 | 270 | Enable support for Keithley Metrabyte/ComputerBoards DAS08 |
| 270 | and compatible ISA and PC/104 cards: | 271 | and compatible ISA and PC/104 cards: |
| 271 | Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH, | 272 | Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH, |
| @@ -280,7 +281,7 @@ config COMEDI_DAS16 · 8 unmodified lines | |||
| 280 | select COMEDI_ISADMA if ISA_DMA_API | 281 | select COMEDI_ISADMA if ISA_DMA_API |
| 281 | select COMEDI_8254 | 282 | select COMEDI_8254 |
| 282 | select COMEDI_8255 | 283 | select COMEDI_8255 |
| 283 | ---help--- | 284 | help |
| 284 | Enable support for Keithley Metrabyte/ComputerBoards DAS16 | 285 | Enable support for Keithley Metrabyte/ComputerBoards DAS16 |
| 285 | and compatible ISA and PC/104 cards: | 286 | and compatible ISA and PC/104 cards: |
| 286 | Keithley Metrabyte DAS-16, DAS-16G, DAS-16F, DAS-1201, DAS-1202, | 287 | Keithley Metrabyte DAS-16, DAS-16G, DAS-16F, DAS-1201, DAS-1202, |
| @@ -296,7 +297,7 @@ config COMEDI_DAS16 · 9 unmodified lines | |||
| 296 | config COMEDI_DAS800 | 297 | config COMEDI_DAS800 |
| 297 | tristate "DAS800 and compatible ISA card support" | 298 | tristate "DAS800 and compatible ISA card support" |
| 298 | select COMEDI_8254 | 299 | select COMEDI_8254 |
| 299 | ---help--- | 300 | help |
| 300 | Enable support for Keithley Metrabyte DAS800 and compatible ISA cards | 301 | Enable support for Keithley Metrabyte DAS800 and compatible ISA cards |
| 301 | Keithley Metrabyte DAS-800, DAS-801, DAS-802 | 302 | Keithley Metrabyte DAS-800, DAS-801, DAS-802 |
| 302 | Measurement Computing CIO-DAS800, CIO-DAS801, CIO-DAS802 and | 303 | Measurement Computing CIO-DAS800, CIO-DAS801, CIO-DAS802 and |
| @@ -309,7 +310,7 @@ config COMEDI_DAS1800 · 6 unmodified lines | |||
| 309 | tristate "DAS1800 and compatible ISA card support" | 310 | tristate "DAS1800 and compatible ISA card support" |
| 310 | select COMEDI_ISADMA if ISA_DMA_API | 311 | select COMEDI_ISADMA if ISA_DMA_API |
| 311 | select COMEDI_8254 | 312 | select COMEDI_8254 |
| 312 | ---help--- | 313 | help |
| 313 | Enable support for DAS1800 and compatible ISA cards | 314 | Enable support for DAS1800 and compatible ISA cards |
| 314 | Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, | 315 | Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, |
| 315 | DAS-1702ST, DAS-1702ST-DA, DAS-1702HR, DAS-1702HR-DA, DAS-1702/AO, | 316 | DAS-1702ST, DAS-1702ST-DA, DAS-1702HR, DAS-1702HR-DA, DAS-1702/AO, |
| @@ -323,7 +324,7 @@ config COMEDI_DAS1800 · 7 unmodified lines | |||
| 323 | config COMEDI_DAS6402 | 324 | config COMEDI_DAS6402 |
| 324 | tristate "DAS6402 and compatible ISA card support" | 325 | tristate "DAS6402 and compatible ISA card support" |
| 325 | select COMEDI_8254 | 326 | select COMEDI_8254 |
| 326 | ---help--- | 327 | help |
| 327 | Enable support for DAS6402 and compatible ISA cards | 328 | Enable support for DAS6402 and compatible ISA cards |
| 328 | Computerboards, Keithley Metrabyte DAS6402 and compatibles | 329 | Computerboards, Keithley Metrabyte DAS6402 and compatibles |
| 329 | 330 | ||
| @@ -332,7 +333,7 @@ config COMEDI_DAS6402 · 2 unmodified lines | |||
| 332 | 333 | ||
| 333 | config COMEDI_DT2801 | 334 | config COMEDI_DT2801 |
| 334 | tristate "Data Translation DT2801 ISA card support" | 335 | tristate "Data Translation DT2801 ISA card support" |
| 335 | ---help--- | 336 | help |
| 336 | Enable support for Data Translation DT2801 ISA cards | 337 | Enable support for Data Translation DT2801 ISA cards |
| 337 | 338 | ||
| 338 | To compile this driver as a module, choose M here: the module will be | 339 | To compile this driver as a module, choose M here: the module will be |
| @@ -340,7 +341,7 @@ config COMEDI_DT2801 · 1 unmodified line | |||
| 340 | 341 | ||
| 341 | config COMEDI_DT2811 | 342 | config COMEDI_DT2811 |
| 342 | tristate "Data Translation DT2811 ISA card support" | 343 | tristate "Data Translation DT2811 ISA card support" |
| 343 | ---help--- | 344 | help |
| 344 | Enable support for Data Translation DT2811 ISA cards | 345 | Enable support for Data Translation DT2811 ISA cards |
| 345 | 346 | ||
| 346 | To compile this driver as a module, choose M here: the module will be | 347 | To compile this driver as a module, choose M here: the module will be |
| @@ -348,7 +349,7 @@ config COMEDI_DT2811 · 1 unmodified line | |||
| 348 | 349 | ||
| 349 | config COMEDI_DT2814 | 350 | config COMEDI_DT2814 |
| 350 | tristate "Data Translation DT2814 ISA card support" | 351 | tristate "Data Translation DT2814 ISA card support" |
| 351 | ---help--- | 352 | help |
| 352 | Enable support for Data Translation DT2814 ISA cards | 353 | Enable support for Data Translation DT2814 ISA cards |
| 353 | 354 | ||
| 354 | To compile this driver as a module, choose M here: the module will be | 355 | To compile this driver as a module, choose M here: the module will be |
| @@ -356,7 +357,7 @@ config COMEDI_DT2814 · 1 unmodified line | |||
| 356 | 357 | ||
| 357 | config COMEDI_DT2815 | 358 | config COMEDI_DT2815 |
| 358 | tristate "Data Translation DT2815 ISA card support" | 359 | tristate "Data Translation DT2815 ISA card support" |
| 359 | ---help--- | 360 | help |
| 360 | Enable support for Data Translation DT2815 ISA cards | 361 | Enable support for Data Translation DT2815 ISA cards |
| 361 | 362 | ||
| 362 | To compile this driver as a module, choose M here: the module will be | 363 | To compile this driver as a module, choose M here: the module will be |
| @@ -364,7 +365,7 @@ config COMEDI_DT2815 · 1 unmodified line | |||
| 364 | 365 | ||
| 365 | config COMEDI_DT2817 | 366 | config COMEDI_DT2817 |
| 366 | tristate "Data Translation DT2817 ISA card support" | 367 | tristate "Data Translation DT2817 ISA card support" |
| 367 | ---help--- | 368 | help |
| 368 | Enable support for Data Translation DT2817 ISA cards | 369 | Enable support for Data Translation DT2817 ISA cards |
| 369 | 370 | ||
| 370 | To compile this driver as a module, choose M here: the module will be | 371 | To compile this driver as a module, choose M here: the module will be |
| @@ -373,7 +374,7 @@ config COMEDI_DT2817 · 2 unmodified lines | |||
| 373 | config COMEDI_DT282X | 374 | config COMEDI_DT282X |
| 374 | tristate "Data Translation DT2821 series and DT-EZ ISA card support" | 375 | tristate "Data Translation DT2821 series and DT-EZ ISA card support" |
| 375 | select COMEDI_ISADMA if ISA_DMA_API | 376 | select COMEDI_ISADMA if ISA_DMA_API |
| 376 | ---help--- | 377 | help |
| 377 | Enable support for Data Translation DT2821 series including DT-EZ | 378 | Enable support for Data Translation DT2821 series including DT-EZ |
| 378 | DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, | 379 | DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, |
| 379 | DT2823 (dt2823), DT2824-PGH, DT2824-PGL, DT2825, DT2827, DT2828, | 380 | DT2823 (dt2823), DT2824-PGH, DT2824-PGL, DT2825, DT2827, DT2828, |
| @@ -385,7 +386,7 @@ config COMEDI_DT282X · 5 unmodified lines | |||
| 385 | config COMEDI_DMM32AT | 386 | config COMEDI_DMM32AT |
| 386 | tristate "Diamond Systems MM-32-AT PC/104 board support" | 387 | tristate "Diamond Systems MM-32-AT PC/104 board support" |
| 387 | select COMEDI_8255 | 388 | select COMEDI_8255 |
| 388 | ---help--- | 389 | help |
| 389 | Enable support for Diamond Systems MM-32-AT PC/104 boards | 390 | Enable support for Diamond Systems MM-32-AT PC/104 boards |
| 390 | 391 | ||
| 391 | To compile this driver as a module, choose M here: the module will be | 392 | To compile this driver as a module, choose M here: the module will be |
| @@ -393,7 +394,7 @@ config COMEDI_DMM32AT · 1 unmodified line | |||
| 393 | 394 | ||
| 394 | config COMEDI_FL512 | 395 | config COMEDI_FL512 |
| 395 | tristate "FL512 ISA card support" | 396 | tristate "FL512 ISA card support" |
| 396 | ---help--- | 397 | help |
| 397 | Enable support for FL512 ISA card | 398 | Enable support for FL512 ISA card |
| 398 | 399 | ||
| 399 | To compile this driver as a module, choose M here: the module will be | 400 | To compile this driver as a module, choose M here: the module will be |
| @@ -403,7 +404,7 @@ config COMEDI_AIO_AIO12_8 · 3 unmodified lines | |||
| 403 | tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" | 404 | tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" |
| 404 | select COMEDI_8254 | 405 | select COMEDI_8254 |
| 405 | select COMEDI_8255 | 406 | select COMEDI_8255 |
| 406 | ---help--- | 407 | help |
| 407 | Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board | 408 | Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board |
| 408 | 409 | ||
| 409 | To compile this driver as a module, choose M here: the module will be | 410 | To compile this driver as a module, choose M here: the module will be |
| @@ -411,7 +412,7 @@ config COMEDI_AIO_AIO12_8 · 1 unmodified line | |||
| 411 | 412 | ||
| 412 | config COMEDI_AIO_IIRO_16 | 413 | config COMEDI_AIO_IIRO_16 |
| 413 | tristate "I/O Products PC/104 IIRO16 Board support" | 414 | tristate "I/O Products PC/104 IIRO16 Board support" |
| 414 | ---help--- | 415 | help |
| 415 | Enable support for I/O Products PC/104 IIRO16 Relay And Isolated | 416 | Enable support for I/O Products PC/104 IIRO16 Relay And Isolated |
| 416 | Input Board | 417 | Input Board |
| 417 | 418 | ||
| @@ -421,7 +422,7 @@ config COMEDI_AIO_IIRO_16 · 3 unmodified lines | |||
| 421 | config COMEDI_II_PCI20KC | 422 | config COMEDI_II_PCI20KC |
| 422 | tristate "Intelligent Instruments PCI-20001C carrier support" | 423 | tristate "Intelligent Instruments PCI-20001C carrier support" |
| 423 | depends on HAS_IOMEM | 424 | depends on HAS_IOMEM |
| 424 | ---help--- | 425 | help |
| 425 | Enable support for Intelligent Instruments PCI-20001C carrier | 426 | Enable support for Intelligent Instruments PCI-20001C carrier |
| 426 | PCI-20001, PCI-20006 and PCI-20341 | 427 | PCI-20001, PCI-20006 and PCI-20341 |
| 427 | 428 | ||
| @@ -430,7 +431,7 @@ config COMEDI_II_PCI20KC · 2 unmodified lines | |||
| 430 | 431 | ||
| 431 | config COMEDI_C6XDIGIO | 432 | config COMEDI_C6XDIGIO |
| 432 | tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" | 433 | tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" |
| 433 | ---help--- | 434 | help |
| 434 | Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter | 435 | Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter |
| 435 | card | 436 | card |
| 436 | 437 | ||
| @@ -439,7 +440,7 @@ config COMEDI_C6XDIGIO · 2 unmodified lines | |||
| 439 | 440 | ||
| 440 | config COMEDI_MPC624 | 441 | config COMEDI_MPC624 |
| 441 | tristate "Micro/sys MPC-624 PC/104 board support" | 442 | tristate "Micro/sys MPC-624 PC/104 board support" |
| 442 | ---help--- | 443 | help |
| 443 | Enable support for Micro/sys MPC-624 PC/104 board | 444 | Enable support for Micro/sys MPC-624 PC/104 board |
| 444 | 445 | ||
| 445 | To compile this driver as a module, choose M here: the module will be | 446 | To compile this driver as a module, choose M here: the module will be |
| @@ -447,7 +448,7 @@ config COMEDI_MPC624 · 1 unmodified line | |||
| 447 | 448 | ||
| 448 | config COMEDI_ADQ12B | 449 | config COMEDI_ADQ12B |
| 449 | tristate "MicroAxial ADQ12-B data acquisition and control card support" | 450 | tristate "MicroAxial ADQ12-B data acquisition and control card support" |
| 450 | ---help--- | 451 | help |
| 451 | Enable MicroAxial ADQ12-B daq and control card support. | 452 | Enable MicroAxial ADQ12-B daq and control card support. |
| 452 | 453 | ||
| 453 | To compile this driver as a module, choose M here: the module will be | 454 | To compile this driver as a module, choose M here: the module will be |
| @@ -457,7 +458,7 @@ config COMEDI_NI_AT_A2150 · 3 unmodified lines | |||
| 457 | tristate "NI AT-A2150 ISA card support" | 458 | tristate "NI AT-A2150 ISA card support" |
| 458 | select COMEDI_ISADMA if ISA_DMA_API | 459 | select COMEDI_ISADMA if ISA_DMA_API |
| 459 | select COMEDI_8254 | 460 | select COMEDI_8254 |
| 460 | ---help--- | 461 | help |
| 461 | Enable support for National Instruments AT-A2150 cards | 462 | Enable support for National Instruments AT-A2150 cards |
| 462 | 463 | ||
| 463 | To compile this driver as a module, choose M here: the module will be | 464 | To compile this driver as a module, choose M here: the module will be |
| @@ -466,7 +467,7 @@ config COMEDI_NI_AT_A2150 · 2 unmodified lines | |||
| 466 | config COMEDI_NI_AT_AO | 467 | config COMEDI_NI_AT_AO |
| 467 | tristate "NI AT-AO-6/10 EISA card support" | 468 | tristate "NI AT-AO-6/10 EISA card support" |
| 468 | select COMEDI_8254 | 469 | select COMEDI_8254 |
| 469 | ---help--- | 470 | help |
| 470 | Enable support for National Instruments AT-AO-6/10 cards | 471 | Enable support for National Instruments AT-AO-6/10 cards |
| 471 | 472 | ||
| 472 | To compile this driver as a module, choose M here: the module will be | 473 | To compile this driver as a module, choose M here: the module will be |
| @@ -476,7 +477,7 @@ config COMEDI_NI_ATMIO · 3 unmodified lines | |||
| 476 | tristate "NI AT-MIO E series ISA-PNP card support" | 477 | tristate "NI AT-MIO E series ISA-PNP card support" |
| 477 | select COMEDI_8255 | 478 | select COMEDI_8255 |
| 478 | select COMEDI_NI_TIO | 479 | select COMEDI_NI_TIO |
| 479 | ---help--- | 480 | help |
| 480 | Enable support for National Instruments AT-MIO E series cards | 481 | Enable support for National Instruments AT-MIO E series cards |
| 481 | National Instruments AT-MIO-16E-1 (ni_atmio), | 482 | National Instruments AT-MIO-16E-1 (ni_atmio), |
| 482 | AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3, | 483 | AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3, |
| @@ -488,7 +489,7 @@ config COMEDI_NI_ATMIO · 5 unmodified lines | |||
| 488 | config COMEDI_NI_ATMIO16D | 489 | config COMEDI_NI_ATMIO16D |
| 489 | tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support" | 490 | tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support" |
| 490 | select COMEDI_8255 | 491 | select COMEDI_8255 |
| 491 | ---help--- | 492 | help |
| 492 | Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards. | 493 | Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards. |
| 493 | 494 | ||
| 494 | To compile this driver as a module, choose M here: the module will be | 495 | To compile this driver as a module, choose M here: the module will be |
| @@ -497,7 +498,7 @@ config COMEDI_NI_ATMIO16D · 2 unmodified lines | |||
| 497 | config COMEDI_NI_LABPC_ISA | 498 | config COMEDI_NI_LABPC_ISA |
| 498 | tristate "NI Lab-PC and compatibles ISA support" | 499 | tristate "NI Lab-PC and compatibles ISA support" |
| 499 | select COMEDI_NI_LABPC | 500 | select COMEDI_NI_LABPC |
| 500 | ---help--- | 501 | help |
| 501 | Enable support for National Instruments Lab-PC and compatibles | 502 | Enable support for National Instruments Lab-PC and compatibles |
| 502 | Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. | 503 | Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. |
| 503 | Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has | 504 | Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has |
| @@ -508,7 +509,7 @@ config COMEDI_NI_LABPC_ISA · 4 unmodified lines | |||
| 508 | 509 | ||
| 509 | config COMEDI_PCMAD | 510 | config COMEDI_PCMAD |
| 510 | tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support" | 511 | tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support" |
| 511 | ---help--- | 512 | help |
| 512 | Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards. | 513 | Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards. |
| 513 | 514 | ||
| 514 | To compile this driver as a module, choose M here: the module will be | 515 | To compile this driver as a module, choose M here: the module will be |
| @@ -516,7 +517,7 @@ config COMEDI_PCMAD · 1 unmodified line | |||
| 516 | 517 | ||
| 517 | config COMEDI_PCMDA12 | 518 | config COMEDI_PCMDA12 |
| 518 | tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support" | 519 | tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support" |
| 519 | ---help--- | 520 | help |
| 520 | Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards. | 521 | Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards. |
| 521 | Note that the board is not ISA-PNP capable and thus needs the I/O | 522 | Note that the board is not ISA-PNP capable and thus needs the I/O |
| 522 | port comedi_config parameter. | 523 | port comedi_config parameter. |
| @@ -526,7 +527,7 @@ config COMEDI_PCMDA12 · 3 unmodified lines | |||
| 526 | 527 | ||
| 527 | config COMEDI_PCMMIO | 528 | config COMEDI_PCMMIO |
| 528 | tristate "Winsystems PCM-MIO PC/104 board support" | 529 | tristate "Winsystems PCM-MIO PC/104 board support" |
| 529 | ---help--- | 530 | help |
| 530 | Enable support for Winsystems PCM-MIO multifunction PC/104 boards. | 531 | Enable support for Winsystems PCM-MIO multifunction PC/104 boards. |
| 531 | 532 | ||
| 532 | To compile this driver as a module, choose M here: the module will be | 533 | To compile this driver as a module, choose M here: the module will be |
| @@ -534,7 +535,7 @@ config COMEDI_PCMMIO · 1 unmodified line | |||
| 534 | 535 | ||
| 535 | config COMEDI_PCMUIO | 536 | config COMEDI_PCMUIO |
| 536 | tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support" | 537 | tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support" |
| 537 | ---help--- | 538 | help |
| 538 | Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards. | 539 | Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards. |
| 539 | 540 | ||
| 540 | To compile this driver as a module, choose M here: the module will be | 541 | To compile this driver as a module, choose M here: the module will be |
| @@ -542,7 +543,7 @@ config COMEDI_PCMUIO · 1 unmodified line | |||
| 542 | 543 | ||
| 543 | config COMEDI_MULTIQ3 | 544 | config COMEDI_MULTIQ3 |
| 544 | tristate "Quanser Consulting MultiQ-3 ISA card support" | 545 | tristate "Quanser Consulting MultiQ-3 ISA card support" |
| 545 | ---help--- | 546 | help |
| 546 | Enable support for Quanser Consulting MultiQ-3 ISA cards | 547 | Enable support for Quanser Consulting MultiQ-3 ISA cards |
| 547 | 548 | ||
| 548 | To compile this driver as a module, choose M here: the module will be | 549 | To compile this driver as a module, choose M here: the module will be |
| @@ -550,7 +551,7 @@ config COMEDI_MULTIQ3 · 1 unmodified line | |||
| 550 | 551 | ||
| 551 | config COMEDI_S526 | 552 | config COMEDI_S526 |
| 552 | tristate "Sensoray s526 support" | 553 | tristate "Sensoray s526 support" |
| 553 | ---help--- | 554 | help |
| 554 | Enable support for Sensoray s526 | 555 | Enable support for Sensoray s526 |
| 555 | 556 | ||
| 556 | To compile this driver as a module, choose M here: the module will be | 557 | To compile this driver as a module, choose M here: the module will be |
| @@ -561,7 +562,7 @@ endif # COMEDI_ISA_DRIVERS · 4 unmodified lines | |||
| 561 | menuconfig COMEDI_PCI_DRIVERS | 562 | menuconfig COMEDI_PCI_DRIVERS |
| 562 | tristate "Comedi PCI drivers" | 563 | tristate "Comedi PCI drivers" |
| 563 | depends on PCI | 564 | depends on PCI |
| 564 | ---help--- | 565 | help |
| 565 | Enable support for comedi PCI drivers. | 566 | Enable support for comedi PCI drivers. |
| 566 | 567 | ||
| 567 | To compile this support as a module, choose M here: the module will | 568 | To compile this support as a module, choose M here: the module will |
| @@ -572,7 +573,7 @@ if COMEDI_PCI_DRIVERS · 4 unmodified lines | |||
| 572 | config COMEDI_8255_PCI | 573 | config COMEDI_8255_PCI |
| 573 | tristate "Generic PCI based 8255 digital i/o board support" | 574 | tristate "Generic PCI based 8255 digital i/o board support" |
| 574 | select COMEDI_8255 | 575 | select COMEDI_8255 |
| 575 | ---help--- | 576 | help |
| 576 | Enable support for PCI based 8255 digital i/o boards. This driver | 577 | Enable support for PCI based 8255 digital i/o boards. This driver |
| 577 | provides a PCI wrapper around the generic 8255 driver. | 578 | provides a PCI wrapper around the generic 8255 driver. |
| 578 | 579 | ||
| @@ -588,14 +589,14 @@ config COMEDI_8255_PCI · 9 unmodified lines | |||
| 588 | 589 | ||
| 589 | config COMEDI_ADDI_WATCHDOG | 590 | config COMEDI_ADDI_WATCHDOG |
| 590 | tristate | 591 | tristate |
| 591 | ---help--- | 592 | help |
| 592 | Provides support for the watchdog subdevice found on many ADDI-DATA | 593 | Provides support for the watchdog subdevice found on many ADDI-DATA |
| 593 | boards. This module will be automatically selected when needed. The | 594 | boards. This module will be automatically selected when needed. The |
| 594 | module will be called addi_watchdog. | 595 | module will be called addi_watchdog. |
| 595 | 596 | ||
| 596 | config COMEDI_ADDI_APCI_1032 | 597 | config COMEDI_ADDI_APCI_1032 |
| 597 | tristate "ADDI-DATA APCI_1032 support" | 598 | tristate "ADDI-DATA APCI_1032 support" |
| 598 | ---help--- | 599 | help |
| 599 | Enable support for ADDI-DATA APCI_1032 cards | 600 | Enable support for ADDI-DATA APCI_1032 cards |
| 600 | 601 | ||
| 601 | To compile this driver as a module, choose M here: the module will be | 602 | To compile this driver as a module, choose M here: the module will be |
| @@ -603,7 +604,7 @@ config COMEDI_ADDI_APCI_1032 · 1 unmodified line | |||
| 603 | 604 | ||
| 604 | config COMEDI_ADDI_APCI_1500 | 605 | config COMEDI_ADDI_APCI_1500 |
| 605 | tristate "ADDI-DATA APCI_1500 support" | 606 | tristate "ADDI-DATA APCI_1500 support" |
| 606 | ---help--- | 607 | help |
| 607 | Enable support for ADDI-DATA APCI_1500 cards | 608 | Enable support for ADDI-DATA APCI_1500 cards |
| 608 | 609 | ||
| 609 | To compile this driver as a module, choose M here: the module will be | 610 | To compile this driver as a module, choose M here: the module will be |
| @@ -612,7 +613,7 @@ config COMEDI_ADDI_APCI_1500 · 2 unmodified lines | |||
| 612 | config COMEDI_ADDI_APCI_1516 | 613 | config COMEDI_ADDI_APCI_1516 |
| 613 | tristate "ADDI-DATA APCI-1016/1516/2016 support" | 614 | tristate "ADDI-DATA APCI-1016/1516/2016 support" |
| 614 | select COMEDI_ADDI_WATCHDOG | 615 | select COMEDI_ADDI_WATCHDOG |
| 615 | ---help--- | 616 | help |
| 616 | Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. | 617 | Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. |
| 617 | These are 16 channel, optically isolated, digital I/O boards. The 1516 | 618 | These are 16 channel, optically isolated, digital I/O boards. The 1516 |
| 618 | and 2016 boards also have a watchdog for resetting the outputs to "0". | 619 | and 2016 boards also have a watchdog for resetting the outputs to "0". |
| @@ -623,7 +624,7 @@ config COMEDI_ADDI_APCI_1516 · 4 unmodified lines | |||
| 623 | config COMEDI_ADDI_APCI_1564 | 624 | config COMEDI_ADDI_APCI_1564 |
| 624 | tristate "ADDI-DATA APCI_1564 support" | 625 | tristate "ADDI-DATA APCI_1564 support" |
| 625 | select COMEDI_ADDI_WATCHDOG | 626 | select COMEDI_ADDI_WATCHDOG |
| 626 | ---help--- | 627 | help |
| 627 | Enable support for ADDI-DATA APCI_1564 cards | 628 | Enable support for ADDI-DATA APCI_1564 cards |
| 628 | 629 | ||
| 629 | To compile this driver as a module, choose M here: the module will be | 630 | To compile this driver as a module, choose M here: the module will be |
| @@ -631,7 +632,7 @@ config COMEDI_ADDI_APCI_1564 · 1 unmodified line | |||
| 631 | 632 | ||
| 632 | config COMEDI_ADDI_APCI_16XX | 633 | config COMEDI_ADDI_APCI_16XX |
| 633 | tristate "ADDI-DATA APCI_16xx support" | 634 | tristate "ADDI-DATA APCI_16xx support" |
| 634 | ---help--- | 635 | help |
| 635 | Enable support for ADDI-DATA APCI_16xx cards | 636 | Enable support for ADDI-DATA APCI_16xx cards |
| 636 | 637 | ||
| 637 | To compile this driver as a module, choose M here: the module will be | 638 | To compile this driver as a module, choose M here: the module will be |
| @@ -640,7 +641,7 @@ config COMEDI_ADDI_APCI_16XX · 2 unmodified lines | |||
| 640 | config COMEDI_ADDI_APCI_2032 | 641 | config COMEDI_ADDI_APCI_2032 |
| 641 | tristate "ADDI-DATA APCI_2032 support" | 642 | tristate "ADDI-DATA APCI_2032 support" |
| 642 | select COMEDI_ADDI_WATCHDOG | 643 | select COMEDI_ADDI_WATCHDOG |
| 643 | ---help--- | 644 | help |
| 644 | Enable support for ADDI-DATA APCI_2032 cards | 645 | Enable support for ADDI-DATA APCI_2032 cards |
| 645 | 646 | ||
| 646 | To compile this driver as a module, choose M here: the module will be | 647 | To compile this driver as a module, choose M here: the module will be |
| @@ -649,7 +650,7 @@ config COMEDI_ADDI_APCI_2032 · 2 unmodified lines | |||
| 649 | config COMEDI_ADDI_APCI_2200 | 650 | config COMEDI_ADDI_APCI_2200 |
| 650 | tristate "ADDI-DATA APCI_2200 support" | 651 | tristate "ADDI-DATA APCI_2200 support" |
| 651 | select COMEDI_ADDI_WATCHDOG | 652 | select COMEDI_ADDI_WATCHDOG |
| 652 | ---help--- | 653 | help |
| 653 | Enable support for ADDI-DATA APCI_2200 cards | 654 | Enable support for ADDI-DATA APCI_2200 cards |
| 654 | 655 | ||
| 655 | To compile this driver as a module, choose M here: the module will be | 656 | To compile this driver as a module, choose M here: the module will be |
| @@ -658,7 +659,7 @@ config COMEDI_ADDI_APCI_2200 · 2 unmodified lines | |||
| 658 | config COMEDI_ADDI_APCI_3120 | 659 | config COMEDI_ADDI_APCI_3120 |
| 659 | tristate "ADDI-DATA APCI_3120/3001 support" | 660 | tristate "ADDI-DATA APCI_3120/3001 support" |
| 660 | depends on HAS_DMA | 661 | depends on HAS_DMA |
| 661 | ---help--- | 662 | help |
| 662 | Enable support for ADDI-DATA APCI_3120/3001 cards | 663 | Enable support for ADDI-DATA APCI_3120/3001 cards |
| 663 | 664 | ||
| 664 | To compile this driver as a module, choose M here: the module will be | 665 | To compile this driver as a module, choose M here: the module will be |
| @@ -666,7 +667,7 @@ config COMEDI_ADDI_APCI_3120 · 1 unmodified line | |||
| 666 | 667 | ||
| 667 | config COMEDI_ADDI_APCI_3501 | 668 | config COMEDI_ADDI_APCI_3501 |
| 668 | tristate "ADDI-DATA APCI_3501 support" | 669 | tristate "ADDI-DATA APCI_3501 support" |
| 669 | ---help--- | 670 | help |
| 670 | Enable support for ADDI-DATA APCI_3501 cards | 671 | Enable support for ADDI-DATA APCI_3501 cards |
| 671 | 672 | ||
| 672 | To compile this driver as a module, choose M here: the module will be | 673 | To compile this driver as a module, choose M here: the module will be |
| @@ -674,7 +675,7 @@ config COMEDI_ADDI_APCI_3501 · 1 unmodified line | |||
| 674 | 675 | ||
| 675 | config COMEDI_ADDI_APCI_3XXX | 676 | config COMEDI_ADDI_APCI_3XXX |
| 676 | tristate "ADDI-DATA APCI_3xxx support" | 677 | tristate "ADDI-DATA APCI_3xxx support" |
| 677 | ---help--- | 678 | help |
| 678 | Enable support for ADDI-DATA APCI_3xxx cards | 679 | Enable support for ADDI-DATA APCI_3xxx cards |
| 679 | 680 | ||
| 680 | To compile this driver as a module, choose M here: the module will be | 681 | To compile this driver as a module, choose M here: the module will be |
| @@ -682,7 +683,7 @@ config COMEDI_ADDI_APCI_3XXX · 1 unmodified line | |||
| 682 | 683 | ||
| 683 | config COMEDI_ADL_PCI6208 | 684 | config COMEDI_ADL_PCI6208 |
| 684 | tristate "ADLink PCI-6208A support" | 685 | tristate "ADLink PCI-6208A support" |
| 685 | ---help--- | 686 | help |
| 686 | Enable support for ADLink PCI-6208A cards | 687 | Enable support for ADLink PCI-6208A cards |
| 687 | 688 | ||
| 688 | To compile this driver as a module, choose M here: the module will be | 689 | To compile this driver as a module, choose M here: the module will be |
| @@ -690,7 +691,7 @@ config COMEDI_ADL_PCI6208 · 1 unmodified line | |||
| 690 | 691 | ||
| 691 | config COMEDI_ADL_PCI7X3X | 692 | config COMEDI_ADL_PCI7X3X |
| 692 | tristate "ADLink PCI-723X/743X isolated digital i/o board support" | 693 | tristate "ADLink PCI-723X/743X isolated digital i/o board support" |
| 693 | ---help--- | 694 | help |
| 694 | Enable support for ADlink PCI-723X/743X isolated digital i/o boards. | 695 | Enable support for ADlink PCI-723X/743X isolated digital i/o boards. |
| 695 | Supported boards include the 32-channel PCI-7230 (16 in/16 out), | 696 | Supported boards include the 32-channel PCI-7230 (16 in/16 out), |
| 696 | PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel | 697 | PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel |
| @@ -701,7 +702,7 @@ config COMEDI_ADL_PCI7X3X · 4 unmodified lines | |||
| 701 | 702 | ||
| 702 | config COMEDI_ADL_PCI8164 | 703 | config COMEDI_ADL_PCI8164 |
| 703 | tristate "ADLink PCI-8164 4 Axes Motion Control board support" | 704 | tristate "ADLink PCI-8164 4 Axes Motion Control board support" |
| 704 | ---help--- | 705 | help |
| 705 | Enable support for ADlink PCI-8164 4 Axes Motion Control board | 706 | Enable support for ADlink PCI-8164 4 Axes Motion Control board |
| 706 | 707 | ||
| 707 | To compile this driver as a module, choose M here: the module will be | 708 | To compile this driver as a module, choose M here: the module will be |
| @@ -710,7 +711,7 @@ config COMEDI_ADL_PCI8164 · 2 unmodified lines | |||
| 710 | config COMEDI_ADL_PCI9111 | 711 | config COMEDI_ADL_PCI9111 |
| 711 | tristate "ADLink PCI-9111HR support" | 712 | tristate "ADLink PCI-9111HR support" |
| 712 | select COMEDI_8254 | 713 | select COMEDI_8254 |
| 713 | ---help--- | 714 | help |
| 714 | Enable support for ADlink PCI9111 cards | 715 | Enable support for ADlink PCI9111 cards |
| 715 | 716 | ||
| 716 | To compile this driver as a module, choose M here: the module will be | 717 | To compile this driver as a module, choose M here: the module will be |
| @@ -720,7 +721,7 @@ config COMEDI_ADL_PCI9118 · 3 unmodified lines | |||
| 720 | tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" | 721 | tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" |
| 721 | depends on HAS_DMA | 722 | depends on HAS_DMA |
| 722 | select COMEDI_8254 | 723 | select COMEDI_8254 |
| 723 | ---help--- | 724 | help |
| 724 | Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards | 725 | Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards |
| 725 | 726 | ||
| 726 | To compile this driver as a module, choose M here: the module will be | 727 | To compile this driver as a module, choose M here: the module will be |
| @@ -729,7 +730,7 @@ config COMEDI_ADL_PCI9118 · 2 unmodified lines | |||
| 729 | config COMEDI_ADV_PCI1710 | 730 | config COMEDI_ADV_PCI1710 |
| 730 | tristate "Advantech PCI-171x and PCI-1731 support" | 731 | tristate "Advantech PCI-171x and PCI-1731 support" |
| 731 | select COMEDI_8254 | 732 | select COMEDI_8254 |
| 732 | ---help--- | 733 | help |
| 733 | Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, | 734 | Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, |
| 734 | PCI-1713 and PCI-1731 | 735 | PCI-1713 and PCI-1731 |
| 735 | 736 | ||
| @@ -738,7 +739,7 @@ config COMEDI_ADV_PCI1710 · 2 unmodified lines | |||
| 738 | 739 | ||
| 739 | config COMEDI_ADV_PCI1720 | 740 | config COMEDI_ADV_PCI1720 |
| 740 | tristate "Advantech PCI-1720 support" | 741 | tristate "Advantech PCI-1720 support" |
| 741 | ---help--- | 742 | help |
| 742 | Enable support for Advantech PCI-1720 Analog Output board. | 743 | Enable support for Advantech PCI-1720 Analog Output board. |
| 743 | 744 | ||
| 744 | To compile this driver as a module, choose M here: the module will be | 745 | To compile this driver as a module, choose M here: the module will be |
| @@ -746,7 +747,7 @@ config COMEDI_ADV_PCI1720 · 1 unmodified line | |||
| 746 | 747 | ||
| 747 | config COMEDI_ADV_PCI1723 | 748 | config COMEDI_ADV_PCI1723 |
| 748 | tristate "Advantech PCI-1723 support" | 749 | tristate "Advantech PCI-1723 support" |
| 749 | ---help--- | 750 | help |
| 750 | Enable support for Advantech PCI-1723 cards | 751 | Enable support for Advantech PCI-1723 cards |
| 751 | 752 | ||
| 752 | To compile this driver as a module, choose M here: the module will be | 753 | To compile this driver as a module, choose M here: the module will be |
| @@ -754,7 +755,7 @@ config COMEDI_ADV_PCI1723 · 1 unmodified line | |||
| 754 | 755 | ||
| 755 | config COMEDI_ADV_PCI1724 | 756 | config COMEDI_ADV_PCI1724 |
| 756 | tristate "Advantech PCI-1724U support" | 757 | tristate "Advantech PCI-1724U support" |
| 757 | ---help--- | 758 | help |
| 758 | Enable support for Advantech PCI-1724U cards. These are 32-channel | 759 | Enable support for Advantech PCI-1724U cards. These are 32-channel |
| 759 | analog output cards with voltage and current loop output ranges and | 760 | analog output cards with voltage and current loop output ranges and |
| 760 | 14-bit resolution. | 761 | 14-bit resolution. |
| @@ -764,7 +765,7 @@ config COMEDI_ADV_PCI1724 · 3 unmodified lines | |||
| 764 | 765 | ||
| 765 | config COMEDI_ADV_PCI1760 | 766 | config COMEDI_ADV_PCI1760 |
| 766 | tristate "Advantech PCI-1760 support" | 767 | tristate "Advantech PCI-1760 support" |
| 767 | ---help--- | 768 | help |
| 768 | Enable support for Advantech PCI-1760 board. | 769 | Enable support for Advantech PCI-1760 board. |
| 769 | 770 | ||
| 770 | To compile this driver as a module, choose M here: the module will be | 771 | To compile this driver as a module, choose M here: the module will be |
| @@ -774,7 +775,7 @@ config COMEDI_ADV_PCI_DIO · 3 unmodified lines | |||
| 774 | tristate "Advantech PCI DIO card support" | 775 | tristate "Advantech PCI DIO card support" |
| 775 | select COMEDI_8254 | 776 | select COMEDI_8254 |
| 776 | select COMEDI_8255 | 777 | select COMEDI_8255 |
| 777 | ---help--- | 778 | help |
| 778 | Enable support for Advantech PCI DIO cards | 779 | Enable support for Advantech PCI DIO cards |
| 779 | PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, | 780 | PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, |
| 780 | PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756, | 781 | PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756, |
| @@ -786,7 +787,7 @@ config COMEDI_ADV_PCI_DIO · 5 unmodified lines | |||
| 786 | config COMEDI_AMPLC_DIO200_PCI | 787 | config COMEDI_AMPLC_DIO200_PCI |
| 787 | tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support" | 788 | tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support" |
| 788 | select COMEDI_AMPLC_DIO200 | 789 | select COMEDI_AMPLC_DIO200 |
| 789 | ---help--- | 790 | help |
| 790 | Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236 | 791 | Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236 |
| 791 | and PCIe296 DIO boards. | 792 | and PCIe296 DIO boards. |
| 792 | 793 | ||
| @@ -796,7 +797,7 @@ config COMEDI_AMPLC_DIO200_PCI · 3 unmodified lines | |||
| 796 | config COMEDI_AMPLC_PC236_PCI | 797 | config COMEDI_AMPLC_PC236_PCI |
| 797 | tristate "Amplicon PCI236 DIO board support" | 798 | tristate "Amplicon PCI236 DIO board support" |
| 798 | select COMEDI_AMPLC_PC236 | 799 | select COMEDI_AMPLC_PC236 |
| 799 | ---help--- | 800 | help |
| 800 | Enable support for Amplicon PCI236 DIO board. | 801 | Enable support for Amplicon PCI236 DIO board. |
| 801 | 802 | ||
| 802 | To compile this driver as a module, choose M here: the module will be | 803 | To compile this driver as a module, choose M here: the module will be |
| @@ -804,7 +805,7 @@ config COMEDI_AMPLC_PC236_PCI · 1 unmodified line | |||
| 804 | 805 | ||
| 805 | config COMEDI_AMPLC_PC263_PCI | 806 | config COMEDI_AMPLC_PC263_PCI |
| 806 | tristate "Amplicon PCI263 relay board support" | 807 | tristate "Amplicon PCI263 relay board support" |
| 807 | ---help--- | 808 | help |
| 808 | Enable support for Amplicon PCI263 relay board. This is a PCI board | 809 | Enable support for Amplicon PCI263 relay board. This is a PCI board |
| 809 | with 16 reed relay output channels. | 810 | with 16 reed relay output channels. |
| 810 | 811 | ||
| @@ -814,7 +815,7 @@ config COMEDI_AMPLC_PC263_PCI · 3 unmodified lines | |||
| 814 | config COMEDI_AMPLC_PCI224 | 815 | config COMEDI_AMPLC_PCI224 |
| 815 | tristate "Amplicon PCI224 and PCI234 support" | 816 | tristate "Amplicon PCI224 and PCI234 support" |
| 816 | select COMEDI_8254 | 817 | select COMEDI_8254 |
| 817 | ---help--- | 818 | help |
| 818 | Enable support for Amplicon PCI224 and PCI234 AO boards | 819 | Enable support for Amplicon PCI224 and PCI234 AO boards |
| 819 | 820 | ||
| 820 | To compile this driver as a module, choose M here: the module will be | 821 | To compile this driver as a module, choose M here: the module will be |
| @@ -824,7 +825,7 @@ config COMEDI_AMPLC_PCI230 · 3 unmodified lines | |||
| 824 | tristate "Amplicon PCI230 and PCI260 support" | 825 | tristate "Amplicon PCI230 and PCI260 support" |
| 825 | select COMEDI_8254 | 826 | select COMEDI_8254 |
| 826 | select COMEDI_8255 | 827 | select COMEDI_8255 |
| 827 | ---help--- | 828 | help |
| 828 | Enable support for Amplicon PCI230 and PCI260 Multifunction I/O | 829 | Enable support for Amplicon PCI230 and PCI260 Multifunction I/O |
| 829 | boards | 830 | boards |
| 830 | 831 | ||
| @@ -833,7 +834,7 @@ config COMEDI_AMPLC_PCI230 · 2 unmodified lines | |||
| 833 | 834 | ||
| 834 | config COMEDI_CONTEC_PCI_DIO | 835 | config COMEDI_CONTEC_PCI_DIO |
| 835 | tristate "Contec PIO1616L digital I/O board support" | 836 | tristate "Contec PIO1616L digital I/O board support" |
| 836 | ---help--- | 837 | help |
| 837 | Enable support for the Contec PIO1616L digital I/O board | 838 | Enable support for the Contec PIO1616L digital I/O board |
| 838 | 839 | ||
| 839 | To compile this driver as a module, choose M here: the module will be | 840 | To compile this driver as a module, choose M here: the module will be |
| @@ -842,7 +843,7 @@ config COMEDI_CONTEC_PCI_DIO · 2 unmodified lines | |||
| 842 | config COMEDI_DAS08_PCI | 843 | config COMEDI_DAS08_PCI |
| 843 | tristate "DAS-08 PCI support" | 844 | tristate "DAS-08 PCI support" |
| 844 | select COMEDI_DAS08 | 845 | select COMEDI_DAS08 |
| 845 | ---help--- | 846 | help |
| 846 | Enable support for PCI DAS-08 cards. | 847 | Enable support for PCI DAS-08 cards. |
| 847 | 848 | ||
| 848 | To compile this driver as a module, choose M here: the module will be | 849 | To compile this driver as a module, choose M here: the module will be |
| @@ -850,7 +851,7 @@ config COMEDI_DAS08_PCI · 1 unmodified line | |||
| 850 | 851 | ||
| 851 | config COMEDI_DT3000 | 852 | config COMEDI_DT3000 |
| 852 | tristate "Data Translation DT3000 series support" | 853 | tristate "Data Translation DT3000 series support" |
| 853 | ---help--- | 854 | help |
| 854 | Enable support for Data Translation DT3000 series | 855 | Enable support for Data Translation DT3000 series |
| 855 | DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and | 856 | DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and |
| 856 | DT3004-200 | 857 | DT3004-200 |
| @@ -860,7 +861,7 @@ config COMEDI_DT3000 · 3 unmodified lines | |||
| 860 | 861 | ||
| 861 | config COMEDI_DYNA_PCI10XX | 862 | config COMEDI_DYNA_PCI10XX |
| 862 | tristate "Dynalog PCI DAQ series support" | 863 | tristate "Dynalog PCI DAQ series support" |
| 863 | ---help--- | 864 | help |
| 864 | Enable support for Dynalog PCI DAQ series | 865 | Enable support for Dynalog PCI DAQ series |
| 865 | PCI-1050 | 866 | PCI-1050 |
| 866 | 867 | ||
| @@ -869,7 +870,7 @@ config COMEDI_DYNA_PCI10XX · 2 unmodified lines | |||
| 869 | 870 | ||
| 870 | config COMEDI_GSC_HPDI | 871 | config COMEDI_GSC_HPDI |
| 871 | tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" | 872 | tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" |
| 872 | ---help--- | 873 | help |
| 873 | Enable support for General Standards Corporation high speed parallel | 874 | Enable support for General Standards Corporation high speed parallel |
| 874 | digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32. | 875 | digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32. |
| 875 | Only receive mode works, transmit not supported. | 876 | Only receive mode works, transmit not supported. |
| @@ -879,13 +880,13 @@ config COMEDI_GSC_HPDI · 3 unmodified lines | |||
| 879 | 880 | ||
| 880 | config COMEDI_MF6X4 | 881 | config COMEDI_MF6X4 |
| 881 | tristate "Humusoft MF634 and MF624 DAQ Card support" | 882 | tristate "Humusoft MF634 and MF624 DAQ Card support" |
| 882 | ---help--- | 883 | help |
| 883 | This driver supports both Humusoft MF634 and MF624 Data acquisition | 884 | This driver supports both Humusoft MF634 and MF624 Data acquisition |
| 884 | cards. The legacy Humusoft MF614 card is not supported. | 885 | cards. The legacy Humusoft MF614 card is not supported. |
| 885 | 886 | ||
| 886 | config COMEDI_ICP_MULTI | 887 | config COMEDI_ICP_MULTI |
| 887 | tristate "Inova ICP_MULTI support" | 888 | tristate "Inova ICP_MULTI support" |
| 888 | ---help--- | 889 | help |
| 889 | Enable support for Inova ICP_MULTI card | 890 | Enable support for Inova ICP_MULTI card |
| 890 | 891 | ||
| 891 | To compile this driver as a module, choose M here: the module will be | 892 | To compile this driver as a module, choose M here: the module will be |
| @@ -894,7 +895,7 @@ config COMEDI_ICP_MULTI · 2 unmodified lines | |||
| 894 | config COMEDI_DAQBOARD2000 | 895 | config COMEDI_DAQBOARD2000 |
| 895 | tristate "IOtech DAQboard/2000 support" | 896 | tristate "IOtech DAQboard/2000 support" |
| 896 | select COMEDI_8255 | 897 | select COMEDI_8255 |
| 897 | ---help--- | 898 | help |
| 898 | Enable support for the IOtech DAQboard/2000 | 899 | Enable support for the IOtech DAQboard/2000 |
| 899 | 900 | ||
| 900 | To compile this driver as a module, choose M here: the module will be | 901 | To compile this driver as a module, choose M here: the module will be |
| @@ -902,7 +903,7 @@ config COMEDI_DAQBOARD2000 · 1 unmodified line | |||
| 902 | 903 | ||
| 903 | config COMEDI_JR3_PCI | 904 | config COMEDI_JR3_PCI |
| 904 | tristate "JR3/PCI force sensor board support" | 905 | tristate "JR3/PCI force sensor board support" |
| 905 | ---help--- | 906 | help |
| 906 | Enable support for JR3/PCI force sensor boards | 907 | Enable support for JR3/PCI force sensor boards |
| 907 | 908 | ||
| 908 | To compile this driver as a module, choose M here: the module will be | 909 | To compile this driver as a module, choose M here: the module will be |
| @@ -910,7 +911,7 @@ config COMEDI_JR3_PCI · 1 unmodified line | |||
| 910 | 911 | ||
| 911 | config COMEDI_KE_COUNTER | 912 | config COMEDI_KE_COUNTER |
| 912 | tristate "Kolter-Electronic PCI Counter 1 card support" | 913 | tristate "Kolter-Electronic PCI Counter 1 card support" |
| 913 | ---help--- | 914 | help |
| 914 | Enable support for Kolter-Electronic PCI Counter 1 cards | 915 | Enable support for Kolter-Electronic PCI Counter 1 cards |
| 915 | 916 | ||
| 916 | To compile this driver as a module, choose M here: the module will be | 917 | To compile this driver as a module, choose M here: the module will be |
| @@ -919,7 +920,7 @@ config COMEDI_KE_COUNTER · 2 unmodified lines | |||
| 919 | config COMEDI_CB_PCIDAS64 | 920 | config COMEDI_CB_PCIDAS64 |
| 920 | tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" | 921 | tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" |
| 921 | select COMEDI_8255 | 922 | select COMEDI_8255 |
| 922 | ---help--- | 923 | help |
| 923 | Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx, | 924 | Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx, |
| 924 | 60xx, and 4020 series with the PLX 9080 PCI controller | 925 | 60xx, and 4020 series with the PLX 9080 PCI controller |
| 925 | 926 | ||
| @@ -930,7 +931,7 @@ config COMEDI_CB_PCIDAS · 4 unmodified lines | |||
| 930 | tristate "MeasurementComputing PCI-DAS support" | 931 | tristate "MeasurementComputing PCI-DAS support" |
| 931 | select COMEDI_8254 | 932 | select COMEDI_8254 |
| 932 | select COMEDI_8255 | 933 | select COMEDI_8255 |
| 933 | ---help--- | 934 | help |
| 934 | Enable support for ComputerBoards/MeasurementComputing PCI-DAS with | 935 | Enable support for ComputerBoards/MeasurementComputing PCI-DAS with |
| 935 | AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr, | 936 | AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr, |
| 936 | PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, PCI-DAS1000, PCI-DAS1001 | 937 | PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, PCI-DAS1000, PCI-DAS1001 |
| @@ -942,7 +943,7 @@ config COMEDI_CB_PCIDAS · 5 unmodified lines | |||
| 942 | config COMEDI_CB_PCIDDA | 943 | config COMEDI_CB_PCIDDA |
| 943 | tristate "MeasurementComputing PCI-DDA series support" | 944 | tristate "MeasurementComputing PCI-DDA series support" |
| 944 | select COMEDI_8255 | 945 | select COMEDI_8255 |
| 945 | ---help--- | 946 | help |
| 946 | Enable support for ComputerBoards/MeasurementComputing PCI-DDA | 947 | Enable support for ComputerBoards/MeasurementComputing PCI-DDA |
| 947 | series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16, | 948 | series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16, |
| 948 | PCI-DDA04/16 and PCI-DDA02/16 | 949 | PCI-DDA04/16 and PCI-DDA02/16 |
| @@ -954,7 +955,7 @@ config COMEDI_CB_PCIMDAS · 5 unmodified lines | |||
| 954 | tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" | 955 | tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" |
| 955 | select COMEDI_8254 | 956 | select COMEDI_8254 |
| 956 | select COMEDI_8255 | 957 | select COMEDI_8255 |
| 957 | ---help--- | 958 | help |
| 958 | Enable support for ComputerBoards/MeasurementComputing PCI Migration | 959 | Enable support for ComputerBoards/MeasurementComputing PCI Migration |
| 959 | series PCIM-DAS1602/16 and PCIe-DAS1602/16. | 960 | series PCIM-DAS1602/16 and PCIe-DAS1602/16. |
| 960 | 961 | ||
| @@ -964,7 +965,7 @@ config COMEDI_CB_PCIMDAS · 3 unmodified lines | |||
| 964 | config COMEDI_CB_PCIMDDA | 965 | config COMEDI_CB_PCIMDDA |
| 965 | tristate "MeasurementComputing PCIM-DDA06-16 support" | 966 | tristate "MeasurementComputing PCIM-DDA06-16 support" |
| 966 | select COMEDI_8255 | 967 | select COMEDI_8255 |
| 967 | ---help--- | 968 | help |
| 968 | Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 | 969 | Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 |
| 969 | 970 | ||
| 970 | To compile this driver as a module, choose M here: the module will be | 971 | To compile this driver as a module, choose M here: the module will be |
| @@ -973,7 +974,7 @@ config COMEDI_CB_PCIMDDA · 2 unmodified lines | |||
| 973 | config COMEDI_ME4000 | 974 | config COMEDI_ME4000 |
| 974 | tristate "Meilhaus ME-4000 support" | 975 | tristate "Meilhaus ME-4000 support" |
| 975 | select COMEDI_8254 | 976 | select COMEDI_8254 |
| 976 | ---help--- | 977 | help |
| 977 | Enable support for Meilhaus PCI data acquisition cards | 978 | Enable support for Meilhaus PCI data acquisition cards |
| 978 | ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is | 979 | ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is |
| 979 | 980 | ||
| @@ -982,7 +983,7 @@ config COMEDI_ME4000 · 2 unmodified lines | |||
| 982 | 983 | ||
| 983 | config COMEDI_ME_DAQ | 984 | config COMEDI_ME_DAQ |
| 984 | tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support" | 985 | tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support" |
| 985 | ---help--- | 986 | help |
| 986 | Enable support for Meilhaus PCI data acquisition cards | 987 | Enable support for Meilhaus PCI data acquisition cards |
| 987 | ME-2000i, ME-2600i and ME-3000vm1 | 988 | ME-2000i, ME-2600i and ME-3000vm1 |
| 988 | 989 | ||
| @@ -991,7 +992,7 @@ config COMEDI_ME_DAQ · 2 unmodified lines | |||
| 991 | 992 | ||
| 992 | config COMEDI_NI_6527 | 993 | config COMEDI_NI_6527 |
| 993 | tristate "NI 6527 support" | 994 | tristate "NI 6527 support" |
| 994 | ---help--- | 995 | help |
| 995 | Enable support for the National Instruments 6527 PCI card | 996 | Enable support for the National Instruments 6527 PCI card |
| 996 | 997 | ||
| 997 | To compile this driver as a module, choose M here: the module will be | 998 | To compile this driver as a module, choose M here: the module will be |
| @@ -999,7 +1000,7 @@ config COMEDI_NI_6527 · 1 unmodified line | |||
| 999 | 1000 | ||
| 1000 | config COMEDI_NI_65XX | 1001 | config COMEDI_NI_65XX |
| 1001 | tristate "NI 65xx static dio PCI card support" | 1002 | tristate "NI 65xx static dio PCI card support" |
| 1002 | ---help--- | 1003 | help |
| 1003 | Enable support for National Instruments 65xx static dio boards. | 1004 | Enable support for National Instruments 65xx static dio boards. |
| 1004 | Supported devices: National Instruments PCI-6509 (ni_65xx), | 1005 | Supported devices: National Instruments PCI-6509 (ni_65xx), |
| 1005 | PXI-6509, PCI-6510, PCI-6511, PXI-6511, PCI-6512, PXI-6512, PCI-6513, | 1006 | PXI-6509, PCI-6510, PCI-6511, PXI-6511, PCI-6512, PXI-6512, PCI-6513, |
| @@ -1013,7 +1014,7 @@ config COMEDI_NI_660X · 7 unmodified lines | |||
| 1013 | tristate "NI 660x counter/timer PCI card support" | 1014 | tristate "NI 660x counter/timer PCI card support" |
| 1014 | depends on HAS_DMA | 1015 | depends on HAS_DMA |
| 1015 | select COMEDI_NI_TIOCMD | 1016 | select COMEDI_NI_TIOCMD |
| 1016 | ---help--- | 1017 | help |
| 1017 | Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, | 1018 | Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, |
| 1018 | PXI-6602, PXI-6608, PCI-6624, and PXI-6624. | 1019 | PXI-6602, PXI-6608, PCI-6624, and PXI-6624. |
| 1019 | 1020 | ||
| @@ -1022,7 +1023,7 @@ config COMEDI_NI_660X · 2 unmodified lines | |||
| 1022 | 1023 | ||
| 1023 | config COMEDI_NI_670X | 1024 | config COMEDI_NI_670X |
| 1024 | tristate "NI 670x PCI card support" | 1025 | tristate "NI 670x PCI card support" |
| 1025 | ---help--- | 1026 | help |
| 1026 | Enable support for National Instruments PCI-6703 and PCI-6704 | 1027 | Enable support for National Instruments PCI-6703 and PCI-6704 |
| 1027 | 1028 | ||
| 1028 | To compile this driver as a module, choose M here: the module will be | 1029 | To compile this driver as a module, choose M here: the module will be |
| @@ -1031,7 +1032,7 @@ config COMEDI_NI_670X · 2 unmodified lines | |||
| 1031 | config COMEDI_NI_LABPC_PCI | 1032 | config COMEDI_NI_LABPC_PCI |
| 1032 | tristate "NI Lab-PC PCI-1200 support" | 1033 | tristate "NI Lab-PC PCI-1200 support" |
| 1033 | select COMEDI_NI_LABPC | 1034 | select COMEDI_NI_LABPC |
| 1034 | ---help--- | 1035 | help |
| 1035 | Enable support for National Instruments Lab-PC PCI-1200. | 1036 | Enable support for National Instruments Lab-PC PCI-1200. |
| 1036 | 1037 | ||
| 1037 | To compile this driver as a module, choose M here: the module will be | 1038 | To compile this driver as a module, choose M here: the module will be |
| @@ -1042,7 +1043,7 @@ config COMEDI_NI_PCIDIO · 4 unmodified lines | |||
| 1042 | depends on HAS_DMA | 1043 | depends on HAS_DMA |
| 1043 | select COMEDI_MITE | 1044 | select COMEDI_MITE |
| 1044 | select COMEDI_8255 | 1045 | select COMEDI_8255 |
| 1045 | ---help--- | 1046 | help |
| 1046 | Enable support for National Instruments PCI-DIO-32HS, PXI-6533, | 1047 | Enable support for National Instruments PCI-DIO-32HS, PXI-6533, |
| 1047 | PCI-6533 and PCI-6534 | 1048 | PCI-6533 and PCI-6534 |
| 1048 | 1049 | ||
| @@ -1054,7 +1055,7 @@ config COMEDI_NI_PCIMIO · 5 unmodified lines | |||
| 1054 | depends on HAS_DMA | 1055 | depends on HAS_DMA |
| 1055 | select COMEDI_NI_TIOCMD | 1056 | select COMEDI_NI_TIOCMD |
| 1056 | select COMEDI_8255 | 1057 | select COMEDI_8255 |
| 1057 | ---help--- | 1058 | help |
| 1058 | Enable support for National Instruments PCI-MIO-E series and M series | 1059 | Enable support for National Instruments PCI-MIO-E series and M series |
| 1059 | (all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, | 1060 | (all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, |
| 1060 | PCI-MIO-16E-4, PCI-6014, PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E, | 1061 | PCI-MIO-16E-4, PCI-6014, PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E, |
| @@ -1074,7 +1075,7 @@ config COMEDI_NI_PCIMIO · 13 unmodified lines | |||
| 1074 | config COMEDI_RTD520 | 1075 | config COMEDI_RTD520 |
| 1075 | tristate "Real Time Devices PCI4520/DM7520 support" | 1076 | tristate "Real Time Devices PCI4520/DM7520 support" |
| 1076 | select COMEDI_8254 | 1077 | select COMEDI_8254 |
| 1077 | ---help--- | 1078 | help |
| 1078 | Enable support for Real Time Devices PCI4520/DM7520 | 1079 | Enable support for Real Time Devices PCI4520/DM7520 |
| 1079 | 1080 | ||
| 1080 | To compile this driver as a module, choose M here: the module will be | 1081 | To compile this driver as a module, choose M here: the module will be |
| @@ -1082,7 +1083,7 @@ config COMEDI_RTD520 · 1 unmodified line | |||
| 1082 | 1083 | ||
| 1083 | config COMEDI_S626 | 1084 | config COMEDI_S626 |
| 1084 | tristate "Sensoray 626 support" | 1085 | tristate "Sensoray 626 support" |
| 1085 | ---help--- | 1086 | help |
| 1086 | Enable support for Sensoray 626 | 1087 | Enable support for Sensoray 626 |
| 1087 | 1088 | ||
| 1088 | To compile this driver as a module, choose M here: the module will be | 1089 | To compile this driver as a module, choose M here: the module will be |
| @@ -1103,7 +1104,7 @@ endif # COMEDI_PCI_DRIVERS · 14 unmodified lines | |||
| 1103 | menuconfig COMEDI_PCMCIA_DRIVERS | 1104 | menuconfig COMEDI_PCMCIA_DRIVERS |
| 1104 | tristate "Comedi PCMCIA drivers" | 1105 | tristate "Comedi PCMCIA drivers" |
| 1105 | depends on PCMCIA | 1106 | depends on PCMCIA |
| 1106 | ---help--- | 1107 | help |
| 1107 | Enable support for comedi PCMCIA drivers. | 1108 | Enable support for comedi PCMCIA drivers. |
| 1108 | 1109 | ||
| 1109 | To compile this support as a module, choose M here: the module will | 1110 | To compile this support as a module, choose M here: the module will |
| @@ -1114,7 +1115,7 @@ if COMEDI_PCMCIA_DRIVERS · 4 unmodified lines | |||
| 1114 | config COMEDI_CB_DAS16_CS | 1115 | config COMEDI_CB_DAS16_CS |
| 1115 | tristate "CB DAS16 series PCMCIA support" | 1116 | tristate "CB DAS16 series PCMCIA support" |
| 1116 | select COMEDI_8254 | 1117 | select COMEDI_8254 |
| 1117 | ---help--- | 1118 | help |
| 1118 | Enable support for the ComputerBoards/MeasurementComputing PCMCIA | 1119 | Enable support for the ComputerBoards/MeasurementComputing PCMCIA |
| 1119 | cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 | 1120 | cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 |
| 1120 | 1121 | ||
| @@ -1124,7 +1125,7 @@ config COMEDI_CB_DAS16_CS · 3 unmodified lines | |||
| 1124 | config COMEDI_DAS08_CS | 1125 | config COMEDI_DAS08_CS |
| 1125 | tristate "CB DAS08 PCMCIA support" | 1126 | tristate "CB DAS08 PCMCIA support" |
| 1126 | select COMEDI_DAS08 | 1127 | select COMEDI_DAS08 |
| 1127 | ---help--- | 1128 | help |
| 1128 | Enable support for the ComputerBoards/MeasurementComputing DAS-08 | 1129 | Enable support for the ComputerBoards/MeasurementComputing DAS-08 |
| 1129 | PCMCIA card | 1130 | PCMCIA card |
| 1130 | 1131 | ||
| @@ -1133,7 +1134,7 @@ config COMEDI_DAS08_CS · 2 unmodified lines | |||
| 1133 | 1134 | ||
| 1134 | config COMEDI_NI_DAQ_700_CS | 1135 | config COMEDI_NI_DAQ_700_CS |
| 1135 | tristate "NI DAQCard-700 PCMCIA support" | 1136 | tristate "NI DAQCard-700 PCMCIA support" |
| 1136 | ---help--- | 1137 | help |
| 1137 | Enable support for the National Instruments PCMCIA DAQCard-700 DIO | 1138 | Enable support for the National Instruments PCMCIA DAQCard-700 DIO |
| 1138 | 1139 | ||
| 1139 | To compile this driver as a module, choose M here: the module will be | 1140 | To compile this driver as a module, choose M here: the module will be |
| @@ -1142,7 +1143,7 @@ config COMEDI_NI_DAQ_700_CS · 2 unmodified lines | |||
| 1142 | config COMEDI_NI_DAQ_DIO24_CS | 1143 | config COMEDI_NI_DAQ_DIO24_CS |
| 1143 | tristate "NI DAQ-Card DIO-24 PCMCIA support" | 1144 | tristate "NI DAQ-Card DIO-24 PCMCIA support" |
| 1144 | select COMEDI_8255 | 1145 | select COMEDI_8255 |
| 1145 | ---help--- | 1146 | help |
| 1146 | Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 | 1147 | Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 |
| 1147 | 1148 | ||
| 1148 | To compile this driver as a module, choose M here: the module will be | 1149 | To compile this driver as a module, choose M here: the module will be |
| @@ -1151,7 +1152,7 @@ config COMEDI_NI_DAQ_DIO24_CS · 2 unmodified lines | |||
| 1151 | config COMEDI_NI_LABPC_CS | 1152 | config COMEDI_NI_LABPC_CS |
| 1152 | tristate "NI DAQCard-1200 PCMCIA support" | 1153 | tristate "NI DAQCard-1200 PCMCIA support" |
| 1153 | select COMEDI_NI_LABPC | 1154 | select COMEDI_NI_LABPC |
| 1154 | ---help--- | 1155 | help |
| 1155 | Enable support for the National Instruments PCMCIA DAQCard-1200 | 1156 | Enable support for the National Instruments PCMCIA DAQCard-1200 |
| 1156 | 1157 | ||
| 1157 | To compile this driver as a module, choose M here: the module will be | 1158 | To compile this driver as a module, choose M here: the module will be |
| @@ -1161,7 +1162,7 @@ config COMEDI_NI_MIO_CS · 3 unmodified lines | |||
| 1161 | tristate "NI DAQCard E series PCMCIA support" | 1162 | tristate "NI DAQCard E series PCMCIA support" |
| 1162 | select COMEDI_NI_TIO | 1163 | select COMEDI_NI_TIO |
| 1163 | select COMEDI_8255 | 1164 | select COMEDI_8255 |
| 1164 | ---help--- | 1165 | help |
| 1165 | Enable support for the National Instruments PCMCIA DAQCard E series | 1166 | Enable support for the National Instruments PCMCIA DAQCard E series |
| 1166 | DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E | 1167 | DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E |
| 1167 | and DAQCard-6036E | 1168 | and DAQCard-6036E |
| @@ -1171,7 +1172,7 @@ config COMEDI_NI_MIO_CS · 3 unmodified lines | |||
| 1171 | 1172 | ||
| 1172 | config COMEDI_QUATECH_DAQP_CS | 1173 | config COMEDI_QUATECH_DAQP_CS |
| 1173 | tristate "Quatech DAQP PCMCIA data capture card support" | 1174 | tristate "Quatech DAQP PCMCIA data capture card support" |
| 1174 | ---help--- | 1175 | help |
| 1175 | Enable support for the Quatech DAQP PCMCIA data capture cards | 1176 | Enable support for the Quatech DAQP PCMCIA data capture cards |
| 1176 | DAQP-208 and DAQP-308 | 1177 | DAQP-208 and DAQP-308 |
| 1177 | 1178 | ||
| @@ -1183,7 +1184,7 @@ endif # COMEDI_PCMCIA_DRIVERS · 5 unmodified lines | |||
| 1183 | menuconfig COMEDI_USB_DRIVERS | 1184 | menuconfig COMEDI_USB_DRIVERS |
| 1184 | tristate "Comedi USB drivers" | 1185 | tristate "Comedi USB drivers" |
| 1185 | depends on USB | 1186 | depends on USB |
| 1186 | ---help--- | 1187 | help |
| 1187 | Enable support for comedi USB drivers. | 1188 | Enable support for comedi USB drivers. |
| 1188 | 1189 | ||
| 1189 | To compile this support as a module, choose M here: the module will | 1190 | To compile this support as a module, choose M here: the module will |
| @@ -1193,7 +1194,7 @@ if COMEDI_USB_DRIVERS · 3 unmodified lines | |||
| 1193 | 1194 | ||
| 1194 | config COMEDI_DT9812 | 1195 | config COMEDI_DT9812 |
| 1195 | tristate "DataTranslation DT9812 USB module support" | 1196 | tristate "DataTranslation DT9812 USB module support" |
| 1196 | ---help--- | 1197 | help |
| 1197 | Enable support for the Data Translation DT9812 USB module | 1198 | Enable support for the Data Translation DT9812 USB module |
| 1198 | 1199 | ||
| 1199 | To compile this driver as a module, choose M here: the module will be | 1200 | To compile this driver as a module, choose M here: the module will be |
| @@ -1201,7 +1202,7 @@ config COMEDI_DT9812 · 1 unmodified line | |||
| 1201 | 1202 | ||
| 1202 | config COMEDI_NI_USB6501 | 1203 | config COMEDI_NI_USB6501 |
| 1203 | tristate "NI USB-6501 support" | 1204 | tristate "NI USB-6501 support" |
| 1204 | ---help--- | 1205 | help |
| 1205 | Enable support for the National Instruments USB-6501 module. | 1206 | Enable support for the National Instruments USB-6501 module. |
| 1206 | 1207 | ||
| 1207 | The NI USB-6501 is a Full-Speed USB 2.0 (12 Mbit/s) device that | 1208 | The NI USB-6501 is a Full-Speed USB 2.0 (12 Mbit/s) device that |
| @@ -1212,7 +1213,7 @@ config COMEDI_NI_USB6501 · 4 unmodified lines | |||
| 1212 | 1213 | ||
| 1213 | config COMEDI_USBDUX | 1214 | config COMEDI_USBDUX |
| 1214 | tristate "ITL USB-DUX-D support" | 1215 | tristate "ITL USB-DUX-D support" |
| 1215 | ---help--- | 1216 | help |
| 1216 | Enable support for the Incite Technology Ltd USB-DUX-D Board | 1217 | Enable support for the Incite Technology Ltd USB-DUX-D Board |
| 1217 | 1218 | ||
| 1218 | To compile this driver as a module, choose M here: the module will be | 1219 | To compile this driver as a module, choose M here: the module will be |
| @@ -1220,7 +1221,7 @@ config COMEDI_USBDUX · 1 unmodified line | |||
| 1220 | 1221 | ||
| 1221 | config COMEDI_USBDUXFAST | 1222 | config COMEDI_USBDUXFAST |
| 1222 | tristate "ITL USB-DUXfast support" | 1223 | tristate "ITL USB-DUXfast support" |
| 1223 | ---help--- | 1224 | help |
| 1224 | Enable support for the Incite Technology Ltd USB-DUXfast Board | 1225 | Enable support for the Incite Technology Ltd USB-DUXfast Board |
| 1225 | 1226 | ||
| 1226 | To compile this driver as a module, choose M here: the module will be | 1227 | To compile this driver as a module, choose M here: the module will be |
| @@ -1228,7 +1229,7 @@ config COMEDI_USBDUXFAST · 1 unmodified line | |||
| 1228 | 1229 | ||
| 1229 | config COMEDI_USBDUXSIGMA | 1230 | config COMEDI_USBDUXSIGMA |
| 1230 | tristate "ITL USB-DUXsigma support" | 1231 | tristate "ITL USB-DUXsigma support" |
| 1231 | ---help--- | 1232 | help |
| 1232 | Enable support for the Incite Technology Ltd USB-DUXsigma Board | 1233 | Enable support for the Incite Technology Ltd USB-DUXsigma Board |
| 1233 | 1234 | ||
| 1234 | To compile this driver as a module, choose M here: the module will be | 1235 | To compile this driver as a module, choose M here: the module will be |
| @@ -1236,7 +1237,7 @@ config COMEDI_USBDUXSIGMA · 1 unmodified line | |||
| 1236 | 1237 | ||
| 1237 | config COMEDI_VMK80XX | 1238 | config COMEDI_VMK80XX |
| 1238 | tristate "Velleman VM110/VM140 USB Board support" | 1239 | tristate "Velleman VM110/VM140 USB Board support" |
| 1239 | ---help--- | 1240 | help |
| 1240 | Build the Velleman USB Board Low-Level Driver supporting the | 1241 | Build the Velleman USB Board Low-Level Driver supporting the |
| 1241 | K8055/K8061 aka VM110/VM140 devices | 1242 | K8055/K8061 aka VM110/VM140 devices |
| 1242 | 1243 | ||
| @@ -1254,7 +1255,7 @@ config COMEDI_8255 · 11 unmodified lines | |||
| 1254 | config COMEDI_8255_SA | 1255 | config COMEDI_8255_SA |
| 1255 | tristate "Standalone 8255 support" | 1256 | tristate "Standalone 8255 support" |
| 1256 | select COMEDI_8255 | 1257 | select COMEDI_8255 |
| 1257 | ---help--- | 1258 | help |
| 1258 | Enable support for 8255 digital I/O as a standalone driver. | 1259 | Enable support for 8255 digital I/O as a standalone driver. |
| 1259 | 1260 | ||
| 1260 | You should enable compilation this driver if you plan to use a board | 1261 | You should enable compilation this driver if you plan to use a board |
| @@ -1271,7 +1272,7 @@ config COMEDI_8255_SA · 10 unmodified lines | |||
| 1271 | 1272 | ||
| 1272 | config COMEDI_KCOMEDILIB | 1273 | config COMEDI_KCOMEDILIB |
| 1273 | tristate "Comedi kcomedilib" | 1274 | tristate "Comedi kcomedilib" |
| 1274 | ---help--- | 1275 | help |
| 1275 | Build the kcomedilib. | 1276 | Build the kcomedilib. |
| 1276 | 1277 | ||
| 1277 | This is a kernel module used to open and manipulate Comedi devices | 1278 | This is a kernel module used to open and manipulate Comedi devices |
| @@ -211,6 +211,8 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, · 210 unmodified lines | |||
| 211 | { | 211 | { |
| 212 | struct comedi_async *async = s->async; | 212 | struct comedi_async *async = s->async; |
| 213 | 213 | ||
| 214 | lockdep_assert_held(&dev->mutex); | ||
| 215 | |||
| 214 | /* Round up new_size to multiple of PAGE_SIZE */ | 216 | /* Round up new_size to multiple of PAGE_SIZE */ |
| 215 | new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; | 217 | new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; |
| 216 | 218 | ||
| @@ -164,6 +164,7 @@ static bool comedi_clear_board_dev(struct comedi_device *dev) · 163 unmodified lines | |||
| 164 | unsigned int i = dev->minor; | 164 | unsigned int i = dev->minor; |
| 165 | bool cleared = false; | 165 | bool cleared = false; |
| 166 | 166 | ||
| 167 | lockdep_assert_held(&dev->mutex); | ||
| 167 | mutex_lock(&comedi_board_minor_table_lock); | 168 | mutex_lock(&comedi_board_minor_table_lock); |
| 168 | if (dev == comedi_board_minor_table[i]) { | 169 | if (dev == comedi_board_minor_table[i]) { |
| 169 | comedi_board_minor_table[i] = NULL; | 170 | comedi_board_minor_table[i] = NULL; |
| @@ -260,6 +261,7 @@ comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor) · 90 unmodified lines | |||
| 260 | { | 261 | { |
| 261 | struct comedi_subdevice *s; | 262 | struct comedi_subdevice *s; |
| 262 | 263 | ||
| 264 | lockdep_assert_held(&dev->mutex); | ||
| 263 | if (minor >= COMEDI_NUM_BOARD_MINORS) { | 265 | if (minor >= COMEDI_NUM_BOARD_MINORS) { |
| 264 | s = comedi_subdevice_from_minor(dev, minor); | 266 | s = comedi_subdevice_from_minor(dev, minor); |
| 265 | if (!s || (s->subdev_flags & SDF_CMD_READ)) | 267 | if (!s || (s->subdev_flags & SDF_CMD_READ)) |
| @@ -273,6 +275,7 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) · 7 unmodified lines | |||
| 273 | { | 275 | { |
| 274 | struct comedi_subdevice *s; | 276 | struct comedi_subdevice *s; |
| 275 | 277 | ||
| 278 | lockdep_assert_held(&dev->mutex); | ||
| 276 | if (minor >= COMEDI_NUM_BOARD_MINORS) { | 279 | if (minor >= COMEDI_NUM_BOARD_MINORS) { |
| 277 | s = comedi_subdevice_from_minor(dev, minor); | 280 | s = comedi_subdevice_from_minor(dev, minor); |
| 278 | if (!s || (s->subdev_flags & SDF_CMD_WRITE)) | 281 | if (!s || (s->subdev_flags & SDF_CMD_WRITE)) |
| @@ -336,6 +339,8 @@ static int resize_async_buffer(struct comedi_device *dev, · 57 unmodified lines | |||
| 336 | struct comedi_async *async = s->async; | 339 | struct comedi_async *async = s->async; |
| 337 | int retval; | 340 | int retval; |
| 338 | 341 | ||
| 342 | lockdep_assert_held(&dev->mutex); | ||
| 343 | |||
| 339 | if (new_size > async->max_bufsize) | 344 | if (new_size > async->max_bufsize) |
| 340 | return -EPERM; | 345 | return -EPERM; |
| 341 | 346 | ||
| @@ -726,6 +731,7 @@ static void do_become_nonbusy(struct comedi_device *dev, · 384 unmodified lines | |||
| 726 | { | 731 | { |
| 727 | struct comedi_async *async = s->async; | 732 | struct comedi_async *async = s->async; |
| 728 | 733 | ||
| 734 | lockdep_assert_held(&dev->mutex); | ||
| 729 | comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0); | 735 | comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0); |
| 730 | if (async) { | 736 | if (async) { |
| 731 | comedi_buf_reset(s); | 737 | comedi_buf_reset(s); |
| @@ -745,6 +751,7 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) · 13 unmodified lines | |||
| 745 | { | 751 | { |
| 746 | int ret = 0; | 752 | int ret = 0; |
| 747 | 753 | ||
| 754 | lockdep_assert_held(&dev->mutex); | ||
| 748 | if (comedi_is_subdevice_running(s) && s->cancel) | 755 | if (comedi_is_subdevice_running(s) && s->cancel) |
| 749 | ret = s->cancel(dev, s); | 756 | ret = s->cancel(dev, s); |
| 750 | 757 | ||
| @@ -758,6 +765,7 @@ void comedi_device_cancel_all(struct comedi_device *dev) · 7 unmodified lines | |||
| 758 | struct comedi_subdevice *s; | 765 | struct comedi_subdevice *s; |
| 759 | int i; | 766 | int i; |
| 760 | 767 | ||
| 768 | lockdep_assert_held(&dev->mutex); | ||
| 761 | if (!dev->attached) | 769 | if (!dev->attached) |
| 762 | return; | 770 | return; |
| 763 | 771 | ||
| @@ -773,6 +781,7 @@ static int is_device_busy(struct comedi_device *dev) · 9 unmodified lines | |||
| 773 | struct comedi_subdevice *s; | 781 | struct comedi_subdevice *s; |
| 774 | int i; | 782 | int i; |
| 775 | 783 | ||
| 784 | lockdep_assert_held(&dev->mutex); | ||
| 776 | if (!dev->attached) | 785 | if (!dev->attached) |
| 777 | return 0; | 786 | return 0; |
| 778 | 787 | ||
| @@ -805,6 +814,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev, · 26 unmodified lines | |||
| 805 | { | 814 | { |
| 806 | struct comedi_devconfig it; | 815 | struct comedi_devconfig it; |
| 807 | 816 | ||
| 817 | lockdep_assert_held(&dev->mutex); | ||
| 808 | if (!capable(CAP_SYS_ADMIN)) | 818 | if (!capable(CAP_SYS_ADMIN)) |
| 809 | return -EPERM; | 819 | return -EPERM; |
| 810 | 820 | ||
| @@ -860,6 +870,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, · 49 unmodified lines | |||
| 860 | struct comedi_subdevice *s; | 870 | struct comedi_subdevice *s; |
| 861 | int retval = 0; | 871 | int retval = 0; |
| 862 | 872 | ||
| 873 | lockdep_assert_held(&dev->mutex); | ||
| 863 | if (copy_from_user(&bc, arg, sizeof(bc))) | 874 | if (copy_from_user(&bc, arg, sizeof(bc))) |
| 864 | return -EFAULT; | 875 | return -EFAULT; |
| 865 | 876 | ||
| @@ -920,6 +931,7 @@ static int do_devinfo_ioctl(struct comedi_device *dev, · 54 unmodified lines | |||
| 920 | struct comedi_subdevice *s; | 931 | struct comedi_subdevice *s; |
| 921 | struct comedi_devinfo devinfo; | 932 | struct comedi_devinfo devinfo; |
| 922 | 933 | ||
| 934 | lockdep_assert_held(&dev->mutex); | ||
| 923 | memset(&devinfo, 0, sizeof(devinfo)); | 935 | memset(&devinfo, 0, sizeof(devinfo)); |
| 924 | 936 | ||
| 925 | /* fill devinfo structure */ | 937 | /* fill devinfo structure */ |
| @@ -966,6 +978,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, · 40 unmodified lines | |||
| 966 | struct comedi_subdinfo *tmp, *us; | 978 | struct comedi_subdinfo *tmp, *us; |
| 967 | struct comedi_subdevice *s; | 979 | struct comedi_subdevice *s; |
| 968 | 980 | ||
| 981 | lockdep_assert_held(&dev->mutex); | ||
| 969 | tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL); | 982 | tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL); |
| 970 | if (!tmp) | 983 | if (!tmp) |
| 971 | return -ENOMEM; | 984 | return -ENOMEM; |
| @@ -1039,6 +1052,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, · 67 unmodified lines | |||
| 1039 | struct comedi_subdevice *s; | 1052 | struct comedi_subdevice *s; |
| 1040 | struct comedi_chaninfo it; | 1053 | struct comedi_chaninfo it; |
| 1041 | 1054 | ||
| 1055 | lockdep_assert_held(&dev->mutex); | ||
| 1042 | if (copy_from_user(&it, arg, sizeof(it))) | 1056 | if (copy_from_user(&it, arg, sizeof(it))) |
| 1043 | return -EFAULT; | 1057 | return -EFAULT; |
| 1044 | 1058 | ||
| @@ -1098,6 +1112,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, · 53 unmodified lines | |||
| 1098 | int retval = 0; | 1112 | int retval = 0; |
| 1099 | bool become_nonbusy = false; | 1113 | bool become_nonbusy = false; |
| 1100 | 1114 | ||
| 1115 | lockdep_assert_held(&dev->mutex); | ||
| 1101 | if (copy_from_user(&bi, arg, sizeof(bi))) | 1116 | if (copy_from_user(&bi, arg, sizeof(bi))) |
| 1102 | return -EFAULT; | 1117 | return -EFAULT; |
| 1103 | 1118 | ||
| @@ -1282,6 +1297,7 @@ static int check_insn_device_config_length(struct comedi_insn *insn, · 178 unmodified lines | |||
| 1282 | */ | 1297 | */ |
| 1283 | static int get_valid_routes(struct comedi_device *dev, unsigned int *data) | 1298 | static int get_valid_routes(struct comedi_device *dev, unsigned int *data) |
| 1284 | { | 1299 | { |
| 1300 | lockdep_assert_held(&dev->mutex); | ||
| 1285 | data[1] = dev->get_valid_routes(dev, data[1], data + 2); | 1301 | data[1] = dev->get_valid_routes(dev, data[1], data + 2); |
| 1286 | return 0; | 1302 | return 0; |
| 1287 | } | 1303 | } |
| @@ -1293,6 +1309,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, · 5 unmodified lines | |||
| 1293 | int ret = 0; | 1309 | int ret = 0; |
| 1294 | int i; | 1310 | int i; |
| 1295 | 1311 | ||
| 1312 | lockdep_assert_held(&dev->mutex); | ||
| 1296 | if (insn->insn & INSN_MASK_SPECIAL) { | 1313 | if (insn->insn & INSN_MASK_SPECIAL) { |
| 1297 | /* a non-subdevice instruction */ | 1314 | /* a non-subdevice instruction */ |
| 1298 | 1315 | ||
| @@ -1513,6 +1530,7 @@ static int do_insnlist_ioctl(struct comedi_device *dev, · 214 unmodified lines | |||
| 1513 | int i = 0; | 1530 | int i = 0; |
| 1514 | int ret = 0; | 1531 | int ret = 0; |
| 1515 | 1532 | ||
| 1533 | lockdep_assert_held(&dev->mutex); | ||
| 1516 | if (copy_from_user(&insnlist, arg, sizeof(insnlist))) | 1534 | if (copy_from_user(&insnlist, arg, sizeof(insnlist))) |
| 1517 | return -EFAULT; | 1535 | return -EFAULT; |
| 1518 | 1536 | ||
| @@ -1605,6 +1623,7 @@ static int do_insn_ioctl(struct comedi_device *dev, · 86 unmodified lines | |||
| 1605 | unsigned int n_data = MIN_SAMPLES; | 1623 | unsigned int n_data = MIN_SAMPLES; |
| 1606 | int ret = 0; | 1624 | int ret = 0; |
| 1607 | 1625 | ||
| 1626 | lockdep_assert_held(&dev->mutex); | ||
| 1608 | if (copy_from_user(&insn, arg, sizeof(insn))) | 1627 | if (copy_from_user(&insn, arg, sizeof(insn))) |
| 1609 | return -EFAULT; | 1628 | return -EFAULT; |
| 1610 | 1629 | ||
| @@ -1655,6 +1674,7 @@ static int __comedi_get_user_cmd(struct comedi_device *dev, · 44 unmodified lines | |||
| 1655 | { | 1674 | { |
| 1656 | struct comedi_subdevice *s; | 1675 | struct comedi_subdevice *s; |
| 1657 | 1676 | ||
| 1677 | lockdep_assert_held(&dev->mutex); | ||
| 1658 | if (copy_from_user(cmd, arg, sizeof(*cmd))) { | 1678 | if (copy_from_user(cmd, arg, sizeof(*cmd))) { |
| 1659 | dev_dbg(dev->class_dev, "bad cmd address\n"); | 1679 | dev_dbg(dev->class_dev, "bad cmd address\n"); |
| 1660 | return -EFAULT; | 1680 | return -EFAULT; |
| @@ -1713,6 +1733,7 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev, · 52 unmodified lines | |||
| 1713 | unsigned int *chanlist; | 1733 | unsigned int *chanlist; |
| 1714 | int ret; | 1734 | int ret; |
| 1715 | 1735 | ||
| 1736 | lockdep_assert_held(&dev->mutex); | ||
| 1716 | cmd->chanlist = NULL; | 1737 | cmd->chanlist = NULL; |
| 1717 | chanlist = memdup_user(user_chanlist, | 1738 | chanlist = memdup_user(user_chanlist, |
| 1718 | cmd->chanlist_len * sizeof(unsigned int)); | 1739 | cmd->chanlist_len * sizeof(unsigned int)); |
| @@ -1754,6 +1775,8 @@ static int do_cmd_ioctl(struct comedi_device *dev, · 35 unmodified lines | |||
| 1754 | unsigned int __user *user_chanlist; | 1775 | unsigned int __user *user_chanlist; |
| 1755 | int ret; | 1776 | int ret; |
| 1756 | 1777 | ||
| 1778 | lockdep_assert_held(&dev->mutex); | ||
| 1779 | |||
| 1757 | /* get the user's cmd and do some simple validation */ | 1780 | /* get the user's cmd and do some simple validation */ |
| 1758 | ret = __comedi_get_user_cmd(dev, arg, &cmd); | 1781 | ret = __comedi_get_user_cmd(dev, arg, &cmd); |
| 1759 | if (ret) | 1782 | if (ret) |
| @@ -1861,6 +1884,8 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, · 101 unmodified lines | |||
| 1861 | unsigned int __user *user_chanlist; | 1884 | unsigned int __user *user_chanlist; |
| 1862 | int ret; | 1885 | int ret; |
| 1863 | 1886 | ||
| 1887 | lockdep_assert_held(&dev->mutex); | ||
| 1888 | |||
| 1864 | /* get the user's cmd and do some simple validation */ | 1889 | /* get the user's cmd and do some simple validation */ |
| 1865 | ret = __comedi_get_user_cmd(dev, arg, &cmd); | 1890 | ret = __comedi_get_user_cmd(dev, arg, &cmd); |
| 1866 | if (ret) | 1891 | if (ret) |
| @@ -1914,6 +1939,7 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg, · 47 unmodified lines | |||
| 1914 | unsigned long flags; | 1939 | unsigned long flags; |
| 1915 | struct comedi_subdevice *s; | 1940 | struct comedi_subdevice *s; |
| 1916 | 1941 | ||
| 1942 | lockdep_assert_held(&dev->mutex); | ||
| 1917 | if (arg >= dev->n_subdevices) | 1943 | if (arg >= dev->n_subdevices) |
| 1918 | return -EINVAL; | 1944 | return -EINVAL; |
| 1919 | s = &dev->subdevices[arg]; | 1945 | s = &dev->subdevices[arg]; |
| @@ -1946,6 +1972,7 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg, · 26 unmodified lines | |||
| 1946 | { | 1972 | { |
| 1947 | struct comedi_subdevice *s; | 1973 | struct comedi_subdevice *s; |
| 1948 | 1974 | ||
| 1975 | lockdep_assert_held(&dev->mutex); | ||
| 1949 | if (arg >= dev->n_subdevices) | 1976 | if (arg >= dev->n_subdevices) |
| 1950 | return -EINVAL; | 1977 | return -EINVAL; |
| 1951 | s = &dev->subdevices[arg]; | 1978 | s = &dev->subdevices[arg]; |
| @@ -1980,6 +2007,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg, · 28 unmodified lines | |||
| 1980 | { | 2007 | { |
| 1981 | struct comedi_subdevice *s; | 2008 | struct comedi_subdevice *s; |
| 1982 | 2009 | ||
| 2010 | lockdep_assert_held(&dev->mutex); | ||
| 1983 | if (arg >= dev->n_subdevices) | 2011 | if (arg >= dev->n_subdevices) |
| 1984 | return -EINVAL; | 2012 | return -EINVAL; |
| 1985 | s = &dev->subdevices[arg]; | 2013 | s = &dev->subdevices[arg]; |
| @@ -2013,6 +2041,7 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg, · 27 unmodified lines | |||
| 2013 | { | 2041 | { |
| 2014 | struct comedi_subdevice *s; | 2042 | struct comedi_subdevice *s; |
| 2015 | 2043 | ||
| 2044 | lockdep_assert_held(&dev->mutex); | ||
| 2016 | if (arg >= dev->n_subdevices) | 2045 | if (arg >= dev->n_subdevices) |
| 2017 | return -EINVAL; | 2046 | return -EINVAL; |
| 2018 | s = &dev->subdevices[arg]; | 2047 | s = &dev->subdevices[arg]; |
| @@ -2048,6 +2077,7 @@ static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg, · 29 unmodified lines | |||
| 2048 | struct comedi_file *cfp = file->private_data; | 2077 | struct comedi_file *cfp = file->private_data; |
| 2049 | struct comedi_subdevice *s_old, *s_new; | 2078 | struct comedi_subdevice *s_old, *s_new; |
| 2050 | 2079 | ||
| 2080 | lockdep_assert_held(&dev->mutex); | ||
| 2051 | if (arg >= dev->n_subdevices) | 2081 | if (arg >= dev->n_subdevices) |
| 2052 | return -EINVAL; | 2082 | return -EINVAL; |
| 2053 | 2083 | ||
| @@ -2090,6 +2120,7 @@ static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg, · 36 unmodified lines | |||
| 2090 | struct comedi_file *cfp = file->private_data; | 2120 | struct comedi_file *cfp = file->private_data; |
| 2091 | struct comedi_subdevice *s_old, *s_new; | 2121 | struct comedi_subdevice *s_old, *s_new; |
| 2092 | 2122 | ||
| 2123 | lockdep_assert_held(&dev->mutex); | ||
| 2093 | if (arg >= dev->n_subdevices) | 2124 | if (arg >= dev->n_subdevices) |
| 2094 | return -EINVAL; | 2125 | return -EINVAL; |
| 2095 | 2126 | ||
| @@ -2995,6 +3026,7 @@ static int __init comedi_init(void) · 899 unmodified lines | |||
| 2995 | goto out_cleanup_board_minors; | 3026 | goto out_cleanup_board_minors; |
| 2996 | } | 3027 | } |
| 2997 | /* comedi_alloc_board_minor() locked the mutex */ | 3028 | /* comedi_alloc_board_minor() locked the mutex */ |
| 3029 | lockdep_assert_held(&dev->mutex); | ||
| 2998 | mutex_unlock(&dev->mutex); | 3030 | mutex_unlock(&dev->mutex); |
| 2999 | } | 3031 | } |
| 3000 | 3032 | ||
| @@ -159,6 +159,8 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev) · 158 unmodified lines | |||
| 159 | int i; | 159 | int i; |
| 160 | struct comedi_subdevice *s; | 160 | struct comedi_subdevice *s; |
| 161 | 161 | ||
| 162 | lockdep_assert_held(&dev->attach_lock); | ||
| 163 | lockdep_assert_held(&dev->mutex); | ||
| 162 | if (dev->subdevices) { | 164 | if (dev->subdevices) { |
| 163 | for (i = 0; i < dev->n_subdevices; i++) { | 165 | for (i = 0; i < dev->n_subdevices; i++) { |
| 164 | s = &dev->subdevices[i]; | 166 | s = &dev->subdevices[i]; |
| @@ -196,6 +198,7 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev) · 31 unmodified lines | |||
| 196 | 198 | ||
| 197 | void comedi_device_detach(struct comedi_device *dev) | 199 | void comedi_device_detach(struct comedi_device *dev) |
| 198 | { | 200 | { |
| 201 | lockdep_assert_held(&dev->mutex); | ||
| 199 | comedi_device_cancel_all(dev); | 202 | comedi_device_cancel_all(dev); |
| 200 | down_write(&dev->attach_lock); | 203 | down_write(&dev->attach_lock); |
| 201 | dev->attached = false; | 204 | dev->attached = false; |
| @@ -643,6 +646,7 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev, · 441 unmodified lines | |||
| 643 | unsigned int buf_size; | 646 | unsigned int buf_size; |
| 644 | int ret; | 647 | int ret; |
| 645 | 648 | ||
| 649 | lockdep_assert_held(&dev->mutex); | ||
| 646 | if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) { | 650 | if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) { |
| 647 | dev_warn(dev->class_dev, | 651 | dev_warn(dev->class_dev, |
| 648 | "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n"); | 652 | "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n"); |
| @@ -690,6 +694,7 @@ static int __comedi_device_postconfig(struct comedi_device *dev) · 41 unmodified lines | |||
| 690 | int ret; | 694 | int ret; |
| 691 | int i; | 695 | int i; |
| 692 | 696 | ||
| 697 | lockdep_assert_held(&dev->mutex); | ||
| 693 | if (!dev->insn_device_config) | 698 | if (!dev->insn_device_config) |
| 694 | dev->insn_device_config = insn_device_inval; | 699 | dev->insn_device_config = insn_device_inval; |
| 695 | 700 | ||
| @@ -747,6 +752,7 @@ static int comedi_device_postconfig(struct comedi_device *dev) · 51 unmodified lines | |||
| 747 | { | 752 | { |
| 748 | int ret; | 753 | int ret; |
| 749 | 754 | ||
| 755 | lockdep_assert_held(&dev->mutex); | ||
| 750 | ret = __comedi_device_postconfig(dev); | 756 | ret = __comedi_device_postconfig(dev); |
| 751 | if (ret < 0) | 757 | if (ret < 0) |
| 752 | return ret; | 758 | return ret; |
| @@ -946,6 +952,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) · 193 unmodified lines | |||
| 946 | struct comedi_driver *driv; | 952 | struct comedi_driver *driv; |
| 947 | int ret; | 953 | int ret; |
| 948 | 954 | ||
| 955 | lockdep_assert_held(&dev->mutex); | ||
| 949 | if (dev->attached) | 956 | if (dev->attached) |
| 950 | return -EBUSY; | 957 | return -EBUSY; |
| 951 | 958 | ||
| @@ -1053,18 +1060,19 @@ int comedi_auto_config(struct device *hardware_device, · 101 unmodified lines | |||
| 1053 | return PTR_ERR(dev); | 1060 | return PTR_ERR(dev); |
| 1054 | } | 1061 | } |
| 1055 | /* Note: comedi_alloc_board_minor() locked dev->mutex. */ | 1062 | /* Note: comedi_alloc_board_minor() locked dev->mutex. */ |
| 1063 | lockdep_assert_held(&dev->mutex); | ||
| 1056 | 1064 | ||
| 1057 | dev->driver = driver; | 1065 | dev->driver = driver; |
| 1058 | dev->board_name = dev->driver->driver_name; | 1066 | dev->board_name = dev->driver->driver_name; |
| 1059 | ret = driver->auto_attach(dev, context); | 1067 | ret = driver->auto_attach(dev, context); |
| 1060 | if (ret >= 0) | 1068 | if (ret >= 0) |
| 1061 | ret = comedi_device_postconfig(dev); | 1069 | ret = comedi_device_postconfig(dev); |
| 1062 | mutex_unlock(&dev->mutex); | ||
| 1063 | 1070 | ||
| 1064 | if (ret < 0) { | 1071 | if (ret < 0) { |
| 1065 | dev_warn(hardware_device, | 1072 | dev_warn(hardware_device, |
| 1066 | "driver '%s' failed to auto-configure device.\n", | 1073 | "driver '%s' failed to auto-configure device.\n", |
| 1067 | driver->driver_name); | 1074 | driver->driver_name); |
| 1075 | mutex_unlock(&dev->mutex); | ||
| 1068 | comedi_release_hardware_device(hardware_device); | 1076 | comedi_release_hardware_device(hardware_device); |
| 1069 | } else { | 1077 | } else { |
| 1070 | /* | 1078 | /* |
| @@ -1074,6 +1082,7 @@ int comedi_auto_config(struct device *hardware_device, · 3 unmodified lines | |||
| 1074 | dev_info(dev->class_dev, | 1082 | dev_info(dev->class_dev, |
| 1075 | "driver '%s' has successfully auto-configured '%s'.\n", | 1083 | "driver '%s' has successfully auto-configured '%s'.\n", |
| 1076 | driver->driver_name, dev->board_name); | 1084 | driver->driver_name, dev->board_name); |
| 1085 | mutex_unlock(&dev->mutex); | ||
| 1077 | } | 1086 | } |
| 1078 | return ret; | 1087 | return ret; |
| 1079 | } | 1088 | } |
| @@ -317,7 +317,7 @@ static int pci1710_ai_read_sample(struct comedi_device *dev, · 316 unmodified lines | |||
| 317 | chan = sample >> 12; | 317 | chan = sample >> 12; |
| 318 | if (chan != devpriv->act_chanlist[cur_chan]) { | 318 | if (chan != devpriv->act_chanlist[cur_chan]) { |
| 319 | dev_err(dev->class_dev, | 319 | dev_err(dev->class_dev, |
| 320 | "A/D data droput: received from channel %d, expected %d\n", | 320 | "A/D data dropout: received from channel %d, expected %d\n", |
| 321 | chan, devpriv->act_chanlist[cur_chan]); | 321 | chan, devpriv->act_chanlist[cur_chan]); |
| 322 | return -ENODATA; | 322 | return -ENODATA; |
| 323 | } | 323 | } |
| @@ -2464,7 +2464,7 @@ static int pci230_auto_attach(struct comedi_device *dev, · 2463 unmodified lines | |||
| 2464 | devpriv->adcg = 0; | 2464 | devpriv->adcg = 0; |
| 2465 | devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE | | 2465 | devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE | |
| 2466 | PCI230_ADC_IR_BIP; | 2466 | PCI230_ADC_IR_BIP; |
| 2467 | outw(1 << 0, devpriv->daqio + PCI230_ADCEN); | 2467 | outw(BIT(0), devpriv->daqio + PCI230_ADCEN); |
| 2468 | outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); | 2468 | outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG); |
| 2469 | outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, | 2469 | outw(devpriv->adccon | PCI230_ADC_FIFO_RESET, |
| 2470 | devpriv->daqio + PCI230_ADCCON); | 2470 | devpriv->daqio + PCI230_ADCCON); |
| @@ -172,6 +172,19 @@ struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev, · 171 unmodified lines | |||
| 172 | goto no_dma; | 172 | goto no_dma; |
| 173 | dma->desc = desc; | 173 | dma->desc = desc; |
| 174 | dma->n_desc = n_desc; | 174 | dma->n_desc = n_desc; |
| 175 | if (dev->hw_dev) { | ||
| 176 | dma->dev = dev->hw_dev; | ||
| 177 | } else { | ||
| 178 | /* Fall back to using the "class" device. */ | ||
| 179 | if (!dev->class_dev) | ||
| 180 | goto no_dma; | ||
| 181 | /* Need 24-bit mask for ISA DMA. */ | ||
| 182 | if (dma_coerce_mask_and_coherent(dev->class_dev, | ||
| 183 | DMA_BIT_MASK(24))) { | ||
| 184 | goto no_dma; | ||
| 185 | } | ||
| 186 | dma->dev = dev->class_dev; | ||
| 187 | } | ||
| 175 | 188 | ||
| 176 | dma_chans[0] = dma_chan1; | 189 | dma_chans[0] = dma_chan1; |
| 177 | if (dma_chan2 == 0 || dma_chan2 == dma_chan1) | 190 | if (dma_chan2 == 0 || dma_chan2 == dma_chan1) |
| @@ -192,7 +205,7 @@ struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev, · 14 unmodified lines | |||
| 192 | desc = &dma->desc[i]; | 205 | desc = &dma->desc[i]; |
| 193 | desc->chan = dma_chans[i]; | 206 | desc->chan = dma_chans[i]; |
| 194 | desc->maxsize = maxsize; | 207 | desc->maxsize = maxsize; |
| 195 | desc->virt_addr = dma_alloc_coherent(NULL, desc->maxsize, | 208 | desc->virt_addr = dma_alloc_coherent(dma->dev, desc->maxsize, |
| 196 | &desc->hw_addr, | 209 | &desc->hw_addr, |
| 197 | GFP_KERNEL); | 210 | GFP_KERNEL); |
| 198 | if (!desc->virt_addr) | 211 | if (!desc->virt_addr) |
| @@ -224,7 +237,7 @@ void comedi_isadma_free(struct comedi_isadma *dma) · 25 unmodified lines | |||
| 224 | for (i = 0; i < dma->n_desc; i++) { | 237 | for (i = 0; i < dma->n_desc; i++) { |
| 225 | desc = &dma->desc[i]; | 238 | desc = &dma->desc[i]; |
| 226 | if (desc->virt_addr) | 239 | if (desc->virt_addr) |
| 227 | dma_free_coherent(NULL, desc->maxsize, | 240 | dma_free_coherent(dma->dev, desc->maxsize, |
| 228 | desc->virt_addr, | 241 | desc->virt_addr, |
| 229 | desc->hw_addr); | 242 | desc->hw_addr); |
| 230 | } | 243 | } |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | 11 | ||
| 12 | struct comedi_device; | 12 | struct comedi_device; |
| 13 | struct device; | ||
| 13 | 14 | ||
| 14 | /* | 15 | /* |
| 15 | * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_ | 16 | * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_ |
| @@ -38,6 +39,7 @@ struct comedi_isadma_desc { · 22 unmodified lines | |||
| 38 | 39 | ||
| 39 | /** | 40 | /** |
| 40 | * struct comedi_isadma - ISA DMA data | 41 | * struct comedi_isadma - ISA DMA data |
| 42 | * @dev: device to allocate non-coherent memory for | ||
| 41 | * @desc: cookie for each DMA buffer | 43 | * @desc: cookie for each DMA buffer |
| 42 | * @n_desc: the number of cookies | 44 | * @n_desc: the number of cookies |
| 43 | * @cur_dma: the current cookie in use | 45 | * @cur_dma: the current cookie in use |
| @@ -45,6 +47,7 @@ struct comedi_isadma_desc { · 1 unmodified line | |||
| 45 | * @chan2: the second DMA channel requested | 47 | * @chan2: the second DMA channel requested |
| 46 | */ | 48 | */ |
| 47 | struct comedi_isadma { | 49 | struct comedi_isadma { |
| 50 | struct device *dev; | ||
| 48 | struct comedi_isadma_desc *desc; | 51 | struct comedi_isadma_desc *desc; |
| 49 | int n_desc; | 52 | int n_desc; |
| 50 | int cur_dma; | 53 | int cur_dma; |
| @@ -236,9 +236,9 @@ static int das08_ai_insn_read(struct comedi_device *dev, · 235 unmodified lines | |||
| 236 | * COMEDI 16-bit bipolar data value for 0V is 0x8000. | 236 | * COMEDI 16-bit bipolar data value for 0V is 0x8000. |
| 237 | */ | 237 | */ |
| 238 | if (msb & 0x80) | 238 | if (msb & 0x80) |
| 239 | data[n] = (1 << 15) + magnitude; | 239 | data[n] = BIT(15) + magnitude; |
| 240 | else | 240 | else |
| 241 | data[n] = (1 << 15) - magnitude; | 241 | data[n] = BIT(15) - magnitude; |
| 242 | } else { | 242 | } else { |
| 243 | dev_err(dev->class_dev, "bug! unknown ai encoding\n"); | 243 | dev_err(dev->class_dev, "bug! unknown ai encoding\n"); |
| 244 | return -1; | 244 | return -1; |
| @@ -52,7 +52,7 @@ · 51 unmodified lines | |||
| 52 | #define DT2811_ADCSR_ADBUSY BIT(5) /* r 1=A/D busy */ | 52 | #define DT2811_ADCSR_ADBUSY BIT(5) /* r 1=A/D busy */ |
| 53 | #define DT2811_ADCSR_CLRERROR BIT(4) | 53 | #define DT2811_ADCSR_CLRERROR BIT(4) |
| 54 | #define DT2811_ADCSR_DMAENB BIT(3) /* r/w 1=dma ena */ | 54 | #define DT2811_ADCSR_DMAENB BIT(3) /* r/w 1=dma ena */ |
| 55 | #define DT2811_ADCSR_INTENB BIT(2) /* r/w 1=interupts ena */ | 55 | #define DT2811_ADCSR_INTENB BIT(2) /* r/w 1=interrupts ena */ |
| 56 | #define DT2811_ADCSR_ADMODE(x) (((x) & 0x3) << 0) | 56 | #define DT2811_ADCSR_ADMODE(x) (((x) & 0x3) << 0) |
| 57 | 57 | ||
| 58 | #define DT2811_ADGCR_REG 0x01 /* r/w A/D Gain/Channel */ | 58 | #define DT2811_ADGCR_REG 0x01 /* r/w A/D Gain/Channel */ |
| @@ -835,11 +835,8 @@ static void dt9812_detach(struct comedi_device *dev) · 834 unmodified lines | |||
| 835 | if (!devpriv) | 835 | if (!devpriv) |
| 836 | return; | 836 | return; |
| 837 | 837 | ||
| 838 | mutex_lock(&devpriv->mut); | 838 | mutex_destroy(&devpriv->mut); |
| 839 | |||
| 840 | usb_set_intfdata(intf, NULL); | 839 | usb_set_intfdata(intf, NULL); |
| 841 | |||
| 842 | mutex_unlock(&devpriv->mut); | ||
| 843 | } | 840 | } |
| 844 | 841 | ||
| 845 | static struct comedi_driver dt9812_driver = { | 842 | static struct comedi_driver dt9812_driver = { |
| @@ -54,7 +54,7 @@ static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, · 53 unmodified lines | |||
| 54 | unsigned int status; | 54 | unsigned int status; |
| 55 | 55 | ||
| 56 | status = inw_p(dev->iobase); | 56 | status = inw_p(dev->iobase); |
| 57 | if (status & (1 << 15)) | 57 | if (status & BIT(15)) |
| 58 | return 0; | 58 | return 0; |
| 59 | return -EBUSY; | 59 | return -EBUSY; |
| 60 | } | 60 | } |
| @@ -106,10 +106,6 @@ static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev, · 45 unmodified lines | |||
| 106 | { | 106 | { |
| 107 | struct dyna_pci10xx_private *devpriv = dev->private; | 107 | struct dyna_pci10xx_private *devpriv = dev->private; |
| 108 | int n; | 108 | int n; |
| 109 | unsigned int chan, range; | ||
| 110 | |||
| 111 | chan = CR_CHAN(insn->chanspec); | ||
| 112 | range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; | ||
| 113 | 109 | ||
| 114 | mutex_lock(&devpriv->mutex); | 110 | mutex_lock(&devpriv->mutex); |
| 115 | for (n = 0; n < insn->n; n++) { | 111 | for (n = 0; n < insn->n; n++) { |
| @@ -194,17 +190,15 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, · 78 unmodified lines | |||
| 194 | s->n_chan = 16; | 190 | s->n_chan = 16; |
| 195 | s->maxdata = 0x0FFF; | 191 | s->maxdata = 0x0FFF; |
| 196 | s->range_table = &range_pci1050_ai; | 192 | s->range_table = &range_pci1050_ai; |
| 197 | s->len_chanlist = 16; | ||
| 198 | s->insn_read = dyna_pci10xx_insn_read_ai; | 193 | s->insn_read = dyna_pci10xx_insn_read_ai; |
| 199 | 194 | ||
| 200 | /* analog output */ | 195 | /* analog output */ |
| 201 | s = &dev->subdevices[1]; | 196 | s = &dev->subdevices[1]; |
| 202 | s->type = COMEDI_SUBD_AO; | 197 | s->type = COMEDI_SUBD_AO; |
| 203 | s->subdev_flags = SDF_WRITABLE; | 198 | s->subdev_flags = SDF_WRITABLE; |
| 204 | s->n_chan = 16; | 199 | s->n_chan = 1; |
| 205 | s->maxdata = 0x0FFF; | 200 | s->maxdata = 0x0FFF; |
| 206 | s->range_table = &range_unipolar10; | 201 | s->range_table = &range_unipolar10; |
| 207 | s->len_chanlist = 16; | ||
| 208 | s->insn_write = dyna_pci10xx_insn_write_ao; | 202 | s->insn_write = dyna_pci10xx_insn_write_ao; |
| 209 | 203 | ||
| 210 | /* digital input */ | 204 | /* digital input */ |
| @@ -214,7 +208,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, · 3 unmodified lines | |||
| 214 | s->n_chan = 16; | 208 | s->n_chan = 16; |
| 215 | s->maxdata = 1; | 209 | s->maxdata = 1; |
| 216 | s->range_table = &range_digital; | 210 | s->range_table = &range_digital; |
| 217 | s->len_chanlist = 16; | ||
| 218 | s->insn_bits = dyna_pci10xx_di_insn_bits; | 211 | s->insn_bits = dyna_pci10xx_di_insn_bits; |
| 219 | 212 | ||
| 220 | /* digital output */ | 213 | /* digital output */ |
| @@ -224,7 +217,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, · 3 unmodified lines | |||
| 224 | s->n_chan = 16; | 217 | s->n_chan = 16; |
| 225 | s->maxdata = 1; | 218 | s->maxdata = 1; |
| 226 | s->range_table = &range_digital; | 219 | s->range_table = &range_digital; |
| 227 | s->len_chanlist = 16; | ||
| 228 | s->state = 0; | 220 | s->state = 0; |
| 229 | s->insn_bits = dyna_pci10xx_do_insn_bits; | 221 | s->insn_bits = dyna_pci10xx_do_insn_bits; |
| 230 | 222 | ||
| @@ -244,7 +244,7 @@ static int atao_calib_insn_write(struct comedi_device *dev, · 243 unmodified lines | |||
| 244 | 244 | ||
| 245 | /* write the channel and last data value to the caldac */ | 245 | /* write the channel and last data value to the caldac */ |
| 246 | /* clock the bitstring to the caldac; MSB -> LSB */ | 246 | /* clock the bitstring to the caldac; MSB -> LSB */ |
| 247 | for (bit = 1 << 10; bit; bit >>= 1) { | 247 | for (bit = BIT(10); bit; bit >>= 1) { |
| 248 | bits = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; | 248 | bits = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; |
| 249 | 249 | ||
| 250 | outw(bits, dev->iobase + ATAO_CFG2_REG); | 250 | outw(bits, dev->iobase + ATAO_CFG2_REG); |
| @@ -239,7 +239,7 @@ static int daq700_auto_attach(struct comedi_device *dev, · 238 unmodified lines | |||
| 239 | s->type = COMEDI_SUBD_AI; | 239 | s->type = COMEDI_SUBD_AI; |
| 240 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; | 240 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; |
| 241 | s->n_chan = 16; | 241 | s->n_chan = 16; |
| 242 | s->maxdata = (1 << 12) - 1; | 242 | s->maxdata = BIT(12) - 1; |
| 243 | s->range_table = &range_daq700_ai; | 243 | s->range_table = &range_daq700_ai; |
| 244 | s->insn_read = daq700_ai_rinsn; | 244 | s->insn_read = daq700_ai_rinsn; |
| 245 | daq700_ai_config(dev, s); | 245 | daq700_ai_config(dev, s); |
| @@ -2109,6 +2109,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, · 2108 unmodified lines | |||
| 2109 | 2109 | ||
| 2110 | if (cmd->scan_begin_src == TRIG_TIMER) { | 2110 | if (cmd->scan_begin_src == TRIG_TIMER) { |
| 2111 | unsigned int tmp = cmd->scan_begin_arg; | 2111 | unsigned int tmp = cmd->scan_begin_arg; |
| 2112 | |||
| 2112 | cmd->scan_begin_arg = | 2113 | cmd->scan_begin_arg = |
| 2113 | ni_timer_to_ns(dev, ni_ns_to_timer(dev, | 2114 | ni_timer_to_ns(dev, ni_ns_to_timer(dev, |
| 2114 | cmd->scan_begin_arg, | 2115 | cmd->scan_begin_arg, |
| @@ -2119,6 +2120,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, · 4 unmodified lines | |||
| 2119 | if (cmd->convert_src == TRIG_TIMER) { | 2120 | if (cmd->convert_src == TRIG_TIMER) { |
| 2120 | if (!devpriv->is_611x && !devpriv->is_6143) { | 2121 | if (!devpriv->is_611x && !devpriv->is_6143) { |
| 2121 | unsigned int tmp = cmd->convert_arg; | 2122 | unsigned int tmp = cmd->convert_arg; |
| 2123 | |||
| 2122 | cmd->convert_arg = | 2124 | cmd->convert_arg = |
| 2123 | ni_timer_to_ns(dev, ni_ns_to_timer(dev, | 2125 | ni_timer_to_ns(dev, ni_ns_to_timer(dev, |
| 2124 | cmd->convert_arg, | 2126 | cmd->convert_arg, |
| @@ -4397,9 +4399,13 @@ static int ni_calib_insn_write(struct comedi_device *dev, · 2272 unmodified lines | |||
| 4397 | struct comedi_insn *insn, | 4399 | struct comedi_insn *insn, |
| 4398 | unsigned int *data) | 4400 | unsigned int *data) |
| 4399 | { | 4401 | { |
| 4400 | ni_write_caldac(dev, CR_CHAN(insn->chanspec), data[0]); | 4402 | if (insn->n) { |
| 4403 | /* only bother writing the last sample to the channel */ | ||
| 4404 | ni_write_caldac(dev, CR_CHAN(insn->chanspec), | ||
| 4405 | data[insn->n - 1]); | ||
| 4406 | } | ||
| 4401 | 4407 | ||
| 4402 | return 1; | 4408 | return insn->n; |
| 4403 | } | 4409 | } |
| 4404 | 4410 | ||
| 4405 | static int ni_calib_insn_read(struct comedi_device *dev, | 4411 | static int ni_calib_insn_read(struct comedi_device *dev, |
| @@ -4408,10 +4414,12 @@ static int ni_calib_insn_read(struct comedi_device *dev, · 2 unmodified lines | |||
| 4408 | unsigned int *data) | 4414 | unsigned int *data) |
| 4409 | { | 4415 | { |
| 4410 | struct ni_private *devpriv = dev->private; | 4416 | struct ni_private *devpriv = dev->private; |
| 4417 | unsigned int i; | ||
| 4411 | 4418 | ||
| 4412 | data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)]; | 4419 | for (i = 0; i < insn->n; i++) |
| 4420 | data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)]; | ||
| 4413 | 4421 | ||
| 4414 | return 1; | 4422 | return insn->n; |
| 4415 | } | 4423 | } |
| 4416 | 4424 | ||
| 4417 | static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) | 4425 | static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) |
| @@ -4504,9 +4512,15 @@ static int ni_eeprom_insn_read(struct comedi_device *dev, · 86 unmodified lines | |||
| 4504 | struct comedi_insn *insn, | 4512 | struct comedi_insn *insn, |
| 4505 | unsigned int *data) | 4513 | unsigned int *data) |
| 4506 | { | 4514 | { |
| 4507 | data[0] = ni_read_eeprom(dev, CR_CHAN(insn->chanspec)); | 4515 | unsigned int val; |
| 4516 | unsigned int i; | ||
| 4508 | 4517 | ||
| 4509 | return 1; | 4518 | if (insn->n) { |
| 4519 | val = ni_read_eeprom(dev, CR_CHAN(insn->chanspec)); | ||
| 4520 | for (i = 0; i < insn->n; i++) | ||
| 4521 | data[i] = val; | ||
| 4522 | } | ||
| 4523 | return insn->n; | ||
| 4510 | } | 4524 | } |
| 4511 | 4525 | ||
| 4512 | static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, | 4526 | static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, |
| @@ -4515,10 +4529,12 @@ static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, · 2 unmodified lines | |||
| 4515 | unsigned int *data) | 4529 | unsigned int *data) |
| 4516 | { | 4530 | { |
| 4517 | struct ni_private *devpriv = dev->private; | 4531 | struct ni_private *devpriv = dev->private; |
| 4532 | unsigned int i; | ||
| 4518 | 4533 | ||
| 4519 | data[0] = devpriv->eeprom_buffer[CR_CHAN(insn->chanspec)]; | 4534 | for (i = 0; i < insn->n; i++) |
| 4535 | data[i] = devpriv->eeprom_buffer[CR_CHAN(insn->chanspec)]; | ||
| 4520 | 4536 | ||
| 4521 | return 1; | 4537 | return insn->n; |
| 4522 | } | 4538 | } |
| 4523 | 4539 | ||
| 4524 | static unsigned int ni_old_get_pfi_routing(struct comedi_device *dev, | 4540 | static unsigned int ni_old_get_pfi_routing(struct comedi_device *dev, |
| @@ -4783,7 +4799,7 @@ static int cs5529_do_conversion(struct comedi_device *dev, · 258 unmodified lines | |||
| 4783 | if (data) { | 4799 | if (data) { |
| 4784 | *data = ni_ao_win_inw(dev, NI67XX_CAL_DATA_REG); | 4800 | *data = ni_ao_win_inw(dev, NI67XX_CAL_DATA_REG); |
| 4785 | /* cs5529 returns 16 bit signed data in bipolar mode */ | 4801 | /* cs5529 returns 16 bit signed data in bipolar mode */ |
| 4786 | *data ^= (1 << 15); | 4802 | *data ^= BIT(15); |
| 4787 | } | 4803 | } |
| 4788 | return 0; | 4804 | return 0; |
| 4789 | } | 4805 | } |
| @@ -6192,7 +6208,7 @@ static int ni_E_init(struct comedi_device *dev, · 1402 unmodified lines | |||
| 6192 | s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL; | 6208 | s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL; |
| 6193 | /* one channel for each analog output channel */ | 6209 | /* one channel for each analog output channel */ |
| 6194 | s->n_chan = board->n_aochan; | 6210 | s->n_chan = board->n_aochan; |
| 6195 | s->maxdata = (1 << 16) - 1; | 6211 | s->maxdata = BIT(16) - 1; |
| 6196 | s->range_table = &range_unknown; /* XXX */ | 6212 | s->range_table = &range_unknown; /* XXX */ |
| 6197 | s->insn_read = cs5529_ai_insn_read; | 6213 | s->insn_read = cs5529_ai_insn_read; |
| 6198 | s->insn_config = NULL; | 6214 | s->insn_config = NULL; |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | # this make file is simply to help autogenerate these files: | 2 | # this make file is simply to help autogenerate these files: |
| 2 | # ni_route_values.h | 3 | # ni_route_values.h |
| 3 | # ni_device_routes.h | 4 | # ni_device_routes.h |
| @@ -1681,9 +1681,11 @@ int ni_tio_insn_write(struct comedi_device *dev, · 1680 unmodified lines | |||
| 1681 | unsigned int cidx = counter->counter_index; | 1681 | unsigned int cidx = counter->counter_index; |
| 1682 | unsigned int chip = counter->chip_index; | 1682 | unsigned int chip = counter->chip_index; |
| 1683 | unsigned int load_reg; | 1683 | unsigned int load_reg; |
| 1684 | unsigned int load_val; | ||
| 1684 | 1685 | ||
| 1685 | if (insn->n < 1) | 1686 | if (insn->n < 1) |
| 1686 | return 0; | 1687 | return 0; |
| 1688 | load_val = data[insn->n - 1]; | ||
| 1687 | switch (channel) { | 1689 | switch (channel) { |
| 1688 | case 0: | 1690 | case 0: |
| 1689 | /* | 1691 | /* |
| @@ -1696,7 +1698,7 @@ int ni_tio_insn_write(struct comedi_device *dev, · 6 unmodified lines | |||
| 1696 | * load register is already selected. | 1698 | * load register is already selected. |
| 1697 | */ | 1699 | */ |
| 1698 | load_reg = ni_tio_next_load_register(counter); | 1700 | load_reg = ni_tio_next_load_register(counter); |
| 1699 | ni_tio_write(counter, data[0], load_reg); | 1701 | ni_tio_write(counter, load_val, load_reg); |
| 1700 | ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), | 1702 | ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), |
| 1701 | 0, 0, GI_LOAD); | 1703 | 0, 0, GI_LOAD); |
| 1702 | /* restore load reg */ | 1704 | /* restore load reg */ |
| @@ -1704,17 +1706,17 @@ int ni_tio_insn_write(struct comedi_device *dev, · 1 unmodified line | |||
| 1704 | load_reg); | 1706 | load_reg); |
| 1705 | break; | 1707 | break; |
| 1706 | case 1: | 1708 | case 1: |
| 1707 | counter_dev->regs[chip][NITIO_LOADA_REG(cidx)] = data[0]; | 1709 | counter_dev->regs[chip][NITIO_LOADA_REG(cidx)] = load_val; |
| 1708 | ni_tio_write(counter, data[0], NITIO_LOADA_REG(cidx)); | 1710 | ni_tio_write(counter, load_val, NITIO_LOADA_REG(cidx)); |
| 1709 | break; | 1711 | break; |
| 1710 | case 2: | 1712 | case 2: |
| 1711 | counter_dev->regs[chip][NITIO_LOADB_REG(cidx)] = data[0]; | 1713 | counter_dev->regs[chip][NITIO_LOADB_REG(cidx)] = load_val; |
| 1712 | ni_tio_write(counter, data[0], NITIO_LOADB_REG(cidx)); | 1714 | ni_tio_write(counter, load_val, NITIO_LOADB_REG(cidx)); |
| 1713 | break; | 1715 | break; |
| 1714 | default: | 1716 | default: |
| 1715 | return -EINVAL; | 1717 | return -EINVAL; |
| 1716 | } | 1718 | } |
| 1717 | return 0; | 1719 | return insn->n; |
| 1718 | } | 1720 | } |
| 1719 | EXPORT_SYMBOL_GPL(ni_tio_insn_write); | 1721 | EXPORT_SYMBOL_GPL(ni_tio_insn_write); |
| 1720 | 1722 | ||
| @@ -562,14 +562,12 @@ static void ni6501_detach(struct comedi_device *dev) · 561 unmodified lines | |||
| 562 | if (!devpriv) | 562 | if (!devpriv) |
| 563 | return; | 563 | return; |
| 564 | 564 | ||
| 565 | mutex_lock(&devpriv->mut); | 565 | mutex_destroy(&devpriv->mut); |
| 566 | 566 | ||
| 567 | usb_set_intfdata(intf, NULL); | 567 | usb_set_intfdata(intf, NULL); |
| 568 | 568 | ||
| 569 | kfree(devpriv->usb_rx_buf); | 569 | kfree(devpriv->usb_rx_buf); |
| 570 | kfree(devpriv->usb_tx_buf); | 570 | kfree(devpriv->usb_tx_buf); |
| 571 | |||
| 572 | mutex_unlock(&devpriv->mut); | ||
| 573 | } | 571 | } |
| 574 | 572 | ||
| 575 | static struct comedi_driver ni6501_driver = { | 573 | static struct comedi_driver ni6501_driver = { |
| @@ -1,3 +1,4 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * quatech_daqp_cs.c | 3 | * quatech_daqp_cs.c |
| 3 | * Quatech DAQP PCMCIA data capture cards COMEDI client driver | 4 | * Quatech DAQP PCMCIA data capture cards COMEDI client driver |
| @@ -282,7 +282,7 @@ void test_ni_sort_device_routes(void) · 281 unmodified lines | |||
| 282 | 282 | ||
| 283 | void test_ni_find_route_set(void) | 283 | void test_ni_find_route_set(void) |
| 284 | { | 284 | { |
| 285 | unittest(ni_find_route_set(bad_dest, &DR) == NULL, | 285 | unittest(!ni_find_route_set(bad_dest, &DR), |
| 286 | "check for nonexistent route_set\n"); | 286 | "check for nonexistent route_set\n"); |
| 287 | unittest(ni_find_route_set(dest0, &DR) == &DR.routes[0], | 287 | unittest(ni_find_route_set(dest0, &DR) == &DR.routes[0], |
| 288 | "find first route_set\n"); | 288 | "find first route_set\n"); |
| @@ -1691,6 +1691,8 @@ static void usbdux_detach(struct comedi_device *dev) · 1690 unmodified lines | |||
| 1691 | usbdux_free_usb_buffers(dev); | 1691 | usbdux_free_usb_buffers(dev); |
| 1692 | 1692 | ||
| 1693 | mutex_unlock(&devpriv->mut); | 1693 | mutex_unlock(&devpriv->mut); |
| 1694 | |||
| 1695 | mutex_destroy(&devpriv->mut); | ||
| 1694 | } | 1696 | } |
| 1695 | 1697 | ||
| 1696 | static struct comedi_driver usbdux_driver = { | 1698 | static struct comedi_driver usbdux_driver = { |
| @@ -993,6 +993,8 @@ static void usbduxfast_detach(struct comedi_device *dev) · 992 unmodified lines | |||
| 993 | kfree(devpriv->duxbuf); | 993 | kfree(devpriv->duxbuf); |
| 994 | 994 | ||
| 995 | mutex_unlock(&devpriv->mut); | 995 | mutex_unlock(&devpriv->mut); |
| 996 | |||
| 997 | mutex_destroy(&devpriv->mut); | ||
| 996 | } | 998 | } |
| 997 | 999 | ||
| 998 | static struct comedi_driver usbduxfast_driver = { | 1000 | static struct comedi_driver usbduxfast_driver = { |
| @@ -1577,6 +1577,8 @@ static void usbduxsigma_detach(struct comedi_device *dev) · 1576 unmodified lines | |||
| 1577 | usbduxsigma_free_usb_buffers(dev); | 1577 | usbduxsigma_free_usb_buffers(dev); |
| 1578 | 1578 | ||
| 1579 | mutex_unlock(&devpriv->mut); | 1579 | mutex_unlock(&devpriv->mut); |
| 1580 | |||
| 1581 | mutex_destroy(&devpriv->mut); | ||
| 1580 | } | 1582 | } |
| 1581 | 1583 | ||
| 1582 | static struct comedi_driver usbduxsigma_driver = { | 1584 | static struct comedi_driver usbduxsigma_driver = { |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG | 2 | ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG |
| 2 | 3 | ||
| 3 | obj-$(CONFIG_COMEDI_KCOMEDILIB) += kcomedilib.o | 4 | obj-$(CONFIG_COMEDI_KCOMEDILIB) += kcomedilib.o |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | config USB_EMXX | 2 | config USB_EMXX |
| 2 | tristate "EMXX USB Function Device Controller" | 3 | tristate "EMXX USB Function Device Controller" |
| 3 | depends on USB_GADGET && (ARCH_RENESAS || (ARM && COMPILE_TEST)) | 4 | depends on USB_GADGET && (ARCH_RENESAS || (ARM && COMPILE_TEST)) |
| @@ -1 +1,2 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | obj-$(CONFIG_USB_EMXX) := emxx_udc.o | 2 | obj-$(CONFIG_USB_EMXX) := emxx_udc.o |
| @@ -136,7 +136,7 @@ static void _nbu2ss_ep0_complete(struct usb_ep *_ep, struct usb_request *_req) · 135 unmodified lines | |||
| 136 | struct usb_ctrlrequest *p_ctrl; | 136 | struct usb_ctrlrequest *p_ctrl; |
| 137 | struct nbu2ss_udc *udc; | 137 | struct nbu2ss_udc *udc; |
| 138 | 138 | ||
| 139 | if ((!_ep) || (!_req)) | 139 | if (!_ep || !_req) |
| 140 | return; | 140 | return; |
| 141 | 141 | ||
| 142 | udc = (struct nbu2ss_udc *)_req->context; | 142 | udc = (struct nbu2ss_udc *)_req->context; |
| @@ -459,22 +459,22 @@ static void _nbu2ss_dma_map_single(struct nbu2ss_udc *udc, · 316 unmodified lines | |||
| 459 | if (req->unaligned) { | 459 | if (req->unaligned) { |
| 460 | req->req.dma = ep->phys_buf; | 460 | req->req.dma = ep->phys_buf; |
| 461 | } else { | 461 | } else { |
| 462 | req->req.dma = dma_map_single( | 462 | req->req.dma = dma_map_single(udc->gadget.dev.parent, |
| 463 | udc->gadget.dev.parent, | 463 | req->req.buf, |
| 464 | req->req.buf, | 464 | req->req.length, |
| 465 | req->req.length, | 465 | (direct == USB_DIR_IN) |
| 466 | (direct == USB_DIR_IN) | 466 | ? DMA_TO_DEVICE |
| 467 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | 467 | : DMA_FROM_DEVICE); |
| 468 | } | 468 | } |
| 469 | req->mapped = 1; | 469 | req->mapped = 1; |
| 470 | } else { | 470 | } else { |
| 471 | if (!req->unaligned) | 471 | if (!req->unaligned) |
| 472 | dma_sync_single_for_device( | 472 | dma_sync_single_for_device(udc->gadget.dev.parent, |
| 473 | udc->gadget.dev.parent, | 473 | req->req.dma, |
| 474 | req->req.dma, | 474 | req->req.length, |
| 475 | req->req.length, | 475 | (direct == USB_DIR_IN) |
| 476 | (direct == USB_DIR_IN) | 476 | ? DMA_TO_DEVICE |
| 477 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | 477 | : DMA_FROM_DEVICE); |
| 478 | 478 | ||
| 479 | req->mapped = 0; | 479 | req->mapped = 0; |
| 480 | } | 480 | } |
| @@ -940,8 +940,8 @@ static int _nbu2ss_epn_out_transfer(struct nbu2ss_udc *udc, · 459 unmodified lines | |||
| 940 | 940 | ||
| 941 | /*-------------------------------------------------------------*/ | 941 | /*-------------------------------------------------------------*/ |
| 942 | /* Receive Length */ | 942 | /* Receive Length */ |
| 943 | i_recv_length | 943 | i_recv_length = |
| 944 | = _nbu2ss_readl(&preg->EP_REGS[num].EP_LEN_DCNT) & EPN_LDATA; | 944 | _nbu2ss_readl(&preg->EP_REGS[num].EP_LEN_DCNT) & EPN_LDATA; |
| 945 | 945 | ||
| 946 | if (i_recv_length != 0) { | 946 | if (i_recv_length != 0) { |
| 947 | result = _nbu2ss_epn_out_data(udc, ep, req, i_recv_length); | 947 | result = _nbu2ss_epn_out_data(udc, ep, req, i_recv_length); |
| @@ -1414,12 +1414,11 @@ static inline int _nbu2ss_req_feature(struct nbu2ss_udc *udc, bool bset) · 466 unmodified lines | |||
| 1414 | if (selector == USB_ENDPOINT_HALT) { | 1414 | if (selector == USB_ENDPOINT_HALT) { |
| 1415 | ep_adrs = wIndex & 0xFF; | 1415 | ep_adrs = wIndex & 0xFF; |
| 1416 | if (!bset) { | 1416 | if (!bset) { |
| 1417 | _nbu2ss_endpoint_toggle_reset( | 1417 | _nbu2ss_endpoint_toggle_reset(udc, |
| 1418 | udc, ep_adrs); | 1418 | ep_adrs); |
| 1419 | } | 1419 | } |
| 1420 | 1420 | ||
| 1421 | _nbu2ss_set_endpoint_stall( | 1421 | _nbu2ss_set_endpoint_stall(udc, ep_adrs, bset); |
| 1422 | udc, ep_adrs, bset); | ||
| 1423 | 1422 | ||
| 1424 | result = 0; | 1423 | result = 0; |
| 1425 | } | 1424 | } |
| @@ -1496,10 +1495,10 @@ static int std_req_get_status(struct nbu2ss_udc *udc) · 70 unmodified lines | |||
| 1496 | case USB_RECIP_DEVICE: | 1495 | case USB_RECIP_DEVICE: |
| 1497 | if (udc->ctrl.wIndex == 0x0000) { | 1496 | if (udc->ctrl.wIndex == 0x0000) { |
| 1498 | if (udc->gadget.is_selfpowered) | 1497 | if (udc->gadget.is_selfpowered) |
| 1499 | status_data |= (1 << USB_DEVICE_SELF_POWERED); | 1498 | status_data |= BIT(USB_DEVICE_SELF_POWERED); |
| 1500 | 1499 | ||
| 1501 | if (udc->remote_wakeup) | 1500 | if (udc->remote_wakeup) |
| 1502 | status_data |= (1 << USB_DEVICE_REMOTE_WAKEUP); | 1501 | status_data |= BIT(USB_DEVICE_REMOTE_WAKEUP); |
| 1503 | 1502 | ||
| 1504 | result = 0; | 1503 | result = 0; |
| 1505 | } | 1504 | } |
| @@ -1511,7 +1510,7 @@ static int std_req_get_status(struct nbu2ss_udc *udc) · 5 unmodified lines | |||
| 1511 | result = _nbu2ss_get_ep_stall(udc, ep_adrs); | 1510 | result = _nbu2ss_get_ep_stall(udc, ep_adrs); |
| 1512 | 1511 | ||
| 1513 | if (result > 0) | 1512 | if (result > 0) |
| 1514 | status_data |= (1 << USB_ENDPOINT_HALT); | 1513 | status_data |= BIT(USB_ENDPOINT_HALT); |
| 1515 | } | 1514 | } |
| 1516 | break; | 1515 | break; |
| 1517 | 1516 | ||
| @@ -2423,13 +2422,13 @@ static int nbu2ss_ep_enable(struct usb_ep *_ep, · 905 unmodified lines | |||
| 2423 | struct nbu2ss_ep *ep; | 2422 | struct nbu2ss_ep *ep; |
| 2424 | struct nbu2ss_udc *udc; | 2423 | struct nbu2ss_udc *udc; |
| 2425 | 2424 | ||
| 2426 | if ((!_ep) || (!desc)) { | 2425 | if (!_ep || !desc) { |
| 2427 | pr_err(" *** %s, bad param\n", __func__); | 2426 | pr_err(" *** %s, bad param\n", __func__); |
| 2428 | return -EINVAL; | 2427 | return -EINVAL; |
| 2429 | } | 2428 | } |
| 2430 | 2429 | ||
| 2431 | ep = container_of(_ep, struct nbu2ss_ep, ep); | 2430 | ep = container_of(_ep, struct nbu2ss_ep, ep); |
| 2432 | if ((!ep->udc)) { | 2431 | if (!ep->udc) { |
| 2433 | pr_err(" *** %s, ep == NULL !!\n", __func__); | 2432 | pr_err(" *** %s, ep == NULL !!\n", __func__); |
| 2434 | return -EINVAL; | 2433 | return -EINVAL; |
| 2435 | } | 2434 | } |
| @@ -2545,7 +2544,7 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep, · 109 unmodified lines | |||
| 2545 | int result = -EINVAL; | 2544 | int result = -EINVAL; |
| 2546 | 2545 | ||
| 2547 | /* catch various bogus parameters */ | 2546 | /* catch various bogus parameters */ |
| 2548 | if ((!_ep) || (!_req)) { | 2547 | if (!_ep || !_req) { |
| 2549 | if (!_ep) | 2548 | if (!_ep) |
| 2550 | pr_err("udc: %s --- _ep == NULL\n", __func__); | 2549 | pr_err("udc: %s --- _ep == NULL\n", __func__); |
| 2551 | 2550 | ||
| @@ -2595,9 +2594,9 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep, · 43 unmodified lines | |||
| 2595 | 2594 | ||
| 2596 | if (req->unaligned) { | 2595 | if (req->unaligned) { |
| 2597 | if (!ep->virt_buf) | 2596 | if (!ep->virt_buf) |
| 2598 | ep->virt_buf = dma_alloc_coherent( | 2597 | ep->virt_buf = dma_alloc_coherent(NULL, PAGE_SIZE, |
| 2599 | NULL, PAGE_SIZE, | 2598 | &ep->phys_buf, |
| 2600 | &ep->phys_buf, GFP_ATOMIC | GFP_DMA); | 2599 | GFP_ATOMIC | GFP_DMA); |
| 2601 | if (ep->epnum > 0) { | 2600 | if (ep->epnum > 0) { |
| 2602 | if (ep->direct == USB_DIR_IN) | 2601 | if (ep->direct == USB_DIR_IN) |
| 2603 | memcpy(ep->virt_buf, req->req.buf, | 2602 | memcpy(ep->virt_buf, req->req.buf, |
| @@ -2647,7 +2646,7 @@ static int nbu2ss_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) · 43 unmodified lines | |||
| 2647 | unsigned long flags; | 2646 | unsigned long flags; |
| 2648 | 2647 | ||
| 2649 | /* catch various bogus parameters */ | 2648 | /* catch various bogus parameters */ |
| 2650 | if ((!_ep) || (!_req)) { | 2649 | if (!_ep || !_req) { |
| 2651 | /* pr_err("%s, bad param(1)\n", __func__); */ | 2650 | /* pr_err("%s, bad param(1)\n", __func__); */ |
| 2652 | return -EINVAL; | 2651 | return -EINVAL; |
| 2653 | } | 2652 | } |
| @@ -60,6 +60,7 @@ fault_injection=%d Enable fault injection in all supported types with · 59 unmodified lines | |||
| 60 | specified injection rate. Supported injection type: | 60 | specified injection rate. Supported injection type: |
| 61 | Type_Name Type_Value | 61 | Type_Name Type_Value |
| 62 | FAULT_KMALLOC 0x000000001 | 62 | FAULT_KMALLOC 0x000000001 |
| 63 | FAULT_READ_IO 0x000000002 | ||
| 63 | (no)user_xattr Setup Extended User Attributes. Note: xattr is enabled | 64 | (no)user_xattr Setup Extended User Attributes. Note: xattr is enabled |
| 64 | by default if CONFIG_EROFS_FS_XATTR is selected. | 65 | by default if CONFIG_EROFS_FS_XATTR is selected. |
| 65 | (no)acl Setup POSIX Access Control List. Note: acl is enabled | 66 | (no)acl Setup POSIX Access Control List. Note: acl is enabled |
| @@ -17,11 +17,17 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | static inline void read_endio(struct bio *bio) | 18 | static inline void read_endio(struct bio *bio) |
| 19 | { | 19 | { |
| 20 | struct super_block *const sb = bio->bi_private; | ||
| 20 | int i; | 21 | int i; |
| 21 | struct bio_vec *bvec; | 22 | struct bio_vec *bvec; |
| 22 | const blk_status_t err = bio->bi_status; | 23 | blk_status_t err = bio->bi_status; |
| 23 | struct bvec_iter_all iter_all; | 24 | struct bvec_iter_all iter_all; |
| 24 | 25 | ||
| 26 | if (time_to_inject(EROFS_SB(sb), FAULT_READ_IO)) { | ||
| 27 | erofs_show_injection_info(FAULT_READ_IO); | ||
| 28 | err = BLK_STS_IOERR; | ||
| 29 | } | ||
| 30 | |||
| 25 | bio_for_each_segment_all(bvec, bio, i, iter_all) { | 31 | bio_for_each_segment_all(bvec, bio, i, iter_all) { |
| 26 | struct page *page = bvec->bv_page; | 32 | struct page *page = bvec->bv_page; |
| 27 | 33 | ||
| @@ -63,7 +69,7 @@ repeat: · 35 unmodified lines | |||
| 63 | if (!PageUptodate(page)) { | 69 | if (!PageUptodate(page)) { |
| 64 | struct bio *bio; | 70 | struct bio *bio; |
| 65 | 71 | ||
| 66 | bio = erofs_grab_bio(sb, blkaddr, 1, read_endio, nofail); | 72 | bio = erofs_grab_bio(sb, blkaddr, 1, sb, read_endio, nofail); |
| 67 | if (IS_ERR(bio)) { | 73 | if (IS_ERR(bio)) { |
| 68 | DBG_BUGON(nofail); | 74 | DBG_BUGON(nofail); |
| 69 | err = PTR_ERR(bio); | 75 | err = PTR_ERR(bio); |
| @@ -188,7 +194,8 @@ static inline struct bio *erofs_read_raw_page(struct bio *bio, · 118 unmodified lines | |||
| 188 | unsigned int nblocks, | 194 | unsigned int nblocks, |
| 189 | bool ra) | 195 | bool ra) |
| 190 | { | 196 | { |
| 191 | struct inode *inode = mapping->host; | 197 | struct inode *const inode = mapping->host; |
| 198 | struct super_block *const sb = inode->i_sb; | ||
| 192 | erofs_off_t current_block = (erofs_off_t)page->index; | 199 | erofs_off_t current_block = (erofs_off_t)page->index; |
| 193 | int err; | 200 | int err; |
| 194 | 201 | ||
| @@ -280,9 +287,8 @@ submit_bio_retry: · 85 unmodified lines | |||
| 280 | if (nblocks > BIO_MAX_PAGES) | 287 | if (nblocks > BIO_MAX_PAGES) |
| 281 | nblocks = BIO_MAX_PAGES; | 288 | nblocks = BIO_MAX_PAGES; |
| 282 | 289 | ||
| 283 | bio = erofs_grab_bio(inode->i_sb, | 290 | bio = erofs_grab_bio(sb, blknr, nblocks, sb, |
| 284 | blknr, nblocks, read_endio, false); | 291 | read_endio, false); |
| 285 | |||
| 286 | if (IS_ERR(bio)) { | 292 | if (IS_ERR(bio)) { |
| 287 | err = PTR_ERR(bio); | 293 | err = PTR_ERR(bio); |
| 288 | bio = NULL; | 294 | bio = NULL; |
| @@ -25,7 +25,7 @@ static int read_inode(struct inode *inode, void *data) · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | if (unlikely(vi->data_mapping_mode >= EROFS_INODE_LAYOUT_MAX)) { | 26 | if (unlikely(vi->data_mapping_mode >= EROFS_INODE_LAYOUT_MAX)) { |
| 27 | errln("unknown data mapping mode %u of nid %llu", | 27 | errln("unknown data mapping mode %u of nid %llu", |
| 28 | vi->data_mapping_mode, vi->nid); | 28 | vi->data_mapping_mode, vi->nid); |
| 29 | DBG_BUGON(1); | 29 | DBG_BUGON(1); |
| 30 | return -EIO; | 30 | return -EIO; |
| 31 | } | 31 | } |
| @@ -38,7 +38,7 @@ static int read_inode(struct inode *inode, void *data) · 6 unmodified lines | |||
| 38 | 38 | ||
| 39 | inode->i_mode = le16_to_cpu(v2->i_mode); | 39 | inode->i_mode = le16_to_cpu(v2->i_mode); |
| 40 | if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 40 | if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
| 41 | S_ISLNK(inode->i_mode)) { | 41 | S_ISLNK(inode->i_mode)) { |
| 42 | vi->raw_blkaddr = le32_to_cpu(v2->i_u.raw_blkaddr); | 42 | vi->raw_blkaddr = le32_to_cpu(v2->i_u.raw_blkaddr); |
| 43 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | 43 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { |
| 44 | inode->i_rdev = | 44 | inode->i_rdev = |
| @@ -68,7 +68,7 @@ static int read_inode(struct inode *inode, void *data) · 23 unmodified lines | |||
| 68 | 68 | ||
| 69 | inode->i_mode = le16_to_cpu(v1->i_mode); | 69 | inode->i_mode = le16_to_cpu(v1->i_mode); |
| 70 | if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 70 | if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
| 71 | S_ISLNK(inode->i_mode)) { | 71 | S_ISLNK(inode->i_mode)) { |
| 72 | vi->raw_blkaddr = le32_to_cpu(v1->i_u.raw_blkaddr); | 72 | vi->raw_blkaddr = le32_to_cpu(v1->i_u.raw_blkaddr); |
| 73 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | 73 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { |
| 74 | inode->i_rdev = | 74 | inode->i_rdev = |
| @@ -92,7 +92,7 @@ static int read_inode(struct inode *inode, void *data) · 17 unmodified lines | |||
| 92 | inode->i_size = le32_to_cpu(v1->i_size); | 92 | inode->i_size = le32_to_cpu(v1->i_size); |
| 93 | } else { | 93 | } else { |
| 94 | errln("unsupported on-disk inode version %u of nid %llu", | 94 | errln("unsupported on-disk inode version %u of nid %llu", |
| 95 | __inode_version(advise), vi->nid); | 95 | __inode_version(advise), vi->nid); |
| 96 | DBG_BUGON(1); | 96 | DBG_BUGON(1); |
| 97 | return -EIO; | 97 | return -EIO; |
| 98 | } | 98 | } |
| @@ -129,7 +129,7 @@ static int fill_inline_data(struct inode *inode, void *data, · 30 unmodified lines | |||
| 129 | if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) { | 129 | if (S_ISLNK(inode->i_mode) && inode->i_size < PAGE_SIZE) { |
| 130 | char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL); | 130 | char *lnk = erofs_kmalloc(sbi, inode->i_size + 1, GFP_KERNEL); |
| 131 | 131 | ||
| 132 | if (unlikely(lnk == NULL)) | 132 | if (unlikely(!lnk)) |
| 133 | return -ENOMEM; | 133 | return -ENOMEM; |
| 134 | 134 | ||
| 135 | m_pofs += vi->inode_isize + vi->xattr_isize; | 135 | m_pofs += vi->inode_isize + vi->xattr_isize; |
| @@ -173,7 +173,7 @@ static int fill_inode(struct inode *inode, int isdir) · 37 unmodified lines | |||
| 173 | 173 | ||
| 174 | if (IS_ERR(page)) { | 174 | if (IS_ERR(page)) { |
| 175 | errln("failed to get inode (nid: %llu) page, err %ld", | 175 | errln("failed to get inode (nid: %llu) page, err %ld", |
| 176 | vi->nid, PTR_ERR(page)); | 176 | vi->nid, PTR_ERR(page)); |
| 177 | return PTR_ERR(page); | 177 | return PTR_ERR(page); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| @@ -260,16 +260,18 @@ static inline struct inode *erofs_iget_locked(struct super_block *sb, · 80 unmodified lines | |||
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | struct inode *erofs_iget(struct super_block *sb, | 262 | struct inode *erofs_iget(struct super_block *sb, |
| 263 | erofs_nid_t nid, bool isdir) | 263 | erofs_nid_t nid, |
| 264 | bool isdir) | ||
| 264 | { | 265 | { |
| 265 | struct inode *inode = erofs_iget_locked(sb, nid); | 266 | struct inode *inode = erofs_iget_locked(sb, nid); |
| 266 | 267 | ||
| 267 | if (unlikely(inode == NULL)) | 268 | if (unlikely(!inode)) |
| 268 | return ERR_PTR(-ENOMEM); | 269 | return ERR_PTR(-ENOMEM); |
| 269 | 270 | ||
| 270 | if (inode->i_state & I_NEW) { | 271 | if (inode->i_state & I_NEW) { |
| 271 | int err; | 272 | int err; |
| 272 | struct erofs_vnode *vi = EROFS_V(inode); | 273 | struct erofs_vnode *vi = EROFS_V(inode); |
| 274 | |||
| 273 | vi->nid = nid; | 275 | vi->nid = nid; |
| 274 | 276 | ||
| 275 | err = fill_inode(inode, isdir); | 277 | err = fill_inode(inode, isdir); |
| @@ -44,11 +44,12 @@ · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | enum { | 45 | enum { |
| 46 | FAULT_KMALLOC, | 46 | FAULT_KMALLOC, |
| 47 | FAULT_READ_IO, | ||
| 47 | FAULT_MAX, | 48 | FAULT_MAX, |
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | #ifdef CONFIG_EROFS_FAULT_INJECTION | 51 | #ifdef CONFIG_EROFS_FAULT_INJECTION |
| 51 | extern char *erofs_fault_name[FAULT_MAX]; | 52 | extern const char *erofs_fault_name[FAULT_MAX]; |
| 52 | #define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type))) | 53 | #define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type))) |
| 53 | 54 | ||
| 54 | struct erofs_fault_info { | 55 | struct erofs_fault_info { |
| @@ -268,8 +269,15 @@ int erofs_try_to_free_cached_page(struct address_space *mapping, · 213 unmodified lines | |||
| 268 | struct page *page); | 269 | struct page *page); |
| 269 | 270 | ||
| 270 | #define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) | 271 | #define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) |
| 272 | static inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi, | ||
| 273 | struct page *page) | ||
| 274 | { | ||
| 275 | return page->mapping == MNGD_MAPPING(sbi); | ||
| 276 | } | ||
| 271 | #else | 277 | #else |
| 272 | #define MNGD_MAPPING(sbi) (NULL) | 278 | #define MNGD_MAPPING(sbi) (NULL) |
| 279 | static inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi, | ||
| 280 | struct page *page) { return false; } | ||
| 273 | #endif | 281 | #endif |
| 274 | 282 | ||
| 275 | #define DEFAULT_MAX_SYNC_DECOMPRESS_PAGES 3 | 283 | #define DEFAULT_MAX_SYNC_DECOMPRESS_PAGES 3 |
| @@ -460,7 +468,7 @@ static inline int z_erofs_map_blocks_iter(struct inode *inode, · 184 unmodified lines | |||
| 460 | /* data.c */ | 468 | /* data.c */ |
| 461 | static inline struct bio * | 469 | static inline struct bio * |
| 462 | erofs_grab_bio(struct super_block *sb, | 470 | erofs_grab_bio(struct super_block *sb, |
| 463 | erofs_blk_t blkaddr, unsigned int nr_pages, | 471 | erofs_blk_t blkaddr, unsigned int nr_pages, void *bi_private, |
| 464 | bio_end_io_t endio, bool nofail) | 472 | bio_end_io_t endio, bool nofail) |
| 465 | { | 473 | { |
| 466 | const gfp_t gfp = GFP_NOIO; | 474 | const gfp_t gfp = GFP_NOIO; |
| @@ -469,7 +477,7 @@ erofs_grab_bio(struct super_block *sb, · 2 unmodified lines | |||
| 469 | do { | 477 | do { |
| 470 | if (nr_pages == 1) { | 478 | if (nr_pages == 1) { |
| 471 | bio = bio_alloc(gfp | (nofail ? __GFP_NOFAIL : 0), 1); | 479 | bio = bio_alloc(gfp | (nofail ? __GFP_NOFAIL : 0), 1); |
| 472 | if (unlikely(bio == NULL)) { | 480 | if (unlikely(!bio)) { |
| 473 | DBG_BUGON(nofail); | 481 | DBG_BUGON(nofail); |
| 474 | return ERR_PTR(-ENOMEM); | 482 | return ERR_PTR(-ENOMEM); |
| 475 | } | 483 | } |
| @@ -477,11 +485,12 @@ erofs_grab_bio(struct super_block *sb, · 1 unmodified line | |||
| 477 | } | 485 | } |
| 478 | bio = bio_alloc(gfp, nr_pages); | 486 | bio = bio_alloc(gfp, nr_pages); |
| 479 | nr_pages /= 2; | 487 | nr_pages /= 2; |
| 480 | } while (unlikely(bio == NULL)); | 488 | } while (unlikely(!bio)); |
| 481 | 489 | ||
| 482 | bio->bi_end_io = endio; | 490 | bio->bi_end_io = endio; |
| 483 | bio_set_dev(bio, sb->s_bdev); | 491 | bio_set_dev(bio, sb->s_bdev); |
| 484 | bio->bi_iter.bi_sector = (sector_t)blkaddr << LOG_SECTORS_PER_BLOCK; | 492 | bio->bi_iter.bi_sector = (sector_t)blkaddr << LOG_SECTORS_PER_BLOCK; |
| 493 | bio->bi_private = bi_private; | ||
| 485 | return bio; | 494 | return bio; |
| 486 | } | 495 | } |
| 487 | 496 | ||
| @@ -565,7 +574,7 @@ static inline void *erofs_vmap(struct page **pages, unsigned int count) · 77 unmodified lines | |||
| 565 | while (1) { | 574 | while (1) { |
| 566 | void *addr = vm_map_ram(pages, count, -1, PAGE_KERNEL); | 575 | void *addr = vm_map_ram(pages, count, -1, PAGE_KERNEL); |
| 567 | /* retry two more times (totally 3 times) */ | 576 | /* retry two more times (totally 3 times) */ |
| 568 | if (addr != NULL || ++i >= 3) | 577 | if (addr || ++i >= 3) |
| 569 | return addr; | 578 | return addr; |
| 570 | vm_unmap_aliases(); | 579 | vm_unmap_aliases(); |
| 571 | } | 580 | } |
| @@ -211,7 +211,8 @@ int erofs_namei(struct inode *dir, · 210 unmodified lines | |||
| 211 | 211 | ||
| 212 | /* NOTE: i_mutex is already held by vfs */ | 212 | /* NOTE: i_mutex is already held by vfs */ |
| 213 | static struct dentry *erofs_lookup(struct inode *dir, | 213 | static struct dentry *erofs_lookup(struct inode *dir, |
| 214 | struct dentry *dentry, unsigned int flags) | 214 | struct dentry *dentry, |
| 215 | unsigned int flags) | ||
| 215 | { | 216 | { |
| 216 | int err; | 217 | int err; |
| 217 | erofs_nid_t nid; | 218 | erofs_nid_t nid; |
| @@ -33,10 +33,11 @@ static void init_once(void *ptr) · 32 unmodified lines | |||
| 33 | static int __init erofs_init_inode_cache(void) | 33 | static int __init erofs_init_inode_cache(void) |
| 34 | { | 34 | { |
| 35 | erofs_inode_cachep = kmem_cache_create("erofs_inode", | 35 | erofs_inode_cachep = kmem_cache_create("erofs_inode", |
| 36 | sizeof(struct erofs_vnode), 0, | 36 | sizeof(struct erofs_vnode), 0, |
| 37 | SLAB_RECLAIM_ACCOUNT, init_once); | 37 | SLAB_RECLAIM_ACCOUNT, |
| 38 | init_once); | ||
| 38 | 39 | ||
| 39 | return erofs_inode_cachep != NULL ? 0 : -ENOMEM; | 40 | return erofs_inode_cachep ? 0 : -ENOMEM; |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | static void erofs_exit_inode_cache(void) | 43 | static void erofs_exit_inode_cache(void) |
| @@ -49,7 +50,7 @@ static struct inode *alloc_inode(struct super_block *sb) · 6 unmodified lines | |||
| 49 | struct erofs_vnode *vi = | 50 | struct erofs_vnode *vi = |
| 50 | kmem_cache_alloc(erofs_inode_cachep, GFP_KERNEL); | 51 | kmem_cache_alloc(erofs_inode_cachep, GFP_KERNEL); |
| 51 | 52 | ||
| 52 | if (vi == NULL) | 53 | if (!vi) |
| 53 | return NULL; | 54 | return NULL; |
| 54 | 55 | ||
| 55 | /* zero out everything except vfs_inode */ | 56 | /* zero out everything except vfs_inode */ |
| @@ -80,7 +81,7 @@ static int superblock_read(struct super_block *sb) · 24 unmodified lines | |||
| 80 | 81 | ||
| 81 | bh = sb_bread(sb, 0); | 82 | bh = sb_bread(sb, 0); |
| 82 | 83 | ||
| 83 | if (bh == NULL) { | 84 | if (!bh) { |
| 84 | errln("cannot read erofs superblock"); | 85 | errln("cannot read erofs superblock"); |
| 85 | return -EIO; | 86 | return -EIO; |
| 86 | } | 87 | } |
| @@ -99,7 +100,7 @@ static int superblock_read(struct super_block *sb) · 12 unmodified lines | |||
| 99 | /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */ | 100 | /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */ |
| 100 | if (unlikely(blkszbits != LOG_BLOCK_SIZE)) { | 101 | if (unlikely(blkszbits != LOG_BLOCK_SIZE)) { |
| 101 | errln("blksize %u isn't supported on this platform", | 102 | errln("blksize %u isn't supported on this platform", |
| 102 | 1 << blkszbits); | 103 | 1 << blkszbits); |
| 103 | goto out; | 104 | goto out; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| @@ -115,7 +116,7 @@ static int superblock_read(struct super_block *sb) · 9 unmodified lines | |||
| 115 | 116 | ||
| 116 | if (1 << (sbi->clusterbits - PAGE_SHIFT) > Z_EROFS_CLUSTER_MAX_PAGES) | 117 | if (1 << (sbi->clusterbits - PAGE_SHIFT) > Z_EROFS_CLUSTER_MAX_PAGES) |
| 117 | errln("clusterbits %u is not supported on this kernel", | 118 | errln("clusterbits %u is not supported on this kernel", |
| 118 | sbi->clusterbits); | 119 | sbi->clusterbits); |
| 119 | #endif | 120 | #endif |
| 120 | 121 | ||
| 121 | sbi->root_nid = le16_to_cpu(layout->root_nid); | 122 | sbi->root_nid = le16_to_cpu(layout->root_nid); |
| @@ -126,7 +127,7 @@ static int superblock_read(struct super_block *sb) · 4 unmodified lines | |||
| 126 | 127 | ||
| 127 | memcpy(&sb->s_uuid, layout->uuid, sizeof(layout->uuid)); | 128 | memcpy(&sb->s_uuid, layout->uuid, sizeof(layout->uuid)); |
| 128 | memcpy(sbi->volume_name, layout->volume_name, | 129 | memcpy(sbi->volume_name, layout->volume_name, |
| 129 | sizeof(layout->volume_name)); | 130 | sizeof(layout->volume_name)); |
| 130 | 131 | ||
| 131 | ret = 0; | 132 | ret = 0; |
| 132 | out: | 133 | out: |
| @@ -135,8 +136,9 @@ out: · 2 unmodified lines | |||
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | #ifdef CONFIG_EROFS_FAULT_INJECTION | 138 | #ifdef CONFIG_EROFS_FAULT_INJECTION |
| 138 | char *erofs_fault_name[FAULT_MAX] = { | 139 | const char *erofs_fault_name[FAULT_MAX] = { |
| 139 | [FAULT_KMALLOC] = "kmalloc", | 140 | [FAULT_KMALLOC] = "kmalloc", |
| 141 | [FAULT_READ_IO] = "read IO error", | ||
| 140 | }; | 142 | }; |
| 141 | 143 | ||
| 142 | static void __erofs_build_fault_attr(struct erofs_sb_info *sbi, | 144 | static void __erofs_build_fault_attr(struct erofs_sb_info *sbi, |
| @@ -233,7 +235,7 @@ static int parse_options(struct super_block *sb, char *options) · 90 unmodified lines | |||
| 233 | if (!options) | 235 | if (!options) |
| 234 | return 0; | 236 | return 0; |
| 235 | 237 | ||
| 236 | while ((p = strsep(&options, ",")) != NULL) { | 238 | while ((p = strsep(&options, ","))) { |
| 237 | int token; | 239 | int token; |
| 238 | 240 | ||
| 239 | if (!*p) | 241 | if (!*p) |
| @@ -307,7 +309,8 @@ static int managed_cache_releasepage(struct page *page, gfp_t gfp_mask) · 67 unmodified lines | |||
| 307 | } | 309 | } |
| 308 | 310 | ||
| 309 | static void managed_cache_invalidatepage(struct page *page, | 311 | static void managed_cache_invalidatepage(struct page *page, |
| 310 | unsigned int offset, unsigned int length) | 312 | unsigned int offset, |
| 313 | unsigned int length) | ||
| 311 | { | 314 | { |
| 312 | const unsigned int stop = length + offset; | 315 | const unsigned int stop = length + offset; |
| 313 | 316 | ||
| @@ -330,7 +333,7 @@ static struct inode *erofs_init_managed_cache(struct super_block *sb) · 16 unmodified lines | |||
| 330 | { | 333 | { |
| 331 | struct inode *inode = new_inode(sb); | 334 | struct inode *inode = new_inode(sb); |
| 332 | 335 | ||
| 333 | if (unlikely(inode == NULL)) | 336 | if (unlikely(!inode)) |
| 334 | return ERR_PTR(-ENOMEM); | 337 | return ERR_PTR(-ENOMEM); |
| 335 | 338 | ||
| 336 | set_nlink(inode, 1); | 339 | set_nlink(inode, 1); |
| @@ -346,7 +349,8 @@ static struct inode *erofs_init_managed_cache(struct super_block *sb) · 9 unmodified lines | |||
| 346 | #endif | 349 | #endif |
| 347 | 350 | ||
| 348 | static int erofs_read_super(struct super_block *sb, | 351 | static int erofs_read_super(struct super_block *sb, |
| 349 | const char *dev_name, void *data, int silent) | 352 | const char *dev_name, |
| 353 | void *data, int silent) | ||
| 350 | { | 354 | { |
| 351 | struct inode *inode; | 355 | struct inode *inode; |
| 352 | struct erofs_sb_info *sbi; | 356 | struct erofs_sb_info *sbi; |
| @@ -361,7 +365,7 @@ static int erofs_read_super(struct super_block *sb, · 8 unmodified lines | |||
| 361 | } | 365 | } |
| 362 | 366 | ||
| 363 | sbi = kzalloc(sizeof(struct erofs_sb_info), GFP_KERNEL); | 367 | sbi = kzalloc(sizeof(struct erofs_sb_info), GFP_KERNEL); |
| 364 | if (unlikely(sbi == NULL)) { | 368 | if (unlikely(!sbi)) { |
| 365 | err = -ENOMEM; | 369 | err = -ENOMEM; |
| 366 | goto err; | 370 | goto err; |
| 367 | } | 371 | } |
| @@ -418,21 +422,21 @@ static int erofs_read_super(struct super_block *sb, · 50 unmodified lines | |||
| 418 | 422 | ||
| 419 | if (!S_ISDIR(inode->i_mode)) { | 423 | if (!S_ISDIR(inode->i_mode)) { |
| 420 | errln("rootino(nid %llu) is not a directory(i_mode %o)", | 424 | errln("rootino(nid %llu) is not a directory(i_mode %o)", |
| 421 | ROOT_NID(sbi), inode->i_mode); | 425 | ROOT_NID(sbi), inode->i_mode); |
| 422 | err = -EINVAL; | 426 | err = -EINVAL; |
| 423 | iput(inode); | 427 | iput(inode); |
| 424 | goto err_iget; | 428 | goto err_iget; |
| 425 | } | 429 | } |
| 426 | 430 | ||
| 427 | sb->s_root = d_make_root(inode); | 431 | sb->s_root = d_make_root(inode); |
| 428 | if (sb->s_root == NULL) { | 432 | if (!sb->s_root) { |
| 429 | err = -ENOMEM; | 433 | err = -ENOMEM; |
| 430 | goto err_iget; | 434 | goto err_iget; |
| 431 | } | 435 | } |
| 432 | 436 | ||
| 433 | /* save the device name to sbi */ | 437 | /* save the device name to sbi */ |
| 434 | sbi->dev_name = __getname(); | 438 | sbi->dev_name = __getname(); |
| 435 | if (sbi->dev_name == NULL) { | 439 | if (!sbi->dev_name) { |
| 436 | err = -ENOMEM; | 440 | err = -ENOMEM; |
| 437 | goto err_devname; | 441 | goto err_devname; |
| 438 | } | 442 | } |
| @@ -444,7 +448,7 @@ static int erofs_read_super(struct super_block *sb, · 5 unmodified lines | |||
| 444 | 448 | ||
| 445 | if (!silent) | 449 | if (!silent) |
| 446 | infoln("mounted on %s with opts: %s.", dev_name, | 450 | infoln("mounted on %s with opts: %s.", dev_name, |
| 447 | (char *)data); | 451 | (char *)data); |
| 448 | return 0; | 452 | return 0; |
| 449 | /* | 453 | /* |
| 450 | * please add a label for each exit point and use | 454 | * please add a label for each exit point and use |
| @@ -475,7 +479,7 @@ static void erofs_put_super(struct super_block *sb) · 24 unmodified lines | |||
| 475 | struct erofs_sb_info *sbi = EROFS_SB(sb); | 479 | struct erofs_sb_info *sbi = EROFS_SB(sb); |
| 476 | 480 | ||
| 477 | /* for cases which are failed in "read_super" */ | 481 | /* for cases which are failed in "read_super" */ |
| 478 | if (sbi == NULL) | 482 | if (!sbi) |
| 479 | return; | 483 | return; |
| 480 | 484 | ||
| 481 | WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC); | 485 | WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC); |
| @@ -509,7 +513,7 @@ struct erofs_mount_private { · 27 unmodified lines | |||
| 509 | 513 | ||
| 510 | /* support mount_bdev() with options */ | 514 | /* support mount_bdev() with options */ |
| 511 | static int erofs_fill_super(struct super_block *sb, | 515 | static int erofs_fill_super(struct super_block *sb, |
| 512 | void *_priv, int silent) | 516 | void *_priv, int silent) |
| 513 | { | 517 | { |
| 514 | struct erofs_mount_private *priv = _priv; | 518 | struct erofs_mount_private *priv = _priv; |
| 515 | 519 | ||
| @@ -629,7 +633,7 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root) · 113 unmodified lines | |||
| 629 | #endif | 633 | #endif |
| 630 | if (test_opt(sbi, FAULT_INJECTION)) | 634 | if (test_opt(sbi, FAULT_INJECTION)) |
| 631 | seq_printf(seq, ",fault_injection=%u", | 635 | seq_printf(seq, ",fault_injection=%u", |
| 632 | erofs_get_fault_rate(sbi)); | 636 | erofs_get_fault_rate(sbi)); |
| 633 | return 0; | 637 | return 0; |
| 634 | } | 638 | } |
| 635 | 639 | ||
| @@ -43,7 +43,7 @@ struct z_erofs_pagevec_ctor { · 42 unmodified lines | |||
| 43 | static inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor, | 43 | static inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor, |
| 44 | bool atomic) | 44 | bool atomic) |
| 45 | { | 45 | { |
| 46 | if (ctor->curr == NULL) | 46 | if (!ctor->curr) |
| 47 | return; | 47 | return; |
| 48 | 48 | ||
| 49 | if (atomic) | 49 | if (atomic) |
| @@ -59,7 +59,7 @@ z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor, · 9 unmodified lines | |||
| 59 | unsigned index; | 59 | unsigned index; |
| 60 | 60 | ||
| 61 | /* keep away from occupied pages */ | 61 | /* keep away from occupied pages */ |
| 62 | if (ctor->next != NULL) | 62 | if (ctor->next) |
| 63 | return ctor->next; | 63 | return ctor->next; |
| 64 | 64 | ||
| 65 | for (index = 0; index < nr; ++index) { | 65 | for (index = 0; index < nr; ++index) { |
| @@ -121,7 +121,7 @@ z_erofs_pagevec_ctor_enqueue(struct z_erofs_pagevec_ctor *ctor, · 55 unmodified lines | |||
| 121 | bool *occupied) | 121 | bool *occupied) |
| 122 | { | 122 | { |
| 123 | *occupied = false; | 123 | *occupied = false; |
| 124 | if (unlikely(ctor->next == NULL && type)) | 124 | if (unlikely(!ctor->next && type)) |
| 125 | if (ctor->index + 1 == ctor->nr) | 125 | if (ctor->index + 1 == ctor->nr) |
| 126 | return false; | 126 | return false; |
| 127 | 127 | ||
| @@ -313,12 +313,12 @@ static int z_erofs_vle_work_add_page( · 312 unmodified lines | |||
| 313 | 313 | ||
| 314 | /* give priority for the compressed data storage */ | 314 | /* give priority for the compressed data storage */ |
| 315 | if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY && | 315 | if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY && |
| 316 | type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && | 316 | type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && |
| 317 | try_to_reuse_as_compressed_page(builder, page)) | 317 | try_to_reuse_as_compressed_page(builder, page)) |
| 318 | return 0; | 318 | return 0; |
| 319 | 319 | ||
| 320 | ret = z_erofs_pagevec_ctor_enqueue(&builder->vector, | 320 | ret = z_erofs_pagevec_ctor_enqueue(&builder->vector, |
| 321 | page, type, &occupied); | 321 | page, type, &occupied); |
| 322 | builder->work->vcnt += (unsigned int)ret; | 322 | builder->work->vcnt += (unsigned int)ret; |
| 323 | 323 | ||
| 324 | return ret ? 0 : -EAGAIN; | 324 | return ret ? 0 : -EAGAIN; |
| @@ -464,10 +464,9 @@ z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f, · 139 unmodified lines | |||
| 464 | grp->obj.index = f->idx; | 464 | grp->obj.index = f->idx; |
| 465 | grp->llen = map->m_llen; | 465 | grp->llen = map->m_llen; |
| 466 | 466 | ||
| 467 | z_erofs_vle_set_workgrp_fmt(grp, | 467 | z_erofs_vle_set_workgrp_fmt(grp, (map->m_flags & EROFS_MAP_ZIPPED) ? |
| 468 | (map->m_flags & EROFS_MAP_ZIPPED) ? | 468 | Z_EROFS_VLE_WORKGRP_FMT_LZ4 : |
| 469 | Z_EROFS_VLE_WORKGRP_FMT_LZ4 : | 469 | Z_EROFS_VLE_WORKGRP_FMT_PLAIN); |
| 470 | Z_EROFS_VLE_WORKGRP_FMT_PLAIN); | ||
| 471 | 470 | ||
| 472 | /* new workgrps have been claimed as type 1 */ | 471 | /* new workgrps have been claimed as type 1 */ |
| 473 | WRITE_ONCE(grp->next, *f->owned_head); | 472 | WRITE_ONCE(grp->next, *f->owned_head); |
| @@ -554,7 +553,8 @@ repeat: · 80 unmodified lines | |||
| 554 | return PTR_ERR(work); | 553 | return PTR_ERR(work); |
| 555 | got_it: | 554 | got_it: |
| 556 | z_erofs_pagevec_ctor_init(&builder->vector, | 555 | z_erofs_pagevec_ctor_init(&builder->vector, |
| 557 | Z_EROFS_VLE_INLINE_PAGEVECS, work->pagevec, work->vcnt); | 556 | Z_EROFS_VLE_INLINE_PAGEVECS, |
| 557 | work->pagevec, work->vcnt); | ||
| 558 | 558 | ||
| 559 | if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY) { | 559 | if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY) { |
| 560 | /* enable possibly in-place decompression */ | 560 | /* enable possibly in-place decompression */ |
| @@ -594,8 +594,9 @@ void erofs_workgroup_free_rcu(struct erofs_workgroup *grp) · 33 unmodified lines | |||
| 594 | call_rcu(&work->rcu, z_erofs_rcu_callback); | 594 | call_rcu(&work->rcu, z_erofs_rcu_callback); |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | static void __z_erofs_vle_work_release(struct z_erofs_vle_workgroup *grp, | 597 | static void |
| 598 | struct z_erofs_vle_work *work __maybe_unused) | 598 | __z_erofs_vle_work_release(struct z_erofs_vle_workgroup *grp, |
| 599 | struct z_erofs_vle_work *work __maybe_unused) | ||
| 599 | { | 600 | { |
| 600 | erofs_workgroup_put(&grp->obj); | 601 | erofs_workgroup_put(&grp->obj); |
| 601 | } | 602 | } |
| @@ -715,7 +716,7 @@ repeat: · 113 unmodified lines | |||
| 715 | 716 | ||
| 716 | /* lucky, within the range of the current map_blocks */ | 717 | /* lucky, within the range of the current map_blocks */ |
| 717 | if (offset + cur >= map->m_la && | 718 | if (offset + cur >= map->m_la && |
| 718 | offset + cur < map->m_la + map->m_llen) { | 719 | offset + cur < map->m_la + map->m_llen) { |
| 719 | /* didn't get a valid unzip work previously (very rare) */ | 720 | /* didn't get a valid unzip work previously (very rare) */ |
| 720 | if (!builder->work) | 721 | if (!builder->work) |
| 721 | goto restart_now; | 722 | goto restart_now; |
| @@ -781,8 +782,8 @@ retry: · 59 unmodified lines | |||
| 781 | struct page *const newpage = | 782 | struct page *const newpage = |
| 782 | __stagingpage_alloc(page_pool, GFP_NOFS); | 783 | __stagingpage_alloc(page_pool, GFP_NOFS); |
| 783 | 784 | ||
| 784 | err = z_erofs_vle_work_add_page(builder, | 785 | err = z_erofs_vle_work_add_page(builder, newpage, |
| 785 | newpage, Z_EROFS_PAGE_TYPE_EXCLUSIVE); | 786 | Z_EROFS_PAGE_TYPE_EXCLUSIVE); |
| 786 | if (likely(!err)) | 787 | if (likely(!err)) |
| 787 | goto retry; | 788 | goto retry; |
| 788 | } | 789 | } |
| @@ -843,12 +844,10 @@ static void z_erofs_vle_unzip_kickoff(void *ptr, int bios) · 54 unmodified lines | |||
| 843 | 844 | ||
| 844 | static inline void z_erofs_vle_read_endio(struct bio *bio) | 845 | static inline void z_erofs_vle_read_endio(struct bio *bio) |
| 845 | { | 846 | { |
| 846 | const blk_status_t err = bio->bi_status; | 847 | struct erofs_sb_info *sbi = NULL; |
| 848 | blk_status_t err = bio->bi_status; | ||
| 847 | unsigned int i; | 849 | unsigned int i; |
| 848 | struct bio_vec *bvec; | 850 | struct bio_vec *bvec; |
| 849 | #ifdef EROFS_FS_HAS_MANAGED_CACHE | ||
| 850 | struct address_space *mc = NULL; | ||
| 851 | #endif | ||
| 852 | struct bvec_iter_all iter_all; | 851 | struct bvec_iter_all iter_all; |
| 853 | 852 | ||
| 854 | bio_for_each_segment_all(bvec, bio, i, iter_all) { | 853 | bio_for_each_segment_all(bvec, bio, i, iter_all) { |
| @@ -858,20 +857,18 @@ static inline void z_erofs_vle_read_endio(struct bio *bio) · 3 unmodified lines | |||
| 858 | DBG_BUGON(PageUptodate(page)); | 857 | DBG_BUGON(PageUptodate(page)); |
| 859 | DBG_BUGON(!page->mapping); | 858 | DBG_BUGON(!page->mapping); |
| 860 | 859 | ||
| 861 | #ifdef EROFS_FS_HAS_MANAGED_CACHE | 860 | if (unlikely(!sbi && !z_erofs_is_stagingpage(page))) { |
| 862 | if (unlikely(!mc && !z_erofs_is_stagingpage(page))) { | 861 | sbi = EROFS_SB(page->mapping->host->i_sb); |
| 863 | struct inode *const inode = page->mapping->host; | ||
| 864 | struct super_block *const sb = inode->i_sb; | ||
| 865 | 862 | ||
| 866 | mc = MNGD_MAPPING(EROFS_SB(sb)); | 863 | if (time_to_inject(sbi, FAULT_READ_IO)) { |
| 864 | erofs_show_injection_info(FAULT_READ_IO); | ||
| 865 | err = BLK_STS_IOERR; | ||
| 866 | } | ||
| 867 | } | 867 | } |
| 868 | 868 | ||
| 869 | /* | 869 | /* sbi should already be gotten if the page is managed */ |
| 870 | * If mc has not gotten, it equals NULL, | 870 | if (sbi) |
| 871 | * however, page->mapping never be NULL if working properly. | 871 | cachemngd = erofs_page_is_managed(sbi, page); |
| 872 | */ | ||
| 873 | cachemngd = (page->mapping == mc); | ||
| 874 | #endif | ||
| 875 | 872 | ||
| 876 | if (unlikely(err)) | 873 | if (unlikely(err)) |
| 877 | SetPageError(page); | 874 | SetPageError(page); |
| @@ -890,8 +887,8 @@ static struct page *z_pagemap_global[Z_EROFS_VLE_VMAP_GLOBAL_PAGES]; · 12 unmodified lines | |||
| 890 | static DEFINE_MUTEX(z_pagemap_global_lock); | 887 | static DEFINE_MUTEX(z_pagemap_global_lock); |
| 891 | 888 | ||
| 892 | static int z_erofs_vle_unzip(struct super_block *sb, | 889 | static int z_erofs_vle_unzip(struct super_block *sb, |
| 893 | struct z_erofs_vle_workgroup *grp, | 890 | struct z_erofs_vle_workgroup *grp, |
| 894 | struct list_head *page_pool) | 891 | struct list_head *page_pool) |
| 895 | { | 892 | { |
| 896 | struct erofs_sb_info *const sbi = EROFS_SB(sb); | 893 | struct erofs_sb_info *const sbi = EROFS_SB(sb); |
| 897 | const unsigned int clusterpages = erofs_clusterpages(sbi); | 894 | const unsigned int clusterpages = erofs_clusterpages(sbi); |
| @@ -919,12 +916,12 @@ static int z_erofs_vle_unzip(struct super_block *sb, · 21 unmodified lines | |||
| 919 | if (likely(nr_pages <= Z_EROFS_VLE_VMAP_ONSTACK_PAGES)) | 916 | if (likely(nr_pages <= Z_EROFS_VLE_VMAP_ONSTACK_PAGES)) |
| 920 | pages = pages_onstack; | 917 | pages = pages_onstack; |
| 921 | else if (nr_pages <= Z_EROFS_VLE_VMAP_GLOBAL_PAGES && | 918 | else if (nr_pages <= Z_EROFS_VLE_VMAP_GLOBAL_PAGES && |
| 922 | mutex_trylock(&z_pagemap_global_lock)) | 919 | mutex_trylock(&z_pagemap_global_lock)) |
| 923 | pages = z_pagemap_global; | 920 | pages = z_pagemap_global; |
| 924 | else { | 921 | else { |
| 925 | repeat: | 922 | repeat: |
| 926 | pages = kvmalloc_array(nr_pages, | 923 | pages = kvmalloc_array(nr_pages, sizeof(struct page *), |
| 927 | sizeof(struct page *), GFP_KERNEL); | 924 | GFP_KERNEL); |
| 928 | 925 | ||
| 929 | /* fallback to global pagemap for the lowmem scenario */ | 926 | /* fallback to global pagemap for the lowmem scenario */ |
| 930 | if (unlikely(!pages)) { | 927 | if (unlikely(!pages)) { |
| @@ -940,8 +937,8 @@ repeat: · 9 unmodified lines | |||
| 940 | for (i = 0; i < nr_pages; ++i) | 937 | for (i = 0; i < nr_pages; ++i) |
| 941 | pages[i] = NULL; | 938 | pages[i] = NULL; |
| 942 | 939 | ||
| 943 | z_erofs_pagevec_ctor_init(&ctor, | 940 | z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_VLE_INLINE_PAGEVECS, |
| 944 | Z_EROFS_VLE_INLINE_PAGEVECS, work->pagevec, 0); | 941 | work->pagevec, 0); |
| 945 | 942 | ||
| 946 | for (i = 0; i < work->vcnt; ++i) { | 943 | for (i = 0; i < work->vcnt; ++i) { |
| 947 | unsigned int pagenr; | 944 | unsigned int pagenr; |
| @@ -983,13 +980,11 @@ repeat: · 35 unmodified lines | |||
| 983 | DBG_BUGON(!page->mapping); | 980 | DBG_BUGON(!page->mapping); |
| 984 | 981 | ||
| 985 | if (!z_erofs_is_stagingpage(page)) { | 982 | if (!z_erofs_is_stagingpage(page)) { |
| 986 | #ifdef EROFS_FS_HAS_MANAGED_CACHE | 983 | if (erofs_page_is_managed(sbi, page)) { |
| 987 | if (page->mapping == MNGD_MAPPING(sbi)) { | ||
| 988 | if (unlikely(!PageUptodate(page))) | 984 | if (unlikely(!PageUptodate(page))) |
| 989 | err = -EIO; | 985 | err = -EIO; |
| 990 | continue; | 986 | continue; |
| 991 | } | 987 | } |
| 992 | #endif | ||
| 993 | 988 | ||
| 994 | /* | 989 | /* |
| 995 | * only if non-head page can be selected | 990 | * only if non-head page can be selected |
| @@ -1019,7 +1014,7 @@ repeat: · 23 unmodified lines | |||
| 1019 | 1014 | ||
| 1020 | if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN) { | 1015 | if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN) { |
| 1021 | err = z_erofs_vle_plain_copy(compressed_pages, clusterpages, | 1016 | err = z_erofs_vle_plain_copy(compressed_pages, clusterpages, |
| 1022 | pages, nr_pages, work->pageofs); | 1017 | pages, nr_pages, work->pageofs); |
| 1023 | goto out; | 1018 | goto out; |
| 1024 | } | 1019 | } |
| 1025 | 1020 | ||
| @@ -1048,8 +1043,8 @@ skip_allocpage: · 22 unmodified lines | |||
| 1048 | goto out; | 1043 | goto out; |
| 1049 | } | 1044 | } |
| 1050 | 1045 | ||
| 1051 | err = z_erofs_vle_unzip_vmap(compressed_pages, | 1046 | err = z_erofs_vle_unzip_vmap(compressed_pages, clusterpages, vout, |
| 1052 | clusterpages, vout, llen, work->pageofs, overlapped); | 1047 | llen, work->pageofs, overlapped); |
| 1053 | 1048 | ||
| 1054 | erofs_vunmap(vout, nr_pages); | 1049 | erofs_vunmap(vout, nr_pages); |
| 1055 | 1050 | ||
| @@ -1058,10 +1053,9 @@ out: · 2 unmodified lines | |||
| 1058 | for (i = 0; i < clusterpages; ++i) { | 1053 | for (i = 0; i < clusterpages; ++i) { |
| 1059 | page = compressed_pages[i]; | 1054 | page = compressed_pages[i]; |
| 1060 | 1055 | ||
| 1061 | #ifdef EROFS_FS_HAS_MANAGED_CACHE | 1056 | if (erofs_page_is_managed(sbi, page)) |
| 1062 | if (page->mapping == MNGD_MAPPING(sbi)) | ||
| 1063 | continue; | 1057 | continue; |
| 1064 | #endif | 1058 | |
| 1065 | /* recycle all individual staging pages */ | 1059 | /* recycle all individual staging pages */ |
| 1066 | (void)z_erofs_gather_if_stagingpage(page_pool, page); | 1060 | (void)z_erofs_gather_if_stagingpage(page_pool, page); |
| 1067 | 1061 | ||
| @@ -1446,10 +1440,8 @@ submit_bio_retry: · 378 unmodified lines | |||
| 1446 | 1440 | ||
| 1447 | if (!bio) { | 1441 | if (!bio) { |
| 1448 | bio = erofs_grab_bio(sb, first_index + i, | 1442 | bio = erofs_grab_bio(sb, first_index + i, |
| 1449 | BIO_MAX_PAGES, | 1443 | BIO_MAX_PAGES, bi_private, |
| 1450 | z_erofs_vle_read_endio, true); | 1444 | z_erofs_vle_read_endio, true); |
| 1451 | bio->bi_private = bi_private; | ||
| 1452 | |||
| 1453 | ++nr_bios; | 1445 | ++nr_bios; |
| 1454 | } | 1446 | } |
| 1455 | 1447 | ||
| @@ -1586,7 +1578,7 @@ static int z_erofs_vle_normalaccess_readpages(struct file *filp, · 130 unmodified lines | |||
| 1586 | struct erofs_vnode *vi = EROFS_V(inode); | 1578 | struct erofs_vnode *vi = EROFS_V(inode); |
| 1587 | 1579 | ||
| 1588 | errln("%s, readahead error at page %lu of nid %llu", | 1580 | errln("%s, readahead error at page %lu of nid %llu", |
| 1589 | __func__, page->index, vi->nid); | 1581 | __func__, page->index, vi->nid); |
| 1590 | } | 1582 | } |
| 1591 | 1583 | ||
| 1592 | put_page(page); | 1584 | put_page(page); |
| @@ -1741,8 +1733,8 @@ vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx, · 148 unmodified lines | |||
| 1741 | } | 1733 | } |
| 1742 | 1734 | ||
| 1743 | int z_erofs_map_blocks_iter(struct inode *inode, | 1735 | int z_erofs_map_blocks_iter(struct inode *inode, |
| 1744 | struct erofs_map_blocks *map, | 1736 | struct erofs_map_blocks *map, |
| 1745 | int flags) | 1737 | int flags) |
| 1746 | { | 1738 | { |
| 1747 | void *kaddr; | 1739 | void *kaddr; |
| 1748 | const struct vle_map_blocks_iter_ctx ctx = { | 1740 | const struct vle_map_blocks_iter_ctx ctx = { |
| @@ -1849,7 +1841,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, · 100 unmodified lines | |||
| 1849 | /* logical cluster number should be >= 1 */ | 1841 | /* logical cluster number should be >= 1 */ |
| 1850 | if (unlikely(!lcn)) { | 1842 | if (unlikely(!lcn)) { |
| 1851 | errln("invalid logical cluster 0 at nid %llu", | 1843 | errln("invalid logical cluster 0 at nid %llu", |
| 1852 | EROFS_V(inode)->nid); | 1844 | EROFS_V(inode)->nid); |
| 1853 | err = -EIO; | 1845 | err = -EIO; |
| 1854 | goto unmap_out; | 1846 | goto unmap_out; |
| 1855 | } | 1847 | } |
| @@ -1869,7 +1861,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, · 13 unmodified lines | |||
| 1869 | break; | 1861 | break; |
| 1870 | default: | 1862 | default: |
| 1871 | errln("unknown cluster type %u at offset %llu of nid %llu", | 1863 | errln("unknown cluster type %u at offset %llu of nid %llu", |
| 1872 | cluster_type, ofs, EROFS_V(inode)->nid); | 1864 | cluster_type, ofs, EROFS_V(inode)->nid); |
| 1873 | err = -EIO; | 1865 | err = -EIO; |
| 1874 | goto unmap_out; | 1866 | goto unmap_out; |
| 1875 | } | 1867 | } |
| @@ -61,7 +61,7 @@ struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb, · 60 unmodified lines | |||
| 61 | repeat: | 61 | repeat: |
| 62 | rcu_read_lock(); | 62 | rcu_read_lock(); |
| 63 | grp = radix_tree_lookup(&sbi->workstn_tree, index); | 63 | grp = radix_tree_lookup(&sbi->workstn_tree, index); |
| 64 | if (grp != NULL) { | 64 | if (grp) { |
| 65 | *tag = xa_pointer_tag(grp); | 65 | *tag = xa_pointer_tag(grp); |
| 66 | grp = xa_untag_pointer(grp); | 66 | grp = xa_untag_pointer(grp); |
| 67 | 67 | ||
| @@ -221,7 +221,7 @@ repeat: · 153 unmodified lines | |||
| 221 | erofs_workstn_lock(sbi); | 221 | erofs_workstn_lock(sbi); |
| 222 | 222 | ||
| 223 | found = radix_tree_gang_lookup(&sbi->workstn_tree, | 223 | found = radix_tree_gang_lookup(&sbi->workstn_tree, |
| 224 | batch, first_index, PAGEVEC_SIZE); | 224 | batch, first_index, PAGEVEC_SIZE); |
| 225 | 225 | ||
| 226 | for (i = 0; i < found; ++i) { | 226 | for (i = 0; i < found; ++i) { |
| 227 | struct erofs_workgroup *grp = xa_untag_pointer(batch[i]); | 227 | struct erofs_workgroup *grp = xa_untag_pointer(batch[i]); |
| @@ -36,7 +36,7 @@ static inline void xattr_iter_end(struct xattr_iter *it, bool atomic) · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | static inline void xattr_iter_end_final(struct xattr_iter *it) | 37 | static inline void xattr_iter_end_final(struct xattr_iter *it) |
| 38 | { | 38 | { |
| 39 | if (it->page == NULL) | 39 | if (!it->page) |
| 40 | return; | 40 | return; |
| 41 | 41 | ||
| 42 | xattr_iter_end(it, true); | 42 | xattr_iter_end(it, true); |
| @@ -107,7 +107,7 @@ static int init_inode_xattrs(struct inode *inode) · 64 unmodified lines | |||
| 107 | vi->xattr_shared_count = ih->h_shared_count; | 107 | vi->xattr_shared_count = ih->h_shared_count; |
| 108 | vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count, | 108 | vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count, |
| 109 | sizeof(uint), GFP_KERNEL); | 109 | sizeof(uint), GFP_KERNEL); |
| 110 | if (vi->xattr_shared_xattrs == NULL) { | 110 | if (!vi->xattr_shared_xattrs) { |
| 111 | xattr_iter_end(&it, atomic_map); | 111 | xattr_iter_end(&it, atomic_map); |
| 112 | ret = -ENOMEM; | 112 | ret = -ENOMEM; |
| 113 | goto out_unlock; | 113 | goto out_unlock; |
| @@ -122,8 +122,8 @@ static int init_inode_xattrs(struct inode *inode) · 8 unmodified lines | |||
| 122 | BUG_ON(it.ofs != EROFS_BLKSIZ); | 122 | BUG_ON(it.ofs != EROFS_BLKSIZ); |
| 123 | xattr_iter_end(&it, atomic_map); | 123 | xattr_iter_end(&it, atomic_map); |
| 124 | 124 | ||
| 125 | it.page = erofs_get_meta_page(sb, | 125 | it.page = erofs_get_meta_page(sb, ++it.blkaddr, |
| 126 | ++it.blkaddr, S_ISDIR(inode->i_mode)); | 126 | S_ISDIR(inode->i_mode)); |
| 127 | if (IS_ERR(it.page)) { | 127 | if (IS_ERR(it.page)) { |
| 128 | kfree(vi->xattr_shared_xattrs); | 128 | kfree(vi->xattr_shared_xattrs); |
| 129 | vi->xattr_shared_xattrs = NULL; | 129 | vi->xattr_shared_xattrs = NULL; |
| @@ -187,7 +187,7 @@ static inline int xattr_iter_fixup(struct xattr_iter *it) · 57 unmodified lines | |||
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | static int inline_xattr_iter_begin(struct xattr_iter *it, | 189 | static int inline_xattr_iter_begin(struct xattr_iter *it, |
| 190 | struct inode *inode) | 190 | struct inode *inode) |
| 191 | { | 191 | { |
| 192 | struct erofs_vnode *const vi = EROFS_V(inode); | 192 | struct erofs_vnode *const vi = EROFS_V(inode); |
| 193 | struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb); | 193 | struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb); |
| @@ -217,7 +217,8 @@ static int inline_xattr_iter_begin(struct xattr_iter *it, · 23 unmodified lines | |||
| 217 | * `ofs' pointing to the next xattr item rather than an arbitrary position. | 217 | * `ofs' pointing to the next xattr item rather than an arbitrary position. |
| 218 | */ | 218 | */ |
| 219 | static int xattr_foreach(struct xattr_iter *it, | 219 | static int xattr_foreach(struct xattr_iter *it, |
| 220 | const struct xattr_iter_handlers *op, unsigned int *tlimit) | 220 | const struct xattr_iter_handlers *op, |
| 221 | unsigned int *tlimit) | ||
| 221 | { | 222 | { |
| 222 | struct erofs_xattr_entry entry; | 223 | struct erofs_xattr_entry entry; |
| 223 | unsigned int value_sz, processed, slice; | 224 | unsigned int value_sz, processed, slice; |
| @@ -234,7 +235,7 @@ static int xattr_foreach(struct xattr_iter *it, · 10 unmodified lines | |||
| 234 | * therefore entry should be in the page | 235 | * therefore entry should be in the page |
| 235 | */ | 236 | */ |
| 236 | entry = *(struct erofs_xattr_entry *)(it->kaddr + it->ofs); | 237 | entry = *(struct erofs_xattr_entry *)(it->kaddr + it->ofs); |
| 237 | if (tlimit != NULL) { | 238 | if (tlimit) { |
| 238 | unsigned int entry_sz = EROFS_XATTR_ENTRY_SIZE(&entry); | 239 | unsigned int entry_sz = EROFS_XATTR_ENTRY_SIZE(&entry); |
| 239 | 240 | ||
| 240 | BUG_ON(*tlimit < entry_sz); | 241 | BUG_ON(*tlimit < entry_sz); |
| @@ -281,7 +282,7 @@ static int xattr_foreach(struct xattr_iter *it, · 40 unmodified lines | |||
| 281 | /* 3. handle xattr value */ | 282 | /* 3. handle xattr value */ |
| 282 | processed = 0; | 283 | processed = 0; |
| 283 | 284 | ||
| 284 | if (op->alloc_buffer != NULL) { | 285 | if (op->alloc_buffer) { |
| 285 | err = op->alloc_buffer(it, value_sz); | 286 | err = op->alloc_buffer(it, value_sz); |
| 286 | if (err) { | 287 | if (err) { |
| 287 | it->ofs += value_sz; | 288 | it->ofs += value_sz; |
| @@ -321,7 +322,7 @@ struct getxattr_iter { · 33 unmodified lines | |||
| 321 | }; | 322 | }; |
| 322 | 323 | ||
| 323 | static int xattr_entrymatch(struct xattr_iter *_it, | 324 | static int xattr_entrymatch(struct xattr_iter *_it, |
| 324 | struct erofs_xattr_entry *entry) | 325 | struct erofs_xattr_entry *entry) |
| 325 | { | 326 | { |
| 326 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); | 327 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); |
| 327 | 328 | ||
| @@ -330,7 +331,7 @@ static int xattr_entrymatch(struct xattr_iter *_it, · 2 unmodified lines | |||
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | static int xattr_namematch(struct xattr_iter *_it, | 333 | static int xattr_namematch(struct xattr_iter *_it, |
| 333 | unsigned int processed, char *buf, unsigned int len) | 334 | unsigned int processed, char *buf, unsigned int len) |
| 334 | { | 335 | { |
| 335 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); | 336 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); |
| 336 | 337 | ||
| @@ -338,17 +339,18 @@ static int xattr_namematch(struct xattr_iter *_it, · 1 unmodified line | |||
| 338 | } | 339 | } |
| 339 | 340 | ||
| 340 | static int xattr_checkbuffer(struct xattr_iter *_it, | 341 | static int xattr_checkbuffer(struct xattr_iter *_it, |
| 341 | unsigned int value_sz) | 342 | unsigned int value_sz) |
| 342 | { | 343 | { |
| 343 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); | 344 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); |
| 344 | int err = it->buffer_size < value_sz ? -ERANGE : 0; | 345 | int err = it->buffer_size < value_sz ? -ERANGE : 0; |
| 345 | 346 | ||
| 346 | it->buffer_size = value_sz; | 347 | it->buffer_size = value_sz; |
| 347 | return it->buffer == NULL ? 1 : err; | 348 | return !it->buffer ? 1 : err; |
| 348 | } | 349 | } |
| 349 | 350 | ||
| 350 | static void xattr_copyvalue(struct xattr_iter *_it, | 351 | static void xattr_copyvalue(struct xattr_iter *_it, |
| 351 | unsigned int processed, char *buf, unsigned int len) | 352 | unsigned int processed, |
| 353 | char *buf, unsigned int len) | ||
| 352 | { | 354 | { |
| 353 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); | 355 | struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it); |
| 354 | 356 | ||
| @@ -429,13 +431,13 @@ static bool erofs_xattr_trusted_list(struct dentry *dentry) · 74 unmodified lines | |||
| 429 | } | 431 | } |
| 430 | 432 | ||
| 431 | int erofs_getxattr(struct inode *inode, int index, | 433 | int erofs_getxattr(struct inode *inode, int index, |
| 432 | const char *name, | 434 | const char *name, |
| 433 | void *buffer, size_t buffer_size) | 435 | void *buffer, size_t buffer_size) |
| 434 | { | 436 | { |
| 435 | int ret; | 437 | int ret; |
| 436 | struct getxattr_iter it; | 438 | struct getxattr_iter it; |
| 437 | 439 | ||
| 438 | if (unlikely(name == NULL)) | 440 | if (unlikely(!name)) |
| 439 | return -EINVAL; | 441 | return -EINVAL; |
| 440 | 442 | ||
| 441 | ret = init_inode_xattrs(inode); | 443 | ret = init_inode_xattrs(inode); |
| @@ -460,8 +462,8 @@ int erofs_getxattr(struct inode *inode, int index, · 18 unmodified lines | |||
| 460 | } | 462 | } |
| 461 | 463 | ||
| 462 | static int erofs_xattr_generic_get(const struct xattr_handler *handler, | 464 | static int erofs_xattr_generic_get(const struct xattr_handler *handler, |
| 463 | struct dentry *unused, struct inode *inode, | 465 | struct dentry *unused, struct inode *inode, |
| 464 | const char *name, void *buffer, size_t size) | 466 | const char *name, void *buffer, size_t size) |
| 465 | { | 467 | { |
| 466 | struct erofs_sb_info *const sbi = EROFS_I_SB(inode); | 468 | struct erofs_sb_info *const sbi = EROFS_I_SB(inode); |
| 467 | 469 | ||
| @@ -527,7 +529,7 @@ struct listxattr_iter { · 59 unmodified lines | |||
| 527 | }; | 529 | }; |
| 528 | 530 | ||
| 529 | static int xattr_entrylist(struct xattr_iter *_it, | 531 | static int xattr_entrylist(struct xattr_iter *_it, |
| 530 | struct erofs_xattr_entry *entry) | 532 | struct erofs_xattr_entry *entry) |
| 531 | { | 533 | { |
| 532 | struct listxattr_iter *it = | 534 | struct listxattr_iter *it = |
| 533 | container_of(_it, struct listxattr_iter, it); | 535 | container_of(_it, struct listxattr_iter, it); |
| @@ -537,13 +539,13 @@ static int xattr_entrylist(struct xattr_iter *_it, · 3 unmodified lines | |||
| 537 | const struct xattr_handler *h = | 539 | const struct xattr_handler *h = |
| 538 | erofs_xattr_handler(entry->e_name_index); | 540 | erofs_xattr_handler(entry->e_name_index); |
| 539 | 541 | ||
| 540 | if (h == NULL || (h->list != NULL && !h->list(it->dentry))) | 542 | if (!h || (h->list && !h->list(it->dentry))) |
| 541 | return 1; | 543 | return 1; |
| 542 | 544 | ||
| 543 | prefix = xattr_prefix(h); | 545 | prefix = xattr_prefix(h); |
| 544 | prefix_len = strlen(prefix); | 546 | prefix_len = strlen(prefix); |
| 545 | 547 | ||
| 546 | if (it->buffer == NULL) { | 548 | if (!it->buffer) { |
| 547 | it->buffer_ofs += prefix_len + entry->e_name_len + 1; | 549 | it->buffer_ofs += prefix_len + entry->e_name_len + 1; |
| 548 | return 1; | 550 | return 1; |
| 549 | } | 551 | } |
| @@ -558,7 +560,7 @@ static int xattr_entrylist(struct xattr_iter *_it, · 8 unmodified lines | |||
| 558 | } | 560 | } |
| 559 | 561 | ||
| 560 | static int xattr_namelist(struct xattr_iter *_it, | 562 | static int xattr_namelist(struct xattr_iter *_it, |
| 561 | unsigned int processed, char *buf, unsigned int len) | 563 | unsigned int processed, char *buf, unsigned int len) |
| 562 | { | 564 | { |
| 563 | struct listxattr_iter *it = | 565 | struct listxattr_iter *it = |
| 564 | container_of(_it, struct listxattr_iter, it); | 566 | container_of(_it, struct listxattr_iter, it); |
| @@ -569,7 +571,7 @@ static int xattr_namelist(struct xattr_iter *_it, · 4 unmodified lines | |||
| 569 | } | 571 | } |
| 570 | 572 | ||
| 571 | static int xattr_skipvalue(struct xattr_iter *_it, | 573 | static int xattr_skipvalue(struct xattr_iter *_it, |
| 572 | unsigned int value_sz) | 574 | unsigned int value_sz) |
| 573 | { | 575 | { |
| 574 | struct listxattr_iter *it = | 576 | struct listxattr_iter *it = |
| 575 | container_of(_it, struct listxattr_iter, it); | 577 | container_of(_it, struct listxattr_iter, it); |
| @@ -641,7 +643,7 @@ static int shared_listxattr(struct listxattr_iter *it) · 65 unmodified lines | |||
| 641 | } | 643 | } |
| 642 | 644 | ||
| 643 | ssize_t erofs_listxattr(struct dentry *dentry, | 645 | ssize_t erofs_listxattr(struct dentry *dentry, |
| 644 | char *buffer, size_t buffer_size) | 646 | char *buffer, size_t buffer_size) |
| 645 | { | 647 | { |
| 646 | int ret; | 648 | int ret; |
| 647 | struct listxattr_iter it; | 649 | struct listxattr_iter it; |
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 1 | menuconfig FB_TFT | 2 | menuconfig FB_TFT |
| 2 | tristate "Support for small TFT LCD display modules" | 3 | tristate "Support for small TFT LCD display modules" |
| 3 | depends on FB && SPI | 4 | depends on FB && SPI |
| @@ -383,7 +383,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) · 382 unmodified lines | |||
| 383 | /* select right side (sc1) | 383 | /* select right side (sc1) |
| 384 | * set addr | 384 | * set addr |
| 385 | */ | 385 | */ |
| 386 | write_reg(par, 0x01, 1 << 6); | 386 | write_reg(par, 0x01, BIT(6)); |
| 387 | write_reg(par, 0x01, (0x17 << 3) | (u8)y); | 387 | write_reg(par, 0x01, (0x17 << 3) | (u8)y); |
| 388 | 388 | ||
| 389 | /* write bitmap */ | 389 | /* write bitmap */ |
| @@ -406,7 +406,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) · 16 unmodified lines | |||
| 406 | static int write(struct fbtft_par *par, void *buf, size_t len) | 406 | static int write(struct fbtft_par *par, void *buf, size_t len) |
| 407 | { | 407 | { |
| 408 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 408 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 409 | "%s(len=%d): ", __func__, len); | 409 | "%s(len=%zu): ", __func__, len); |
| 410 | 410 | ||
| 411 | gpiod_set_value(par->RW, 0); /* set write mode */ | 411 | gpiod_set_value(par->RW, 0); /* set write mode */ |
| 412 | 412 | ||
| @@ -24,7 +24,7 @@ static int write_spi(struct fbtft_par *par, void *buf, size_t len) · 23 unmodified lines | |||
| 24 | struct spi_message m; | 24 | struct spi_message m; |
| 25 | 25 | ||
| 26 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 26 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 27 | "%s(len=%d): ", __func__, len); | 27 | "%s(len=%zu): ", __func__, len); |
| 28 | 28 | ||
| 29 | if (!par->spi) { | 29 | if (!par->spi) { |
| 30 | dev_err(par->info->device, | 30 | dev_err(par->info->device, |
| @@ -184,7 +184,8 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) · 183 unmodified lines | |||
| 184 | for (y = 0; y < yres / 8; y++) { | 184 | for (y = 0; y < yres / 8; y++) { |
| 185 | *buf = 0x00; | 185 | *buf = 0x00; |
| 186 | for (i = 0; i < 8; i++) | 186 | for (i = 0; i < 8; i++) |
| 187 | *buf |= (vmem16[(y * 8 + i) * xres + x] ? 1 : 0) << i; | 187 | if (vmem16[(y * 8 + i) * xres + x]) |
| 188 | *buf |= BIT(i); | ||
| 188 | buf++; | 189 | buf++; |
| 189 | } | 190 | } |
| 190 | } | 191 | } |
| @@ -74,7 +74,8 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...) · 73 unmodified lines | |||
| 74 | for (i = 0; i < len; i++) | 74 | for (i = 0; i < len; i++) |
| 75 | buf[i] = (u8)va_arg(args, unsigned int); | 75 | buf[i] = (u8)va_arg(args, unsigned int); |
| 76 | va_end(args); | 76 | va_end(args); |
| 77 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__); | 77 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, |
| 78 | u8, buf, len, "%s: ", __func__); | ||
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | va_start(args, len); | 81 | va_start(args, len); |
| @@ -81,10 +81,10 @@ static int set_var(struct fbtft_par *par) · 80 unmodified lines | |||
| 81 | 81 | ||
| 82 | switch (par->info->var.rotate) { | 82 | switch (par->info->var.rotate) { |
| 83 | case 0: | 83 | case 0: |
| 84 | write_reg(par, 0xA0, remap | 0x00 | 1 << 4); | 84 | write_reg(par, 0xA0, remap | 0x00 | BIT(4)); |
| 85 | break; | 85 | break; |
| 86 | case 270: | 86 | case 270: |
| 87 | write_reg(par, 0xA0, remap | 0x03 | 1 << 4); | 87 | write_reg(par, 0xA0, remap | 0x03 | BIT(4)); |
| 88 | break; | 88 | break; |
| 89 | case 180: | 89 | case 180: |
| 90 | write_reg(par, 0xA0, remap | 0x02); | 90 | write_reg(par, 0xA0, remap | 0x02); |
| @@ -90,15 +90,10 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) · 89 unmodified lines | |||
| 90 | return 0; | 90 | return 0; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | #define RGB565toRGB323(c) ((((c) & 0xE000) >> 8) |\ | 93 | static inline int rgb565_to_rgb332(u16 c) |
| 94 | (((c) & 000600) >> 6) |\ | 94 | { |
| 95 | (((c) & 0x001C) >> 2)) | 95 | return ((c & 0xE000) >> 8) | ((c & 000700) >> 6) | ((c & 0x0018) >> 3); |
| 96 | #define RGB565toRGB332(c) ((((c) & 0xE000) >> 8) |\ | 96 | } |
| 97 | (((c) & 000700) >> 6) |\ | ||
| 98 | (((c) & 0x0018) >> 3)) | ||
| 99 | #define RGB565toRGB233(c) ((((c) & 0xC000) >> 8) |\ | ||
| 100 | (((c) & 000700) >> 5) |\ | ||
| 101 | (((c) & 0x001C) >> 2)) | ||
| 102 | 97 | ||
| 103 | static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) | 98 | static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) |
| 104 | { | 99 | { |
| @@ -122,7 +117,7 @@ static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) · 17 unmodified lines | |||
| 122 | for (i = start_line; i <= end_line; i++) { | 117 | for (i = start_line; i <= end_line; i++) { |
| 123 | pos[1] = cpu_to_be16(i); | 118 | pos[1] = cpu_to_be16(i); |
| 124 | for (j = 0; j < par->info->var.xres; j++) { | 119 | for (j = 0; j < par->info->var.xres; j++) { |
| 125 | buf8[j] = RGB565toRGB332(*vmem16); | 120 | buf8[j] = rgb565_to_rgb332(*vmem16); |
| 126 | vmem16++; | 121 | vmem16++; |
| 127 | } | 122 | } |
| 128 | ret = par->fbtftops.write(par, | 123 | ret = par->fbtftops.write(par, |
| @@ -14,7 +14,7 @@ int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) · 13 unmodified lines | |||
| 14 | struct spi_message m; | 14 | struct spi_message m; |
| 15 | 15 | ||
| 16 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 16 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 17 | "%s(len=%d): ", __func__, len); | 17 | "%s(len=%zu): ", __func__, len); |
| 18 | 18 | ||
| 19 | if (!par->spi) { | 19 | if (!par->spi) { |
| 20 | dev_err(par->info->device, | 20 | dev_err(par->info->device, |
| @@ -47,7 +47,7 @@ int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len) · 26 unmodified lines | |||
| 47 | u64 val, dc, tmp; | 47 | u64 val, dc, tmp; |
| 48 | 48 | ||
| 49 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 49 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 50 | "%s(len=%d): ", __func__, len); | 50 | "%s(len=%zu): ", __func__, len); |
| 51 | 51 | ||
| 52 | if (!par->extra) { | 52 | if (!par->extra) { |
| 53 | dev_err(par->info->device, "%s: error: par->extra is NULL\n", | 53 | dev_err(par->info->device, "%s: error: par->extra is NULL\n", |
| @@ -109,7 +109,7 @@ int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) · 55 unmodified lines | |||
| 109 | txbuf[0] = par->startbyte | 0x3; | 109 | txbuf[0] = par->startbyte | 0x3; |
| 110 | t.tx_buf = txbuf; | 110 | t.tx_buf = txbuf; |
| 111 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, | 111 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, |
| 112 | txbuf, len, "%s(len=%d) txbuf => ", | 112 | txbuf, len, "%s(len=%zu) txbuf => ", |
| 113 | __func__, len); | 113 | __func__, len); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| @@ -117,7 +117,7 @@ int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) · 1 unmodified line | |||
| 117 | spi_message_add_tail(&t, &m); | 117 | spi_message_add_tail(&t, &m); |
| 118 | ret = spi_sync(par->spi, &m); | 118 | ret = spi_sync(par->spi, &m); |
| 119 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, | 119 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, |
| 120 | "%s(len=%d) buf <= ", __func__, len); | 120 | "%s(len=%zu) buf <= ", __func__, len); |
| 121 | 121 | ||
| 122 | return ret; | 122 | return ret; |
| 123 | } | 123 | } |
| @@ -136,7 +136,7 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) · 12 unmodified lines | |||
| 136 | #endif | 136 | #endif |
| 137 | 137 | ||
| 138 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 138 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 139 | "%s(len=%d): ", __func__, len); | 139 | "%s(len=%zu): ", __func__, len); |
| 140 | 140 | ||
| 141 | while (len--) { | 141 | while (len--) { |
| 142 | data = *(u8 *)buf; | 142 | data = *(u8 *)buf; |
| @@ -186,7 +186,7 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) · 43 unmodified lines | |||
| 186 | #endif | 186 | #endif |
| 187 | 187 | ||
| 188 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 188 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 189 | "%s(len=%d): ", __func__, len); | 189 | "%s(len=%zu): ", __func__, len); |
| 190 | 190 | ||
| 191 | while (len) { | 191 | while (len) { |
| 192 | data = *(u16 *)buf; | 192 | data = *(u16 *)buf; |
| @@ -238,6 +238,7 @@ struct fbtft_par { · 237 unmodified lines | |||
| 238 | 238 | ||
| 239 | /* fbtft-core.c */ | 239 | /* fbtft-core.c */ |
| 240 | int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc); | 240 | int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc); |
| 241 | __printf(5, 6) | ||
| 241 | void fbtft_dbg_hex(const struct device *dev, int groupsize, | 242 | void fbtft_dbg_hex(const struct device *dev, int groupsize, |
| 242 | void *buf, size_t len, const char *fmt, ...); | 243 | void *buf, size_t len, const char *fmt, ...); |
| 243 | struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, | 244 | struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, |
| @@ -965,7 +965,7 @@ static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len) · 964 unmodified lines | |||
| 965 | #endif | 965 | #endif |
| 966 | 966 | ||
| 967 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, | 967 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, |
| 968 | "%s(len=%d): ", __func__, len); | 968 | "%s(len=%zu): ", __func__, len); |
| 969 | 969 | ||
| 970 | while (len) { | 970 | while (len) { |
| 971 | data = *(u16 *)buf; | 971 | data = *(u16 *)buf; |
| @@ -671,7 +671,8 @@ static int flexfb_probe_common(struct spi_device *sdev, · 670 unmodified lines | |||
| 671 | break; | 671 | break; |
| 672 | case 9: | 672 | case 9: |
| 673 | if (regwidth == 16) { | 673 | if (regwidth == 16) { |
| 674 | dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", regwidth, buswidth); | 674 | dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", |
| 675 | regwidth, buswidth); | ||
| 675 | return -EINVAL; | 676 | return -EINVAL; |
| 676 | } | 677 | } |
| 677 | par->fbtftops.write_register = fbtft_write_reg8_bus9; | 678 | par->fbtftops.write_register = fbtft_write_reg8_bus9; |
| @@ -718,7 +719,9 @@ static int flexfb_probe_common(struct spi_device *sdev, · 40 unmodified lines | |||
| 718 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; | 719 | par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; |
| 719 | break; | 720 | break; |
| 720 | default: | 721 | default: |
| 721 | dev_err(dev, "argument 'buswidth': %d is not supported with parallel.\n", buswidth); | 722 | dev_err(dev, |
| 723 | "argument 'buswidth': %d is not supported with parallel.\n", | ||
| 724 | buswidth); | ||
| 722 | return -EINVAL; | 725 | return -EINVAL; |
| 723 | } | 726 | } |
| 724 | } | 727 | } |
| @@ -0,0 +1,31 @@ | |||
| 1 | What: /dev/fieldbus_devX | ||
| 2 | Date: December 2018 | ||
| 3 | KernelVersion: 5.1 (staging) | ||
| 4 | Contact: Sven Van Asbroeck <TheSven73@gmail.com> | ||
| 5 | Description: | ||
| 6 | The cdev interface to drivers for Fieldbus Device Memory | ||
| 7 | (aka. Process Memory). | ||
| 8 | |||
| 9 | The following file operations are supported: | ||
| 10 | |||
| 11 | open(2) | ||
| 12 | Create an I/O context associated with the file descriptor. | ||
| 13 | |||
| 14 | read(2) | ||
| 15 | Read from Process Memory's "read area". | ||
| 16 | Clears POLLERR | POLLPRI from the file descriptor. | ||
| 17 | |||
| 18 | write(2) | ||
| 19 | Write to Process Memory's "write area". | ||
| 20 | |||
| 21 | poll(2), select(2), epoll_wait(2) etc. | ||
| 22 | When a "Process Memory Read Area Changed" event occurs, | ||
| 23 | POLLERR | POLLPRI will be set on the file descriptor. | ||
| 24 | Note that POLLIN | POLLOUT events are always set, because the | ||
| 25 | process memory area is always readable and writable. | ||
| 26 | |||
| 27 | close(2) | ||
| 28 | Free up the I/O context that was associated | ||
3 more lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 400 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 1459 lines aren’t shown here.
This diff is large: its 352 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 10 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 11 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 420 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 168 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 472 lines aren’t shown here.
This diff is large: its 438 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
This diff is large: its 421 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 700 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 508 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 139 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 5 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 356 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 166 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 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 677 lines aren’t shown here.
This diff is large: its 429 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 305 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 489 lines aren’t shown here.
This diff is large: its 1856 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 481 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 254 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 340 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 9 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 24 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 20 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 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 75 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 9 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 86 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 46 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 54 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 50 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 34 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 2816 lines aren’t shown here.
This diff is large: its 176 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 5234 lines aren’t shown here.
This diff is large: its 434 lines aren’t shown here.
This diff is large: its 5211 lines aren’t shown here.
This diff is large: its 488 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 1838 lines aren’t shown here.
This diff is large: its 792 lines aren’t shown here.
This diff is large: its 518 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 316 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 1997 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 625 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 1330 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 553 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 333 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 313 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 404 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 5971 lines aren’t shown here.
This diff is large: its 386 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 964 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 544 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 4466 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 416 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 13397 lines aren’t shown here.
This diff is large: its 12093 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 505 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 393 lines aren’t shown here.
This diff is large: its 1001 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 1122 lines aren’t shown here.
This diff is large: its 718 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 434 lines aren’t shown here.
This diff is large: its 496 lines aren’t shown here.
This diff is large: its 1924 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 1374 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 2497 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 955 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 1976 lines aren’t shown here.
This diff is large: its 936 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 931 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 617 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 291 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 448 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 333 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 2889 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 1522 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 1849 lines aren’t shown here.
This diff is large: its 488 lines aren’t shown here.
This diff is large: its 308 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 320 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 634 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 603 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 407 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 1197 lines aren’t shown here.
This diff is large: its 259 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 1957 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 4731 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 1805 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 1400 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 866 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 997 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 310 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 459 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 965 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 2431 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 2224 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 1643 lines aren’t shown here.
This diff is large: its 471 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 1005 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 3363 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 181 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 265 lines aren’t shown here.
This diff is large: its 8 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 9 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 294 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 30 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 101 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 511 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 89 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 22 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.