Pull Char/Misc/IIO driver updates from Greg KH: "Here is the "big" set of char/misc/iio and other smaller driver subsystem updates for 6.14-rc1. Loads of different things in here this development cycle, highlights are: - ntsync "driver" to handle Windows locking types enabling Wine to work much better on many workloads (i.e. games). The driver framework was in 6.13, but now it's enabled and fully working properly. Should make many SteamOS users happy. Even comes with tests! - Large IIO driver updates and bugfixes - FPGA driver updates - Coresight driver updates - MHI driver updates - PPS driver updatesa - const bin_attribute reworking for many drivers - binder driver updates - smaller driver updates and fixes All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (311 commits) ntsync: Fix reference leaks in the remaining create ioctls. spmi: hisi-spmi-controller: Drop duplicated OF node assignment in spmi_controller_probe() spmi: Set fwnode for spmi devices ntsync: fix a file reference leak in drivers/misc/ntsync.c scripts/tags.sh: Don't tag usages of DECLARE_BITMAP dt-bindings: interconnect: qcom,msm8998-bwmon: Add SM8750 CPU BWMONs dt-bindings: interconnect: OSM L3: Document sm8650 OSM L3 compatible dt-bindings: interconnect: qcom-bwmon: Document QCS615 bwmon compatibles interconnect: sm8750: Add missing const to static qcom_icc_desc memstick: core: fix kernel-doc notation intel_th: core: fix kernel-doc warnings binder: log transaction code on failure iio: dac: ad3552r-hs: clear reset status flag iio: dac: ad3552r-common: fix ad3541/2r ranges iio: chemical: bme680: Fix uninitialized variable in __bme680_read_raw() misc: fastrpc: Fix copy buffer page size misc: fastrpc: Fix registered buffer page address misc: fastrpc: Deregister device nodes properly in error scenarios nvmem: core: improve range check for nvmem_cell_write() nvmem: qcom-spmi-sdam: Set size in struct nvmem_config ...
Unified · Split
| @@ -0,0 +1,15 @@ | |||
| 1 | What: /sys/bus/coresight/devices/dummy_source<N>/enable_source | ||
| 2 | Date: Dec 2024 | ||
| 3 | KernelVersion: 6.14 | ||
| 4 | Contact: Mao Jinlong <quic_jinlmao@quicinc.com> | ||
| 5 | Description: (RW) Enable/disable tracing of dummy source. A sink should be activated | ||
| 6 | before enabling the source. The path of coresight components linking | ||
| 7 | the source to the sink is configured and managed automatically by the | ||
| 8 | coresight framework. | ||
| 9 | |||
| 10 | What: /sys/bus/coresight/devices/dummy_source<N>/traceid | ||
| 11 | Date: Dec 2024 | ||
| 12 | KernelVersion: 6.14 | ||
| 13 | Contact: Mao Jinlong <quic_jinlmao@quicinc.com> | ||
| 14 | Description: (R) Show the trace ID that will appear in the trace stream | ||
| 15 | coming from this trace entity. | ||
| @@ -168,18 +168,6 @@ Description: · 167 unmodified lines | |||
| 168 | is required is a consistent labeling. Units after application | 168 | is required is a consistent labeling. Units after application |
| 169 | of scale and offset are millivolts. | 169 | of scale and offset are millivolts. |
| 170 | 170 | ||
| 171 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw | ||
| 172 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw | ||
| 173 | KernelVersion: 3.17 | ||
| 174 | Contact: linux-iio@vger.kernel.org | ||
| 175 | Description: | ||
| 176 | Raw (unscaled no bias removal etc.) current measurement from | ||
| 177 | channel Y. In special cases where the channel does not | ||
| 178 | correspond to externally available input one of the named | ||
| 179 | versions may be used. The number must always be specified and | ||
| 180 | unique to allow association with event codes. Units after | ||
| 181 | application of scale and offset are milliamps. | ||
| 182 | |||
| 183 | What: /sys/bus/iio/devices/iio:deviceX/in_powerY_raw | 171 | What: /sys/bus/iio/devices/iio:deviceX/in_powerY_raw |
| 184 | KernelVersion: 4.5 | 172 | KernelVersion: 4.5 |
| 185 | Contact: linux-iio@vger.kernel.org | 173 | Contact: linux-iio@vger.kernel.org |
| @@ -227,7 +215,7 @@ Description: · 41 unmodified lines | |||
| 227 | same scaling as _raw. | 215 | same scaling as _raw. |
| 228 | 216 | ||
| 229 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw | 217 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw |
| 230 | What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw | 218 | What: /sys/bus/iio/devices/iio:deviceX/in_tempY_raw |
| 231 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw | 219 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw |
| 232 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw | 220 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw |
| 233 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_ambient_raw | 221 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_ambient_raw |
| @@ -416,11 +404,11 @@ Contact: linux-iio@vger.kernel.org · 182 unmodified lines | |||
| 416 | Description: | 404 | Description: |
| 417 | Scaled humidity measurement in milli percent. | 405 | Scaled humidity measurement in milli percent. |
| 418 | 406 | ||
| 419 | What: /sys/bus/iio/devices/iio:deviceX/in_X_mean_raw | 407 | What: /sys/bus/iio/devices/iio:deviceX/in_Y_mean_raw |
| 420 | KernelVersion: 3.5 | 408 | KernelVersion: 3.5 |
| 421 | Contact: linux-iio@vger.kernel.org | 409 | Contact: linux-iio@vger.kernel.org |
| 422 | Description: | 410 | Description: |
| 423 | Averaged raw measurement from channel X. The number of values | 411 | Averaged raw measurement from channel Y. The number of values |
| 424 | used for averaging is device specific. The converting rules for | 412 | used for averaging is device specific. The converting rules for |
| 425 | normal raw values also applies to the averaged raw values. | 413 | normal raw values also applies to the averaged raw values. |
| 426 | 414 | ||
| @@ -448,7 +436,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset · 21 unmodified lines | |||
| 448 | What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset | 436 | What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset |
| 449 | What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset | 437 | What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset |
| 450 | What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset | 438 | What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset |
| 451 | What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceX_offset | 439 | What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_offset |
| 452 | KernelVersion: 2.6.35 | 440 | KernelVersion: 2.6.35 |
| 453 | Contact: linux-iio@vger.kernel.org | 441 | Contact: linux-iio@vger.kernel.org |
| 454 | Description: | 442 | Description: |
| @@ -508,6 +496,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale · 53 unmodified lines | |||
| 508 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale | 496 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale |
| 509 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale | 497 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale |
| 510 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale | 498 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale |
| 499 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale | ||
| 500 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale | ||
| 501 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale | ||
| 511 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale | 502 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale |
| 512 | KernelVersion: 2.6.35 | 503 | KernelVersion: 2.6.35 |
| 513 | Contact: linux-iio@vger.kernel.org | 504 | Contact: linux-iio@vger.kernel.org |
| @@ -660,10 +651,10 @@ What: /sys/.../iio:deviceX/in_magn_scale_available · 146 unmodified lines | |||
| 660 | What: /sys/.../iio:deviceX/in_illuminance_scale_available | 651 | What: /sys/.../iio:deviceX/in_illuminance_scale_available |
| 661 | What: /sys/.../iio:deviceX/in_intensity_scale_available | 652 | What: /sys/.../iio:deviceX/in_intensity_scale_available |
| 662 | What: /sys/.../iio:deviceX/in_proximity_scale_available | 653 | What: /sys/.../iio:deviceX/in_proximity_scale_available |
| 663 | What: /sys/.../iio:deviceX/in_voltageX_scale_available | 654 | What: /sys/.../iio:deviceX/in_voltageY_scale_available |
| 664 | What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available | 655 | What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available |
| 665 | What: /sys/.../iio:deviceX/out_voltageX_scale_available | 656 | What: /sys/.../iio:deviceX/out_voltageY_scale_available |
| 666 | What: /sys/.../iio:deviceX/out_altvoltageX_scale_available | 657 | What: /sys/.../iio:deviceX/out_altvoltageY_scale_available |
| 667 | What: /sys/.../iio:deviceX/in_capacitance_scale_available | 658 | What: /sys/.../iio:deviceX/in_capacitance_scale_available |
| 668 | What: /sys/.../iio:deviceX/in_pressure_scale_available | 659 | What: /sys/.../iio:deviceX/in_pressure_scale_available |
| 669 | What: /sys/.../iio:deviceX/in_pressureY_scale_available | 660 | What: /sys/.../iio:deviceX/in_pressureY_scale_available |
| @@ -681,6 +672,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain · 11 unmodified lines | |||
| 681 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain | 672 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain |
| 682 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain | 673 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain |
| 683 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain | 674 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain |
| 675 | What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_hardwaregain | ||
| 684 | KernelVersion: 2.6.35 | 676 | KernelVersion: 2.6.35 |
| 685 | Contact: linux-iio@vger.kernel.org | 677 | Contact: linux-iio@vger.kernel.org |
| 686 | Description: | 678 | Description: |
| @@ -1562,7 +1554,7 @@ Description: · 875 unmodified lines | |||
| 1562 | This attribute is used to read the amount of quadrature error | 1554 | This attribute is used to read the amount of quadrature error |
| 1563 | present in the device at a given time. | 1555 | present in the device at a given time. |
| 1564 | 1556 | ||
| 1565 | What: /sys/.../iio:deviceX/in_accelX_power_mode | 1557 | What: /sys/.../iio:deviceX/in_accelY_power_mode |
| 1566 | KernelVersion: 3.11 | 1558 | KernelVersion: 3.11 |
| 1567 | Contact: linux-iio@vger.kernel.org | 1559 | Contact: linux-iio@vger.kernel.org |
| 1568 | Description: | 1560 | Description: |
| @@ -1633,6 +1625,10 @@ What: /sys/.../iio:deviceX/in_intensityY_uv_raw · 64 unmodified lines | |||
| 1633 | What: /sys/.../iio:deviceX/in_intensityY_uva_raw | 1625 | What: /sys/.../iio:deviceX/in_intensityY_uva_raw |
| 1634 | What: /sys/.../iio:deviceX/in_intensityY_uvb_raw | 1626 | What: /sys/.../iio:deviceX/in_intensityY_uvb_raw |
| 1635 | What: /sys/.../iio:deviceX/in_intensityY_duv_raw | 1627 | What: /sys/.../iio:deviceX/in_intensityY_duv_raw |
| 1628 | What: /sys/.../iio:deviceX/in_intensity_red_raw | ||
| 1629 | What: /sys/.../iio:deviceX/in_intensity_green_raw | ||
| 1630 | What: /sys/.../iio:deviceX/in_intensity_blue_raw | ||
| 1631 | What: /sys/.../iio:deviceX/in_intensity_clear_raw | ||
| 1636 | KernelVersion: 3.4 | 1632 | KernelVersion: 3.4 |
| 1637 | Contact: linux-iio@vger.kernel.org | 1633 | Contact: linux-iio@vger.kernel.org |
| 1638 | Description: | 1634 | Description: |
| @@ -1691,16 +1687,19 @@ Description: · 52 unmodified lines | |||
| 1691 | Raw value of rotation from true/magnetic north measured with | 1687 | Raw value of rotation from true/magnetic north measured with |
| 1692 | or without compensation from tilt sensors. | 1688 | or without compensation from tilt sensors. |
| 1693 | 1689 | ||
| 1694 | What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw | 1690 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw |
| 1695 | What: /sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw | 1691 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw |
| 1696 | What: /sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw | 1692 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_raw |
| 1697 | KernelVersion: 3.18 | 1693 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_raw |
| 1694 | KernelVersion: 3.17 | ||
| 1698 | Contact: linux-iio@vger.kernel.org | 1695 | Contact: linux-iio@vger.kernel.org |
| 1699 | Description: | 1696 | Description: |
| 1700 | Raw current measurement from channel X. Units are in milliamps | 1697 | Raw current measurement from channel Y. Units are in milliamps |
| 1701 | after application of scale and offset. If no offset or scale is | 1698 | after application of scale and offset. If no offset or scale is |
| 1702 | present, output should be considered as processed with the | 1699 | present, output should be considered as processed with the |
| 1703 | unit in milliamps. | 1700 | unit in milliamps. In special cases where the channel does not |
| 1701 | correspond to externally available input one of the named | ||
| 1702 | versions may be used. | ||
| 1704 | 1703 | ||
| 1705 | Channels with 'i' and 'q' modifiers always exist in pairs and both | 1704 | Channels with 'i' and 'q' modifiers always exist in pairs and both |
| 1706 | channels refer to the same signal. The 'i' channel contains the in-phase | 1705 | channels refer to the same signal. The 'i' channel contains the in-phase |
| @@ -1864,9 +1863,9 @@ Description: · 157 unmodified lines | |||
| 1864 | hardware fifo watermark level. | 1863 | hardware fifo watermark level. |
| 1865 | 1864 | ||
| 1866 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibemissivity | 1865 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibemissivity |
| 1867 | What: /sys/bus/iio/devices/iio:deviceX/in_tempX_calibemissivity | 1866 | What: /sys/bus/iio/devices/iio:deviceX/in_tempY_calibemissivity |
| 1868 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibemissivity | 1867 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibemissivity |
| 1869 | What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibemissivity | 1868 | What: /sys/bus/iio/devices/iio:deviceX/in_tempY_object_calibemissivity |
| 1870 | KernelVersion: 4.1 | 1869 | KernelVersion: 4.1 |
| 1871 | Contact: linux-iio@vger.kernel.org | 1870 | Contact: linux-iio@vger.kernel.org |
| 1872 | Description: | 1871 | Description: |
| @@ -1887,17 +1886,17 @@ Description: · 14 unmodified lines | |||
| 1887 | is considered as one sample for <type>[_name]_sampling_frequency. | 1886 | is considered as one sample for <type>[_name]_sampling_frequency. |
| 1888 | 1887 | ||
| 1889 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw | 1888 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw |
| 1890 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw | 1889 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_raw |
| 1891 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw | 1890 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw |
| 1892 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw | 1891 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_co2_raw |
| 1893 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw | 1892 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw |
| 1894 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw | 1893 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_ethanol_raw |
| 1895 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw | 1894 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw |
| 1896 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw | 1895 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_h2_raw |
| 1897 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_o2_raw | 1896 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_o2_raw |
| 1898 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_o2_raw | 1897 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_o2_raw |
| 1899 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw | 1898 | What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw |
| 1900 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw | 1899 | What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_voc_raw |
| 1901 | KernelVersion: 4.3 | 1900 | KernelVersion: 4.3 |
| 1902 | Contact: linux-iio@vger.kernel.org | 1901 | Contact: linux-iio@vger.kernel.org |
| 1903 | Description: | 1902 | Description: |
| @@ -1905,9 +1904,9 @@ Description: · 1 unmodified line | |||
| 1905 | after application of scale and offset are percents. | 1904 | after application of scale and offset are percents. |
| 1906 | 1905 | ||
| 1907 | What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw | 1906 | What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw |
| 1908 | What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw | 1907 | What: /sys/bus/iio/devices/iio:deviceX/in_resistanceY_raw |
| 1909 | What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw | 1908 | What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw |
| 1910 | What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw | 1909 | What: /sys/bus/iio/devices/iio:deviceX/out_resistanceY_raw |
| 1911 | KernelVersion: 4.3 | 1910 | KernelVersion: 4.3 |
| 1912 | Contact: linux-iio@vger.kernel.org | 1911 | Contact: linux-iio@vger.kernel.org |
| 1913 | Description: | 1912 | Description: |
| @@ -2096,7 +2095,7 @@ Description: · 182 unmodified lines | |||
| 2096 | One of the following thermocouple types: B, E, J, K, N, R, S, T. | 2095 | One of the following thermocouple types: B, E, J, K, N, R, S, T. |
| 2097 | 2096 | ||
| 2098 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibambient | 2097 | What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibambient |
| 2099 | What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibambient | 2098 | What: /sys/bus/iio/devices/iio:deviceX/in_tempY_object_calibambient |
| 2100 | KernelVersion: 5.10 | 2099 | KernelVersion: 5.10 |
| 2101 | Contact: linux-iio@vger.kernel.org | 2100 | Contact: linux-iio@vger.kernel.org |
| 2102 | Description: | 2101 | Description: |
| @@ -2172,9 +2171,9 @@ Description: · 69 unmodified lines | |||
| 2172 | 2171 | ||
| 2173 | - a range specified as "[min step max]" | 2172 | - a range specified as "[min step max]" |
| 2174 | 2173 | ||
| 2175 | What: /sys/bus/iio/devices/iio:deviceX/in_voltageX_sampling_frequency | 2174 | What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sampling_frequency |
| 2176 | What: /sys/bus/iio/devices/iio:deviceX/in_powerY_sampling_frequency | 2175 | What: /sys/bus/iio/devices/iio:deviceX/in_powerY_sampling_frequency |
| 2177 | What: /sys/bus/iio/devices/iio:deviceX/in_currentZ_sampling_frequency | 2176 | What: /sys/bus/iio/devices/iio:deviceX/in_currentY_sampling_frequency |
| 2178 | KernelVersion: 5.20 | 2177 | KernelVersion: 5.20 |
| 2179 | Contact: linux-iio@vger.kernel.org | 2178 | Contact: linux-iio@vger.kernel.org |
| 2180 | Description: | 2179 | Description: |
| @@ -0,0 +1,23 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration | ||
| 2 | KernelVersion: 5.5 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | This attribute, if available, initiates the system calibration procedure. This is done on a | ||
| 6 | single channel at a time. Write '1' to start the calibration. | ||
| 7 | |||
| 8 | What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode_available | ||
| 9 | KernelVersion: 5.5 | ||
| 10 | Contact: linux-iio@vger.kernel.org | ||
| 11 | Description: | ||
| 12 | This attribute, if available, returns a list with the possible calibration modes. | ||
| 13 | There are two available options: | ||
| 14 | "zero_scale" - calibrate to zero scale | ||
| 15 | "full_scale" - calibrate to full scale | ||
| 16 | |||
| 17 | What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode | ||
| 18 | KernelVersion: 5.5 | ||
| 19 | Contact: linux-iio@vger.kernel.org | ||
| 20 | Description: | ||
| 21 | This attribute, if available, sets up the calibration mode used in the system calibration | ||
| 22 | procedure. Reading returns the current calibration mode. | ||
| 23 | Writing sets the system calibration mode. | ||
| @@ -19,33 +19,9 @@ Description: · 18 unmodified lines | |||
| 19 | the bridge can be disconnected (when it is not being used | 19 | the bridge can be disconnected (when it is not being used |
| 20 | using the bridge_switch_en attribute. | 20 | using the bridge_switch_en attribute. |
| 21 | 21 | ||
| 22 | What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration | ||
| 23 | KernelVersion: | ||
| 24 | Contact: linux-iio@vger.kernel.org | ||
| 25 | Description: | ||
| 26 | Initiates the system calibration procedure. This is done on a | ||
| 27 | single channel at a time. Write '1' to start the calibration. | ||
| 28 | |||
| 29 | What: /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw | 22 | What: /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw |
| 30 | KernelVersion: | 23 | KernelVersion: |
| 31 | Contact: linux-iio@vger.kernel.org | 24 | Contact: linux-iio@vger.kernel.org |
| 32 | Description: | 25 | Description: |
| 33 | Measure voltage from AIN2 pin connected to AIN(+) | 26 | Measure voltage from AIN2 pin connected to AIN(+) |
| 34 | and AIN(-) shorted. | 27 | and AIN(-) shorted. |
| 35 | |||
| 36 | What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode_available | ||
| 37 | KernelVersion: | ||
| 38 | Contact: linux-iio@vger.kernel.org | ||
| 39 | Description: | ||
| 40 | Reading returns a list with the possible calibration modes. | ||
| 41 | There are two available options: | ||
| 42 | "zero_scale" - calibrate to zero scale | ||
| 43 | "full_scale" - calibrate to full scale | ||
| 44 | |||
| 45 | What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode | ||
| 46 | KernelVersion: | ||
| 47 | Contact: linux-iio@vger.kernel.org | ||
| 48 | Description: | ||
| 49 | Sets up the calibration mode used in the system calibration | ||
| 50 | procedure. Reading returns the current calibration mode. | ||
| 51 | Writing sets the system calibration mode. | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | What: /sys/class/pps-gen/ | ||
| 2 | Date: February 2025 | ||
| 3 | KernelVersion: 6.13 | ||
| 4 | Contact: Rodolfo Giometti <giometti@enneenne.com> | ||
| 5 | Description: | ||
| 6 | The /sys/class/pps-gen/ directory contains files and | ||
| 7 | directories that provide a unified interface to the PPS | ||
| 8 | generators. | ||
| 9 | |||
| 10 | What: /sys/class/pps-gen/pps-genX/ | ||
| 11 | Date: February 2025 | ||
| 12 | KernelVersion: 6.13 | ||
| 13 | Contact: Rodolfo Giometti <giometti@enneenne.com> | ||
| 14 | Description: | ||
| 15 | The /sys/class/pps-gen/pps-genX/ directory is related to X-th | ||
| 16 | PPS generator in the system. Each directory contain files to | ||
| 17 | manage and control its PPS generator. | ||
| 18 | |||
| 19 | What: /sys/class/pps-gen/pps-genX/enable | ||
| 20 | Date: February 2025 | ||
| 21 | KernelVersion: 6.13 | ||
| 22 | Contact: Rodolfo Giometti <giometti@enneenne.com> | ||
| 23 | Description: | ||
| 24 | This write-only file enables or disables generation of the | ||
| 25 | PPS signal. | ||
| 26 | |||
| 27 | What: /sys/class/pps-gen/pps-genX/system | ||
| 28 | Date: February 2025 | ||
| 29 | KernelVersion: 6.13 | ||
| 30 | Contact: Rodolfo Giometti <giometti@enneenne.com> | ||
| 31 | Description: | ||
| 32 | This read-only file returns "1" if the generator takes the | ||
| 33 | timing from the system clock, while it returns "0" if not | ||
| 34 | (i.e. from a peripheral device clock). | ||
| 35 | |||
| 36 | What: /sys/class/pps-gen/pps-genX/time | ||
| 37 | Date: February 2025 | ||
| 38 | KernelVersion: 6.13 | ||
| 39 | Contact: Rodolfo Giometti <giometti@enneenne.com> | ||
| 40 | Description: | ||
| 41 | This read-only file contains the current time stored into the | ||
| 42 | generator clock as two integers representing the current time | ||
| 43 | seconds and nanoseconds. | ||
| @@ -38,6 +38,12 @@ properties: · 37 unmodified lines | |||
| 38 | enum: | 38 | enum: |
| 39 | - arm,coresight-dummy-source | 39 | - arm,coresight-dummy-source |
| 40 | 40 | ||
| 41 | arm,static-trace-id: | ||
| 42 | description: If dummy source needs static id support, use this to set trace id. | ||
| 43 | $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 44 | minimum: 1 | ||
| 45 | maximum: 111 | ||
| 46 | |||
| 41 | out-ports: | 47 | out-ports: |
| 42 | $ref: /schemas/graph.yaml#/properties/ports | 48 | $ref: /schemas/graph.yaml#/properties/ports |
| 43 | 49 | ||
| @@ -45,7 +45,22 @@ properties: · 44 unmodified lines | |||
| 45 | patternProperties: | 45 | patternProperties: |
| 46 | '^port@[01]$': | 46 | '^port@[01]$': |
| 47 | description: Output connections to CoreSight Trace bus | 47 | description: Output connections to CoreSight Trace bus |
| 48 | $ref: /schemas/graph.yaml#/properties/port | 48 | $ref: /schemas/graph.yaml#/$defs/port-base |
| 49 | unevaluatedProperties: false | ||
| 50 | |||
| 51 | properties: | ||
| 52 | endpoint: | ||
| 53 | $ref: /schemas/graph.yaml#/$defs/endpoint-base | ||
| 54 | unevaluatedProperties: false | ||
| 55 | |||
| 56 | properties: | ||
| 57 | filter-source: | ||
| 58 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 59 | description: | ||
| 60 | phandle to the coresight trace source device matching the | ||
| 61 | hard coded filtering for this port | ||
| 62 | |||
| 63 | remote-endpoint: true | ||
| 49 | 64 | ||
| 50 | required: | 65 | required: |
| 51 | - compatible | 66 | - compatible |
| @@ -72,6 +87,7 @@ examples: · 20 unmodified lines | |||
| 72 | reg = <0>; | 87 | reg = <0>; |
| 73 | replicator_out_port0: endpoint { | 88 | replicator_out_port0: endpoint { |
| 74 | remote-endpoint = <&etb_in_port>; | 89 | remote-endpoint = <&etb_in_port>; |
| 90 | filter-source = <&tpdm_video>; | ||
| 75 | }; | 91 | }; |
| 76 | }; | 92 | }; |
| 77 | 93 | ||
| @@ -79,6 +95,7 @@ examples: · 1 unmodified line | |||
| 79 | reg = <1>; | 95 | reg = <1>; |
| 80 | replicator_out_port1: endpoint { | 96 | replicator_out_port1: endpoint { |
| 81 | remote-endpoint = <&tpiu_in_port>; | 97 | remote-endpoint = <&tpiu_in_port>; |
| 98 | filter-source = <&tpdm_mdss>; | ||
| 82 | }; | 99 | }; |
| 83 | }; | 100 | }; |
| 84 | }; | 101 | }; |
| @@ -37,10 +37,17 @@ properties: · 36 unmodified lines | |||
| 37 | interrupts: | 37 | interrupts: |
| 38 | maxItems: 1 | 38 | maxItems: 1 |
| 39 | 39 | ||
| 40 | interrupt-names: | ||
| 41 | items: | ||
| 42 | - enum: [INT1, INT2] | ||
| 43 | |||
| 44 | dependencies: | ||
| 45 | interrupts: [ interrupt-names ] | ||
| 46 | interrupt-names: [ interrupts ] | ||
| 47 | |||
| 40 | required: | 48 | required: |
| 41 | - compatible | 49 | - compatible |
| 42 | - reg | 50 | - reg |
| 43 | - interrupts | ||
| 44 | 51 | ||
| 45 | allOf: | 52 | allOf: |
| 46 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | 53 | - $ref: /schemas/spi/spi-peripheral-props.yaml# |
| @@ -61,6 +68,7 @@ examples: · 14 unmodified lines | |||
| 61 | reg = <0x2a>; | 68 | reg = <0x2a>; |
| 62 | interrupt-parent = <&gpio0>; | 69 | interrupt-parent = <&gpio0>; |
| 63 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; | 70 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; |
| 71 | interrupt-names = "INT1"; | ||
| 64 | }; | 72 | }; |
| 65 | }; | 73 | }; |
| 66 | - | | 74 | - | |
| @@ -79,5 +87,6 @@ examples: · 12 unmodified lines | |||
| 79 | spi-cpha; | 87 | spi-cpha; |
| 80 | interrupt-parent = <&gpio0>; | 88 | interrupt-parent = <&gpio0>; |
| 81 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; | 89 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; |
| 90 | interrupt-names = "INT2"; | ||
| 82 | }; | 91 | }; |
| 83 | }; | 92 | }; |
| @@ -4,23 +4,26 @@ · 3 unmodified lines | |||
| 4 | $id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml# | 4 | $id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml# |
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | ||
| 7 | title: ROHM/Kionix KX022A, KX132-1211 and KX132ACR-LBZ Accelerometers | 7 | title: ROHM/Kionix KX022A, KX132/134-1211 and KX132/134ACR-LBZ Accelerometers |
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Matti Vaittinen <mazziesaccount@gmail.com> | 10 | - Matti Vaittinen <mazziesaccount@gmail.com> |
| 11 | 11 | ||
| 12 | description: | | 12 | description: | |
| 13 | KX022A, KX132ACR-LBZ and KX132-1211 are 3-axis accelerometers supporting | 13 | KX022A, KX132ACR-LBZ and KX132-1211 are 3-axis accelerometers supporting |
| 14 | +/- 2G, 4G, 8G and 16G ranges, variable output data-rates and a | 14 | +/- 2G, 4G, 8G and 16G ranges. The KX134ACR-LBZ and KX134-1211 support |
| 15 | hardware-fifo buffering. These accelerometers can be accessed either | 15 | +/- 8G, 16G, 32G and 64G. All the sensors also have variable output |
| 16 | via I2C or SPI. | 16 | data-rates and a hardware-fifo buffering. These accelerometers can be |
| 17 | accessed either via I2C or SPI. | ||
| 17 | 18 | ||
| 18 | properties: | 19 | properties: |
| 19 | compatible: | 20 | compatible: |
| 20 | enum: | 21 | enum: |
| 21 | - kionix,kx022a | 22 | - kionix,kx022a |
| 22 | - kionix,kx132-1211 | 23 | - kionix,kx132-1211 |
| 24 | - kionix,kx134-1211 | ||
| 23 | - rohm,kx132acr-lbz | 25 | - rohm,kx132acr-lbz |
| 26 | - rohm,kx134acr-lbz | ||
| 24 | 27 | ||
| 25 | reg: | 28 | reg: |
| 26 | maxItems: 1 | 29 | maxItems: 1 |
| @@ -14,12 +14,20 @@ description: | · 13 unmodified lines | |||
| 14 | SPI and I2C interface. | 14 | SPI and I2C interface. |
| 15 | https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf | 15 | https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf |
| 16 | https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf | 16 | https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf |
| 17 | https://www.nxp.com/docs/en/data-sheet/FXLS8967AF.pdf | ||
| 18 | https://www.nxp.com/docs/en/data-sheet/FXLS8974CF.pdf | ||
| 17 | 19 | ||
| 18 | properties: | 20 | properties: |
| 19 | compatible: | 21 | compatible: |
| 20 | enum: | 22 | oneOf: |
| 21 | - nxp,fxls8962af | 23 | - enum: |
| 22 | - nxp,fxls8964af | 24 | - nxp,fxls8962af |
| 25 | - nxp,fxls8964af | ||
| 26 | - items: | ||
| 27 | - enum: | ||
| 28 | - nxp,fxls8967af | ||
| 29 | - nxp,fxls8974cf | ||
| 30 | - const: nxp,fxls8962af | ||
| 23 | 31 | ||
| 24 | reg: | 32 | reg: |
| 25 | maxItems: 1 | 33 | maxItems: 1 |
| @@ -38,6 +46,11 @@ properties: · 12 unmodified lines | |||
| 38 | drive-open-drain: | 46 | drive-open-drain: |
| 39 | type: boolean | 47 | type: boolean |
| 40 | 48 | ||
| 49 | wakeup-source: | ||
| 50 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 51 | description: | ||
| 52 | Enable wake on accelerometer event | ||
| 53 | |||
| 41 | required: | 54 | required: |
| 42 | - compatible | 55 | - compatible |
| 43 | - reg | 56 | - reg |
| @@ -61,6 +74,7 @@ examples: · 17 unmodified lines | |||
| 61 | interrupt-parent = <&gpio0>; | 74 | interrupt-parent = <&gpio0>; |
| 62 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; | 75 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; |
| 63 | interrupt-names = "INT1"; | 76 | interrupt-names = "INT1"; |
| 77 | wakeup-source; | ||
| 64 | }; | 78 | }; |
| 65 | }; | 79 | }; |
| 66 | - | | 80 | - | |
| @@ -19,49 +19,82 @@ description: | · 18 unmodified lines | |||
| 19 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf | 19 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf |
| 20 | https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf | 20 | https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf |
| 21 | https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf | 21 | https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf |
| 22 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7685.pdf | ||
| 23 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7686.pdf | ||
| 24 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7687.pdf | ||
| 25 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7688.pdf | ||
| 26 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7690.pdf | ||
| 27 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7691.pdf | ||
| 28 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7693.pdf | ||
| 29 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7942.pdf | ||
| 30 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7946.pdf | ||
| 31 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7980.pdf | ||
| 32 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7982.pdf | ||
| 33 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7983.pdf | ||
| 34 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7984.pdf | ||
| 35 | https://www.analog.com/media/en/technical-documentation/data-sheets/ad7988-1_7988-5.pdf | ||
| 22 | 36 | ||
| 23 | $ref: /schemas/spi/spi-peripheral-props.yaml# | 37 | $ref: /schemas/spi/spi-peripheral-props.yaml# |
| 24 | 38 | ||
| 25 | properties: | 39 | properties: |
| 26 | compatible: | 40 | compatible: |
| 27 | oneOf: | 41 | oneOf: |
| 28 | - const: adi,ad4000 | 42 | - enum: |
| 43 | - adi,ad4000 | ||
| 44 | - adi,ad4001 | ||
| 45 | - adi,ad4002 | ||
| 46 | - adi,ad4003 | ||
| 47 | - adi,ad4020 | ||
| 48 | - adi,adaq4001 | ||
| 49 | - adi,adaq4003 | ||
| 50 | - adi,ad7687 | ||
| 51 | - adi,ad7691 | ||
| 52 | - adi,ad7942 | ||
| 53 | - adi,ad7946 | ||
| 54 | - adi,ad7983 | ||
| 29 | - items: | 55 | - items: |
| 30 | - enum: | 56 | - enum: |
| 31 | - adi,ad4004 | 57 | - adi,ad4004 |
| 32 | - adi,ad4008 | 58 | - adi,ad4008 |
| 33 | - const: adi,ad4000 | 59 | - const: adi,ad4000 |
| 34 | |||
| 35 | - const: adi,ad4001 | ||
| 36 | - items: | 60 | - items: |
| 37 | - enum: | 61 | - enum: |
| 38 | - adi,ad4005 | 62 | - adi,ad4005 |
| 39 | - const: adi,ad4001 | 63 | - const: adi,ad4001 |
| 40 | |||
| 41 | - const: adi,ad4002 | ||
| 42 | - items: | 64 | - items: |
| 43 | - enum: | 65 | - enum: |
| 44 | - adi,ad4006 | 66 | - adi,ad4006 |
| 45 | - adi,ad4010 | 67 | - adi,ad4010 |
| 46 | - const: adi,ad4002 | 68 | - const: adi,ad4002 |
| 47 | |||
| 48 | - const: adi,ad4003 | ||
| 49 | - items: | 69 | - items: |
| 50 | - enum: | 70 | - enum: |
| 51 | - adi,ad4007 | 71 | - adi,ad4007 |
| 52 | - adi,ad4011 | 72 | - adi,ad4011 |
| 53 | - const: adi,ad4003 | 73 | - const: adi,ad4003 |
| 54 | |||
| 55 | - const: adi,ad4020 | ||
| 56 | - items: | 74 | - items: |
| 57 | - enum: | 75 | - enum: |
| 58 | - adi,ad4021 | 76 | - adi,ad4021 |
| 59 | - adi,ad4022 | 77 | - adi,ad4022 |
| 60 | - const: adi,ad4020 | 78 | - const: adi,ad4020 |
| 61 | 79 | - items: | |
| 62 | - const: adi,adaq4001 | 80 | - enum: |
| 63 | 81 | - adi,ad7685 | |
| 64 | - const: adi,adaq4003 | 82 | - adi,ad7686 |
| 83 | - adi,ad7980 | ||
| 84 | - adi,ad7988-1 | ||
| 85 | - adi,ad7988-5 | ||
| 86 | - const: adi,ad7983 | ||
| 87 | - items: | ||
| 88 | - enum: | ||
| 89 | - adi,ad7688 | ||
| 90 | - adi,ad7693 | ||
| 91 | - const: adi,ad7687 | ||
| 92 | - items: | ||
| 93 | - enum: | ||
| 94 | - adi,ad7690 | ||
| 95 | - adi,ad7982 | ||
| 96 | - adi,ad7984 | ||
| 97 | - const: adi,ad7691 | ||
| 65 | 98 | ||
| 66 | reg: | 99 | reg: |
| 67 | maxItems: 1 | 100 | maxItems: 1 |
| @@ -133,6 +166,22 @@ required: · 65 unmodified lines | |||
| 133 | - ref-supply | 166 | - ref-supply |
| 134 | 167 | ||
| 135 | allOf: | 168 | allOf: |
| 169 | # Single-channel PulSAR devices have SDI either tied to VIO, GND, or host CS. | ||
| 170 | - if: | ||
| 171 | properties: | ||
| 172 | compatible: | ||
| 173 | contains: | ||
| 174 | enum: | ||
| 175 | - adi,ad7687 | ||
| 176 | - adi,ad7691 | ||
| 177 | - adi,ad7942 | ||
| 178 | - adi,ad7946 | ||
| 179 | - adi,ad7983 | ||
| 180 | then: | ||
| 181 | properties: | ||
| 182 | adi,sdi-pin: | ||
| 183 | enum: [ high, low, cs ] | ||
| 184 | default: cs | ||
| 136 | # The configuration register can only be accessed if SDI is connected to MOSI | 185 | # The configuration register can only be accessed if SDI is connected to MOSI |
| 137 | - if: | 186 | - if: |
| 138 | required: | 187 | required: |
| @@ -134,8 +134,9 @@ patternProperties: · 133 unmodified lines | |||
| 134 | description: | 134 | description: |
| 135 | Describes the common mode channel for single channels. 0xFF is REFGND | 135 | Describes the common mode channel for single channels. 0xFF is REFGND |
| 136 | and OxFE is COM. Macros are available for these values in | 136 | and OxFE is COM. Macros are available for these values in |
| 137 | dt-bindings/iio/adi,ad4695.h. Values 1 to 15 correspond to INx inputs. | 137 | dt-bindings/iio/adc/adi,ad4695.h. Values 1 to 15 correspond to INx |
| 138 | Only odd numbered INx inputs can be used as common mode channels. | 138 | inputs. Only odd numbered INx inputs can be used as common mode |
| 139 | channels. | ||
| 139 | enum: [1, 3, 5, 7, 9, 11, 13, 15, 0xFE, 0xFF] | 140 | enum: [1, 3, 5, 7, 9, 11, 13, 15, 0xFE, 0xFF] |
| 140 | default: 0xFF | 141 | default: 0xFF |
| 141 | 142 | ||
| @@ -209,7 +210,7 @@ unevaluatedProperties: false · 67 unmodified lines | |||
| 209 | examples: | 210 | examples: |
| 210 | - | | 211 | - | |
| 211 | #include <dt-bindings/gpio/gpio.h> | 212 | #include <dt-bindings/gpio/gpio.h> |
| 212 | #include <dt-bindings/iio/adi,ad4695.h> | 213 | #include <dt-bindings/iio/adc/adi,ad4695.h> |
| 213 | 214 | ||
| 214 | spi { | 215 | spi { |
| 215 | #address-cells = <1>; | 216 | #address-cells = <1>; |
| @@ -37,6 +37,17 @@ properties: · 36 unmodified lines | |||
| 37 | description: IRQ line for the ADC | 37 | description: IRQ line for the ADC |
| 38 | maxItems: 1 | 38 | maxItems: 1 |
| 39 | 39 | ||
| 40 | rdy-gpios: | ||
| 41 | description: | ||
| 42 | GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but | ||
| 43 | highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its | ||
| 44 | DOUT aka MISO role) and so usually triggers a spurious interrupt. The | ||
| 45 | distinction between such a spurious event and a real one can only be done | ||
| 46 | by reading such a GPIO. (There is a register telling the same | ||
| 47 | information, but accessing that one needs a SPI transfer which then | ||
| 48 | triggers another interrupt event.) | ||
| 49 | maxItems: 1 | ||
| 50 | |||
| 40 | '#address-cells': | 51 | '#address-cells': |
| 41 | const: 1 | 52 | const: 1 |
| 42 | 53 | ||
| @@ -111,6 +122,7 @@ unevaluatedProperties: false · 68 unmodified lines | |||
| 111 | 122 | ||
| 112 | examples: | 123 | examples: |
| 113 | - | | 124 | - | |
| 125 | #include <dt-bindings/gpio/gpio.h> | ||
| 114 | spi { | 126 | spi { |
| 115 | #address-cells = <1>; | 127 | #address-cells = <1>; |
| 116 | #size-cells = <0>; | 128 | #size-cells = <0>; |
| @@ -121,6 +133,7 @@ examples: · 4 unmodified lines | |||
| 121 | spi-max-frequency = <5000000>; | 133 | spi-max-frequency = <5000000>; |
| 122 | interrupts = <25 2>; | 134 | interrupts = <25 2>; |
| 123 | interrupt-parent = <&gpio>; | 135 | interrupt-parent = <&gpio>; |
| 136 | rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; | ||
| 124 | refin1-supply = <&adc_vref>; | 137 | refin1-supply = <&adc_vref>; |
| 125 | clocks = <&ad7124_mclk>; | 138 | clocks = <&ad7124_mclk>; |
| 126 | clock-names = "mclk"; | 139 | clock-names = "mclk"; |
| @@ -135,6 +135,17 @@ properties: · 134 unmodified lines | |||
| 135 | '#clock-cells': | 135 | '#clock-cells': |
| 136 | const: 0 | 136 | const: 0 |
| 137 | 137 | ||
| 138 | rdy-gpios: | ||
| 139 | description: | ||
| 140 | GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but | ||
| 141 | highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its | ||
| 142 | DOUT aka MISO role) and so usually triggers a spurious interrupt. The | ||
| 143 | distinction between such a spurious event and a real one can only be done | ||
| 144 | by reading such a GPIO. (There is a register telling the same | ||
| 145 | information, but accessing that one needs a SPI transfer which then | ||
| 146 | triggers another interrupt event.) | ||
| 147 | maxItems: 1 | ||
| 148 | |||
| 138 | patternProperties: | 149 | patternProperties: |
| 139 | "^channel@[0-9a-f]$": | 150 | "^channel@[0-9a-f]$": |
| 140 | type: object | 151 | type: object |
| @@ -443,6 +454,7 @@ examples: · 302 unmodified lines | |||
| 443 | interrupts = <25 IRQ_TYPE_EDGE_FALLING>; | 454 | interrupts = <25 IRQ_TYPE_EDGE_FALLING>; |
| 444 | interrupt-names = "rdy"; | 455 | interrupt-names = "rdy"; |
| 445 | interrupt-parent = <&gpio>; | 456 | interrupt-parent = <&gpio>; |
| 457 | rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; | ||
| 446 | spi-max-frequency = <5000000>; | 458 | spi-max-frequency = <5000000>; |
| 447 | gpio-controller; | 459 | gpio-controller; |
| 448 | #gpio-cells = <2>; | 460 | #gpio-cells = <2>; |
| @@ -106,6 +106,17 @@ properties: · 105 unmodified lines | |||
| 106 | description: see Documentation/devicetree/bindings/iio/adc/adc.yaml | 106 | description: see Documentation/devicetree/bindings/iio/adc/adc.yaml |
| 107 | type: boolean | 107 | type: boolean |
| 108 | 108 | ||
| 109 | rdy-gpios: | ||
| 110 | description: | ||
| 111 | GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but | ||
| 112 | highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its | ||
| 113 | DOUT aka MISO role) and so usually triggers a spurious interrupt. The | ||
| 114 | distinction between such a spurious event and a real one can only be done | ||
| 115 | by reading such a GPIO. (There is a register telling the same | ||
| 116 | information, but accessing that one needs a SPI transfer which then | ||
| 117 | triggers another interrupt event.) | ||
| 118 | maxItems: 1 | ||
| 119 | |||
| 109 | patternProperties: | 120 | patternProperties: |
| 110 | "^channel@[0-9a-f]+$": | 121 | "^channel@[0-9a-f]+$": |
| 111 | type: object | 122 | type: object |
| @@ -181,6 +192,7 @@ unevaluatedProperties: false · 69 unmodified lines | |||
| 181 | 192 | ||
| 182 | examples: | 193 | examples: |
| 183 | - | | 194 | - | |
| 195 | #include <dt-bindings/gpio/gpio.h> | ||
| 184 | spi { | 196 | spi { |
| 185 | #address-cells = <1>; | 197 | #address-cells = <1>; |
| 186 | #size-cells = <0>; | 198 | #size-cells = <0>; |
| @@ -195,6 +207,7 @@ examples: · 8 unmodified lines | |||
| 195 | clock-names = "mclk"; | 207 | clock-names = "mclk"; |
| 196 | interrupts = <25 0x2>; | 208 | interrupts = <25 0x2>; |
| 197 | interrupt-parent = <&gpio>; | 209 | interrupt-parent = <&gpio>; |
| 210 | rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; | ||
| 198 | aincom-supply = <&aincom>; | 211 | aincom-supply = <&aincom>; |
| 199 | dvdd-supply = <&dvdd>; | 212 | dvdd-supply = <&dvdd>; |
| 200 | avdd-supply = <&avdd>; | 213 | avdd-supply = <&avdd>; |
| @@ -207,6 +220,7 @@ examples: · 6 unmodified lines | |||
| 207 | }; | 220 | }; |
| 208 | }; | 221 | }; |
| 209 | - | | 222 | - | |
| 223 | #include <dt-bindings/gpio/gpio.h> | ||
| 210 | spi { | 224 | spi { |
| 211 | #address-cells = <1>; | 225 | #address-cells = <1>; |
| 212 | #size-cells = <0>; | 226 | #size-cells = <0>; |
| @@ -224,6 +238,7 @@ examples: · 11 unmodified lines | |||
| 224 | #clock-cells = <0>; | 238 | #clock-cells = <0>; |
| 225 | interrupts = <25 0x2>; | 239 | interrupts = <25 0x2>; |
| 226 | interrupt-parent = <&gpio>; | 240 | interrupt-parent = <&gpio>; |
| 241 | rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; | ||
| 227 | aincom-supply = <&aincom>; | 242 | aincom-supply = <&aincom>; |
| 228 | dvdd-supply = <&dvdd>; | 243 | dvdd-supply = <&dvdd>; |
| 229 | avdd-supply = <&avdd>; | 244 | avdd-supply = <&avdd>; |
| @@ -63,6 +63,17 @@ properties: · 62 unmodified lines | |||
| 63 | marked GPIO_ACTIVE_LOW. | 63 | marked GPIO_ACTIVE_LOW. |
| 64 | maxItems: 1 | 64 | maxItems: 1 |
| 65 | 65 | ||
| 66 | rdy-gpios: | ||
| 67 | description: | ||
| 68 | GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but | ||
| 69 | highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its | ||
| 70 | DOUT aka MISO role) and so usually triggers a spurious interrupt. The | ||
| 71 | distinction between such a spurious event and a real one can only be done | ||
| 72 | by reading such a GPIO. (There is a register telling the same | ||
| 73 | information, but accessing that one needs a SPI transfer which then | ||
| 74 | triggers another interrupt event.) | ||
| 75 | maxItems: 1 | ||
| 76 | |||
| 66 | required: | 77 | required: |
| 67 | - compatible | 78 | - compatible |
| 68 | - reg | 79 | - reg |
| @@ -17,12 +17,15 @@ description: | · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | properties: | 18 | properties: |
| 19 | compatible: | 19 | compatible: |
| 20 | items: | 20 | oneOf: |
| 21 | - enum: | 21 | - items: |
| 22 | - renesas,r9a07g043-adc # RZ/G2UL and RZ/Five | 22 | - enum: |
| 23 | - renesas,r9a07g044-adc # RZ/G2L | 23 | - renesas,r9a07g043-adc # RZ/G2UL and RZ/Five |
| 24 | - renesas,r9a07g054-adc # RZ/V2L | 24 | - renesas,r9a07g044-adc # RZ/G2L |
| 25 | - const: renesas,rzg2l-adc | 25 | - renesas,r9a07g054-adc # RZ/V2L |
| 26 | - const: renesas,rzg2l-adc | ||
| 27 | - items: | ||
| 28 | - const: renesas,r9a08g045-adc # RZ/G3S | ||
| 26 | 29 | ||
| 27 | reg: | 30 | reg: |
| 28 | maxItems: 1 | 31 | maxItems: 1 |
| @@ -57,6 +60,9 @@ properties: · 28 unmodified lines | |||
| 57 | '#size-cells': | 60 | '#size-cells': |
| 58 | const: 0 | 61 | const: 0 |
| 59 | 62 | ||
| 63 | "#io-channel-cells": | ||
| 64 | const: 1 | ||
| 65 | |||
| 60 | required: | 66 | required: |
| 61 | - compatible | 67 | - compatible |
| 62 | - reg | 68 | - reg |
| @@ -68,7 +74,7 @@ required: · 5 unmodified lines | |||
| 68 | - reset-names | 74 | - reset-names |
| 69 | 75 | ||
| 70 | patternProperties: | 76 | patternProperties: |
| 71 | "^channel@[0-7]$": | 77 | "^channel@[0-8]$": |
| 72 | $ref: adc.yaml | 78 | $ref: adc.yaml |
| 73 | type: object | 79 | type: object |
| 74 | description: | | 80 | description: | |
| @@ -78,6 +84,8 @@ patternProperties: · 3 unmodified lines | |||
| 78 | reg: | 84 | reg: |
| 79 | description: | | 85 | description: | |
| 80 | The channel number. | 86 | The channel number. |
| 87 | minimum: 0 | ||
| 88 | maximum: 8 | ||
| 81 | 89 | ||
| 82 | required: | 90 | required: |
| 83 | - reg | 91 | - reg |
| @@ -92,18 +100,25 @@ allOf: · 8 unmodified lines | |||
| 92 | const: renesas,r9a07g043-adc | 100 | const: renesas,r9a07g043-adc |
| 93 | then: | 101 | then: |
| 94 | patternProperties: | 102 | patternProperties: |
| 95 | "^channel@[2-7]$": false | 103 | "^channel@[2-8]$": false |
| 96 | "^channel@[0-1]$": | 104 | "^channel@[0-1]$": |
| 97 | properties: | 105 | properties: |
| 98 | reg: | 106 | reg: |
| 99 | minimum: 0 | ||
| 100 | maximum: 1 | 107 | maximum: 1 |
| 101 | else: | 108 | |
| 109 | - if: | ||
| 110 | properties: | ||
| 111 | compatible: | ||
| 112 | contains: | ||
| 113 | enum: | ||
| 114 | - renesas,r9a07g044-adc | ||
| 115 | - renesas,r9a07g054-adc | ||
| 116 | then: | ||
| 102 | patternProperties: | 117 | patternProperties: |
| 118 | "^channel@[8]$": false | ||
| 103 | "^channel@[0-7]$": | 119 | "^channel@[0-7]$": |
| 104 | properties: | 120 | properties: |
| 105 | reg: | 121 | reg: |
| 106 | minimum: 0 | ||
| 107 | maximum: 7 | 122 | maximum: 7 |
| 108 | 123 | ||
| 109 | additionalProperties: false | 124 | additionalProperties: false |
| @@ -0,0 +1,62 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/chemical/bosch,bme680.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Bosch BME680 Gas sensor | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Vasileios Amoiridis <vassilisamir@gmail.com> | ||
| 11 | |||
| 12 | description: > | ||
| 13 | BME680 is a gas sensor which combines relative humidity, barometric pressure, | ||
| 14 | ambient temperature and gas (VOC - Volatile Organic Compounds) measurements. | ||
| 15 | |||
| 16 | https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf | ||
| 17 | |||
| 18 | properties: | ||
| 19 | compatible: | ||
| 20 | const: bosch,bme680 | ||
| 21 | |||
| 22 | reg: | ||
| 23 | maxItems: 1 | ||
| 24 | |||
| 25 | vdd-supply: true | ||
| 26 | vddio-supply: true | ||
| 27 | |||
| 28 | required: | ||
| 29 | - compatible | ||
| 30 | - reg | ||
| 31 | |||
| 32 | allOf: | ||
| 33 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
| 34 | |||
| 35 | unevaluatedProperties: false | ||
| 36 | |||
| 37 | examples: | ||
| 38 | - | | ||
| 39 | i2c { | ||
| 40 | #address-cells = <1>; | ||
| 41 | #size-cells = <0>; | ||
| 42 | |||
| 43 | co2-sensor@77 { | ||
| 44 | compatible = "bosch,bme680"; | ||
| 45 | reg = <0x77>; | ||
| 46 | vddio-supply = <&vddio>; | ||
| 47 | vdd-supply = <&vdd>; | ||
| 48 | }; | ||
| 49 | }; | ||
| 50 | - | | ||
| 51 | spi { | ||
| 52 | #address-cells = <1>; | ||
| 53 | #size-cells = <0>; | ||
| 54 | |||
| 55 | co2-sensor@0 { | ||
| 56 | compatible = "bosch,bme680"; | ||
| 57 | reg = <0>; | ||
| 58 | spi-max-frequency = <500000>; | ||
| 59 | vddio-supply = <&vddio>; | ||
| 60 | vdd-supply = <&vdd>; | ||
| 61 | }; | ||
| 62 | }; | ||
| @@ -91,7 +91,7 @@ examples: · 90 unmodified lines | |||
| 91 | vrefn-supply = <&dac_vrefn>; | 91 | vrefn-supply = <&dac_vrefn>; |
| 92 | reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>; | 92 | reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>; |
| 93 | clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>; | 93 | clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>; |
| 94 | ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_HIGH>; | 94 | ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_LOW>; |
| 95 | }; | 95 | }; |
| 96 | }; | 96 | }; |
| 97 | ... | 97 | ... |
| @@ -0,0 +1,62 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | # Copyright 2024 ROHM Semiconductor. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/iio/dac/rohm,bd79703.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: ROHM BD79703 DAC device driver | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Matti Vaittinen <mazziesaccount@gmail.com> | ||
| 12 | |||
| 13 | description: | | ||
| 14 | The ROHM BD79703 is a 6 channel, 8-bit DAC. | ||
| 15 | Datasheet can be found here: | ||
| 16 | https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79702fv-lb_bd79703fv-lb-e.pdf | ||
| 17 | |||
| 18 | properties: | ||
| 19 | compatible: | ||
| 20 | const: rohm,bd79703 | ||
| 21 | |||
| 22 | reg: | ||
| 23 | maxItems: 1 | ||
| 24 | |||
| 25 | spi-max-frequency: | ||
| 26 | maximum: 30000000 | ||
| 27 | |||
| 28 | vfs-supply: | ||
| 29 | description: | ||
| 30 | The regulator to use as a full scale voltage. The voltage should be between 2.7V .. VCC | ||
| 31 | |||
| 32 | vcc-supply: | ||
| 33 | description: | ||
| 34 | The regulator supplying the operating voltage. Should be between 2.7V ... 5.5V | ||
| 35 | |||
| 36 | required: | ||
| 37 | - compatible | ||
| 38 | - reg | ||
| 39 | - spi-max-frequency | ||
| 40 | - vfs-supply | ||
| 41 | - vcc-supply | ||
| 42 | |||
| 43 | allOf: | ||
| 44 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
| 45 | |||
| 46 | additionalProperties: false | ||
| 47 | |||
| 48 | examples: | ||
| 49 | - | | ||
| 50 | spi { | ||
| 51 | #address-cells = <1>; | ||
| 52 | #size-cells = <0>; | ||
| 53 | |||
| 54 | dac@0 { | ||
| 55 | compatible = "rohm,bd79703"; | ||
| 56 | reg = <0>; | ||
| 57 | spi-max-frequency = <30000000>; | ||
| 58 | vcc-supply = <&vcc>; | ||
| 59 | vfs-supply = <&vref>; | ||
| 60 | }; | ||
| 61 | }; | ||
| 62 | ... | ||
| @@ -11,24 +11,30 @@ maintainers: · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | properties: | 12 | properties: |
| 13 | compatible: | 13 | compatible: |
| 14 | enum: | 14 | oneOf: |
| 15 | - adi,adis16375 | 15 | - enum: |
| 16 | - adi,adis16480 | 16 | - adi,adis16375 |
| 17 | - adi,adis16485 | 17 | - adi,adis16480 |
| 18 | - adi,adis16488 | 18 | - adi,adis16485 |
| 19 | - adi,adis16490 | 19 | - adi,adis16486 |
| 20 | - adi,adis16495-1 | 20 | - adi,adis16488 |
| 21 | - adi,adis16495-2 | 21 | - adi,adis16489 |
| 22 | - adi,adis16495-3 | 22 | - adi,adis16490 |
| 23 | - adi,adis16497-1 | 23 | - adi,adis16495-1 |
| 24 | - adi,adis16497-2 | 24 | - adi,adis16495-2 |
| 25 | - adi,adis16497-3 | 25 | - adi,adis16495-3 |
| 26 | - adi,adis16545-1 | 26 | - adi,adis16497-1 |
| 27 | - adi,adis16545-2 | 27 | - adi,adis16497-2 |
| 28 | - adi,adis16545-3 | 28 | - adi,adis16497-3 |
| 29 | - adi,adis16547-1 | 29 | - adi,adis16545-1 |
| 30 | - adi,adis16547-2 | 30 | - adi,adis16545-2 |
| 31 | - adi,adis16547-3 | 31 | - adi,adis16545-3 |
| 32 | - adi,adis16547-1 | ||
| 33 | - adi,adis16547-2 | ||
| 34 | - adi,adis16547-3 | ||
| 35 | - items: | ||
| 36 | - const: adi,adis16487 | ||
| 37 | - const: adi,adis16485 | ||
| 32 | 38 | ||
| 33 | reg: | 39 | reg: |
| 34 | maxItems: 1 | 40 | maxItems: 1 |
| @@ -37,6 +37,7 @@ properties: · 36 unmodified lines | |||
| 37 | to "INT2" if INT2 pin should be used instead | 37 | to "INT2" if INT2 pin should be used instead |
| 38 | 38 | ||
| 39 | drive-open-drain: | 39 | drive-open-drain: |
| 40 | type: boolean | ||
| 40 | description: | | 41 | description: | |
| 41 | set if the specified interrupt pin should be configured as | 42 | set if the specified interrupt pin should be configured as |
| 42 | open drain. If not set, defaults to push-pull. | 43 | open drain. If not set, defaults to push-pull. |
| @@ -41,6 +41,7 @@ properties: · 40 unmodified lines | |||
| 41 | - INT2 | 41 | - INT2 |
| 42 | 42 | ||
| 43 | drive-open-drain: | 43 | drive-open-drain: |
| 44 | type: boolean | ||
| 44 | description: | 45 | description: |
| 45 | set if the specified interrupt pins should be configured as | 46 | set if the specified interrupt pins should be configured as |
| 46 | open drain. If not set, defaults to push-pull. | 47 | open drain. If not set, defaults to push-pull. |
| @@ -38,6 +38,7 @@ properties: · 37 unmodified lines | |||
| 38 | - INT2 | 38 | - INT2 |
| 39 | 39 | ||
| 40 | drive-open-drain: | 40 | drive-open-drain: |
| 41 | type: boolean | ||
| 41 | description: | 42 | description: |
| 42 | set if the specified interrupt pin should be configured as | 43 | set if the specified interrupt pin should be configured as |
| 43 | open drain. If not set, defaults to push-pull. | 44 | open drain. If not set, defaults to push-pull. |
| @@ -16,6 +16,7 @@ properties: · 15 unmodified lines | |||
| 16 | compatible: | 16 | compatible: |
| 17 | oneOf: | 17 | oneOf: |
| 18 | - enum: | 18 | - enum: |
| 19 | - invensense,iam20380 | ||
| 19 | - invensense,iam20680 | 20 | - invensense,iam20680 |
| 20 | - invensense,icm20608 | 21 | - invensense,icm20608 |
| 21 | - invensense,icm20609 | 22 | - invensense,icm20609 |
| @@ -1,49 +0,0 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/light/rohm,bu27008.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: ROHM BU27008 color sensor | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Matti Vaittinen <mazziesaccount@gmail.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear | ||
| 14 | and IR) with four configurable channels. Red and green being always | ||
| 15 | available and two out of the rest three (blue, clear, IR) can be | ||
| 16 | selected to be simultaneously measured. Typical application is adjusting | ||
| 17 | LCD backlight of TVs, mobile phones and tablet PCs. | ||
| 18 | |||
| 19 | properties: | ||
| 20 | compatible: | ||
| 21 | const: rohm,bu27008 | ||
| 22 | |||
| 23 | reg: | ||
| 24 | maxItems: 1 | ||
| 25 | |||
| 26 | interrupts: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | vdd-supply: true | ||
| 30 | |||
| 31 | required: | ||
| 32 | - compatible | ||
| 33 | - reg | ||
| 34 | |||
| 35 | additionalProperties: false | ||
| 36 | |||
| 37 | examples: | ||
| 38 | - | | ||
| 39 | i2c { | ||
| 40 | #address-cells = <1>; | ||
| 41 | #size-cells = <0>; | ||
| 42 | |||
| 43 | light-sensor@38 { | ||
| 44 | compatible = "rohm,bu27008"; | ||
| 45 | reg = <0x38>; | ||
| 46 | }; | ||
| 47 | }; | ||
| 48 | |||
| 49 | ... | ||
| @@ -1,50 +0,0 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/light/rohm,bu27010.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: ROHM BU27010 color sensor | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Matti Vaittinen <mazziesaccount@gmail.com> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | The ROHM BU27010 is a sensor with 6 photodiodes (red, green, blue, clear, | ||
| 14 | IR and flickering detection) with five configurable channels. Red, green | ||
| 15 | and flickering detection being always available and two out of the rest | ||
| 16 | three (blue, clear, IR) can be selected to be simultaneously measured. | ||
| 17 | Typical application is adjusting LCD/OLED backlight of TVs, mobile phones | ||
| 18 | and tablet PCs. | ||
| 19 | |||
| 20 | properties: | ||
| 21 | compatible: | ||
| 22 | const: rohm,bu27010 | ||
| 23 | |||
| 24 | reg: | ||
| 25 | maxItems: 1 | ||
| 26 | |||
| 27 | interrupts: | ||
| 28 | maxItems: 1 | ||
| 29 | |||
| 30 | vdd-supply: true | ||
| 31 | |||
| 32 | required: | ||
| 33 | - compatible | ||
| 34 | - reg | ||
| 35 | - vdd-supply | ||
| 36 | |||
| 37 | additionalProperties: false | ||
| 38 | |||
| 39 | examples: | ||
| 40 | - | | ||
| 41 | i2c { | ||
| 42 | #address-cells = <1>; | ||
| 43 | #size-cells = <0>; | ||
| 44 | |||
| 45 | light-sensor@38 { | ||
| 46 | compatible = "rohm,bu27010"; | ||
| 47 | reg = <0x38>; | ||
| 48 | vdd-supply = <&vdd>; | ||
| 49 | }; | ||
| 50 | }; | ||
| @@ -0,0 +1,51 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/iio/light/ti,opt4060.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Texas Instruments OPT4060 RGBW Color Sensor | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Per-Daniel Olsson <perdaniel.olsson@axis.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | Texas Instrument RGBW high resolution color sensor over I2C. | ||
| 14 | https://www.ti.com/lit/gpn/opt4060 | ||
| 15 | |||
| 16 | properties: | ||
| 17 | compatible: | ||
| 18 | enum: | ||
| 19 | - ti,opt4060 | ||
| 20 | |||
| 21 | reg: | ||
| 22 | maxItems: 1 | ||
| 23 | |||
| 24 | interrupts: | ||
| 25 | maxItems: 1 | ||
| 26 | |||
| 27 | vdd-supply: true | ||
| 28 | |||
| 29 | required: | ||
| 30 | - compatible | ||
| 31 | - reg | ||
| 32 | - vdd-supply | ||
| 33 | |||
| 34 | additionalProperties: false | ||
| 35 | |||
| 36 | examples: | ||
| 37 | - | | ||
| 38 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 39 | i2c { | ||
| 40 | #address-cells = <1>; | ||
| 41 | #size-cells = <0>; | ||
| 42 | |||
| 43 | light-sensor@44 { | ||
| 44 | compatible = "ti,opt4060"; | ||
| 45 | reg = <0x44>; | ||
| 46 | vdd-supply = <&vdd_reg>; | ||
| 47 | interrupt-parent = <&gpio5>; | ||
| 48 | interrupts = <13 IRQ_TYPE_EDGE_FALLING>; | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | ... | ||
| @@ -55,12 +55,16 @@ properties: · 54 unmodified lines | |||
| 55 | If not set, defaults to push-pull configuration. | 55 | If not set, defaults to push-pull configuration. |
| 56 | type: boolean | 56 | type: boolean |
| 57 | 57 | ||
| 58 | spi-max-frequency: | ||
| 59 | maximum: 10000000 | ||
| 60 | |||
| 58 | required: | 61 | required: |
| 59 | - compatible | 62 | - compatible |
| 60 | - vddd-supply | 63 | - vddd-supply |
| 61 | - vdda-supply | 64 | - vdda-supply |
| 62 | 65 | ||
| 63 | allOf: | 66 | allOf: |
| 67 | - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
| 64 | - if: | 68 | - if: |
| 65 | properties: | 69 | properties: |
| 66 | compatible: | 70 | compatible: |
| @@ -73,6 +77,16 @@ allOf: · 6 unmodified lines | |||
| 73 | then: | 77 | then: |
| 74 | properties: | 78 | properties: |
| 75 | interrupts: false | 79 | interrupts: false |
| 80 | - if: | ||
| 81 | properties: | ||
| 82 | compatible: | ||
| 83 | contains: | ||
| 84 | enum: | ||
| 85 | - bosch,bmp085 | ||
| 86 | - bosch,bmp180 | ||
| 87 | then: | ||
| 88 | properties: | ||
| 89 | spi-max-frequency: false | ||
| 76 | 90 | ||
| 77 | additionalProperties: false | 91 | additionalProperties: false |
| 78 | 92 | ||
| @@ -93,3 +107,18 @@ examples: · 14 unmodified lines | |||
| 93 | vdda-supply = <&bar>; | 107 | vdda-supply = <&bar>; |
| 94 | }; | 108 | }; |
| 95 | }; | 109 | }; |
| 110 | - | | ||
| 111 | # include <dt-bindings/gpio/gpio.h> | ||
| 112 | # include <dt-bindings/interrupt-controller/irq.h> | ||
| 113 | spi { | ||
| 114 | #address-cells = <1>; | ||
| 115 | #size-cells = <0>; | ||
| 116 | pressure@0 { | ||
| 117 | compatible = "bosch,bmp280"; | ||
| 118 | reg = <0>; | ||
| 119 | spi-max-frequency = <10000000>; | ||
| 120 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; | ||
| 121 | vddd-supply = <&foo>; | ||
| 122 | vdda-supply = <&bar>; | ||
| 123 | }; | ||
| 124 | }; | ||
| @@ -38,6 +38,7 @@ properties: · 37 unmodified lines | |||
| 38 | - qcom,sm8250-cpu-bwmon | 38 | - qcom,sm8250-cpu-bwmon |
| 39 | - qcom,sm8550-cpu-bwmon | 39 | - qcom,sm8550-cpu-bwmon |
| 40 | - qcom,sm8650-cpu-bwmon | 40 | - qcom,sm8650-cpu-bwmon |
| 41 | - qcom,sm8750-cpu-bwmon | ||
| 41 | - qcom,x1e80100-cpu-bwmon | 42 | - qcom,x1e80100-cpu-bwmon |
| 42 | - const: qcom,sdm845-bwmon # BWMON v4, unified register space | 43 | - const: qcom,sdm845-bwmon # BWMON v4, unified register space |
| 43 | - items: | 44 | - items: |
| @@ -33,6 +33,7 @@ properties: · 32 unmodified lines | |||
| 33 | - qcom,sm6375-cpucp-l3 | 33 | - qcom,sm6375-cpucp-l3 |
| 34 | - qcom,sm8250-epss-l3 | 34 | - qcom,sm8250-epss-l3 |
| 35 | - qcom,sm8350-epss-l3 | 35 | - qcom,sm8350-epss-l3 |
| 36 | - qcom,sm8650-epss-l3 | ||
| 36 | - const: qcom,epss-l3 | 37 | - const: qcom,epss-l3 |
| 37 | 38 | ||
| 38 | reg: | 39 | reg: |
| @@ -20,12 +20,14 @@ properties: · 19 unmodified lines | |||
| 20 | - qcom,apq8064-qfprom | 20 | - qcom,apq8064-qfprom |
| 21 | - qcom,apq8084-qfprom | 21 | - qcom,apq8084-qfprom |
| 22 | - qcom,ipq5332-qfprom | 22 | - qcom,ipq5332-qfprom |
| 23 | - qcom,ipq5424-qfprom | ||
| 23 | - qcom,ipq6018-qfprom | 24 | - qcom,ipq6018-qfprom |
| 24 | - qcom,ipq8064-qfprom | 25 | - qcom,ipq8064-qfprom |
| 25 | - qcom,ipq8074-qfprom | 26 | - qcom,ipq8074-qfprom |
| 26 | - qcom,ipq9574-qfprom | 27 | - qcom,ipq9574-qfprom |
| 27 | - qcom,msm8226-qfprom | 28 | - qcom,msm8226-qfprom |
| 28 | - qcom,msm8916-qfprom | 29 | - qcom,msm8916-qfprom |
| 30 | - qcom,msm8917-qfprom | ||
| 29 | - qcom,msm8974-qfprom | 31 | - qcom,msm8974-qfprom |
| 30 | - qcom,msm8976-qfprom | 32 | - qcom,msm8976-qfprom |
| 31 | - qcom,msm8996-qfprom | 33 | - qcom,msm8996-qfprom |
| @@ -33,6 +35,7 @@ properties: · 1 unmodified line | |||
| 33 | - qcom,qcm2290-qfprom | 35 | - qcom,qcm2290-qfprom |
| 34 | - qcom,qcs404-qfprom | 36 | - qcom,qcs404-qfprom |
| 35 | - qcom,qcs615-qfprom | 37 | - qcom,qcs615-qfprom |
| 38 | - qcom,qcs8300-qfprom | ||
| 36 | - qcom,sc7180-qfprom | 39 | - qcom,sc7180-qfprom |
| 37 | - qcom,sc7280-qfprom | 40 | - qcom,sc7280-qfprom |
| 38 | - qcom,sc8280xp-qfprom | 41 | - qcom,sc8280xp-qfprom |
| @@ -16,6 +16,7 @@ properties: · 15 unmodified lines | |||
| 16 | compatible: | 16 | compatible: |
| 17 | items: | 17 | items: |
| 18 | - enum: | 18 | - enum: |
| 19 | - mobileye,eyeq5-bootloader-config | ||
| 19 | - raspberrypi,bootloader-config | 20 | - raspberrypi,bootloader-config |
| 20 | - raspberrypi,bootloader-public-key | 21 | - raspberrypi,bootloader-public-key |
| 21 | - const: nvmem-rmem | 22 | - const: nvmem-rmem |
| @@ -55,8 +55,6 @@ properties: · 54 unmodified lines | |||
| 55 | - atmel,atsha204a | 55 | - atmel,atsha204a |
| 56 | # BPA-RS600: Power Supply | 56 | # BPA-RS600: Power Supply |
| 57 | - blutek,bpa-rs600 | 57 | - blutek,bpa-rs600 |
| 58 | # Bosch Sensortec pressure, temperature, humididty and VOC sensor | ||
| 59 | - bosch,bme680 | ||
| 60 | # CM32181: Ambient Light Sensor | 58 | # CM32181: Ambient Light Sensor |
| 61 | - capella,cm32181 | 59 | - capella,cm32181 |
| 62 | # CM3232: Ambient Light Sensor | 60 | # CM3232: Ambient Light Sensor |
| @@ -25,6 +25,8 @@ properties: · 24 unmodified lines | |||
| 25 | reg: | 25 | reg: |
| 26 | maxItems: 1 | 26 | maxItems: 1 |
| 27 | 27 | ||
| 28 | vcc-supply: true | ||
| 29 | |||
| 28 | required: | 30 | required: |
| 29 | - compatible | 31 | - compatible |
| 30 | - reg | 32 | - reg |
| @@ -0,0 +1,255 @@ | |||
| 1 | ======================= | ||
| 2 | Extcon Device Subsystem | ||
| 3 | ======================= | ||
| 4 | |||
| 5 | Overview | ||
| 6 | ======== | ||
| 7 | |||
| 8 | The Extcon (External Connector) subsystem provides a unified framework for | ||
| 9 | managing external connectors in Linux systems. It allows drivers to report | ||
| 10 | the state of external connectors and provides a standardized interface for | ||
| 11 | userspace to query and monitor these states. | ||
| 12 | |||
| 13 | Extcon is particularly useful in modern devices with multiple connectivity | ||
| 14 | options, such as smartphones, tablets, and laptops. It helps manage various | ||
| 15 | types of connectors, including: | ||
| 16 | |||
| 17 | 1. USB connectors (e.g., USB-C, micro-USB) | ||
| 18 | 2. Charging ports (e.g., fast charging, wireless charging) | ||
| 19 | 3. Audio jacks (e.g., 3.5mm headphone jack) | ||
| 20 | 4. Video outputs (e.g., HDMI, DisplayPort) | ||
| 21 | 5. Docking stations | ||
| 22 | |||
| 23 | Real-world examples: | ||
| 24 | |||
| 25 | 1. Smartphone USB-C port: | ||
| 26 | A single USB-C port on a smartphone can serve multiple functions. Extcon | ||
| 27 | can manage the different states of this port, such as: | ||
| 28 | - USB data connection | ||
| 29 | - Charging (various types like fast charging, USB Power Delivery) | ||
| 30 | - Audio output (USB-C headphones) | ||
| 31 | - Video output (USB-C to HDMI adapter) | ||
| 32 | |||
| 33 | 2. Laptop docking station: | ||
| 34 | When a laptop is connected to a docking station, multiple connections are | ||
| 35 | made simultaneously. Extcon can handle the state changes for: | ||
| 36 | - Power delivery | ||
| 37 | - External displays | ||
| 38 | - USB hub connections | ||
| 39 | - Ethernet connectivity | ||
| 40 | |||
| 41 | 3. Wireless charging pad: | ||
| 42 | Extcon can manage the state of a wireless charging connection, allowing | ||
| 43 | the system to respond appropriately when a device is placed on or removed | ||
| 44 | from the charging pad. | ||
| 45 | |||
| 46 | 4. Smart TV HDMI ports: | ||
| 47 | In a smart TV, Extcon can manage multiple HDMI ports, detecting when | ||
| 48 | devices are connected or disconnected, and potentially identifying the | ||
| 49 | type of device (e.g., gaming console, set-top box, Blu-ray player). | ||
| 50 | |||
| 51 | The Extcon framework simplifies the development of drivers for these complex | ||
| 52 | scenarios by providing a standardized way to report and query connector | ||
| 53 | states, handle mutually exclusive connections, and manage connector | ||
| 54 | properties. This allows for more robust and flexible handling of external | ||
| 55 | connections in modern devices. | ||
| 56 | |||
| 57 | Key Components | ||
| 58 | ============== | ||
| 59 | |||
| 60 | extcon_dev | ||
| 61 | ---------- | ||
| 62 | |||
| 63 | The core structure representing an Extcon device:: | ||
| 64 | |||
| 65 | struct extcon_dev { | ||
| 66 | const char *name; | ||
| 67 | const unsigned int *supported_cable; | ||
| 68 | const u32 *mutually_exclusive; | ||
| 69 | |||
| 70 | /* Internal data */ | ||
| 71 | struct device dev; | ||
| 72 | unsigned int id; | ||
| 73 | struct raw_notifier_head nh_all; | ||
| 74 | struct raw_notifier_head *nh; | ||
| 75 | struct list_head entry; | ||
| 76 | int max_supported; | ||
| 77 | spinlock_t lock; | ||
| 78 | u32 state; | ||
| 79 | |||
| 80 | /* Sysfs related */ | ||
| 81 | struct device_type extcon_dev_type; | ||
| 82 | struct extcon_cable *cables; | ||
| 83 | struct attribute_group attr_g_muex; | ||
| 84 | struct attribute **attrs_muex; | ||
| 85 | struct device_attribute *d_attrs_muex; | ||
| 86 | }; | ||
| 87 | |||
| 88 | Key fields: | ||
| 89 | |||
| 90 | - ``name``: Name of the Extcon device | ||
| 91 | - ``supported_cable``: Array of supported cable types | ||
| 92 | - ``mutually_exclusive``: Array defining mutually exclusive cable types | ||
| 93 | This field is crucial for enforcing hardware constraints. It's an array of | ||
| 94 | 32-bit unsigned integers, where each element represents a set of mutually | ||
| 95 | exclusive cable types. The array should be terminated with a 0. | ||
| 96 | |||
| 97 | For example: | ||
| 98 | |||
| 99 | :: | ||
| 100 | |||
| 101 | static const u32 mutually_exclusive[] = { | ||
| 102 | BIT(0) | BIT(1), /* Cable 0 and 1 are mutually exclusive */ | ||
| 103 | BIT(2) | BIT(3) | BIT(4), /* Cables 2, 3, and 4 are mutually exclusive */ | ||
| 104 | 0 /* Terminator */ | ||
| 105 | }; | ||
| 106 | |||
| 107 | In this example, cables 0 and 1 cannot be connected simultaneously, and | ||
| 108 | cables 2, 3, and 4 are also mutually exclusive. This is useful for | ||
| 109 | scenarios like a single port that can either be USB or HDMI, but not both | ||
| 110 | at the same time. | ||
| 111 | |||
| 112 | The Extcon core uses this information to prevent invalid combinations of | ||
| 113 | cable states, ensuring that the reported states are always consistent | ||
| 114 | with the hardware capabilities. | ||
| 115 | |||
| 116 | - ``state``: Current state of the device (bitmap of connected cables) | ||
| 117 | |||
| 118 | |||
| 119 | extcon_cable | ||
| 120 | ------------ | ||
| 121 | |||
| 122 | Represents an individual cable managed by an Extcon device:: | ||
| 123 | |||
| 124 | struct extcon_cable { | ||
| 125 | struct extcon_dev *edev; | ||
| 126 | int cable_index; | ||
| 127 | struct attribute_group attr_g; | ||
| 128 | struct device_attribute attr_name; | ||
| 129 | struct device_attribute attr_state; | ||
| 130 | struct attribute *attrs[3]; | ||
| 131 | union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; | ||
| 132 | union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; | ||
| 133 | union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; | ||
| 134 | union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; | ||
| 135 | DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT); | ||
| 136 | DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT); | ||
| 137 | DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT); | ||
| 138 | DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT); | ||
| 139 | }; | ||
| 140 | |||
| 141 | Core Functions | ||
| 142 | ============== | ||
| 143 | |||
| 144 | .. kernel-doc:: drivers/extcon/extcon.c | ||
| 145 | :identifiers: extcon_get_state | ||
| 146 | |||
| 147 | .. kernel-doc:: drivers/extcon/extcon.c | ||
| 148 | :identifiers: extcon_set_state | ||
| 149 | |||
| 150 | .. kernel-doc:: drivers/extcon/extcon.c | ||
| 151 | :identifiers: extcon_set_state_sync | ||
| 152 | |||
| 153 | .. kernel-doc:: drivers/extcon/extcon.c | ||
| 154 | :identifiers: extcon_get_property | ||
| 155 | |||
| 156 | |||
| 157 | Sysfs Interface | ||
| 158 | =============== | ||
| 159 | |||
| 160 | Extcon devices expose the following sysfs attributes: | ||
| 161 | |||
| 162 | - ``name``: Name of the Extcon device | ||
| 163 | - ``state``: Current state of all supported cables | ||
| 164 | - ``cable.N/name``: Name of the Nth supported cable | ||
| 165 | - ``cable.N/state``: State of the Nth supported cable | ||
| 166 | |||
| 167 | Usage Example | ||
| 168 | ------------- | ||
| 169 | |||
| 170 | .. code-block:: c | ||
| 171 | |||
| 172 | #include <linux/module.h> | ||
| 173 | #include <linux/platform_device.h> | ||
| 174 | #include <linux/extcon.h> | ||
| 175 | |||
| 176 | struct my_extcon_data { | ||
| 177 | struct extcon_dev *edev; | ||
| 178 | struct device *dev; | ||
| 179 | }; | ||
| 180 | |||
| 181 | static const unsigned int my_extcon_cable[] = { | ||
| 182 | EXTCON_USB, | ||
| 183 | EXTCON_USB_HOST, | ||
| 184 | EXTCON_NONE, | ||
| 185 | }; | ||
| 186 | |||
| 187 | static int my_extcon_probe(struct platform_device *pdev) | ||
| 188 | { | ||
| 189 | struct my_extcon_data *data; | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
| 193 | if (!data) | ||
| 194 | return -ENOMEM; | ||
| 195 | |||
| 196 | data->dev = &pdev->dev; | ||
| 197 | |||
| 198 | /* Initialize extcon device */ | ||
| 199 | data->edev = devm_extcon_dev_allocate(data->dev, my_extcon_cable); | ||
| 200 | if (IS_ERR(data->edev)) { | ||
| 201 | dev_err(data->dev, "Failed to allocate extcon device\n"); | ||
| 202 | return PTR_ERR(data->edev); | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Register extcon device */ | ||
| 206 | ret = devm_extcon_dev_register(data->dev, data->edev); | ||
| 207 | if (ret < 0) { | ||
| 208 | dev_err(data->dev, "Failed to register extcon device\n"); | ||
| 209 | return ret; | ||
| 210 | } | ||
| 211 | |||
| 212 | platform_set_drvdata(pdev, data); | ||
| 213 | |||
| 214 | /* Example: Set initial state */ | ||
| 215 | extcon_set_state_sync(data->edev, EXTCON_USB, true); | ||
| 216 | |||
| 217 | dev_info(data->dev, "My extcon driver probed successfully\n"); | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int my_extcon_remove(struct platform_device *pdev) | ||
| 222 | { | ||
| 223 | struct my_extcon_data *data = platform_get_drvdata(pdev); | ||
| 224 | |||
| 225 | /* Example: Clear state before removal */ | ||
| 226 | extcon_set_state_sync(data->edev, EXTCON_USB, false); | ||
| 227 | |||
| 228 | dev_info(data->dev, "My extcon driver removed\n"); | ||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | static const struct of_device_id my_extcon_of_match[] = { | ||
| 233 | { .compatible = "my,extcon-device", }, | ||
| 234 | { }, | ||
| 235 | }; | ||
| 236 | MODULE_DEVICE_TABLE(of, my_extcon_of_match); | ||
| 237 | |||
| 238 | static struct platform_driver my_extcon_driver = { | ||
| 239 | .driver = { | ||
| 240 | .name = "my-extcon-driver", | ||
| 241 | .of_match_table = my_extcon_of_match, | ||
| 242 | }, | ||
| 243 | .probe = my_extcon_probe, | ||
| 244 | .remove = my_extcon_remove, | ||
| 245 | }; | ||
| 246 | |||
| 247 | module_platform_driver(my_extcon_driver); | ||
| 248 | |||
| 249 | This example demonstrates: | ||
| 250 | --------------------------- | ||
| 251 | |||
| 252 | - Defining supported cable types (USB and USB Host in this case). | ||
| 253 | - Allocating and registering an extcon device. | ||
| 254 | - Setting an initial state for a cable (USB connected in this example). | ||
| 255 | - Clearing the state when the driver is removed. | ||
| @@ -86,6 +86,7 @@ Subsystem-specific APIs · 85 unmodified lines | |||
| 86 | dmaengine/index | 86 | dmaengine/index |
| 87 | dpll | 87 | dpll |
| 88 | edac | 88 | edac |
| 89 | extcon | ||
| 89 | firmware/index | 90 | firmware/index |
| 90 | fpga/index | 91 | fpga/index |
| 91 | frame-buffer | 92 | frame-buffer |
| @@ -202,6 +202,46 @@ Sometimes one needs to be able not only to catch PPS signals but to produce · 201 unmodified lines | |||
| 202 | them also. For example, running a distributed simulation, which requires | 202 | them also. For example, running a distributed simulation, which requires |
| 203 | computers' clock to be synchronized very tightly. | 203 | computers' clock to be synchronized very tightly. |
| 204 | 204 | ||
| 205 | To do so the class pps-gen has been added. PPS generators can be | ||
| 206 | registered in the kernel by defining a struct pps_gen_source_info as | ||
| 207 | follows:: | ||
| 208 | |||
| 209 | static struct pps_gen_source_info pps_gen_dummy_info = { | ||
| 210 | .name = "dummy", | ||
| 211 | .use_system_clock = true, | ||
| 212 | .get_time = pps_gen_dummy_get_time, | ||
| 213 | .enable = pps_gen_dummy_enable, | ||
| 214 | }; | ||
| 215 | |||
| 216 | Where the use_system_clock states if the generator uses the system | ||
| 217 | clock to generate its pulses, or they are from a peripheral device | ||
| 218 | clock. Method get_time() is used to query the time stored into the | ||
| 219 | generator clock, while the method enable() is used to enable or | ||
| 220 | disable the PPS pulse generation. | ||
| 221 | |||
| 222 | Then calling the function pps_gen_register_source() in your | ||
| 223 | initialization routine as follows creates a new generator in the | ||
| 224 | system:: | ||
| 225 | |||
| 226 | pps_gen = pps_gen_register_source(&pps_gen_dummy_info); | ||
| 227 | |||
| 228 | Generators SYSFS support | ||
| 229 | ------------------------ | ||
| 230 | |||
| 231 | If the SYSFS filesystem is enabled in the kernel it provides a new class:: | ||
| 232 | |||
| 233 | $ ls /sys/class/pps-gen/ | ||
| 234 | pps-gen0/ pps-gen1/ pps-gen2/ | ||
| 235 | |||
| 236 | Every directory is the ID of a PPS generator defined in the system and | ||
| 237 | inside of it you find several files:: | ||
| 238 | |||
| 239 | $ ls -F /sys/class/pps-gen/pps-gen0/ | ||
| 240 | dev enable name power/ subsystem@ system time uevent | ||
| 241 | |||
| 242 | To enable the PPS signal generation you can use the command below:: | ||
| 243 | |||
| 244 | $ echo 1 > /sys/class/pps-gen/pps-gen0/enable | ||
| 205 | 245 | ||
| 206 | Parallel port generator | 246 | Parallel port generator |
| 207 | ------------------------ | 247 | ------------------------ |
| @@ -101,7 +101,7 @@ The macro comes from: · 100 unmodified lines | |||
| 101 | 101 | ||
| 102 | .. code-block:: | 102 | .. code-block:: |
| 103 | 103 | ||
| 104 | #include <dt-bindings/iio/adi,ad4695.h> | 104 | #include <dt-bindings/iio/adc/adi,ad4695.h> |
| 105 | 105 | ||
| 106 | Pairing two INx pins | 106 | Pairing two INx pins |
| 107 | ^^^^^^^^^^^^^^^^^^^^ | 107 | ^^^^^^^^^^^^^^^^^^^^ |
| @@ -12,7 +12,10 @@ This driver supports Analog Device's IMUs on SPI bus. · 11 unmodified lines | |||
| 12 | * `ADIS16375 <https://www.analog.com/ADIS16375>`_ | 12 | * `ADIS16375 <https://www.analog.com/ADIS16375>`_ |
| 13 | * `ADIS16480 <https://www.analog.com/ADIS16480>`_ | 13 | * `ADIS16480 <https://www.analog.com/ADIS16480>`_ |
| 14 | * `ADIS16485 <https://www.analog.com/ADIS16485>`_ | 14 | * `ADIS16485 <https://www.analog.com/ADIS16485>`_ |
| 15 | * `ADIS16486 <https://www.analog.com/ADIS16486>`_ | ||
| 16 | * `ADIS16487 <https://www.analog.com/ADIS16487>`_ | ||
| 15 | * `ADIS16488 <https://www.analog.com/ADIS16488>`_ | 17 | * `ADIS16488 <https://www.analog.com/ADIS16488>`_ |
| 18 | * `ADIS16489 <https://www.analog.com/ADIS16489>`_ | ||
| 16 | * `ADIS16490 <https://www.analog.com/ADIS16490>`_ | 19 | * `ADIS16490 <https://www.analog.com/ADIS16490>`_ |
| 17 | * `ADIS16495 <https://www.analog.com/ADIS16495>`_ | 20 | * `ADIS16495 <https://www.analog.com/ADIS16495>`_ |
| 18 | * `ADIS16497 <https://www.analog.com/ADIS16497>`_ | 21 | * `ADIS16497 <https://www.analog.com/ADIS16497>`_ |
| @@ -29,3 +29,4 @@ Industrial I/O Kernel Drivers · 28 unmodified lines | |||
| 29 | adxl380 | 29 | adxl380 |
| 30 | bno055 | 30 | bno055 |
| 31 | ep93xx_adc | 31 | ep93xx_adc |
| 32 | opt4060 | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | ============================== | ||
| 2 | OPT4060 driver | ||
| 3 | ============================== | ||
| 4 | |||
| 5 | 1. Overview | ||
| 6 | ============================= | ||
| 7 | |||
| 8 | This driver supports the Texas Instrument RGBW high resolution color sensor over | ||
| 9 | I2C. | ||
| 10 | https://www.ti.com/lit/gpn/opt4060 | ||
| 11 | |||
| 12 | The driver supports: | ||
| 13 | - Raw values for red, green, blue and clear. | ||
| 14 | - Illuminance values. | ||
| 15 | - Scaled color values for red, green and blue. | ||
| 16 | - IIO events for thresholds. | ||
| 17 | - IIO triggered buffer using both its own data ready trigger and triggers from | ||
| 18 | other drivers. | ||
| 19 | |||
| 20 | 2. Illuminance calculation | ||
| 21 | ============================= | ||
| 22 | |||
| 23 | Illuminance is calculated using the wide spectrum green channel. | ||
| 24 | |||
| 25 | lux = GREEN_RAW x 2.15e-3 | ||
| 26 | |||
| 27 | The value is accessed from: | ||
| 28 | /sys/bus/iio/devices/iio:deviceX/in_illuminance_input | ||
| 29 | |||
| 30 | See section 8.4.5.2 in the data sheet for additional details. | ||
| 31 | |||
| 32 | 3. Color scale values | ||
| 33 | ============================= | ||
| 34 | |||
| 35 | The sensor has different sensitivity for the different color components and | ||
| 36 | compensating factors are exposed from the driver. | ||
| 37 | |||
| 38 | The values are accessed from: | ||
| 39 | /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale | ||
| 40 | /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale | ||
| 41 | /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale | ||
| 42 | |||
| 43 | A userspace application can multiply the raw values with the scale values so | ||
| 44 | that for a particular test light source, typically white, the measurement | ||
| 45 | intensity is the same across the different color channels. This is calculated | ||
| 46 | in the following way: | ||
| 47 | |||
| 48 | R = RED_RAW x SCALE_RED(2.4) | ||
| 49 | G = GREEN_RAW x SCALE_GREEN(1.0) | ||
| 50 | B = BLUE_RAW x SCALE_BLUE(1.3) | ||
| 51 | |||
| 52 | The data sheet suggests using the scaled values to normalize the scaled R, G | ||
| 53 | and B values. This is useful to get a value for the ratio between colors | ||
| 54 | independent of light intensity. A userspace application can do this in the | ||
| 55 | following way: | ||
| 56 | |||
| 57 | R_NORMALIZED = R / (R + G + B) | ||
| 58 | G_NORMALIZED = G / (R + G + B) | ||
| 59 | B_NORMALIZED = B / (R + G + B) | ||
| 60 | |||
| 61 | See section 8.4.5.2 in the data sheet for additional details. | ||
| @@ -64,6 +64,7 @@ Everything else · 63 unmodified lines | |||
| 64 | vduse | 64 | vduse |
| 65 | futex2 | 65 | futex2 |
| 66 | perf_ring_buffer | 66 | perf_ring_buffer |
| 67 | ntsync | ||
| 67 | 68 | ||
| 68 | .. only:: subproject and html | 69 | .. only:: subproject and html |
| 69 | 70 | ||
| @@ -283,6 +283,7 @@ Code Seq# Include File Comments · 282 unmodified lines | |||
| 283 | 'p' 80-9F linux/ppdev.h user-space parport | 283 | 'p' 80-9F linux/ppdev.h user-space parport |
| 284 | <mailto:tim@cyberelk.net> | 284 | <mailto:tim@cyberelk.net> |
| 285 | 'p' A1-A5 linux/pps.h LinuxPPS | 285 | 'p' A1-A5 linux/pps.h LinuxPPS |
| 286 | 'p' B1-B3 linux/pps_gen.h LinuxPPS | ||
| 286 | <mailto:giometti@linux.it> | 287 | <mailto:giometti@linux.it> |
| 287 | 'q' 00-1F linux/serio.h | 288 | 'q' 00-1F linux/serio.h |
| 288 | 'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK | 289 | 'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK |
| @@ -0,0 +1,385 @@ | |||
| 1 | =================================== | ||
| 2 | NT synchronization primitive driver | ||
| 3 | =================================== | ||
| 4 | |||
| 5 | This page documents the user-space API for the ntsync driver. | ||
| 6 | |||
| 7 | ntsync is a support driver for emulation of NT synchronization | ||
| 8 | primitives by user-space NT emulators. It exists because implementation | ||
| 9 | in user-space, using existing tools, cannot match Windows performance | ||
| 10 | while offering accurate semantics. It is implemented entirely in | ||
| 11 | software, and does not drive any hardware device. | ||
| 12 | |||
| 13 | This interface is meant as a compatibility tool only, and should not | ||
| 14 | be used for general synchronization. Instead use generic, versatile | ||
| 15 | interfaces such as futex(2) and poll(2). | ||
| 16 | |||
| 17 | Synchronization primitives | ||
| 18 | ========================== | ||
| 19 | |||
| 20 | The ntsync driver exposes three types of synchronization primitives: | ||
| 21 | semaphores, mutexes, and events. | ||
| 22 | |||
| 23 | A semaphore holds a single volatile 32-bit counter, and a static 32-bit | ||
| 24 | integer denoting the maximum value. It is considered signaled (that is, | ||
| 25 | can be acquired without contention, or will wake up a waiting thread) | ||
| 26 | when the counter is nonzero. The counter is decremented by one when a | ||
| 27 | wait is satisfied. Both the initial and maximum count are established | ||
| 28 | when the semaphore is created. | ||
| 29 | |||
| 30 | A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit | ||
| 31 | identifier denoting its owner. A mutex is considered signaled when its | ||
| 32 | owner is zero (indicating that it is not owned). The recursion count is | ||
| 33 | incremented when a wait is satisfied, and ownership is set to the given | ||
| 34 | identifier. | ||
| 35 | |||
| 36 | A mutex also holds an internal flag denoting whether its previous owner | ||
| 37 | has died; such a mutex is said to be abandoned. Owner death is not | ||
| 38 | tracked automatically based on thread death, but rather must be | ||
| 39 | communicated using ``NTSYNC_IOC_MUTEX_KILL``. An abandoned mutex is | ||
| 40 | inherently considered unowned. | ||
| 41 | |||
| 42 | Except for the "unowned" semantics of zero, the actual value of the | ||
| 43 | owner identifier is not interpreted by the ntsync driver at all. The | ||
| 44 | intended use is to store a thread identifier; however, the ntsync | ||
| 45 | driver does not actually validate that a calling thread provides | ||
| 46 | consistent or unique identifiers. | ||
| 47 | |||
| 48 | An event is similar to a semaphore with a maximum count of one. It holds | ||
| 49 | a volatile boolean state denoting whether it is signaled or not. There | ||
| 50 | are two types of events, auto-reset and manual-reset. An auto-reset | ||
| 51 | event is designaled when a wait is satisfied; a manual-reset event is | ||
| 52 | not. The event type is specified when the event is created. | ||
| 53 | |||
| 54 | Unless specified otherwise, all operations on an object are atomic and | ||
| 55 | totally ordered with respect to other operations on the same object. | ||
| 56 | |||
| 57 | Objects are represented by files. When all file descriptors to an | ||
| 58 | object are closed, that object is deleted. | ||
| 59 | |||
| 60 | Char device | ||
| 61 | =========== | ||
| 62 | |||
| 63 | The ntsync driver creates a single char device /dev/ntsync. Each file | ||
| 64 | description opened on the device represents a unique instance intended | ||
| 65 | to back an individual NT virtual machine. Objects created by one ntsync | ||
| 66 | instance may only be used with other objects created by the same | ||
| 67 | instance. | ||
| 68 | |||
| 69 | ioctl reference | ||
| 70 | =============== | ||
| 71 | |||
| 72 | All operations on the device are done through ioctls. There are four | ||
| 73 | structures used in ioctl calls:: | ||
| 74 | |||
| 75 | struct ntsync_sem_args { | ||
| 76 | __u32 count; | ||
| 77 | __u32 max; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct ntsync_mutex_args { | ||
| 81 | __u32 owner; | ||
| 82 | __u32 count; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct ntsync_event_args { | ||
| 86 | __u32 signaled; | ||
| 87 | __u32 manual; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct ntsync_wait_args { | ||
| 91 | __u64 timeout; | ||
| 92 | __u64 objs; | ||
| 93 | __u32 count; | ||
| 94 | __u32 owner; | ||
| 95 | __u32 index; | ||
| 96 | __u32 alert; | ||
| 97 | __u32 flags; | ||
| 98 | __u32 pad; | ||
| 99 | }; | ||
| 100 | |||
| 101 | Depending on the ioctl, members of the structure may be used as input, | ||
| 102 | output, or not at all. | ||
| 103 | |||
| 104 | The ioctls on the device file are as follows: | ||
| 105 | |||
| 106 | .. c:macro:: NTSYNC_IOC_CREATE_SEM | ||
| 107 | |||
| 108 | Create a semaphore object. Takes a pointer to struct | ||
| 109 | :c:type:`ntsync_sem_args`, which is used as follows: | ||
| 110 | |||
| 111 | .. list-table:: | ||
| 112 | |||
| 113 | * - ``count`` | ||
| 114 | - Initial count of the semaphore. | ||
| 115 | * - ``max`` | ||
| 116 | - Maximum count of the semaphore. | ||
| 117 | |||
| 118 | Fails with ``EINVAL`` if ``count`` is greater than ``max``. | ||
| 119 | On success, returns a file descriptor the created semaphore. | ||
| 120 | |||
| 121 | .. c:macro:: NTSYNC_IOC_CREATE_MUTEX | ||
| 122 | |||
| 123 | Create a mutex object. Takes a pointer to struct | ||
| 124 | :c:type:`ntsync_mutex_args`, which is used as follows: | ||
| 125 | |||
| 126 | .. list-table:: | ||
| 127 | |||
| 128 | * - ``count`` | ||
| 129 | - Initial recursion count of the mutex. | ||
| 130 | * - ``owner`` | ||
| 131 | - Initial owner of the mutex. | ||
| 132 | |||
| 133 | If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is | ||
| 134 | zero and ``count`` is nonzero, the function fails with ``EINVAL``. | ||
| 135 | On success, returns a file descriptor the created mutex. | ||
| 136 | |||
| 137 | .. c:macro:: NTSYNC_IOC_CREATE_EVENT | ||
| 138 | |||
| 139 | Create an event object. Takes a pointer to struct | ||
| 140 | :c:type:`ntsync_event_args`, which is used as follows: | ||
| 141 | |||
| 142 | .. list-table:: | ||
| 143 | |||
| 144 | * - ``signaled`` | ||
| 145 | - If nonzero, the event is initially signaled, otherwise | ||
| 146 | nonsignaled. | ||
| 147 | * - ``manual`` | ||
| 148 | - If nonzero, the event is a manual-reset event, otherwise | ||
| 149 | auto-reset. | ||
| 150 | |||
| 151 | On success, returns a file descriptor the created event. | ||
| 152 | |||
| 153 | The ioctls on the individual objects are as follows: | ||
| 154 | |||
| 155 | .. c:macro:: NTSYNC_IOC_SEM_POST | ||
| 156 | |||
| 157 | Post to a semaphore object. Takes a pointer to a 32-bit integer, | ||
| 158 | which on input holds the count to be added to the semaphore, and on | ||
| 159 | output contains its previous count. | ||
| 160 | |||
| 161 | If adding to the semaphore's current count would raise the latter | ||
| 162 | past the semaphore's maximum count, the ioctl fails with | ||
| 163 | ``EOVERFLOW`` and the semaphore is not affected. If raising the | ||
| 164 | semaphore's count causes it to become signaled, eligible threads | ||
| 165 | waiting on this semaphore will be woken and the semaphore's count | ||
| 166 | decremented appropriately. | ||
| 167 | |||
| 168 | .. c:macro:: NTSYNC_IOC_MUTEX_UNLOCK | ||
| 169 | |||
| 170 | Release a mutex object. Takes a pointer to struct | ||
| 171 | :c:type:`ntsync_mutex_args`, which is used as follows: | ||
| 172 | |||
| 173 | .. list-table:: | ||
| 174 | |||
| 175 | * - ``owner`` | ||
| 176 | - Specifies the owner trying to release this mutex. | ||
| 177 | * - ``count`` | ||
| 178 | - On output, contains the previous recursion count. | ||
| 179 | |||
| 180 | If ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner`` | ||
| 181 | is not the current owner of the mutex, the ioctl fails with | ||
| 182 | ``EPERM``. | ||
| 183 | |||
| 184 | The mutex's count will be decremented by one. If decrementing the | ||
| 185 | mutex's count causes it to become zero, the mutex is marked as | ||
| 186 | unowned and signaled, and eligible threads waiting on it will be | ||
| 187 | woken as appropriate. | ||
| 188 | |||
| 189 | .. c:macro:: NTSYNC_IOC_SET_EVENT | ||
| 190 | |||
| 191 | Signal an event object. Takes a pointer to a 32-bit integer, which on | ||
| 192 | output contains the previous state of the event. | ||
| 193 | |||
| 194 | Eligible threads will be woken, and auto-reset events will be | ||
| 195 | designaled appropriately. | ||
| 196 | |||
| 197 | .. c:macro:: NTSYNC_IOC_RESET_EVENT | ||
| 198 | |||
| 199 | Designal an event object. Takes a pointer to a 32-bit integer, which | ||
| 200 | on output contains the previous state of the event. | ||
| 201 | |||
| 202 | .. c:macro:: NTSYNC_IOC_PULSE_EVENT | ||
| 203 | |||
| 204 | Wake threads waiting on an event object while leaving it in an | ||
| 205 | unsignaled state. Takes a pointer to a 32-bit integer, which on | ||
| 206 | output contains the previous state of the event. | ||
| 207 | |||
| 208 | A pulse operation can be thought of as a set followed by a reset, | ||
| 209 | performed as a single atomic operation. If two threads are waiting on | ||
| 210 | an auto-reset event which is pulsed, only one will be woken. If two | ||
| 211 | threads are waiting a manual-reset event which is pulsed, both will | ||
| 212 | be woken. However, in both cases, the event will be unsignaled | ||
| 213 | afterwards, and a simultaneous read operation will always report the | ||
| 214 | event as unsignaled. | ||
| 215 | |||
| 216 | .. c:macro:: NTSYNC_IOC_READ_SEM | ||
| 217 | |||
| 218 | Read the current state of a semaphore object. Takes a pointer to | ||
| 219 | struct :c:type:`ntsync_sem_args`, which is used as follows: | ||
| 220 | |||
| 221 | .. list-table:: | ||
| 222 | |||
| 223 | * - ``count`` | ||
| 224 | - On output, contains the current count of the semaphore. | ||
| 225 | * - ``max`` | ||
| 226 | - On output, contains the maximum count of the semaphore. | ||
| 227 | |||
| 228 | .. c:macro:: NTSYNC_IOC_READ_MUTEX | ||
| 229 | |||
| 230 | Read the current state of a mutex object. Takes a pointer to struct | ||
| 231 | :c:type:`ntsync_mutex_args`, which is used as follows: | ||
| 232 | |||
| 233 | .. list-table:: | ||
| 234 | |||
| 235 | * - ``owner`` | ||
| 236 | - On output, contains the current owner of the mutex, or zero | ||
| 237 | if the mutex is not currently owned. | ||
| 238 | * - ``count`` | ||
| 239 | - On output, contains the current recursion count of the mutex. | ||
| 240 | |||
| 241 | If the mutex is marked as abandoned, the function fails with | ||
| 242 | ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to | ||
| 243 | zero. | ||
| 244 | |||
| 245 | .. c:macro:: NTSYNC_IOC_READ_EVENT | ||
| 246 | |||
| 247 | Read the current state of an event object. Takes a pointer to struct | ||
| 248 | :c:type:`ntsync_event_args`, which is used as follows: | ||
| 249 | |||
| 250 | .. list-table:: | ||
| 251 | |||
| 252 | * - ``signaled`` | ||
| 253 | - On output, contains the current state of the event. | ||
| 254 | * - ``manual`` | ||
| 255 | - On output, contains 1 if the event is a manual-reset event, | ||
| 256 | and 0 otherwise. | ||
| 257 | |||
| 258 | .. c:macro:: NTSYNC_IOC_KILL_OWNER | ||
| 259 | |||
| 260 | Mark a mutex as unowned and abandoned if it is owned by the given | ||
| 261 | owner. Takes an input-only pointer to a 32-bit integer denoting the | ||
| 262 | owner. If the owner is zero, the ioctl fails with ``EINVAL``. If the | ||
| 263 | owner does not own the mutex, the function fails with ``EPERM``. | ||
| 264 | |||
| 265 | Eligible threads waiting on the mutex will be woken as appropriate | ||
| 266 | (and such waits will fail with ``EOWNERDEAD``, as described below). | ||
| 267 | |||
| 268 | .. c:macro:: NTSYNC_IOC_WAIT_ANY | ||
| 269 | |||
| 270 | Poll on any of a list of objects, atomically acquiring at most one. | ||
| 271 | Takes a pointer to struct :c:type:`ntsync_wait_args`, which is | ||
| 272 | used as follows: | ||
| 273 | |||
| 274 | .. list-table:: | ||
| 275 | |||
| 276 | * - ``timeout`` | ||
| 277 | - Absolute timeout in nanoseconds. If ``NTSYNC_WAIT_REALTIME`` | ||
| 278 | is set, the timeout is measured against the REALTIME clock; | ||
| 279 | otherwise it is measured against the MONOTONIC clock. If the | ||
| 280 | timeout is equal to or earlier than the current time, the | ||
| 281 | function returns immediately without sleeping. If ``timeout`` | ||
| 282 | is U64_MAX, the function will sleep until an object is | ||
| 283 | signaled, and will not fail with ``ETIMEDOUT``. | ||
| 284 | * - ``objs`` | ||
| 285 | - Pointer to an array of ``count`` file descriptors | ||
| 286 | (specified as an integer so that the structure has the same | ||
| 287 | size regardless of architecture). If any object is | ||
| 288 | invalid, the function fails with ``EINVAL``. | ||
| 289 | * - ``count`` | ||
| 290 | - Number of objects specified in the ``objs`` array. | ||
| 291 | If greater than ``NTSYNC_MAX_WAIT_COUNT``, the function fails | ||
| 292 | with ``EINVAL``. | ||
| 293 | * - ``owner`` | ||
| 294 | - Mutex owner identifier. If any object in ``objs`` is a mutex, | ||
| 295 | the ioctl will attempt to acquire that mutex on behalf of | ||
| 296 | ``owner``. If ``owner`` is zero, the ioctl fails with | ||
| 297 | ``EINVAL``. | ||
| 298 | * - ``index`` | ||
| 299 | - On success, contains the index (into ``objs``) of the object | ||
| 300 | which was signaled. If ``alert`` was signaled instead, | ||
| 301 | this contains ``count``. | ||
| 302 | * - ``alert`` | ||
| 303 | - Optional event object file descriptor. If nonzero, this | ||
| 304 | specifies an "alert" event object which, if signaled, will | ||
| 305 | terminate the wait. If nonzero, the identifier must point to a | ||
| 306 | valid event. | ||
| 307 | * - ``flags`` | ||
| 308 | - Zero or more flags. Currently the only flag is | ||
| 309 | ``NTSYNC_WAIT_REALTIME``, which causes the timeout to be | ||
| 310 | measured against the REALTIME clock instead of MONOTONIC. | ||
| 311 | * - ``pad`` | ||
| 312 | - Unused, must be set to zero. | ||
| 313 | |||
| 314 | This function attempts to acquire one of the given objects. If unable | ||
| 315 | to do so, it sleeps until an object becomes signaled, subsequently | ||
| 316 | acquiring it, or the timeout expires. In the latter case the ioctl | ||
| 317 | fails with ``ETIMEDOUT``. The function only acquires one object, even | ||
| 318 | if multiple objects are signaled. | ||
| 319 | |||
| 320 | A semaphore is considered to be signaled if its count is nonzero, and | ||
| 321 | is acquired by decrementing its count by one. A mutex is considered | ||
| 322 | to be signaled if it is unowned or if its owner matches the ``owner`` | ||
| 323 | argument, and is acquired by incrementing its recursion count by one | ||
| 324 | and setting its owner to the ``owner`` argument. An auto-reset event | ||
| 325 | is acquired by designaling it; a manual-reset event is not affected | ||
| 326 | by acquisition. | ||
| 327 | |||
| 328 | Acquisition is atomic and totally ordered with respect to other | ||
| 329 | operations on the same object. If two wait operations (with different | ||
| 330 | ``owner`` identifiers) are queued on the same mutex, only one is | ||
| 331 | signaled. If two wait operations are queued on the same semaphore, | ||
| 332 | and a value of one is posted to it, only one is signaled. | ||
| 333 | |||
| 334 | If an abandoned mutex is acquired, the ioctl fails with | ||
| 335 | ``EOWNERDEAD``. Although this is a failure return, the function may | ||
| 336 | otherwise be considered successful. The mutex is marked as owned by | ||
| 337 | the given owner (with a recursion count of 1) and as no longer | ||
| 338 | abandoned, and ``index`` is still set to the index of the mutex. | ||
| 339 | |||
| 340 | The ``alert`` argument is an "extra" event which can terminate the | ||
| 341 | wait, independently of all other objects. | ||
| 342 | |||
| 343 | It is valid to pass the same object more than once, including by | ||
| 344 | passing the same event in the ``objs`` array and in ``alert``. If a | ||
| 345 | wakeup occurs due to that object being signaled, ``index`` is set to | ||
| 346 | the lowest index corresponding to that object. | ||
| 347 | |||
| 348 | The function may fail with ``EINTR`` if a signal is received. | ||
| 349 | |||
| 350 | .. c:macro:: NTSYNC_IOC_WAIT_ALL | ||
| 351 | |||
| 352 | Poll on a list of objects, atomically acquiring all of them. Takes a | ||
| 353 | pointer to struct :c:type:`ntsync_wait_args`, which is used | ||
| 354 | identically to ``NTSYNC_IOC_WAIT_ANY``, except that ``index`` is | ||
| 355 | always filled with zero on success if not woken via alert. | ||
| 356 | |||
| 357 | This function attempts to simultaneously acquire all of the given | ||
| 358 | objects. If unable to do so, it sleeps until all objects become | ||
| 359 | simultaneously signaled, subsequently acquiring them, or the timeout | ||
| 360 | expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and no | ||
| 361 | objects are modified. | ||
| 362 | |||
| 363 | Objects may become signaled and subsequently designaled (through | ||
| 364 | acquisition by other threads) while this thread is sleeping. Only | ||
| 365 | once all objects are simultaneously signaled does the ioctl acquire | ||
| 366 | them and return. The entire acquisition is atomic and totally ordered | ||
| 367 | with respect to other operations on any of the given objects. | ||
| 368 | |||
| 369 | If an abandoned mutex is acquired, the ioctl fails with | ||
| 370 | ``EOWNERDEAD``. Similarly to ``NTSYNC_IOC_WAIT_ANY``, all objects are | ||
| 371 | nevertheless marked as acquired. Note that if multiple mutex objects | ||
| 372 | are specified, there is no way to know which were marked as | ||
| 373 | abandoned. | ||
| 374 | |||
| 375 | As with "any" waits, the ``alert`` argument is an "extra" event which | ||
| 376 | can terminate the wait. Critically, however, an "all" wait will | ||
| 377 | succeed if all members in ``objs`` are signaled, *or* if ``alert`` is | ||
| 378 | signaled. In the latter case ``index`` will be set to ``count``. As | ||
| 379 | with "any" waits, if both conditions are filled, the former takes | ||
| 380 | priority, and objects in ``objs`` will be acquired. | ||
| 381 | |||
| 382 | Unlike ``NTSYNC_IOC_WAIT_ANY``, it is not valid to pass the same | ||
| 383 | object more than once, nor is it valid to pass the same object in | ||
| 384 | ``objs`` and in ``alert``. If this is attempted, the function fails | ||
| 385 | with ``EINVAL``. | ||
| @@ -1318,7 +1318,7 @@ W: https://ez.analog.com/linux-software-drivers · 1317 unmodified lines | |||
| 1318 | F: Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml | 1318 | F: Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml |
| 1319 | F: Documentation/iio/ad4695.rst | 1319 | F: Documentation/iio/ad4695.rst |
| 1320 | F: drivers/iio/adc/ad4695.c | 1320 | F: drivers/iio/adc/ad4695.c |
| 1321 | F: include/dt-bindings/iio/adi,ad4695.h | 1321 | F: include/dt-bindings/iio/adc/adi,ad4695.h |
| 1322 | 1322 | ||
| 1323 | ANALOG DEVICES INC AD7091R DRIVER | 1323 | ANALOG DEVICES INC AD7091R DRIVER |
| 1324 | M: Marcelo Schmitt <marcelo.schmitt@analog.com> | 1324 | M: Marcelo Schmitt <marcelo.schmitt@analog.com> |
| @@ -8710,6 +8710,7 @@ L: linux-kernel@vger.kernel.org · 7385 unmodified lines | |||
| 8710 | S: Maintained | 8710 | S: Maintained |
| 8711 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git | 8711 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git |
| 8712 | F: Documentation/devicetree/bindings/extcon/ | 8712 | F: Documentation/devicetree/bindings/extcon/ |
| 8713 | F: Documentation/driver-api/extcon.rst | ||
| 8713 | F: Documentation/firmware-guide/acpi/extcon-intel-int3496.rst | 8714 | F: Documentation/firmware-guide/acpi/extcon-intel-int3496.rst |
| 8714 | F: drivers/extcon/ | 8715 | F: drivers/extcon/ |
| 8715 | F: include/linux/extcon.h | 8716 | F: include/linux/extcon.h |
| @@ -16833,6 +16834,15 @@ T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git · 8117 unmodified lines | |||
| 16833 | F: Documentation/filesystems/ntfs3.rst | 16834 | F: Documentation/filesystems/ntfs3.rst |
| 16834 | F: fs/ntfs3/ | 16835 | F: fs/ntfs3/ |
| 16835 | 16836 | ||
| 16837 | NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER | ||
| 16838 | M: Elizabeth Figura <zfigura@codeweavers.com> | ||
| 16839 | L: wine-devel@winehq.org | ||
| 16840 | S: Supported | ||
| 16841 | F: Documentation/userspace-api/ntsync.rst | ||
| 16842 | F: drivers/misc/ntsync.c | ||
| 16843 | F: include/uapi/linux/ntsync.h | ||
| 16844 | F: tools/testing/selftests/drivers/ntsync/ | ||
| 16845 | |||
| 16836 | NUBUS SUBSYSTEM | 16846 | NUBUS SUBSYSTEM |
| 16837 | M: Finn Thain <fthain@linux-m68k.org> | 16847 | M: Finn Thain <fthain@linux-m68k.org> |
| 16838 | L: linux-m68k@lists.linux-m68k.org | 16848 | L: linux-m68k@lists.linux-m68k.org |
| @@ -16914,6 +16924,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git · 75 unmodified lines | |||
| 16914 | F: Documentation/ABI/stable/sysfs-bus-nvmem | 16924 | F: Documentation/ABI/stable/sysfs-bus-nvmem |
| 16915 | F: Documentation/devicetree/bindings/nvmem/ | 16925 | F: Documentation/devicetree/bindings/nvmem/ |
| 16916 | F: drivers/nvmem/ | 16926 | F: drivers/nvmem/ |
| 16927 | F: include/dt-bindings/nvmem/ | ||
| 16917 | F: include/linux/nvmem-consumer.h | 16928 | F: include/linux/nvmem-consumer.h |
| 16918 | F: include/linux/nvmem-provider.h | 16929 | F: include/linux/nvmem-provider.h |
| 16919 | 16930 | ||
| @@ -18834,11 +18845,13 @@ L: linuxpps@ml.enneenne.com (subscribers-only) · 1914 unmodified lines | |||
| 18834 | S: Maintained | 18845 | S: Maintained |
| 18835 | W: http://wiki.enneenne.com/index.php/LinuxPPS_support | 18846 | W: http://wiki.enneenne.com/index.php/LinuxPPS_support |
| 18836 | F: Documentation/ABI/testing/sysfs-pps | 18847 | F: Documentation/ABI/testing/sysfs-pps |
| 18848 | F: Documentation/ABI/testing/sysfs-pps-gen | ||
| 18837 | F: Documentation/devicetree/bindings/pps/pps-gpio.yaml | 18849 | F: Documentation/devicetree/bindings/pps/pps-gpio.yaml |
| 18838 | F: Documentation/driver-api/pps.rst | 18850 | F: Documentation/driver-api/pps.rst |
| 18839 | F: drivers/pps/ | 18851 | F: drivers/pps/ |
| 18840 | F: include/linux/pps*.h | 18852 | F: include/linux/pps*.h |
| 18841 | F: include/uapi/linux/pps.h | 18853 | F: include/uapi/linux/pps.h |
| 18854 | F: include/uapi/linux/pps_gen.h | ||
| 18842 | 18855 | ||
| 18843 | PRESSURE STALL INFORMATION (PSI) | 18856 | PRESSURE STALL INFORMATION (PSI) |
| 18844 | M: Johannes Weiner <hannes@cmpxchg.org> | 18857 | M: Johannes Weiner <hannes@cmpxchg.org> |
| @@ -20429,6 +20442,11 @@ L: linux-serial@vger.kernel.org · 1584 unmodified lines | |||
| 20429 | S: Odd Fixes | 20442 | S: Odd Fixes |
| 20430 | F: drivers/tty/serial/rp2.* | 20443 | F: drivers/tty/serial/rp2.* |
| 20431 | 20444 | ||
| 20445 | ROHM BD79703 DAC | ||
| 20446 | M: Matti Vaittinen <mazziesaccount@gmail.com> | ||
| 20447 | S: Supported | ||
| 20448 | F: drivers/iio/dac/rohm-bd79703.c | ||
| 20449 | |||
| 20432 | ROHM BD99954 CHARGER IC | 20450 | ROHM BD99954 CHARGER IC |
| 20433 | M: Matti Vaittinen <mazziesaccount@gmail.com> | 20451 | M: Matti Vaittinen <mazziesaccount@gmail.com> |
| 20434 | S: Supported | 20452 | S: Supported |
| @@ -20457,7 +20475,6 @@ ROHM BU270xx LIGHT SENSOR DRIVERs · 22 unmodified lines | |||
| 20457 | M: Matti Vaittinen <mazziesaccount@gmail.com> | 20475 | M: Matti Vaittinen <mazziesaccount@gmail.com> |
| 20458 | L: linux-iio@vger.kernel.org | 20476 | L: linux-iio@vger.kernel.org |
| 20459 | S: Supported | 20477 | S: Supported |
| 20460 | F: drivers/iio/light/rohm-bu27008.c | ||
| 20461 | F: drivers/iio/light/rohm-bu27034.c | 20478 | F: drivers/iio/light/rohm-bu27034.c |
| 20462 | 20479 | ||
| 20463 | ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS | 20480 | ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS |
| @@ -21389,6 +21406,7 @@ M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> · 925 unmodified lines | |||
| 21389 | L: linux-sound@vger.kernel.org | 21406 | L: linux-sound@vger.kernel.org |
| 21390 | S: Maintained | 21407 | S: Maintained |
| 21391 | F: Documentation/devicetree/bindings/slimbus/ | 21408 | F: Documentation/devicetree/bindings/slimbus/ |
| 21409 | F: Documentation/driver-api/slimbus.rst | ||
| 21392 | F: drivers/slimbus/ | 21410 | F: drivers/slimbus/ |
| 21393 | F: include/linux/slimbus.h | 21411 | F: include/linux/slimbus.h |
| 21394 | 21412 | ||
| @@ -49,6 +49,28 @@ · 48 unmodified lines | |||
| 49 | mhm_reserved_0: the-mhm-reserved-0@0 { | 49 | mhm_reserved_0: the-mhm-reserved-0@0 { |
| 50 | reg = <0x8 0x00000000 0x0 0x0000800>; | 50 | reg = <0x8 0x00000000 0x0 0x0000800>; |
| 51 | }; | 51 | }; |
| 52 | |||
| 53 | nvram@461fe00 { | ||
| 54 | compatible = "mobileye,eyeq5-bootloader-config", "nvmem-rmem"; | ||
| 55 | reg = <0x0 0x0461fe00 0x0 0x200>; | ||
| 56 | #address-cells = <1>; | ||
| 57 | #size-cells = <1>; | ||
| 58 | no-map; | ||
| 59 | |||
| 60 | nvmem-layout { | ||
| 61 | compatible = "fixed-layout"; | ||
| 62 | #address-cells = <1>; | ||
| 63 | #size-cells = <1>; | ||
| 64 | |||
| 65 | eth0_mac: mac@7c { | ||
| 66 | reg = <0x7c 0x6>; | ||
| 67 | }; | ||
| 68 | |||
| 69 | eth1_mac: mac@82 { | ||
| 70 | reg = <0x82 0x6>; | ||
| 71 | }; | ||
| 72 | }; | ||
| 73 | }; | ||
| 52 | }; | 74 | }; |
| 53 | 75 | ||
| 54 | aliases { | 76 | aliases { |
| @@ -1971,7 +1971,7 @@ static bool binder_validate_fixup(struct binder_proc *proc, · 1970 unmodified lines | |||
| 1971 | * struct binder_task_work_cb - for deferred close | 1971 | * struct binder_task_work_cb - for deferred close |
| 1972 | * | 1972 | * |
| 1973 | * @twork: callback_head for task work | 1973 | * @twork: callback_head for task work |
| 1974 | * @fd: fd to close | 1974 | * @file: file to close |
| 1975 | * | 1975 | * |
| 1976 | * Structure to pass task work to be handled after | 1976 | * Structure to pass task work to be handled after |
| 1977 | * returning from binder_ioctl() via task_work_add(). | 1977 | * returning from binder_ioctl() via task_work_add(). |
| @@ -3800,13 +3800,13 @@ err_invalid_target_handle: · 1822 unmodified lines | |||
| 3800 | } | 3800 | } |
| 3801 | 3801 | ||
| 3802 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, | 3802 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, |
| 3803 | "%d:%d transaction %s to %d:%d failed %d/%d/%d, size %lld-%lld line %d\n", | 3803 | "%d:%d transaction %s to %d:%d failed %d/%d/%d, code %u size %lld-%lld line %d\n", |
| 3804 | proc->pid, thread->pid, reply ? "reply" : | 3804 | proc->pid, thread->pid, reply ? "reply" : |
| 3805 | (tr->flags & TF_ONE_WAY ? "async" : "call"), | 3805 | (tr->flags & TF_ONE_WAY ? "async" : "call"), |
| 3806 | target_proc ? target_proc->pid : 0, | 3806 | target_proc ? target_proc->pid : 0, |
| 3807 | target_thread ? target_thread->pid : 0, | 3807 | target_thread ? target_thread->pid : 0, |
| 3808 | t_debug_id, return_error, return_error_param, | 3808 | t_debug_id, return_error, return_error_param, |
| 3809 | (u64)tr->data_size, (u64)tr->offsets_size, | 3809 | tr->code, (u64)tr->data_size, (u64)tr->offsets_size, |
| 3810 | return_error_line); | 3810 | return_error_line); |
| 3811 | 3811 | ||
| 3812 | if (target_thread) | 3812 | if (target_thread) |
| @@ -6373,7 +6373,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m, · 2560 unmodified lines | |||
| 6373 | seq_printf(m, " node %d", buffer->target_node->debug_id); | 6373 | seq_printf(m, " node %d", buffer->target_node->debug_id); |
| 6374 | seq_printf(m, " size %zd:%zd offset %lx\n", | 6374 | seq_printf(m, " size %zd:%zd offset %lx\n", |
| 6375 | buffer->data_size, buffer->offsets_size, | 6375 | buffer->data_size, buffer->offsets_size, |
| 6376 | proc->alloc.buffer - buffer->user_data); | 6376 | proc->alloc.vm_start - buffer->user_data); |
| 6377 | } | 6377 | } |
| 6378 | 6378 | ||
| 6379 | static void print_binder_work_ilocked(struct seq_file *m, | 6379 | static void print_binder_work_ilocked(struct seq_file *m, |
| @@ -6927,6 +6927,11 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = { · 547 unmodified lines | |||
| 6927 | {} /* terminator */ | 6927 | {} /* terminator */ |
| 6928 | }; | 6928 | }; |
| 6929 | 6929 | ||
| 6930 | void binder_add_device(struct binder_device *device) | ||
| 6931 | { | ||
| 6932 | hlist_add_head(&device->hlist, &binder_devices); | ||
| 6933 | } | ||
| 6934 | |||
| 6930 | static int __init init_binder_device(const char *name) | 6935 | static int __init init_binder_device(const char *name) |
| 6931 | { | 6936 | { |
| 6932 | int ret; | 6937 | int ret; |
| @@ -61,7 +61,7 @@ static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, · 60 unmodified lines | |||
| 61 | struct binder_buffer *buffer) | 61 | struct binder_buffer *buffer) |
| 62 | { | 62 | { |
| 63 | if (list_is_last(&buffer->entry, &alloc->buffers)) | 63 | if (list_is_last(&buffer->entry, &alloc->buffers)) |
| 64 | return alloc->buffer + alloc->buffer_size - buffer->user_data; | 64 | return alloc->vm_start + alloc->buffer_size - buffer->user_data; |
| 65 | return binder_buffer_next(buffer)->user_data - buffer->user_data; | 65 | return binder_buffer_next(buffer)->user_data - buffer->user_data; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| @@ -169,32 +169,33 @@ struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, · 101 unmodified lines | |||
| 169 | { | 169 | { |
| 170 | struct binder_buffer *buffer; | 170 | struct binder_buffer *buffer; |
| 171 | 171 | ||
| 172 | spin_lock(&alloc->lock); | 172 | mutex_lock(&alloc->mutex); |
| 173 | buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); | 173 | buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); |
| 174 | spin_unlock(&alloc->lock); | 174 | mutex_unlock(&alloc->mutex); |
| 175 | return buffer; | 175 | return buffer; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | static inline void | 178 | static inline void |
| 179 | binder_set_installed_page(struct binder_lru_page *lru_page, | 179 | binder_set_installed_page(struct binder_alloc *alloc, |
| 180 | unsigned long index, | ||
| 180 | struct page *page) | 181 | struct page *page) |
| 181 | { | 182 | { |
| 182 | /* Pairs with acquire in binder_get_installed_page() */ | 183 | /* Pairs with acquire in binder_get_installed_page() */ |
| 183 | smp_store_release(&lru_page->page_ptr, page); | 184 | smp_store_release(&alloc->pages[index], page); |
| 184 | } | 185 | } |
| 185 | 186 | ||
| 186 | static inline struct page * | 187 | static inline struct page * |
| 187 | binder_get_installed_page(struct binder_lru_page *lru_page) | 188 | binder_get_installed_page(struct binder_alloc *alloc, unsigned long index) |
| 188 | { | 189 | { |
| 189 | /* Pairs with release in binder_set_installed_page() */ | 190 | /* Pairs with release in binder_set_installed_page() */ |
| 190 | return smp_load_acquire(&lru_page->page_ptr); | 191 | return smp_load_acquire(&alloc->pages[index]); |
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | static void binder_lru_freelist_add(struct binder_alloc *alloc, | 194 | static void binder_lru_freelist_add(struct binder_alloc *alloc, |
| 194 | unsigned long start, unsigned long end) | 195 | unsigned long start, unsigned long end) |
| 195 | { | 196 | { |
| 196 | struct binder_lru_page *page; | ||
| 197 | unsigned long page_addr; | 197 | unsigned long page_addr; |
| 198 | struct page *page; | ||
| 198 | 199 | ||
| 199 | trace_binder_update_page_range(alloc, false, start, end); | 200 | trace_binder_update_page_range(alloc, false, start, end); |
| 200 | 201 | ||
| @@ -202,65 +203,159 @@ static void binder_lru_freelist_add(struct binder_alloc *alloc, · 1 unmodified line | |||
| 202 | size_t index; | 203 | size_t index; |
| 203 | int ret; | 204 | int ret; |
| 204 | 205 | ||
| 205 | index = (page_addr - alloc->buffer) / PAGE_SIZE; | 206 | index = (page_addr - alloc->vm_start) / PAGE_SIZE; |
| 206 | page = &alloc->pages[index]; | 207 | page = binder_get_installed_page(alloc, index); |
| 207 | 208 | if (!page) | |
| 208 | if (!binder_get_installed_page(page)) | ||
| 209 | continue; | 209 | continue; |
| 210 | 210 | ||
| 211 | trace_binder_free_lru_start(alloc, index); | 211 | trace_binder_free_lru_start(alloc, index); |
| 212 | 212 | ||
| 213 | ret = list_lru_add_obj(&binder_freelist, &page->lru); | 213 | ret = list_lru_add(&binder_freelist, |
| 214 | page_to_lru(page), | ||
| 215 | page_to_nid(page), | ||
| 216 | NULL); | ||
| 214 | WARN_ON(!ret); | 217 | WARN_ON(!ret); |
| 215 | 218 | ||
| 216 | trace_binder_free_lru_end(alloc, index); | 219 | trace_binder_free_lru_end(alloc, index); |
| 217 | } | 220 | } |
| 218 | } | 221 | } |
| 219 | 222 | ||
| 220 | static int binder_install_single_page(struct binder_alloc *alloc, | 223 | static inline |
| 221 | struct binder_lru_page *lru_page, | 224 | void binder_alloc_set_mapped(struct binder_alloc *alloc, bool state) |
| 222 | unsigned long addr) | ||
| 223 | { | 225 | { |
| 224 | struct page *page; | 226 | /* pairs with smp_load_acquire in binder_alloc_is_mapped() */ |
| 225 | int ret = 0; | 227 | smp_store_release(&alloc->mapped, state); |
| 228 | } | ||
| 226 | 229 | ||
| 227 | if (!mmget_not_zero(alloc->mm)) | 230 | static inline bool binder_alloc_is_mapped(struct binder_alloc *alloc) |
| 228 | return -ESRCH; | 231 | { |
| 232 | /* pairs with smp_store_release in binder_alloc_set_mapped() */ | ||
| 233 | return smp_load_acquire(&alloc->mapped); | ||
| 234 | } | ||
| 235 | |||
| 236 | static struct page *binder_page_lookup(struct binder_alloc *alloc, | ||
| 237 | unsigned long addr) | ||
| 238 | { | ||
| 239 | struct mm_struct *mm = alloc->mm; | ||
| 240 | struct page *page; | ||
| 241 | long npages = 0; | ||
| 229 | 242 | ||
| 230 | /* | 243 | /* |
| 231 | * Protected with mmap_sem in write mode as multiple tasks | 244 | * Find an existing page in the remote mm. If missing, |
| 232 | * might race to install the same page. | 245 | * don't attempt to fault-in just propagate an error. |
| 233 | */ | 246 | */ |
| 234 | mmap_write_lock(alloc->mm); | 247 | mmap_read_lock(mm); |
| 235 | if (binder_get_installed_page(lru_page)) | 248 | if (binder_alloc_is_mapped(alloc)) |
| 236 | goto out; | 249 | npages = get_user_pages_remote(mm, addr, 1, FOLL_NOFAULT, |
| 250 | &page, NULL); | ||
| 251 | mmap_read_unlock(mm); | ||
| 237 | 252 | ||
| 238 | if (!alloc->vma) { | 253 | return npages > 0 ? page : NULL; |
| 239 | pr_err("%d: %s failed, no vma\n", alloc->pid, __func__); | 254 | } |
| 240 | ret = -ESRCH; | 255 | |
| 241 | goto out; | 256 | static int binder_page_insert(struct binder_alloc *alloc, |
| 257 | unsigned long addr, | ||
| 258 | struct page *page) | ||
| 259 | { | ||
| 260 | struct mm_struct *mm = alloc->mm; | ||
| 261 | struct vm_area_struct *vma; | ||
| 262 | int ret = -ESRCH; | ||
| 263 | |||
| 264 | /* attempt per-vma lock first */ | ||
| 265 | vma = lock_vma_under_rcu(mm, addr); | ||
| 266 | if (vma) { | ||
| 267 | if (binder_alloc_is_mapped(alloc)) | ||
| 268 | ret = vm_insert_page(vma, addr, page); | ||
| 269 | vma_end_read(vma); | ||
| 270 | return ret; | ||
| 242 | } | 271 | } |
| 243 | 272 | ||
| 273 | /* fall back to mmap_lock */ | ||
| 274 | mmap_read_lock(mm); | ||
| 275 | vma = vma_lookup(mm, addr); | ||
| 276 | if (vma && binder_alloc_is_mapped(alloc)) | ||
| 277 | ret = vm_insert_page(vma, addr, page); | ||
| 278 | mmap_read_unlock(mm); | ||
| 279 | |||
| 280 | return ret; | ||
| 281 | } | ||
| 282 | |||
| 283 | static struct page *binder_page_alloc(struct binder_alloc *alloc, | ||
| 284 | unsigned long index) | ||
| 285 | { | ||
| 286 | struct binder_shrinker_mdata *mdata; | ||
| 287 | struct page *page; | ||
| 288 | |||
| 244 | page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); | 289 | page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); |
| 290 | if (!page) | ||
| 291 | return NULL; | ||
| 292 | |||
| 293 | /* allocate and install shrinker metadata under page->private */ | ||
| 294 | mdata = kzalloc(sizeof(*mdata), GFP_KERNEL); | ||
| 295 | if (!mdata) { | ||
| 296 | __free_page(page); | ||
| 297 | return NULL; | ||
| 298 | } | ||
| 299 | |||
| 300 | mdata->alloc = alloc; | ||
| 301 | mdata->page_index = index; | ||
| 302 | INIT_LIST_HEAD(&mdata->lru); | ||
| 303 | set_page_private(page, (unsigned long)mdata); | ||
| 304 | |||
| 305 | return page; | ||
| 306 | } | ||
| 307 | |||
| 308 | static void binder_free_page(struct page *page) | ||
| 309 | { | ||
| 310 | kfree((struct binder_shrinker_mdata *)page_private(page)); | ||
| 311 | __free_page(page); | ||
| 312 | } | ||
| 313 | |||
| 314 | static int binder_install_single_page(struct binder_alloc *alloc, | ||
| 315 | unsigned long index, | ||
| 316 | unsigned long addr) | ||
| 317 | { | ||
| 318 | struct page *page; | ||
| 319 | int ret; | ||
| 320 | |||
| 321 | if (!mmget_not_zero(alloc->mm)) | ||
| 322 | return -ESRCH; | ||
| 323 | |||
| 324 | page = binder_page_alloc(alloc, index); | ||
| 245 | if (!page) { | 325 | if (!page) { |
| 246 | pr_err("%d: failed to allocate page\n", alloc->pid); | ||
| 247 | ret = -ENOMEM; | 326 | ret = -ENOMEM; |
| 248 | goto out; | 327 | goto out; |
| 249 | } | 328 | } |
| 250 | 329 | ||
| 251 | ret = vm_insert_page(alloc->vma, addr, page); | 330 | ret = binder_page_insert(alloc, addr, page); |
| 252 | if (ret) { | 331 | switch (ret) { |
| 332 | case -EBUSY: | ||
| 333 | /* | ||
| 334 | * EBUSY is ok. Someone installed the pte first but the | ||
| 335 | * alloc->pages[index] has not been updated yet. Discard | ||
| 336 | * our page and look up the one already installed. | ||
| 337 | */ | ||
| 338 | ret = 0; | ||
| 339 | binder_free_page(page); | ||
| 340 | page = binder_page_lookup(alloc, addr); | ||
| 341 | if (!page) { | ||
| 342 | pr_err("%d: failed to find page at offset %lx\n", | ||
| 343 | alloc->pid, addr - alloc->vm_start); | ||
| 344 | ret = -ESRCH; | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | fallthrough; | ||
| 348 | case 0: | ||
| 349 | /* Mark page installation complete and safe to use */ | ||
| 350 | binder_set_installed_page(alloc, index, page); | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | binder_free_page(page); | ||
| 253 | pr_err("%d: %s failed to insert page at offset %lx with %d\n", | 354 | pr_err("%d: %s failed to insert page at offset %lx with %d\n", |
| 254 | alloc->pid, __func__, addr - alloc->buffer, ret); | 355 | alloc->pid, __func__, addr - alloc->vm_start, ret); |
| 255 | __free_page(page); | 356 | break; |
| 256 | ret = -ENOMEM; | ||
| 257 | goto out; | ||
| 258 | } | 357 | } |
| 259 | |||
| 260 | /* Mark page installation complete and safe to use */ | ||
| 261 | binder_set_installed_page(lru_page, page); | ||
| 262 | out: | 358 | out: |
| 263 | mmap_write_unlock(alloc->mm); | ||
| 264 | mmput_async(alloc->mm); | 359 | mmput_async(alloc->mm); |
| 265 | return ret; | 360 | return ret; |
| 266 | } | 361 | } |
| @@ -269,7 +364,6 @@ static int binder_install_buffer_pages(struct binder_alloc *alloc, · 2 unmodified lines | |||
| 269 | struct binder_buffer *buffer, | 364 | struct binder_buffer *buffer, |
| 270 | size_t size) | 365 | size_t size) |
| 271 | { | 366 | { |
| 272 | struct binder_lru_page *page; | ||
| 273 | unsigned long start, final; | 367 | unsigned long start, final; |
| 274 | unsigned long page_addr; | 368 | unsigned long page_addr; |
| 275 | 369 | ||
| @@ -280,15 +374,13 @@ static int binder_install_buffer_pages(struct binder_alloc *alloc, · 4 unmodified lines | |||
| 280 | unsigned long index; | 374 | unsigned long index; |
| 281 | int ret; | 375 | int ret; |
| 282 | 376 | ||
| 283 | index = (page_addr - alloc->buffer) / PAGE_SIZE; | 377 | index = (page_addr - alloc->vm_start) / PAGE_SIZE; |
| 284 | page = &alloc->pages[index]; | 378 | if (binder_get_installed_page(alloc, index)) |
| 285 | |||
| 286 | if (binder_get_installed_page(page)) | ||
| 287 | continue; | 379 | continue; |
| 288 | 380 | ||
| 289 | trace_binder_alloc_page_start(alloc, index); | 381 | trace_binder_alloc_page_start(alloc, index); |
| 290 | 382 | ||
| 291 | ret = binder_install_single_page(alloc, page, page_addr); | 383 | ret = binder_install_single_page(alloc, index, page_addr); |
| 292 | if (ret) | 384 | if (ret) |
| 293 | return ret; | 385 | return ret; |
| 294 | 386 | ||
| @@ -302,8 +394,8 @@ static int binder_install_buffer_pages(struct binder_alloc *alloc, · 7 unmodified lines | |||
| 302 | static void binder_lru_freelist_del(struct binder_alloc *alloc, | 394 | static void binder_lru_freelist_del(struct binder_alloc *alloc, |
| 303 | unsigned long start, unsigned long end) | 395 | unsigned long start, unsigned long end) |
| 304 | { | 396 | { |
| 305 | struct binder_lru_page *page; | ||
| 306 | unsigned long page_addr; | 397 | unsigned long page_addr; |
| 398 | struct page *page; | ||
| 307 | 399 | ||
| 308 | trace_binder_update_page_range(alloc, true, start, end); | 400 | trace_binder_update_page_range(alloc, true, start, end); |
| 309 | 401 | ||
| @@ -311,13 +403,16 @@ static void binder_lru_freelist_del(struct binder_alloc *alloc, · 1 unmodified line | |||
| 311 | unsigned long index; | 403 | unsigned long index; |
| 312 | bool on_lru; | 404 | bool on_lru; |
| 313 | 405 | ||
| 314 | index = (page_addr - alloc->buffer) / PAGE_SIZE; | 406 | index = (page_addr - alloc->vm_start) / PAGE_SIZE; |
| 315 | page = &alloc->pages[index]; | 407 | page = binder_get_installed_page(alloc, index); |
| 316 | 408 | ||
| 317 | if (page->page_ptr) { | 409 | if (page) { |
| 318 | trace_binder_alloc_lru_start(alloc, index); | 410 | trace_binder_alloc_lru_start(alloc, index); |
| 319 | 411 | ||
| 320 | on_lru = list_lru_del_obj(&binder_freelist, &page->lru); | 412 | on_lru = list_lru_del(&binder_freelist, |
| 413 | page_to_lru(page), | ||
| 414 | page_to_nid(page), | ||
| 415 | NULL); | ||
| 321 | WARN_ON(!on_lru); | 416 | WARN_ON(!on_lru); |
| 322 | 417 | ||
| 323 | trace_binder_alloc_lru_end(alloc, index); | 418 | trace_binder_alloc_lru_end(alloc, index); |
| @@ -329,20 +424,6 @@ static void binder_lru_freelist_del(struct binder_alloc *alloc, · 5 unmodified lines | |||
| 329 | } | 424 | } |
| 330 | } | 425 | } |
| 331 | 426 | ||
| 332 | static inline void binder_alloc_set_vma(struct binder_alloc *alloc, | ||
| 333 | struct vm_area_struct *vma) | ||
| 334 | { | ||
| 335 | /* pairs with smp_load_acquire in binder_alloc_get_vma() */ | ||
| 336 | smp_store_release(&alloc->vma, vma); | ||
| 337 | } | ||
| 338 | |||
| 339 | static inline struct vm_area_struct *binder_alloc_get_vma( | ||
| 340 | struct binder_alloc *alloc) | ||
| 341 | { | ||
| 342 | /* pairs with smp_store_release in binder_alloc_set_vma() */ | ||
| 343 | return smp_load_acquire(&alloc->vma); | ||
| 344 | } | ||
| 345 | |||
| 346 | static void debug_no_space_locked(struct binder_alloc *alloc) | 427 | static void debug_no_space_locked(struct binder_alloc *alloc) |
| 347 | { | 428 | { |
| 348 | size_t largest_alloc_size = 0; | 429 | size_t largest_alloc_size = 0; |
| @@ -576,7 +657,7 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, · 227 unmodified lines | |||
| 576 | int ret; | 657 | int ret; |
| 577 | 658 | ||
| 578 | /* Check binder_alloc is fully initialized */ | 659 | /* Check binder_alloc is fully initialized */ |
| 579 | if (!binder_alloc_get_vma(alloc)) { | 660 | if (!binder_alloc_is_mapped(alloc)) { |
| 580 | binder_alloc_debug(BINDER_DEBUG_USER_ERROR, | 661 | binder_alloc_debug(BINDER_DEBUG_USER_ERROR, |
| 581 | "%d: binder_alloc_buf, no vma\n", | 662 | "%d: binder_alloc_buf, no vma\n", |
| 582 | alloc->pid); | 663 | alloc->pid); |
| @@ -597,10 +678,10 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, · 14 unmodified lines | |||
| 597 | if (!next) | 678 | if (!next) |
| 598 | return ERR_PTR(-ENOMEM); | 679 | return ERR_PTR(-ENOMEM); |
| 599 | 680 | ||
| 600 | spin_lock(&alloc->lock); | 681 | mutex_lock(&alloc->mutex); |
| 601 | buffer = binder_alloc_new_buf_locked(alloc, next, size, is_async); | 682 | buffer = binder_alloc_new_buf_locked(alloc, next, size, is_async); |
| 602 | if (IS_ERR(buffer)) { | 683 | if (IS_ERR(buffer)) { |
| 603 | spin_unlock(&alloc->lock); | 684 | mutex_unlock(&alloc->mutex); |
| 604 | goto out; | 685 | goto out; |
| 605 | } | 686 | } |
| 606 | 687 | ||
| @@ -608,7 +689,7 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, · 1 unmodified line | |||
| 608 | buffer->offsets_size = offsets_size; | 689 | buffer->offsets_size = offsets_size; |
| 609 | buffer->extra_buffers_size = extra_buffers_size; | 690 | buffer->extra_buffers_size = extra_buffers_size; |
| 610 | buffer->pid = current->tgid; | 691 | buffer->pid = current->tgid; |
| 611 | spin_unlock(&alloc->lock); | 692 | mutex_unlock(&alloc->mutex); |
| 612 | 693 | ||
| 613 | ret = binder_install_buffer_pages(alloc, buffer, size); | 694 | ret = binder_install_buffer_pages(alloc, buffer, size); |
| 614 | if (ret) { | 695 | if (ret) { |
| @@ -674,8 +755,8 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, · 59 unmodified lines | |||
| 674 | BUG_ON(buffer->free); | 755 | BUG_ON(buffer->free); |
| 675 | BUG_ON(size > buffer_size); | 756 | BUG_ON(size > buffer_size); |
| 676 | BUG_ON(buffer->transaction != NULL); | 757 | BUG_ON(buffer->transaction != NULL); |
| 677 | BUG_ON(buffer->user_data < alloc->buffer); | 758 | BUG_ON(buffer->user_data < alloc->vm_start); |
| 678 | BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size); | 759 | BUG_ON(buffer->user_data > alloc->vm_start + alloc->buffer_size); |
| 679 | 760 | ||
| 680 | if (buffer->async_transaction) { | 761 | if (buffer->async_transaction) { |
| 681 | alloc->free_async_space += buffer_size; | 762 | alloc->free_async_space += buffer_size; |
| @@ -734,14 +815,13 @@ static struct page *binder_alloc_get_page(struct binder_alloc *alloc, · 52 unmodified lines | |||
| 734 | pgoff_t *pgoffp) | 815 | pgoff_t *pgoffp) |
| 735 | { | 816 | { |
| 736 | binder_size_t buffer_space_offset = buffer_offset + | 817 | binder_size_t buffer_space_offset = buffer_offset + |
| 737 | (buffer->user_data - alloc->buffer); | 818 | (buffer->user_data - alloc->vm_start); |
| 738 | pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; | 819 | pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; |
| 739 | size_t index = buffer_space_offset >> PAGE_SHIFT; | 820 | size_t index = buffer_space_offset >> PAGE_SHIFT; |
| 740 | struct binder_lru_page *lru_page; | ||
| 741 | 821 | ||
| 742 | lru_page = &alloc->pages[index]; | ||
| 743 | *pgoffp = pgoff; | 822 | *pgoffp = pgoff; |
| 744 | return lru_page->page_ptr; | 823 | |
| 824 | return alloc->pages[index]; | ||
| 745 | } | 825 | } |
| 746 | 826 | ||
| 747 | /** | 827 | /** |
| @@ -785,17 +865,17 @@ void binder_alloc_free_buf(struct binder_alloc *alloc, · 37 unmodified lines | |||
| 785 | * We could eliminate the call to binder_alloc_clear_buf() | 865 | * We could eliminate the call to binder_alloc_clear_buf() |
| 786 | * from binder_alloc_deferred_release() by moving this to | 866 | * from binder_alloc_deferred_release() by moving this to |
| 787 | * binder_free_buf_locked(). However, that could | 867 | * binder_free_buf_locked(). However, that could |
| 788 | * increase contention for the alloc->lock if clear_on_free | 868 | * increase contention for the alloc mutex if clear_on_free |
| 789 | * is used frequently for large buffers. This lock is not | 869 | * is used frequently for large buffers. The mutex is not |
| 790 | * needed for correctness here. | 870 | * needed for correctness here. |
| 791 | */ | 871 | */ |
| 792 | if (buffer->clear_on_free) { | 872 | if (buffer->clear_on_free) { |
| 793 | binder_alloc_clear_buf(alloc, buffer); | 873 | binder_alloc_clear_buf(alloc, buffer); |
| 794 | buffer->clear_on_free = false; | 874 | buffer->clear_on_free = false; |
| 795 | } | 875 | } |
| 796 | spin_lock(&alloc->lock); | 876 | mutex_lock(&alloc->mutex); |
| 797 | binder_free_buf_locked(alloc, buffer); | 877 | binder_free_buf_locked(alloc, buffer); |
| 798 | spin_unlock(&alloc->lock); | 878 | mutex_unlock(&alloc->mutex); |
| 799 | } | 879 | } |
| 800 | 880 | ||
| 801 | /** | 881 | /** |
| @@ -816,7 +896,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, · 14 unmodified lines | |||
| 816 | { | 896 | { |
| 817 | struct binder_buffer *buffer; | 897 | struct binder_buffer *buffer; |
| 818 | const char *failure_string; | 898 | const char *failure_string; |
| 819 | int ret, i; | 899 | int ret; |
| 820 | 900 | ||
| 821 | if (unlikely(vma->vm_mm != alloc->mm)) { | 901 | if (unlikely(vma->vm_mm != alloc->mm)) { |
| 822 | ret = -EINVAL; | 902 | ret = -EINVAL; |
| @@ -834,22 +914,17 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, · 11 unmodified lines | |||
| 834 | SZ_4M); | 914 | SZ_4M); |
| 835 | mutex_unlock(&binder_alloc_mmap_lock); | 915 | mutex_unlock(&binder_alloc_mmap_lock); |
| 836 | 916 | ||
| 837 | alloc->buffer = vma->vm_start; | 917 | alloc->vm_start = vma->vm_start; |
| 838 | 918 | ||
| 839 | alloc->pages = kvcalloc(alloc->buffer_size / PAGE_SIZE, | 919 | alloc->pages = kvcalloc(alloc->buffer_size / PAGE_SIZE, |
| 840 | sizeof(alloc->pages[0]), | 920 | sizeof(alloc->pages[0]), |
| 841 | GFP_KERNEL); | 921 | GFP_KERNEL); |
| 842 | if (alloc->pages == NULL) { | 922 | if (!alloc->pages) { |
| 843 | ret = -ENOMEM; | 923 | ret = -ENOMEM; |
| 844 | failure_string = "alloc page array"; | 924 | failure_string = "alloc page array"; |
| 845 | goto err_alloc_pages_failed; | 925 | goto err_alloc_pages_failed; |
| 846 | } | 926 | } |
| 847 | 927 | ||
| 848 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | ||
| 849 | alloc->pages[i].alloc = alloc; | ||
| 850 | INIT_LIST_HEAD(&alloc->pages[i].lru); | ||
| 851 | } | ||
| 852 | |||
| 853 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | 928 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| 854 | if (!buffer) { | 929 | if (!buffer) { |
| 855 | ret = -ENOMEM; | 930 | ret = -ENOMEM; |
| @@ -857,14 +932,14 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, · 1 unmodified line | |||
| 857 | goto err_alloc_buf_struct_failed; | 932 | goto err_alloc_buf_struct_failed; |
| 858 | } | 933 | } |
| 859 | 934 | ||
| 860 | buffer->user_data = alloc->buffer; | 935 | buffer->user_data = alloc->vm_start; |
| 861 | list_add(&buffer->entry, &alloc->buffers); | 936 | list_add(&buffer->entry, &alloc->buffers); |
| 862 | buffer->free = 1; | 937 | buffer->free = 1; |
| 863 | binder_insert_free_buffer(alloc, buffer); | 938 | binder_insert_free_buffer(alloc, buffer); |
| 864 | alloc->free_async_space = alloc->buffer_size / 2; | 939 | alloc->free_async_space = alloc->buffer_size / 2; |
| 865 | 940 | ||
| 866 | /* Signal binder_alloc is fully initialized */ | 941 | /* Signal binder_alloc is fully initialized */ |
| 867 | binder_alloc_set_vma(alloc, vma); | 942 | binder_alloc_set_mapped(alloc, true); |
| 868 | 943 | ||
| 869 | return 0; | 944 | return 0; |
| 870 | 945 | ||
| @@ -872,7 +947,7 @@ err_alloc_buf_struct_failed: · 1 unmodified line | |||
| 872 | kvfree(alloc->pages); | 947 | kvfree(alloc->pages); |
| 873 | alloc->pages = NULL; | 948 | alloc->pages = NULL; |
| 874 | err_alloc_pages_failed: | 949 | err_alloc_pages_failed: |
| 875 | alloc->buffer = 0; | 950 | alloc->vm_start = 0; |
| 876 | mutex_lock(&binder_alloc_mmap_lock); | 951 | mutex_lock(&binder_alloc_mmap_lock); |
| 877 | alloc->buffer_size = 0; | 952 | alloc->buffer_size = 0; |
| 878 | err_already_mapped: | 953 | err_already_mapped: |
| @@ -893,8 +968,8 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) · 14 unmodified lines | |||
| 893 | struct binder_buffer *buffer; | 968 | struct binder_buffer *buffer; |
| 894 | 969 | ||
| 895 | buffers = 0; | 970 | buffers = 0; |
| 896 | spin_lock(&alloc->lock); | 971 | mutex_lock(&alloc->mutex); |
| 897 | BUG_ON(alloc->vma); | 972 | BUG_ON(alloc->mapped); |
| 898 | 973 | ||
| 899 | while ((n = rb_first(&alloc->allocated_buffers))) { | 974 | while ((n = rb_first(&alloc->allocated_buffers))) { |
| 900 | buffer = rb_entry(n, struct binder_buffer, rb_node); | 975 | buffer = rb_entry(n, struct binder_buffer, rb_node); |
| @@ -925,22 +1000,26 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) · 24 unmodified lines | |||
| 925 | int i; | 1000 | int i; |
| 926 | 1001 | ||
| 927 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | 1002 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { |
| 1003 | struct page *page; | ||
| 928 | bool on_lru; | 1004 | bool on_lru; |
| 929 | 1005 | ||
| 930 | if (!alloc->pages[i].page_ptr) | 1006 | page = binder_get_installed_page(alloc, i); |
| 1007 | if (!page) | ||
| 931 | continue; | 1008 | continue; |
| 932 | 1009 | ||
| 933 | on_lru = list_lru_del_obj(&binder_freelist, | 1010 | on_lru = list_lru_del(&binder_freelist, |
| 934 | &alloc->pages[i].lru); | 1011 | page_to_lru(page), |
| 1012 | page_to_nid(page), | ||
| 1013 | NULL); | ||
| 935 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | 1014 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, |
| 936 | "%s: %d: page %d %s\n", | 1015 | "%s: %d: page %d %s\n", |
| 937 | __func__, alloc->pid, i, | 1016 | __func__, alloc->pid, i, |
| 938 | on_lru ? "on lru" : "active"); | 1017 | on_lru ? "on lru" : "active"); |
| 939 | __free_page(alloc->pages[i].page_ptr); | 1018 | binder_free_page(page); |
| 940 | page_count++; | 1019 | page_count++; |
| 941 | } | 1020 | } |
| 942 | } | 1021 | } |
| 943 | spin_unlock(&alloc->lock); | 1022 | mutex_unlock(&alloc->mutex); |
| 944 | kvfree(alloc->pages); | 1023 | kvfree(alloc->pages); |
| 945 | if (alloc->mm) | 1024 | if (alloc->mm) |
| 946 | mmdrop(alloc->mm); | 1025 | mmdrop(alloc->mm); |
| @@ -964,17 +1043,17 @@ void binder_alloc_print_allocated(struct seq_file *m, · 17 unmodified lines | |||
| 964 | struct binder_buffer *buffer; | 1043 | struct binder_buffer *buffer; |
| 965 | struct rb_node *n; | 1044 | struct rb_node *n; |
| 966 | 1045 | ||
| 967 | spin_lock(&alloc->lock); | 1046 | mutex_lock(&alloc->mutex); |
| 968 | for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) { | 1047 | for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) { |
| 969 | buffer = rb_entry(n, struct binder_buffer, rb_node); | 1048 | buffer = rb_entry(n, struct binder_buffer, rb_node); |
| 970 | seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n", | 1049 | seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n", |
| 971 | buffer->debug_id, | 1050 | buffer->debug_id, |
| 972 | buffer->user_data - alloc->buffer, | 1051 | buffer->user_data - alloc->vm_start, |
| 973 | buffer->data_size, buffer->offsets_size, | 1052 | buffer->data_size, buffer->offsets_size, |
| 974 | buffer->extra_buffers_size, | 1053 | buffer->extra_buffers_size, |
| 975 | buffer->transaction ? "active" : "delivered"); | 1054 | buffer->transaction ? "active" : "delivered"); |
| 976 | } | 1055 | } |
| 977 | spin_unlock(&alloc->lock); | 1056 | mutex_unlock(&alloc->mutex); |
| 978 | } | 1057 | } |
| 979 | 1058 | ||
| 980 | /** | 1059 | /** |
| @@ -985,29 +1064,29 @@ void binder_alloc_print_allocated(struct seq_file *m, · 4 unmodified lines | |||
| 985 | void binder_alloc_print_pages(struct seq_file *m, | 1064 | void binder_alloc_print_pages(struct seq_file *m, |
| 986 | struct binder_alloc *alloc) | 1065 | struct binder_alloc *alloc) |
| 987 | { | 1066 | { |
| 988 | struct binder_lru_page *page; | 1067 | struct page *page; |
| 989 | int i; | 1068 | int i; |
| 990 | int active = 0; | 1069 | int active = 0; |
| 991 | int lru = 0; | 1070 | int lru = 0; |
| 992 | int free = 0; | 1071 | int free = 0; |
| 993 | 1072 | ||
| 994 | spin_lock(&alloc->lock); | 1073 | mutex_lock(&alloc->mutex); |
| 995 | /* | 1074 | /* |
| 996 | * Make sure the binder_alloc is fully initialized, otherwise we might | 1075 | * Make sure the binder_alloc is fully initialized, otherwise we might |
| 997 | * read inconsistent state. | 1076 | * read inconsistent state. |
| 998 | */ | 1077 | */ |
| 999 | if (binder_alloc_get_vma(alloc) != NULL) { | 1078 | if (binder_alloc_is_mapped(alloc)) { |
| 1000 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | 1079 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { |
| 1001 | page = &alloc->pages[i]; | 1080 | page = binder_get_installed_page(alloc, i); |
| 1002 | if (!page->page_ptr) | 1081 | if (!page) |
| 1003 | free++; | 1082 | free++; |
| 1004 | else if (list_empty(&page->lru)) | 1083 | else if (list_empty(page_to_lru(page))) |
| 1005 | active++; | 1084 | active++; |
| 1006 | else | 1085 | else |
| 1007 | lru++; | 1086 | lru++; |
| 1008 | } | 1087 | } |
| 1009 | } | 1088 | } |
| 1010 | spin_unlock(&alloc->lock); | 1089 | mutex_unlock(&alloc->mutex); |
| 1011 | seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); | 1090 | seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); |
| 1012 | seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high); | 1091 | seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high); |
| 1013 | } | 1092 | } |
| @@ -1023,10 +1102,10 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) · 9 unmodified lines | |||
| 1023 | struct rb_node *n; | 1102 | struct rb_node *n; |
| 1024 | int count = 0; | 1103 | int count = 0; |
| 1025 | 1104 | ||
| 1026 | spin_lock(&alloc->lock); | 1105 | mutex_lock(&alloc->mutex); |
| 1027 | for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) | 1106 | for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) |
| 1028 | count++; | 1107 | count++; |
| 1029 | spin_unlock(&alloc->lock); | 1108 | mutex_unlock(&alloc->mutex); |
| 1030 | return count; | 1109 | return count; |
| 1031 | } | 1110 | } |
| 1032 | 1111 | ||
| @@ -1036,12 +1115,12 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) · 3 unmodified lines | |||
| 1036 | * @alloc: binder_alloc for this proc | 1115 | * @alloc: binder_alloc for this proc |
| 1037 | * | 1116 | * |
| 1038 | * Called from binder_vma_close() when releasing address space. | 1117 | * Called from binder_vma_close() when releasing address space. |
| 1039 | * Clears alloc->vma to prevent new incoming transactions from | 1118 | * Clears alloc->mapped to prevent new incoming transactions from |
| 1040 | * allocating more buffers. | 1119 | * allocating more buffers. |
| 1041 | */ | 1120 | */ |
| 1042 | void binder_alloc_vma_close(struct binder_alloc *alloc) | 1121 | void binder_alloc_vma_close(struct binder_alloc *alloc) |
| 1043 | { | 1122 | { |
| 1044 | binder_alloc_set_vma(alloc, NULL); | 1123 | binder_alloc_set_mapped(alloc, false); |
| 1045 | } | 1124 | } |
| 1046 | 1125 | ||
| 1047 | /** | 1126 | /** |
| @@ -1058,39 +1137,50 @@ enum lru_status binder_alloc_free_page(struct list_head *item, · 10 unmodified lines | |||
| 1058 | void *cb_arg) | 1137 | void *cb_arg) |
| 1059 | __must_hold(&lru->lock) | 1138 | __must_hold(&lru->lock) |
| 1060 | { | 1139 | { |
| 1061 | struct binder_lru_page *page = container_of(item, typeof(*page), lru); | 1140 | struct binder_shrinker_mdata *mdata = container_of(item, typeof(*mdata), lru); |
| 1062 | struct binder_alloc *alloc = page->alloc; | 1141 | struct binder_alloc *alloc = mdata->alloc; |
| 1063 | struct mm_struct *mm = alloc->mm; | 1142 | struct mm_struct *mm = alloc->mm; |
| 1064 | struct vm_area_struct *vma; | 1143 | struct vm_area_struct *vma; |
| 1065 | struct page *page_to_free; | 1144 | struct page *page_to_free; |
| 1066 | unsigned long page_addr; | 1145 | unsigned long page_addr; |
| 1146 | int mm_locked = 0; | ||
| 1067 | size_t index; | 1147 | size_t index; |
| 1068 | 1148 | ||
| 1069 | if (!mmget_not_zero(mm)) | 1149 | if (!mmget_not_zero(mm)) |
| 1070 | goto err_mmget; | 1150 | goto err_mmget; |
| 1071 | if (!mmap_read_trylock(mm)) | 1151 | |
| 1072 | goto err_mmap_read_lock_failed; | 1152 | index = mdata->page_index; |
| 1073 | if (!spin_trylock(&alloc->lock)) | 1153 | page_addr = alloc->vm_start + index * PAGE_SIZE; |
| 1074 | goto err_get_alloc_lock_failed; | 1154 | |
| 1075 | if (!page->page_ptr) | 1155 | /* attempt per-vma lock first */ |
| 1076 | goto err_page_already_freed; | 1156 | vma = lock_vma_under_rcu(mm, page_addr); |
| 1077 | 1157 | if (!vma) { | |
| 1078 | index = page - alloc->pages; | 1158 | /* fall back to mmap_lock */ |
| 1079 | page_addr = alloc->buffer + index * PAGE_SIZE; | 1159 | if (!mmap_read_trylock(mm)) |
| 1080 | 1160 | goto err_mmap_read_lock_failed; | |
| 1081 | vma = vma_lookup(mm, page_addr); | 1161 | mm_locked = 1; |
| 1082 | if (vma && vma != binder_alloc_get_vma(alloc)) | 1162 | vma = vma_lookup(mm, page_addr); |
| 1163 | } | ||
| 1164 | |||
| 1165 | if (!mutex_trylock(&alloc->mutex)) | ||
| 1166 | goto err_get_alloc_mutex_failed; | ||
| 1167 | |||
| 1168 | /* | ||
| 1169 | * Since a binder_alloc can only be mapped once, we ensure | ||
| 1170 | * the vma corresponds to this mapping by checking whether | ||
| 1171 | * the binder_alloc is still mapped. | ||
| 1172 | */ | ||
| 1173 | if (vma && !binder_alloc_is_mapped(alloc)) | ||
| 1083 | goto err_invalid_vma; | 1174 | goto err_invalid_vma; |
| 1084 | 1175 | ||
| 1085 | trace_binder_unmap_kernel_start(alloc, index); | 1176 | trace_binder_unmap_kernel_start(alloc, index); |
| 1086 | 1177 | ||
| 1087 | page_to_free = page->page_ptr; | 1178 | page_to_free = alloc->pages[index]; |
| 1088 | page->page_ptr = NULL; | 1179 | binder_set_installed_page(alloc, index, NULL); |
| 1089 | 1180 | ||
| 1090 | trace_binder_unmap_kernel_end(alloc, index); | 1181 | trace_binder_unmap_kernel_end(alloc, index); |
| 1091 | 1182 | ||
| 1092 | list_lru_isolate(lru, item); | 1183 | list_lru_isolate(lru, item); |
| 1093 | spin_unlock(&alloc->lock); | ||
| 1094 | spin_unlock(&lru->lock); | 1184 | spin_unlock(&lru->lock); |
| 1095 | 1185 | ||
| 1096 | if (vma) { | 1186 | if (vma) { |
| @@ -1101,17 +1191,23 @@ enum lru_status binder_alloc_free_page(struct list_head *item, · 4 unmodified lines | |||
| 1101 | trace_binder_unmap_user_end(alloc, index); | 1191 | trace_binder_unmap_user_end(alloc, index); |
| 1102 | } | 1192 | } |
| 1103 | 1193 | ||
| 1104 | mmap_read_unlock(mm); | 1194 | mutex_unlock(&alloc->mutex); |
| 1195 | if (mm_locked) | ||
| 1196 | mmap_read_unlock(mm); | ||
| 1197 | else | ||
| 1198 | vma_end_read(vma); | ||
| 1105 | mmput_async(mm); | 1199 | mmput_async(mm); |
| 1106 | __free_page(page_to_free); | 1200 | binder_free_page(page_to_free); |
| 1107 | 1201 | ||
| 1108 | return LRU_REMOVED_RETRY; | 1202 | return LRU_REMOVED_RETRY; |
| 1109 | 1203 | ||
| 1110 | err_invalid_vma: | 1204 | err_invalid_vma: |
| 1111 | err_page_already_freed: | 1205 | mutex_unlock(&alloc->mutex); |
| 1112 | spin_unlock(&alloc->lock); | 1206 | err_get_alloc_mutex_failed: |
| 1113 | err_get_alloc_lock_failed: | 1207 | if (mm_locked) |
| 1114 | mmap_read_unlock(mm); | 1208 | mmap_read_unlock(mm); |
| 1209 | else | ||
| 1210 | vma_end_read(vma); | ||
| 1115 | err_mmap_read_lock_failed: | 1211 | err_mmap_read_lock_failed: |
| 1116 | mmput_async(mm); | 1212 | mmput_async(mm); |
| 1117 | err_mmget: | 1213 | err_mmget: |
| @@ -1145,7 +1241,7 @@ void binder_alloc_init(struct binder_alloc *alloc) · 27 unmodified lines | |||
| 1145 | alloc->pid = current->group_leader->pid; | 1241 | alloc->pid = current->group_leader->pid; |
| 1146 | alloc->mm = current->mm; | 1242 | alloc->mm = current->mm; |
| 1147 | mmgrab(alloc->mm); | 1243 | mmgrab(alloc->mm); |
| 1148 | spin_lock_init(&alloc->lock); | 1244 | mutex_init(&alloc->mutex); |
| 1149 | INIT_LIST_HEAD(&alloc->buffers); | 1245 | INIT_LIST_HEAD(&alloc->buffers); |
| 1150 | } | 1246 | } |
| 1151 | 1247 | ||
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/rbtree.h> | 9 | #include <linux/rbtree.h> |
| 10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
| 11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 12 | #include <linux/spinlock.h> | 12 | #include <linux/rtmutex.h> |
| 13 | #include <linux/vmalloc.h> | 13 | #include <linux/vmalloc.h> |
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/list_lru.h> | 15 | #include <linux/list_lru.h> |
| @@ -59,34 +59,43 @@ struct binder_buffer { · 43 unmodified lines | |||
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | /** | 61 | /** |
| 62 | * struct binder_lru_page - page object used for binder shrinker | 62 | * struct binder_shrinker_mdata - binder metadata used to reclaim pages |
| 63 | * @page_ptr: pointer to physical page in mmap'd space | 63 | * @lru: LRU entry in binder_freelist |
| 64 | * @lru: entry in binder_freelist | 64 | * @alloc: binder_alloc owning the page to reclaim |
| 65 | * @alloc: binder_alloc for a proc | 65 | * @page_index: offset in @alloc->pages[] into the page to reclaim |
| 66 | */ | 66 | */ |
| 67 | struct binder_lru_page { | 67 | struct binder_shrinker_mdata { |
| 68 | struct list_head lru; | 68 | struct list_head lru; |
| 69 | struct page *page_ptr; | ||
| 70 | struct binder_alloc *alloc; | 69 | struct binder_alloc *alloc; |
| 70 | unsigned long page_index; | ||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static inline struct list_head *page_to_lru(struct page *p) | ||
| 74 | { | ||
| 75 | struct binder_shrinker_mdata *mdata; | ||
| 76 | |||
| 77 | mdata = (struct binder_shrinker_mdata *)page_private(p); | ||
| 78 | |||
| 79 | return &mdata->lru; | ||
| 80 | } | ||
| 81 | |||
| 73 | /** | 82 | /** |
| 74 | * struct binder_alloc - per-binder proc state for binder allocator | 83 | * struct binder_alloc - per-binder proc state for binder allocator |
| 75 | * @lock: protects binder_alloc fields | 84 | * @mutex: protects binder_alloc fields |
| 76 | * @vma: vm_area_struct passed to mmap_handler | ||
| 77 | * (invariant after mmap) | ||
| 78 | * @mm: copy of task->mm (invariant after open) | 85 | * @mm: copy of task->mm (invariant after open) |
| 79 | * @buffer: base of per-proc address space mapped via mmap | 86 | * @vm_start: base of per-proc address space mapped via mmap |
| 80 | * @buffers: list of all buffers for this proc | 87 | * @buffers: list of all buffers for this proc |
| 81 | * @free_buffers: rb tree of buffers available for allocation | 88 | * @free_buffers: rb tree of buffers available for allocation |
| 82 | * sorted by size | 89 | * sorted by size |
| 83 | * @allocated_buffers: rb tree of allocated buffers sorted by address | 90 | * @allocated_buffers: rb tree of allocated buffers sorted by address |
| 84 | * @free_async_space: VA space available for async buffers. This is | 91 | * @free_async_space: VA space available for async buffers. This is |
| 85 | * initialized at mmap time to 1/2 the full VA space | 92 | * initialized at mmap time to 1/2 the full VA space |
| 86 | * @pages: array of binder_lru_page | 93 | * @pages: array of struct page * |
| 87 | * @buffer_size: size of address space specified via mmap | 94 | * @buffer_size: size of address space specified via mmap |
| 88 | * @pid: pid for associated binder_proc (invariant after init) | 95 | * @pid: pid for associated binder_proc (invariant after init) |
| 89 | * @pages_high: high watermark of offset in @pages | 96 | * @pages_high: high watermark of offset in @pages |
| 97 | * @mapped: whether the vm area is mapped, each binder instance is | ||
| 98 | * allowed a single mapping throughout its lifetime | ||
| 90 | * @oneway_spam_detected: %true if oneway spam detection fired, clear that | 99 | * @oneway_spam_detected: %true if oneway spam detection fired, clear that |
| 91 | * flag once the async buffer has returned to a healthy state | 100 | * flag once the async buffer has returned to a healthy state |
| 92 | * | 101 | * |
| @@ -96,18 +105,18 @@ struct binder_lru_page { · 3 unmodified lines | |||
| 96 | * struct binder_buffer objects used to track the user buffers | 105 | * struct binder_buffer objects used to track the user buffers |
| 97 | */ | 106 | */ |
| 98 | struct binder_alloc { | 107 | struct binder_alloc { |
| 99 | spinlock_t lock; | 108 | struct mutex mutex; |
| 100 | struct vm_area_struct *vma; | ||
| 101 | struct mm_struct *mm; | 109 | struct mm_struct *mm; |
| 102 | unsigned long buffer; | 110 | unsigned long vm_start; |
| 103 | struct list_head buffers; | 111 | struct list_head buffers; |
| 104 | struct rb_root free_buffers; | 112 | struct rb_root free_buffers; |
| 105 | struct rb_root allocated_buffers; | 113 | struct rb_root allocated_buffers; |
| 106 | size_t free_async_space; | 114 | size_t free_async_space; |
| 107 | struct binder_lru_page *pages; | 115 | struct page **pages; |
| 108 | size_t buffer_size; | 116 | size_t buffer_size; |
| 109 | int pid; | 117 | int pid; |
| 110 | size_t pages_high; | 118 | size_t pages_high; |
| 119 | bool mapped; | ||
| 111 | bool oneway_spam_detected; | 120 | bool oneway_spam_detected; |
| 112 | }; | 121 | }; |
| 113 | 122 | ||
| @@ -153,9 +162,9 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc) · 39 unmodified lines | |||
| 153 | { | 162 | { |
| 154 | size_t free_async_space; | 163 | size_t free_async_space; |
| 155 | 164 | ||
| 156 | spin_lock(&alloc->lock); | 165 | mutex_lock(&alloc->mutex); |
| 157 | free_async_space = alloc->free_async_space; | 166 | free_async_space = alloc->free_async_space; |
| 158 | spin_unlock(&alloc->lock); | 167 | mutex_unlock(&alloc->mutex); |
| 159 | return free_async_space; | 168 | return free_async_space; |
| 160 | } | 169 | } |
| 161 | 170 | ||
| @@ -104,11 +104,11 @@ static bool check_buffer_pages_allocated(struct binder_alloc *alloc, · 103 unmodified lines | |||
| 104 | end = PAGE_ALIGN(buffer->user_data + size); | 104 | end = PAGE_ALIGN(buffer->user_data + size); |
| 105 | page_addr = buffer->user_data; | 105 | page_addr = buffer->user_data; |
| 106 | for (; page_addr < end; page_addr += PAGE_SIZE) { | 106 | for (; page_addr < end; page_addr += PAGE_SIZE) { |
| 107 | page_index = (page_addr - alloc->buffer) / PAGE_SIZE; | 107 | page_index = (page_addr - alloc->vm_start) / PAGE_SIZE; |
| 108 | if (!alloc->pages[page_index].page_ptr || | 108 | if (!alloc->pages[page_index] || |
| 109 | !list_empty(&alloc->pages[page_index].lru)) { | 109 | !list_empty(page_to_lru(alloc->pages[page_index]))) { |
| 110 | pr_err("expect alloc but is %s at page index %d\n", | 110 | pr_err("expect alloc but is %s at page index %d\n", |
| 111 | alloc->pages[page_index].page_ptr ? | 111 | alloc->pages[page_index] ? |
| 112 | "lru" : "free", page_index); | 112 | "lru" : "free", page_index); |
| 113 | return false; | 113 | return false; |
| 114 | } | 114 | } |
| @@ -148,10 +148,10 @@ static void binder_selftest_free_buf(struct binder_alloc *alloc, · 33 unmodified lines | |||
| 148 | * if binder shrinker ran during binder_alloc_free_buf | 148 | * if binder shrinker ran during binder_alloc_free_buf |
| 149 | * calls above. | 149 | * calls above. |
| 150 | */ | 150 | */ |
| 151 | if (list_empty(&alloc->pages[i].lru)) { | 151 | if (list_empty(page_to_lru(alloc->pages[i]))) { |
| 152 | pr_err_size_seq(sizes, seq); | 152 | pr_err_size_seq(sizes, seq); |
| 153 | pr_err("expect lru but is %s at page index %d\n", | 153 | pr_err("expect lru but is %s at page index %d\n", |
| 154 | alloc->pages[i].page_ptr ? "alloc" : "free", i); | 154 | alloc->pages[i] ? "alloc" : "free", i); |
| 155 | binder_selftest_failures++; | 155 | binder_selftest_failures++; |
| 156 | } | 156 | } |
| 157 | } | 157 | } |
| @@ -168,9 +168,9 @@ static void binder_selftest_free_page(struct binder_alloc *alloc) · 10 unmodified lines | |||
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { | 170 | for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { |
| 171 | if (alloc->pages[i].page_ptr) { | 171 | if (alloc->pages[i]) { |
| 172 | pr_err("expect free but is %s at page index %d\n", | 172 | pr_err("expect free but is %s at page index %d\n", |
| 173 | list_empty(&alloc->pages[i].lru) ? | 173 | list_empty(page_to_lru(alloc->pages[i])) ? |
| 174 | "alloc" : "lru", i); | 174 | "alloc" : "lru", i); |
| 175 | binder_selftest_failures++; | 175 | binder_selftest_failures++; |
| 176 | } | 176 | } |
| @@ -291,7 +291,7 @@ void binder_selftest_alloc(struct binder_alloc *alloc) · 114 unmodified lines | |||
| 291 | if (!binder_selftest_run) | 291 | if (!binder_selftest_run) |
| 292 | return; | 292 | return; |
| 293 | mutex_lock(&binder_selftest_lock); | 293 | mutex_lock(&binder_selftest_lock); |
| 294 | if (!binder_selftest_run || !alloc->vma) | 294 | if (!binder_selftest_run || !alloc->mapped) |
| 295 | goto done; | 295 | goto done; |
| 296 | pr_info("STARTED\n"); | 296 | pr_info("STARTED\n"); |
| 297 | binder_selftest_alloc_offset(alloc, end_offset, 0); | 297 | binder_selftest_alloc_offset(alloc, end_offset, 0); |
| @@ -25,8 +25,7 @@ struct binder_context { · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * struct binder_device - information about a binder device node | 27 | * struct binder_device - information about a binder device node |
| 28 | * @hlist: list of binder devices (only used for devices requested via | 28 | * @hlist: list of binder devices |
| 29 | * CONFIG_ANDROID_BINDER_DEVICES) | ||
| 30 | * @miscdev: information about a binder character device node | 29 | * @miscdev: information about a binder character device node |
| 31 | * @context: binder context information | 30 | * @context: binder context information |
| 32 | * @binderfs_inode: This is the inode of the root dentry of the super block | 31 | * @binderfs_inode: This is the inode of the root dentry of the super block |
| @@ -582,4 +581,12 @@ struct binder_object { · 549 unmodified lines | |||
| 582 | }; | 581 | }; |
| 583 | }; | 582 | }; |
| 584 | 583 | ||
| 584 | /** | ||
| 585 | * Add a binder device to binder_devices | ||
| 586 | * @device: the new binder device to add to the global list | ||
| 587 | * | ||
| 588 | * Not reentrant as the list is not protected by any locks | ||
| 589 | */ | ||
| 590 | void binder_add_device(struct binder_device *device); | ||
| 591 | |||
| 585 | #endif /* _LINUX_BINDER_INTERNAL_H */ | 592 | #endif /* _LINUX_BINDER_INTERNAL_H */ |
| @@ -328,7 +328,7 @@ TRACE_EVENT(binder_update_page_range, · 327 unmodified lines | |||
| 328 | TP_fast_assign( | 328 | TP_fast_assign( |
| 329 | __entry->proc = alloc->pid; | 329 | __entry->proc = alloc->pid; |
| 330 | __entry->allocate = allocate; | 330 | __entry->allocate = allocate; |
| 331 | __entry->offset = start - alloc->buffer; | 331 | __entry->offset = start - alloc->vm_start; |
| 332 | __entry->size = end - start; | 332 | __entry->size = end - start; |
| 333 | ), | 333 | ), |
| 334 | TP_printk("proc=%d allocate=%d offset=%zu size=%zu", | 334 | TP_printk("proc=%d allocate=%d offset=%zu size=%zu", |
| @@ -207,6 +207,8 @@ static int binderfs_binder_device_create(struct inode *ref_inode, · 206 unmodified lines | |||
| 207 | fsnotify_create(root->d_inode, dentry); | 207 | fsnotify_create(root->d_inode, dentry); |
| 208 | inode_unlock(d_inode(root)); | 208 | inode_unlock(d_inode(root)); |
| 209 | 209 | ||
| 210 | binder_add_device(device); | ||
| 211 | |||
| 210 | return 0; | 212 | return 0; |
| 211 | 213 | ||
| 212 | err: | 214 | err: |
| @@ -357,6 +357,7 @@ error_alloc_segment: · 356 unmodified lines | |||
| 357 | for (--i, --mhi_buf; i >= 0; i--, mhi_buf--) | 357 | for (--i, --mhi_buf; i >= 0; i--, mhi_buf--) |
| 358 | dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, | 358 | dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, |
| 359 | mhi_buf->buf, mhi_buf->dma_addr); | 359 | mhi_buf->buf, mhi_buf->dma_addr); |
| 360 | kfree(img_info->mhi_buf); | ||
| 360 | 361 | ||
| 361 | error_alloc_mhi_buf: | 362 | error_alloc_mhi_buf: |
| 362 | kfree(img_info); | 363 | kfree(img_info); |
| @@ -245,6 +245,58 @@ struct mhi_pci_dev_info { · 244 unmodified lines | |||
| 245 | .channel = ch_num, \ | 245 | .channel = ch_num, \ |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | static const struct mhi_channel_config mhi_qcom_qdu100_channels[] = { | ||
| 249 | MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 2), | ||
| 250 | MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 2), | ||
| 251 | MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 128, 1), | ||
| 252 | MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 128, 1), | ||
| 253 | MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 3), | ||
| 254 | MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 3), | ||
| 255 | MHI_CHANNEL_CONFIG_UL(9, "QDSS", 64, 3), | ||
| 256 | MHI_CHANNEL_CONFIG_UL(14, "NMEA", 32, 4), | ||
| 257 | MHI_CHANNEL_CONFIG_DL(15, "NMEA", 32, 4), | ||
| 258 | MHI_CHANNEL_CONFIG_UL(16, "CSM_CTRL", 32, 4), | ||
| 259 | MHI_CHANNEL_CONFIG_DL(17, "CSM_CTRL", 32, 4), | ||
| 260 | MHI_CHANNEL_CONFIG_UL(40, "MHI_PHC", 32, 4), | ||
| 261 | MHI_CHANNEL_CONFIG_DL(41, "MHI_PHC", 32, 4), | ||
| 262 | MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 256, 5), | ||
| 263 | MHI_CHANNEL_CONFIG_DL(47, "IP_SW0", 256, 5), | ||
| 264 | }; | ||
| 265 | |||
| 266 | static struct mhi_event_config mhi_qcom_qdu100_events[] = { | ||
| 267 | /* first ring is control+data ring */ | ||
| 268 | MHI_EVENT_CONFIG_CTRL(0, 64), | ||
| 269 | /* SAHARA dedicated event ring */ | ||
| 270 | MHI_EVENT_CONFIG_SW_DATA(1, 256), | ||
| 271 | /* Software channels dedicated event ring */ | ||
| 272 | MHI_EVENT_CONFIG_SW_DATA(2, 64), | ||
| 273 | MHI_EVENT_CONFIG_SW_DATA(3, 256), | ||
| 274 | MHI_EVENT_CONFIG_SW_DATA(4, 256), | ||
| 275 | /* Software IP channels dedicated event ring */ | ||
| 276 | MHI_EVENT_CONFIG_SW_DATA(5, 512), | ||
| 277 | MHI_EVENT_CONFIG_SW_DATA(6, 512), | ||
| 278 | MHI_EVENT_CONFIG_SW_DATA(7, 512), | ||
| 279 | }; | ||
| 280 | |||
| 281 | static const struct mhi_controller_config mhi_qcom_qdu100_config = { | ||
| 282 | .max_channels = 128, | ||
| 283 | .timeout_ms = 120000, | ||
| 284 | .num_channels = ARRAY_SIZE(mhi_qcom_qdu100_channels), | ||
| 285 | .ch_cfg = mhi_qcom_qdu100_channels, | ||
| 286 | .num_events = ARRAY_SIZE(mhi_qcom_qdu100_events), | ||
| 287 | .event_cfg = mhi_qcom_qdu100_events, | ||
| 288 | }; | ||
| 289 | |||
| 290 | static const struct mhi_pci_dev_info mhi_qcom_qdu100_info = { | ||
| 291 | .name = "qcom-qdu100", | ||
| 292 | .fw = "qcom/qdu100/xbl_s.melf", | ||
| 293 | .edl_trigger = true, | ||
| 294 | .config = &mhi_qcom_qdu100_config, | ||
| 295 | .bar_num = MHI_PCI_DEFAULT_BAR_NUM, | ||
| 296 | .dma_data_width = 32, | ||
| 297 | .sideband_wake = false, | ||
| 298 | }; | ||
| 299 | |||
| 248 | static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { | 300 | static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { |
| 249 | MHI_CHANNEL_CONFIG_UL(4, "DIAG", 16, 1), | 301 | MHI_CHANNEL_CONFIG_UL(4, "DIAG", 16, 1), |
| 250 | MHI_CHANNEL_CONFIG_DL(5, "DIAG", 16, 1), | 302 | MHI_CHANNEL_CONFIG_DL(5, "DIAG", 16, 1), |
| @@ -742,6 +794,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { · 491 unmodified lines | |||
| 742 | .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, | 794 | .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, |
| 743 | { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309), | 795 | { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309), |
| 744 | .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info }, | 796 | .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info }, |
| 797 | /* QDU100, x100-DU */ | ||
| 798 | { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0601), | ||
| 799 | .driver_data = (kernel_ulong_t) &mhi_qcom_qdu100_info }, | ||
| 745 | { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ | 800 | { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ |
| 746 | .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, | 801 | .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, |
| 747 | { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ | 802 | { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ |
| @@ -949,7 +1004,7 @@ static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl, · 201 unmodified lines | |||
| 949 | */ | 1004 | */ |
| 950 | mhi_cntrl->nr_irqs = 1 + mhi_cntrl_config->num_events; | 1005 | mhi_cntrl->nr_irqs = 1 + mhi_cntrl_config->num_events; |
| 951 | 1006 | ||
| 952 | nr_vectors = pci_alloc_irq_vectors(pdev, 1, mhi_cntrl->nr_irqs, PCI_IRQ_MSI); | 1007 | nr_vectors = pci_alloc_irq_vectors(pdev, 1, mhi_cntrl->nr_irqs, PCI_IRQ_MSIX | PCI_IRQ_MSI); |
| 953 | if (nr_vectors < 0) { | 1008 | if (nr_vectors < 0) { |
| 954 | dev_err(&pdev->dev, "Error allocating MSI vectors %d\n", | 1009 | dev_err(&pdev->dev, "Error allocating MSI vectors %d\n", |
| 955 | nr_vectors); | 1010 | nr_vectors); |
| @@ -338,7 +338,10 @@ static void cdx_shutdown(struct device *dev) · 337 unmodified lines | |||
| 338 | { | 338 | { |
| 339 | struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); | 339 | struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); |
| 340 | struct cdx_device *cdx_dev = to_cdx_device(dev); | 340 | struct cdx_device *cdx_dev = to_cdx_device(dev); |
| 341 | struct cdx_controller *cdx = cdx_dev->cdx; | ||
| 341 | 342 | ||
| 343 | if (cdx_dev->is_bus && cdx_dev->enabled && cdx->ops->bus_disable) | ||
| 344 | cdx->ops->bus_disable(cdx, cdx_dev->bus_num); | ||
| 342 | if (cdx_drv && cdx_drv->shutdown) | 345 | if (cdx_drv && cdx_drv->shutdown) |
| 343 | cdx_drv->shutdown(cdx_dev); | 346 | cdx_drv->shutdown(cdx_dev); |
| 344 | } | 347 | } |
| @@ -63,16 +63,30 @@ static DEFINE_MUTEX(misc_mtx); · 62 unmodified lines | |||
| 63 | #define DYNAMIC_MINORS 128 /* like dynamic majors */ | 63 | #define DYNAMIC_MINORS 128 /* like dynamic majors */ |
| 64 | static DEFINE_IDA(misc_minors_ida); | 64 | static DEFINE_IDA(misc_minors_ida); |
| 65 | 65 | ||
| 66 | static int misc_minor_alloc(void) | 66 | static int misc_minor_alloc(int minor) |
| 67 | { | 67 | { |
| 68 | int ret; | 68 | int ret = 0; |
| 69 | 69 | ||
| 70 | ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL); | 70 | if (minor == MISC_DYNAMIC_MINOR) { |
| 71 | if (ret >= 0) { | 71 | /* allocate free id */ |
| 72 | ret = DYNAMIC_MINORS - ret - 1; | 72 | ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL); |
| 73 | if (ret >= 0) { | ||
| 74 | ret = DYNAMIC_MINORS - ret - 1; | ||
| 75 | } else { | ||
| 76 | ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1, | ||
| 77 | MINORMASK, GFP_KERNEL); | ||
| 78 | } | ||
| 73 | } else { | 79 | } else { |
| 74 | ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1, | 80 | /* specific minor, check if it is in dynamic or misc dynamic range */ |
| 75 | MINORMASK, GFP_KERNEL); | 81 | if (minor < DYNAMIC_MINORS) { |
| 82 | minor = DYNAMIC_MINORS - minor - 1; | ||
| 83 | ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL); | ||
| 84 | } else if (minor > MISC_DYNAMIC_MINOR) { | ||
| 85 | ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL); | ||
| 86 | } else { | ||
| 87 | /* case of non-dynamic minors, no need to allocate id */ | ||
| 88 | ret = 0; | ||
| 89 | } | ||
| 76 | } | 90 | } |
| 77 | return ret; | 91 | return ret; |
| 78 | } | 92 | } |
| @@ -219,7 +233,7 @@ int misc_register(struct miscdevice *misc) · 140 unmodified lines | |||
| 219 | mutex_lock(&misc_mtx); | 233 | mutex_lock(&misc_mtx); |
| 220 | 234 | ||
| 221 | if (is_dynamic) { | 235 | if (is_dynamic) { |
| 222 | int i = misc_minor_alloc(); | 236 | int i = misc_minor_alloc(misc->minor); |
| 223 | 237 | ||
| 224 | if (i < 0) { | 238 | if (i < 0) { |
| 225 | err = -EBUSY; | 239 | err = -EBUSY; |
| @@ -228,6 +242,7 @@ int misc_register(struct miscdevice *misc) · 2 unmodified lines | |||
| 228 | misc->minor = i; | 242 | misc->minor = i; |
| 229 | } else { | 243 | } else { |
| 230 | struct miscdevice *c; | 244 | struct miscdevice *c; |
| 245 | int i; | ||
| 231 | 246 | ||
| 232 | list_for_each_entry(c, &misc_list, list) { | 247 | list_for_each_entry(c, &misc_list, list) { |
| 233 | if (c->minor == misc->minor) { | 248 | if (c->minor == misc->minor) { |
| @@ -235,6 +250,12 @@ int misc_register(struct miscdevice *misc) · 1 unmodified line | |||
| 235 | goto out; | 250 | goto out; |
| 236 | } | 251 | } |
| 237 | } | 252 | } |
| 253 | |||
| 254 | i = misc_minor_alloc(misc->minor); | ||
| 255 | if (i < 0) { | ||
| 256 | err = -EBUSY; | ||
| 257 | goto out; | ||
| 258 | } | ||
| 238 | } | 259 | } |
| 239 | 260 | ||
| 240 | dev = MKDEV(MISC_MAJOR, misc->minor); | 261 | dev = MKDEV(MISC_MAJOR, misc->minor); |
| @@ -883,9 +883,9 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, · 882 unmodified lines | |||
| 883 | if (len + offset > PAGE_SIZE) | 883 | if (len + offset > PAGE_SIZE) |
| 884 | len = PAGE_SIZE - offset; | 884 | len = PAGE_SIZE - offset; |
| 885 | 885 | ||
| 886 | src = kmap_atomic(buf->page); | 886 | src = kmap_local_page(buf->page); |
| 887 | memcpy(page_address(page) + offset, src + buf->offset, len); | 887 | memcpy(page_address(page) + offset, src + buf->offset, len); |
| 888 | kunmap_atomic(src); | 888 | kunmap_local(src); |
| 889 | 889 | ||
| 890 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); | 890 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); |
| 891 | } | 891 | } |
| @@ -350,7 +350,7 @@ static const struct dev_pm_ops fsa9480_pm_ops = { · 349 unmodified lines | |||
| 350 | }; | 350 | }; |
| 351 | 351 | ||
| 352 | static const struct i2c_device_id fsa9480_id[] = { | 352 | static const struct i2c_device_id fsa9480_id[] = { |
| 353 | { "fsa9480", 0 }, | 353 | { "fsa9480" }, |
| 354 | {} | 354 | {} |
| 355 | }; | 355 | }; |
| 356 | MODULE_DEVICE_TABLE(i2c, fsa9480_id); | 356 | MODULE_DEVICE_TABLE(i2c, fsa9480_id); |
| @@ -338,7 +338,7 @@ static const struct of_device_id ptn5150_dt_match[] = { · 337 unmodified lines | |||
| 338 | MODULE_DEVICE_TABLE(of, ptn5150_dt_match); | 338 | MODULE_DEVICE_TABLE(of, ptn5150_dt_match); |
| 339 | 339 | ||
| 340 | static const struct i2c_device_id ptn5150_i2c_id[] = { | 340 | static const struct i2c_device_id ptn5150_i2c_id[] = { |
| 341 | { "ptn5150", 0 }, | 341 | { "ptn5150" }, |
| 342 | { } | 342 | { } |
| 343 | }; | 343 | }; |
| 344 | MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id); | 344 | MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id); |
| @@ -1369,6 +1369,8 @@ static int extcon_rtk_type_c_probe(struct platform_device *pdev) · 1368 unmodified lines | |||
| 1369 | } | 1369 | } |
| 1370 | 1370 | ||
| 1371 | type_c->type_c_cfg = devm_kzalloc(dev, sizeof(*type_c_cfg), GFP_KERNEL); | 1371 | type_c->type_c_cfg = devm_kzalloc(dev, sizeof(*type_c_cfg), GFP_KERNEL); |
| 1372 | if (!type_c->type_c_cfg) | ||
| 1373 | return -ENOMEM; | ||
| 1372 | 1374 | ||
| 1373 | memcpy(type_c->type_c_cfg, type_c_cfg, sizeof(*type_c_cfg)); | 1375 | memcpy(type_c->type_c_cfg, type_c_cfg, sizeof(*type_c_cfg)); |
| 1374 | 1376 | ||
| @@ -967,18 +967,15 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg) · 966 unmodified lines | |||
| 967 | /* first client will create kernel thread */ | 967 | /* first client will create kernel thread */ |
| 968 | if (!chan->ctrl->task) { | 968 | if (!chan->ctrl->task) { |
| 969 | chan->ctrl->task = | 969 | chan->ctrl->task = |
| 970 | kthread_create_on_node(svc_normal_to_secure_thread, | 970 | kthread_run_on_cpu(svc_normal_to_secure_thread, |
| 971 | (void *)chan->ctrl, | 971 | (void *)chan->ctrl, |
| 972 | cpu_to_node(cpu), | 972 | cpu, "svc_smc_hvc_thread"); |
| 973 | "svc_smc_hvc_thread"); | ||
| 974 | if (IS_ERR(chan->ctrl->task)) { | 973 | if (IS_ERR(chan->ctrl->task)) { |
| 975 | dev_err(chan->ctrl->dev, | 974 | dev_err(chan->ctrl->dev, |
| 976 | "failed to create svc_smc_hvc_thread\n"); | 975 | "failed to create svc_smc_hvc_thread\n"); |
| 977 | kfree(p_data); | 976 | kfree(p_data); |
| 978 | return -EINVAL; | 977 | return -EINVAL; |
| 979 | } | 978 | } |
| 980 | kthread_bind(chan->ctrl->task, cpu); | ||
| 981 | wake_up_process(chan->ctrl->task); | ||
| 982 | } | 979 | } |
| 983 | 980 | ||
| 984 | pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__, | 981 | pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__, |
| @@ -16,26 +16,26 @@ · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | #include "dfl-afu.h" | 17 | #include "dfl-afu.h" |
| 18 | 18 | ||
| 19 | void afu_dma_region_init(struct dfl_feature_platform_data *pdata) | 19 | void afu_dma_region_init(struct dfl_feature_dev_data *fdata) |
| 20 | { | 20 | { |
| 21 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 21 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 22 | 22 | ||
| 23 | afu->dma_regions = RB_ROOT; | 23 | afu->dma_regions = RB_ROOT; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * afu_dma_pin_pages - pin pages of given dma memory region | 27 | * afu_dma_pin_pages - pin pages of given dma memory region |
| 28 | * @pdata: feature device platform data | 28 | * @fdata: feature dev data |
| 29 | * @region: dma memory region to be pinned | 29 | * @region: dma memory region to be pinned |
| 30 | * | 30 | * |
| 31 | * Pin all the pages of given dfl_afu_dma_region. | 31 | * Pin all the pages of given dfl_afu_dma_region. |
| 32 | * Return 0 for success or negative error code. | 32 | * Return 0 for success or negative error code. |
| 33 | */ | 33 | */ |
| 34 | static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata, | 34 | static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata, |
| 35 | struct dfl_afu_dma_region *region) | 35 | struct dfl_afu_dma_region *region) |
| 36 | { | 36 | { |
| 37 | int npages = region->length >> PAGE_SHIFT; | 37 | int npages = region->length >> PAGE_SHIFT; |
| 38 | struct device *dev = &pdata->dev->dev; | 38 | struct device *dev = &fdata->dev->dev; |
| 39 | int ret, pinned; | 39 | int ret, pinned; |
| 40 | 40 | ||
| 41 | ret = account_locked_vm(current->mm, npages, true); | 41 | ret = account_locked_vm(current->mm, npages, true); |
| @@ -73,17 +73,17 @@ unlock_vm: · 31 unmodified lines | |||
| 73 | 73 | ||
| 74 | /** | 74 | /** |
| 75 | * afu_dma_unpin_pages - unpin pages of given dma memory region | 75 | * afu_dma_unpin_pages - unpin pages of given dma memory region |
| 76 | * @pdata: feature device platform data | 76 | * @fdata: feature dev data |
| 77 | * @region: dma memory region to be unpinned | 77 | * @region: dma memory region to be unpinned |
| 78 | * | 78 | * |
| 79 | * Unpin all the pages of given dfl_afu_dma_region. | 79 | * Unpin all the pages of given dfl_afu_dma_region. |
| 80 | * Return 0 for success or negative error code. | 80 | * Return 0 for success or negative error code. |
| 81 | */ | 81 | */ |
| 82 | static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata, | 82 | static void afu_dma_unpin_pages(struct dfl_feature_dev_data *fdata, |
| 83 | struct dfl_afu_dma_region *region) | 83 | struct dfl_afu_dma_region *region) |
| 84 | { | 84 | { |
| 85 | long npages = region->length >> PAGE_SHIFT; | 85 | long npages = region->length >> PAGE_SHIFT; |
| 86 | struct device *dev = &pdata->dev->dev; | 86 | struct device *dev = &fdata->dev->dev; |
| 87 | 87 | ||
| 88 | unpin_user_pages(region->pages, npages); | 88 | unpin_user_pages(region->pages, npages); |
| 89 | kfree(region->pages); | 89 | kfree(region->pages); |
| @@ -133,20 +133,20 @@ static bool dma_region_check_iova(struct dfl_afu_dma_region *region, · 43 unmodified lines | |||
| 133 | 133 | ||
| 134 | /** | 134 | /** |
| 135 | * afu_dma_region_add - add given dma region to rbtree | 135 | * afu_dma_region_add - add given dma region to rbtree |
| 136 | * @pdata: feature device platform data | 136 | * @fdata: feature dev data |
| 137 | * @region: dma region to be added | 137 | * @region: dma region to be added |
| 138 | * | 138 | * |
| 139 | * Return 0 for success, -EEXIST if dma region has already been added. | 139 | * Return 0 for success, -EEXIST if dma region has already been added. |
| 140 | * | 140 | * |
| 141 | * Needs to be called with pdata->lock heold. | 141 | * Needs to be called with fdata->lock held. |
| 142 | */ | 142 | */ |
| 143 | static int afu_dma_region_add(struct dfl_feature_platform_data *pdata, | 143 | static int afu_dma_region_add(struct dfl_feature_dev_data *fdata, |
| 144 | struct dfl_afu_dma_region *region) | 144 | struct dfl_afu_dma_region *region) |
| 145 | { | 145 | { |
| 146 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 146 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 147 | struct rb_node **new, *parent = NULL; | 147 | struct rb_node **new, *parent = NULL; |
| 148 | 148 | ||
| 149 | dev_dbg(&pdata->dev->dev, "add region (iova = %llx)\n", | 149 | dev_dbg(&fdata->dev->dev, "add region (iova = %llx)\n", |
| 150 | (unsigned long long)region->iova); | 150 | (unsigned long long)region->iova); |
| 151 | 151 | ||
| 152 | new = &afu->dma_regions.rb_node; | 152 | new = &afu->dma_regions.rb_node; |
| @@ -177,50 +177,50 @@ static int afu_dma_region_add(struct dfl_feature_platform_data *pdata, · 24 unmodified lines | |||
| 177 | 177 | ||
| 178 | /** | 178 | /** |
| 179 | * afu_dma_region_remove - remove given dma region from rbtree | 179 | * afu_dma_region_remove - remove given dma region from rbtree |
| 180 | * @pdata: feature device platform data | 180 | * @fdata: feature dev data |
| 181 | * @region: dma region to be removed | 181 | * @region: dma region to be removed |
| 182 | * | 182 | * |
| 183 | * Needs to be called with pdata->lock heold. | 183 | * Needs to be called with fdata->lock held. |
| 184 | */ | 184 | */ |
| 185 | static void afu_dma_region_remove(struct dfl_feature_platform_data *pdata, | 185 | static void afu_dma_region_remove(struct dfl_feature_dev_data *fdata, |
| 186 | struct dfl_afu_dma_region *region) | 186 | struct dfl_afu_dma_region *region) |
| 187 | { | 187 | { |
| 188 | struct dfl_afu *afu; | 188 | struct dfl_afu *afu; |
| 189 | 189 | ||
| 190 | dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", | 190 | dev_dbg(&fdata->dev->dev, "del region (iova = %llx)\n", |
| 191 | (unsigned long long)region->iova); | 191 | (unsigned long long)region->iova); |
| 192 | 192 | ||
| 193 | afu = dfl_fpga_pdata_get_private(pdata); | 193 | afu = dfl_fpga_fdata_get_private(fdata); |
| 194 | rb_erase(®ion->node, &afu->dma_regions); | 194 | rb_erase(®ion->node, &afu->dma_regions); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | /** | 197 | /** |
| 198 | * afu_dma_region_destroy - destroy all regions in rbtree | 198 | * afu_dma_region_destroy - destroy all regions in rbtree |
| 199 | * @pdata: feature device platform data | 199 | * @fdata: feature dev data |
| 200 | * | 200 | * |
| 201 | * Needs to be called with pdata->lock heold. | 201 | * Needs to be called with fdata->lock held. |
| 202 | */ | 202 | */ |
| 203 | void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) | 203 | void afu_dma_region_destroy(struct dfl_feature_dev_data *fdata) |
| 204 | { | 204 | { |
| 205 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 205 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 206 | struct rb_node *node = rb_first(&afu->dma_regions); | 206 | struct rb_node *node = rb_first(&afu->dma_regions); |
| 207 | struct dfl_afu_dma_region *region; | 207 | struct dfl_afu_dma_region *region; |
| 208 | 208 | ||
| 209 | while (node) { | 209 | while (node) { |
| 210 | region = container_of(node, struct dfl_afu_dma_region, node); | 210 | region = container_of(node, struct dfl_afu_dma_region, node); |
| 211 | 211 | ||
| 212 | dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", | 212 | dev_dbg(&fdata->dev->dev, "del region (iova = %llx)\n", |
| 213 | (unsigned long long)region->iova); | 213 | (unsigned long long)region->iova); |
| 214 | 214 | ||
| 215 | rb_erase(node, &afu->dma_regions); | 215 | rb_erase(node, &afu->dma_regions); |
| 216 | 216 | ||
| 217 | if (region->iova) | 217 | if (region->iova) |
| 218 | dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), | 218 | dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), |
| 219 | region->iova, region->length, | 219 | region->iova, region->length, |
| 220 | DMA_BIDIRECTIONAL); | 220 | DMA_BIDIRECTIONAL); |
| 221 | 221 | ||
| 222 | if (region->pages) | 222 | if (region->pages) |
| 223 | afu_dma_unpin_pages(pdata, region); | 223 | afu_dma_unpin_pages(fdata, region); |
| 224 | 224 | ||
| 225 | node = rb_next(node); | 225 | node = rb_next(node); |
| 226 | kfree(region); | 226 | kfree(region); |
| @@ -229,7 +229,7 @@ void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) · 2 unmodified lines | |||
| 229 | 229 | ||
| 230 | /** | 230 | /** |
| 231 | * afu_dma_region_find - find the dma region from rbtree based on iova and size | 231 | * afu_dma_region_find - find the dma region from rbtree based on iova and size |
| 232 | * @pdata: feature device platform data | 232 | * @fdata: feature dev data |
| 233 | * @iova: address of the dma memory area | 233 | * @iova: address of the dma memory area |
| 234 | * @size: size of the dma memory area | 234 | * @size: size of the dma memory area |
| 235 | * | 235 | * |
| @@ -239,14 +239,14 @@ void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) · 3 unmodified lines | |||
| 239 | * [@iova, @iova+size) | 239 | * [@iova, @iova+size) |
| 240 | * If nothing is matched returns NULL. | 240 | * If nothing is matched returns NULL. |
| 241 | * | 241 | * |
| 242 | * Needs to be called with pdata->lock held. | 242 | * Needs to be called with fdata->lock held. |
| 243 | */ | 243 | */ |
| 244 | struct dfl_afu_dma_region * | 244 | struct dfl_afu_dma_region * |
| 245 | afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) | 245 | afu_dma_region_find(struct dfl_feature_dev_data *fdata, u64 iova, u64 size) |
| 246 | { | 246 | { |
| 247 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 247 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 248 | struct rb_node *node = afu->dma_regions.rb_node; | 248 | struct rb_node *node = afu->dma_regions.rb_node; |
| 249 | struct device *dev = &pdata->dev->dev; | 249 | struct device *dev = &fdata->dev->dev; |
| 250 | 250 | ||
| 251 | while (node) { | 251 | while (node) { |
| 252 | struct dfl_afu_dma_region *region; | 252 | struct dfl_afu_dma_region *region; |
| @@ -276,20 +276,20 @@ afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) · 23 unmodified lines | |||
| 276 | 276 | ||
| 277 | /** | 277 | /** |
| 278 | * afu_dma_region_find_iova - find the dma region from rbtree by iova | 278 | * afu_dma_region_find_iova - find the dma region from rbtree by iova |
| 279 | * @pdata: feature device platform data | 279 | * @fdata: feature dev data |
| 280 | * @iova: address of the dma region | 280 | * @iova: address of the dma region |
| 281 | * | 281 | * |
| 282 | * Needs to be called with pdata->lock held. | 282 | * Needs to be called with fdata->lock held. |
| 283 | */ | 283 | */ |
| 284 | static struct dfl_afu_dma_region * | 284 | static struct dfl_afu_dma_region * |
| 285 | afu_dma_region_find_iova(struct dfl_feature_platform_data *pdata, u64 iova) | 285 | afu_dma_region_find_iova(struct dfl_feature_dev_data *fdata, u64 iova) |
| 286 | { | 286 | { |
| 287 | return afu_dma_region_find(pdata, iova, 0); | 287 | return afu_dma_region_find(fdata, iova, 0); |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | /** | 290 | /** |
| 291 | * afu_dma_map_region - map memory region for dma | 291 | * afu_dma_map_region - map memory region for dma |
| 292 | * @pdata: feature device platform data | 292 | * @fdata: feature dev data |
| 293 | * @user_addr: address of the memory region | 293 | * @user_addr: address of the memory region |
| 294 | * @length: size of the memory region | 294 | * @length: size of the memory region |
| 295 | * @iova: pointer of iova address | 295 | * @iova: pointer of iova address |
| @@ -298,9 +298,10 @@ afu_dma_region_find_iova(struct dfl_feature_platform_data *pdata, u64 iova) · 2 unmodified lines | |||
| 298 | * of the memory region via @iova. | 298 | * of the memory region via @iova. |
| 299 | * Return 0 for success, otherwise error code. | 299 | * Return 0 for success, otherwise error code. |
| 300 | */ | 300 | */ |
| 301 | int afu_dma_map_region(struct dfl_feature_platform_data *pdata, | 301 | int afu_dma_map_region(struct dfl_feature_dev_data *fdata, |
| 302 | u64 user_addr, u64 length, u64 *iova) | 302 | u64 user_addr, u64 length, u64 *iova) |
| 303 | { | 303 | { |
| 304 | struct device *dev = &fdata->dev->dev; | ||
| 304 | struct dfl_afu_dma_region *region; | 305 | struct dfl_afu_dma_region *region; |
| 305 | int ret; | 306 | int ret; |
| 306 | 307 | ||
| @@ -323,47 +324,47 @@ int afu_dma_map_region(struct dfl_feature_platform_data *pdata, · 16 unmodified lines | |||
| 323 | region->length = length; | 324 | region->length = length; |
| 324 | 325 | ||
| 325 | /* Pin the user memory region */ | 326 | /* Pin the user memory region */ |
| 326 | ret = afu_dma_pin_pages(pdata, region); | 327 | ret = afu_dma_pin_pages(fdata, region); |
| 327 | if (ret) { | 328 | if (ret) { |
| 328 | dev_err(&pdata->dev->dev, "failed to pin memory region\n"); | 329 | dev_err(dev, "failed to pin memory region\n"); |
| 329 | goto free_region; | 330 | goto free_region; |
| 330 | } | 331 | } |
| 331 | 332 | ||
| 332 | /* Only accept continuous pages, return error else */ | 333 | /* Only accept continuous pages, return error else */ |
| 333 | if (!afu_dma_check_continuous_pages(region)) { | 334 | if (!afu_dma_check_continuous_pages(region)) { |
| 334 | dev_err(&pdata->dev->dev, "pages are not continuous\n"); | 335 | dev_err(dev, "pages are not continuous\n"); |
| 335 | ret = -EINVAL; | 336 | ret = -EINVAL; |
| 336 | goto unpin_pages; | 337 | goto unpin_pages; |
| 337 | } | 338 | } |
| 338 | 339 | ||
| 339 | /* As pages are continuous then start to do DMA mapping */ | 340 | /* As pages are continuous then start to do DMA mapping */ |
| 340 | region->iova = dma_map_page(dfl_fpga_pdata_to_parent(pdata), | 341 | region->iova = dma_map_page(dfl_fpga_fdata_to_parent(fdata), |
| 341 | region->pages[0], 0, | 342 | region->pages[0], 0, |
| 342 | region->length, | 343 | region->length, |
| 343 | DMA_BIDIRECTIONAL); | 344 | DMA_BIDIRECTIONAL); |
| 344 | if (dma_mapping_error(dfl_fpga_pdata_to_parent(pdata), region->iova)) { | 345 | if (dma_mapping_error(dfl_fpga_fdata_to_parent(fdata), region->iova)) { |
| 345 | dev_err(&pdata->dev->dev, "failed to map for dma\n"); | 346 | dev_err(dev, "failed to map for dma\n"); |
| 346 | ret = -EFAULT; | 347 | ret = -EFAULT; |
| 347 | goto unpin_pages; | 348 | goto unpin_pages; |
| 348 | } | 349 | } |
| 349 | 350 | ||
| 350 | *iova = region->iova; | 351 | *iova = region->iova; |
| 351 | 352 | ||
| 352 | mutex_lock(&pdata->lock); | 353 | mutex_lock(&fdata->lock); |
| 353 | ret = afu_dma_region_add(pdata, region); | 354 | ret = afu_dma_region_add(fdata, region); |
| 354 | mutex_unlock(&pdata->lock); | 355 | mutex_unlock(&fdata->lock); |
| 355 | if (ret) { | 356 | if (ret) { |
| 356 | dev_err(&pdata->dev->dev, "failed to add dma region\n"); | 357 | dev_err(dev, "failed to add dma region\n"); |
| 357 | goto unmap_dma; | 358 | goto unmap_dma; |
| 358 | } | 359 | } |
| 359 | 360 | ||
| 360 | return 0; | 361 | return 0; |
| 361 | 362 | ||
| 362 | unmap_dma: | 363 | unmap_dma: |
| 363 | dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), | 364 | dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), |
| 364 | region->iova, region->length, DMA_BIDIRECTIONAL); | 365 | region->iova, region->length, DMA_BIDIRECTIONAL); |
| 365 | unpin_pages: | 366 | unpin_pages: |
| 366 | afu_dma_unpin_pages(pdata, region); | 367 | afu_dma_unpin_pages(fdata, region); |
| 367 | free_region: | 368 | free_region: |
| 368 | kfree(region); | 369 | kfree(region); |
| 369 | return ret; | 370 | return ret; |
| @@ -371,34 +372,34 @@ free_region: · 1 unmodified line | |||
| 371 | 372 | ||
| 372 | /** | 373 | /** |
| 373 | * afu_dma_unmap_region - unmap dma memory region | 374 | * afu_dma_unmap_region - unmap dma memory region |
| 374 | * @pdata: feature device platform data | 375 | * @fdata: feature dev data |
| 375 | * @iova: dma address of the region | 376 | * @iova: dma address of the region |
| 376 | * | 377 | * |
| 377 | * Unmap dma memory region based on @iova. | 378 | * Unmap dma memory region based on @iova. |
| 378 | * Return 0 for success, otherwise error code. | 379 | * Return 0 for success, otherwise error code. |
| 379 | */ | 380 | */ |
| 380 | int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova) | 381 | int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova) |
| 381 | { | 382 | { |
| 382 | struct dfl_afu_dma_region *region; | 383 | struct dfl_afu_dma_region *region; |
| 383 | 384 | ||
| 384 | mutex_lock(&pdata->lock); | 385 | mutex_lock(&fdata->lock); |
| 385 | region = afu_dma_region_find_iova(pdata, iova); | 386 | region = afu_dma_region_find_iova(fdata, iova); |
| 386 | if (!region) { | 387 | if (!region) { |
| 387 | mutex_unlock(&pdata->lock); | 388 | mutex_unlock(&fdata->lock); |
| 388 | return -EINVAL; | 389 | return -EINVAL; |
| 389 | } | 390 | } |
| 390 | 391 | ||
| 391 | if (region->in_use) { | 392 | if (region->in_use) { |
| 392 | mutex_unlock(&pdata->lock); | 393 | mutex_unlock(&fdata->lock); |
| 393 | return -EBUSY; | 394 | return -EBUSY; |
| 394 | } | 395 | } |
| 395 | 396 | ||
| 396 | afu_dma_region_remove(pdata, region); | 397 | afu_dma_region_remove(fdata, region); |
| 397 | mutex_unlock(&pdata->lock); | 398 | mutex_unlock(&fdata->lock); |
| 398 | 399 | ||
| 399 | dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), | 400 | dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), |
| 400 | region->iova, region->length, DMA_BIDIRECTIONAL); | 401 | region->iova, region->length, DMA_BIDIRECTIONAL); |
| 401 | afu_dma_unpin_pages(pdata, region); | 402 | afu_dma_unpin_pages(fdata, region); |
| 402 | kfree(region); | 403 | kfree(region); |
| 403 | 404 | ||
| 404 | return 0; | 405 | return 0; |
| @@ -28,37 +28,36 @@ · 27 unmodified lines | |||
| 28 | #define ERROR_MASK GENMASK_ULL(63, 0) | 28 | #define ERROR_MASK GENMASK_ULL(63, 0) |
| 29 | 29 | ||
| 30 | /* mask or unmask port errors by the error mask register. */ | 30 | /* mask or unmask port errors by the error mask register. */ |
| 31 | static void __afu_port_err_mask(struct device *dev, bool mask) | 31 | static void __afu_port_err_mask(struct dfl_feature_dev_data *fdata, bool mask) |
| 32 | { | 32 | { |
| 33 | void __iomem *base; | 33 | void __iomem *base; |
| 34 | 34 | ||
| 35 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); | 35 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); |
| 36 | 36 | ||
| 37 | writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK); | 37 | writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static void afu_port_err_mask(struct device *dev, bool mask) | 40 | static void afu_port_err_mask(struct device *dev, bool mask) |
| 41 | { | 41 | { |
| 42 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 42 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 43 | 43 | ||
| 44 | mutex_lock(&pdata->lock); | 44 | mutex_lock(&fdata->lock); |
| 45 | __afu_port_err_mask(dev, mask); | 45 | __afu_port_err_mask(fdata, mask); |
| 46 | mutex_unlock(&pdata->lock); | 46 | mutex_unlock(&fdata->lock); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | /* clear port errors. */ | 49 | /* clear port errors. */ |
| 50 | static int afu_port_err_clear(struct device *dev, u64 err) | 50 | static int afu_port_err_clear(struct device *dev, u64 err) |
| 51 | { | 51 | { |
| 52 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 52 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 53 | struct platform_device *pdev = to_platform_device(dev); | ||
| 54 | void __iomem *base_err, *base_hdr; | 53 | void __iomem *base_err, *base_hdr; |
| 55 | int enable_ret = 0, ret = -EBUSY; | 54 | int enable_ret = 0, ret = -EBUSY; |
| 56 | u64 v; | 55 | u64 v; |
| 57 | 56 | ||
| 58 | base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); | 57 | base_err = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); |
| 59 | base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 58 | base_hdr = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 60 | 59 | ||
| 61 | mutex_lock(&pdata->lock); | 60 | mutex_lock(&fdata->lock); |
| 62 | 61 | ||
| 63 | /* | 62 | /* |
| 64 | * clear Port Errors | 63 | * clear Port Errors |
| @@ -80,12 +79,12 @@ static int afu_port_err_clear(struct device *dev, u64 err) · 15 unmodified lines | |||
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | /* Halt Port by keeping Port in reset */ | 81 | /* Halt Port by keeping Port in reset */ |
| 83 | ret = __afu_port_disable(pdev); | 82 | ret = __afu_port_disable(fdata); |
| 84 | if (ret) | 83 | if (ret) |
| 85 | goto done; | 84 | goto done; |
| 86 | 85 | ||
| 87 | /* Mask all errors */ | 86 | /* Mask all errors */ |
| 88 | __afu_port_err_mask(dev, true); | 87 | __afu_port_err_mask(fdata, true); |
| 89 | 88 | ||
| 90 | /* Clear errors if err input matches with current port errors.*/ | 89 | /* Clear errors if err input matches with current port errors.*/ |
| 91 | v = readq(base_err + PORT_ERROR); | 90 | v = readq(base_err + PORT_ERROR); |
| @@ -102,28 +101,28 @@ static int afu_port_err_clear(struct device *dev, u64 err) · 10 unmodified lines | |||
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | /* Clear mask */ | 103 | /* Clear mask */ |
| 105 | __afu_port_err_mask(dev, false); | 104 | __afu_port_err_mask(fdata, false); |
| 106 | 105 | ||
| 107 | /* Enable the Port by clearing the reset */ | 106 | /* Enable the Port by clearing the reset */ |
| 108 | enable_ret = __afu_port_enable(pdev); | 107 | enable_ret = __afu_port_enable(fdata); |
| 109 | 108 | ||
| 110 | done: | 109 | done: |
| 111 | mutex_unlock(&pdata->lock); | 110 | mutex_unlock(&fdata->lock); |
| 112 | return enable_ret ? enable_ret : ret; | 111 | return enable_ret ? enable_ret : ret; |
| 113 | } | 112 | } |
| 114 | 113 | ||
| 115 | static ssize_t errors_show(struct device *dev, struct device_attribute *attr, | 114 | static ssize_t errors_show(struct device *dev, struct device_attribute *attr, |
| 116 | char *buf) | 115 | char *buf) |
| 117 | { | 116 | { |
| 118 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 117 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 119 | void __iomem *base; | 118 | void __iomem *base; |
| 120 | u64 error; | 119 | u64 error; |
| 121 | 120 | ||
| 122 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); | 121 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); |
| 123 | 122 | ||
| 124 | mutex_lock(&pdata->lock); | 123 | mutex_lock(&fdata->lock); |
| 125 | error = readq(base + PORT_ERROR); | 124 | error = readq(base + PORT_ERROR); |
| 126 | mutex_unlock(&pdata->lock); | 125 | mutex_unlock(&fdata->lock); |
| 127 | 126 | ||
| 128 | return sprintf(buf, "0x%llx\n", (unsigned long long)error); | 127 | return sprintf(buf, "0x%llx\n", (unsigned long long)error); |
| 129 | } | 128 | } |
| @@ -146,15 +145,15 @@ static DEVICE_ATTR_RW(errors); · 16 unmodified lines | |||
| 146 | static ssize_t first_error_show(struct device *dev, | 145 | static ssize_t first_error_show(struct device *dev, |
| 147 | struct device_attribute *attr, char *buf) | 146 | struct device_attribute *attr, char *buf) |
| 148 | { | 147 | { |
| 149 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 148 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 150 | void __iomem *base; | 149 | void __iomem *base; |
| 151 | u64 error; | 150 | u64 error; |
| 152 | 151 | ||
| 153 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); | 152 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); |
| 154 | 153 | ||
| 155 | mutex_lock(&pdata->lock); | 154 | mutex_lock(&fdata->lock); |
| 156 | error = readq(base + PORT_FIRST_ERROR); | 155 | error = readq(base + PORT_FIRST_ERROR); |
| 157 | mutex_unlock(&pdata->lock); | 156 | mutex_unlock(&fdata->lock); |
| 158 | 157 | ||
| 159 | return sprintf(buf, "0x%llx\n", (unsigned long long)error); | 158 | return sprintf(buf, "0x%llx\n", (unsigned long long)error); |
| 160 | } | 159 | } |
| @@ -164,16 +163,16 @@ static ssize_t first_malformed_req_show(struct device *dev, · 3 unmodified lines | |||
| 164 | struct device_attribute *attr, | 163 | struct device_attribute *attr, |
| 165 | char *buf) | 164 | char *buf) |
| 166 | { | 165 | { |
| 167 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 166 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 168 | void __iomem *base; | 167 | void __iomem *base; |
| 169 | u64 req0, req1; | 168 | u64 req0, req1; |
| 170 | 169 | ||
| 171 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); | 170 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); |
| 172 | 171 | ||
| 173 | mutex_lock(&pdata->lock); | 172 | mutex_lock(&fdata->lock); |
| 174 | req0 = readq(base + PORT_MALFORMED_REQ0); | 173 | req0 = readq(base + PORT_MALFORMED_REQ0); |
| 175 | req1 = readq(base + PORT_MALFORMED_REQ1); | 174 | req1 = readq(base + PORT_MALFORMED_REQ1); |
| 176 | mutex_unlock(&pdata->lock); | 175 | mutex_unlock(&fdata->lock); |
| 177 | 176 | ||
| 178 | return sprintf(buf, "0x%016llx%016llx\n", | 177 | return sprintf(buf, "0x%016llx%016llx\n", |
| 179 | (unsigned long long)req1, (unsigned long long)req0); | 178 | (unsigned long long)req1, (unsigned long long)req0); |
| @@ -191,12 +190,14 @@ static umode_t port_err_attrs_visible(struct kobject *kobj, · 11 unmodified lines | |||
| 191 | struct attribute *attr, int n) | 190 | struct attribute *attr, int n) |
| 192 | { | 191 | { |
| 193 | struct device *dev = kobj_to_dev(kobj); | 192 | struct device *dev = kobj_to_dev(kobj); |
| 193 | struct dfl_feature_dev_data *fdata; | ||
| 194 | 194 | ||
| 195 | fdata = to_dfl_feature_dev_data(dev); | ||
| 195 | /* | 196 | /* |
| 196 | * sysfs entries are visible only if related private feature is | 197 | * sysfs entries are visible only if related private feature is |
| 197 | * enumerated. | 198 | * enumerated. |
| 198 | */ | 199 | */ |
| 199 | if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_ERROR)) | 200 | if (!dfl_get_feature_by_id(fdata, PORT_FEATURE_ID_ERROR)) |
| 200 | return 0; | 201 | return 0; |
| 201 | 202 | ||
| 202 | return attr->mode; | 203 | return attr->mode; |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * __afu_port_enable - enable a port by clear reset | 28 | * __afu_port_enable - enable a port by clear reset |
| 29 | * @pdev: port platform device. | 29 | * @fdata: port feature dev data. |
| 30 | * | 30 | * |
| 31 | * Enable Port by clear the port soft reset bit, which is set by default. | 31 | * Enable Port by clear the port soft reset bit, which is set by default. |
| 32 | * The AFU is unable to respond to any MMIO access while in reset. | 32 | * The AFU is unable to respond to any MMIO access while in reset. |
| @@ -35,18 +35,17 @@ · 2 unmodified lines | |||
| 35 | * | 35 | * |
| 36 | * The caller needs to hold lock for protection. | 36 | * The caller needs to hold lock for protection. |
| 37 | */ | 37 | */ |
| 38 | int __afu_port_enable(struct platform_device *pdev) | 38 | int __afu_port_enable(struct dfl_feature_dev_data *fdata) |
| 39 | { | 39 | { |
| 40 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
| 41 | void __iomem *base; | 40 | void __iomem *base; |
| 42 | u64 v; | 41 | u64 v; |
| 43 | 42 | ||
| 44 | WARN_ON(!pdata->disable_count); | 43 | WARN_ON(!fdata->disable_count); |
| 45 | 44 | ||
| 46 | if (--pdata->disable_count != 0) | 45 | if (--fdata->disable_count != 0) |
| 47 | return 0; | 46 | return 0; |
| 48 | 47 | ||
| 49 | base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); | 48 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 50 | 49 | ||
| 51 | /* Clear port soft reset */ | 50 | /* Clear port soft reset */ |
| 52 | v = readq(base + PORT_HDR_CTRL); | 51 | v = readq(base + PORT_HDR_CTRL); |
| @@ -60,7 +59,8 @@ int __afu_port_enable(struct platform_device *pdev) · 7 unmodified lines | |||
| 60 | if (readq_poll_timeout(base + PORT_HDR_CTRL, v, | 59 | if (readq_poll_timeout(base + PORT_HDR_CTRL, v, |
| 61 | !(v & PORT_CTRL_SFTRST_ACK), | 60 | !(v & PORT_CTRL_SFTRST_ACK), |
| 62 | RST_POLL_INVL, RST_POLL_TIMEOUT)) { | 61 | RST_POLL_INVL, RST_POLL_TIMEOUT)) { |
| 63 | dev_err(&pdev->dev, "timeout, failure to enable device\n"); | 62 | dev_err(fdata->dfl_cdev->parent, |
| 63 | "timeout, failure to enable device\n"); | ||
| 64 | return -ETIMEDOUT; | 64 | return -ETIMEDOUT; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -69,22 +69,21 @@ int __afu_port_enable(struct platform_device *pdev) · 2 unmodified lines | |||
| 69 | 69 | ||
| 70 | /** | 70 | /** |
| 71 | * __afu_port_disable - disable a port by hold reset | 71 | * __afu_port_disable - disable a port by hold reset |
| 72 | * @pdev: port platform device. | 72 | * @fdata: port feature dev data. |
| 73 | * | 73 | * |
| 74 | * Disable Port by setting the port soft reset bit, it puts the port into reset. | 74 | * Disable Port by setting the port soft reset bit, it puts the port into reset. |
| 75 | * | 75 | * |
| 76 | * The caller needs to hold lock for protection. | 76 | * The caller needs to hold lock for protection. |
| 77 | */ | 77 | */ |
| 78 | int __afu_port_disable(struct platform_device *pdev) | 78 | int __afu_port_disable(struct dfl_feature_dev_data *fdata) |
| 79 | { | 79 | { |
| 80 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
| 81 | void __iomem *base; | 80 | void __iomem *base; |
| 82 | u64 v; | 81 | u64 v; |
| 83 | 82 | ||
| 84 | if (pdata->disable_count++ != 0) | 83 | if (fdata->disable_count++ != 0) |
| 85 | return 0; | 84 | return 0; |
| 86 | 85 | ||
| 87 | base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); | 86 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 88 | 87 | ||
| 89 | /* Set port soft reset */ | 88 | /* Set port soft reset */ |
| 90 | v = readq(base + PORT_HDR_CTRL); | 89 | v = readq(base + PORT_HDR_CTRL); |
| @@ -99,7 +98,8 @@ int __afu_port_disable(struct platform_device *pdev) · 8 unmodified lines | |||
| 99 | if (readq_poll_timeout(base + PORT_HDR_CTRL, v, | 98 | if (readq_poll_timeout(base + PORT_HDR_CTRL, v, |
| 100 | v & PORT_CTRL_SFTRST_ACK, | 99 | v & PORT_CTRL_SFTRST_ACK, |
| 101 | RST_POLL_INVL, RST_POLL_TIMEOUT)) { | 100 | RST_POLL_INVL, RST_POLL_TIMEOUT)) { |
| 102 | dev_err(&pdev->dev, "timeout, failure to disable device\n"); | 101 | dev_err(fdata->dfl_cdev->parent, |
| 102 | "timeout, failure to disable device\n"); | ||
| 103 | return -ETIMEDOUT; | 103 | return -ETIMEDOUT; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| @@ -118,34 +118,34 @@ int __afu_port_disable(struct platform_device *pdev) · 12 unmodified lines | |||
| 118 | * (disabled). Any attempts on MMIO access to AFU while in reset, will | 118 | * (disabled). Any attempts on MMIO access to AFU while in reset, will |
| 119 | * result errors reported via port error reporting sub feature (if present). | 119 | * result errors reported via port error reporting sub feature (if present). |
| 120 | */ | 120 | */ |
| 121 | static int __port_reset(struct platform_device *pdev) | 121 | static int __port_reset(struct dfl_feature_dev_data *fdata) |
| 122 | { | 122 | { |
| 123 | int ret; | 123 | int ret; |
| 124 | 124 | ||
| 125 | ret = __afu_port_disable(pdev); | 125 | ret = __afu_port_disable(fdata); |
| 126 | if (ret) | 126 | if (ret) |
| 127 | return ret; | 127 | return ret; |
| 128 | 128 | ||
| 129 | return __afu_port_enable(pdev); | 129 | return __afu_port_enable(fdata); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static int port_reset(struct platform_device *pdev) | 132 | static int port_reset(struct platform_device *pdev) |
| 133 | { | 133 | { |
| 134 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 134 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 135 | int ret; | 135 | int ret; |
| 136 | 136 | ||
| 137 | mutex_lock(&pdata->lock); | 137 | mutex_lock(&fdata->lock); |
| 138 | ret = __port_reset(pdev); | 138 | ret = __port_reset(fdata); |
| 139 | mutex_unlock(&pdata->lock); | 139 | mutex_unlock(&fdata->lock); |
| 140 | 140 | ||
| 141 | return ret; | 141 | return ret; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static int port_get_id(struct platform_device *pdev) | 144 | static int port_get_id(struct dfl_feature_dev_data *fdata) |
| 145 | { | 145 | { |
| 146 | void __iomem *base; | 146 | void __iomem *base; |
| 147 | 147 | ||
| 148 | base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); | 148 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 149 | 149 | ||
| 150 | return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); | 150 | return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); |
| 151 | } | 151 | } |
| @@ -153,7 +153,8 @@ static int port_get_id(struct platform_device *pdev) · 1 unmodified line | |||
| 153 | static ssize_t | 153 | static ssize_t |
| 154 | id_show(struct device *dev, struct device_attribute *attr, char *buf) | 154 | id_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 155 | { | 155 | { |
| 156 | int id = port_get_id(to_platform_device(dev)); | 156 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 157 | int id = port_get_id(fdata); | ||
| 157 | 158 | ||
| 158 | return scnprintf(buf, PAGE_SIZE, "%d\n", id); | 159 | return scnprintf(buf, PAGE_SIZE, "%d\n", id); |
| 159 | } | 160 | } |
| @@ -162,15 +163,15 @@ static DEVICE_ATTR_RO(id); · 2 unmodified lines | |||
| 162 | static ssize_t | 163 | static ssize_t |
| 163 | ltr_show(struct device *dev, struct device_attribute *attr, char *buf) | 164 | ltr_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 164 | { | 165 | { |
| 165 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 166 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 166 | void __iomem *base; | 167 | void __iomem *base; |
| 167 | u64 v; | 168 | u64 v; |
| 168 | 169 | ||
| 169 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 170 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 170 | 171 | ||
| 171 | mutex_lock(&pdata->lock); | 172 | mutex_lock(&fdata->lock); |
| 172 | v = readq(base + PORT_HDR_CTRL); | 173 | v = readq(base + PORT_HDR_CTRL); |
| 173 | mutex_unlock(&pdata->lock); | 174 | mutex_unlock(&fdata->lock); |
| 174 | 175 | ||
| 175 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); | 176 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); |
| 176 | } | 177 | } |
| @@ -179,7 +180,7 @@ static ssize_t · 2 unmodified lines | |||
| 179 | ltr_store(struct device *dev, struct device_attribute *attr, | 180 | ltr_store(struct device *dev, struct device_attribute *attr, |
| 180 | const char *buf, size_t count) | 181 | const char *buf, size_t count) |
| 181 | { | 182 | { |
| 182 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 183 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 183 | void __iomem *base; | 184 | void __iomem *base; |
| 184 | bool ltr; | 185 | bool ltr; |
| 185 | u64 v; | 186 | u64 v; |
| @@ -187,14 +188,14 @@ ltr_store(struct device *dev, struct device_attribute *attr, · 1 unmodified line | |||
| 187 | if (kstrtobool(buf, <r)) | 188 | if (kstrtobool(buf, <r)) |
| 188 | return -EINVAL; | 189 | return -EINVAL; |
| 189 | 190 | ||
| 190 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 191 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 191 | 192 | ||
| 192 | mutex_lock(&pdata->lock); | 193 | mutex_lock(&fdata->lock); |
| 193 | v = readq(base + PORT_HDR_CTRL); | 194 | v = readq(base + PORT_HDR_CTRL); |
| 194 | v &= ~PORT_CTRL_LATENCY; | 195 | v &= ~PORT_CTRL_LATENCY; |
| 195 | v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); | 196 | v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); |
| 196 | writeq(v, base + PORT_HDR_CTRL); | 197 | writeq(v, base + PORT_HDR_CTRL); |
| 197 | mutex_unlock(&pdata->lock); | 198 | mutex_unlock(&fdata->lock); |
| 198 | 199 | ||
| 199 | return count; | 200 | return count; |
| 200 | } | 201 | } |
| @@ -203,15 +204,15 @@ static DEVICE_ATTR_RW(ltr); · 2 unmodified lines | |||
| 203 | static ssize_t | 204 | static ssize_t |
| 204 | ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) | 205 | ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 205 | { | 206 | { |
| 206 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 207 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 207 | void __iomem *base; | 208 | void __iomem *base; |
| 208 | u64 v; | 209 | u64 v; |
| 209 | 210 | ||
| 210 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 211 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 211 | 212 | ||
| 212 | mutex_lock(&pdata->lock); | 213 | mutex_lock(&fdata->lock); |
| 213 | v = readq(base + PORT_HDR_STS); | 214 | v = readq(base + PORT_HDR_STS); |
| 214 | mutex_unlock(&pdata->lock); | 215 | mutex_unlock(&fdata->lock); |
| 215 | 216 | ||
| 216 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); | 217 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); |
| 217 | } | 218 | } |
| @@ -220,18 +221,18 @@ static ssize_t · 2 unmodified lines | |||
| 220 | ap1_event_store(struct device *dev, struct device_attribute *attr, | 221 | ap1_event_store(struct device *dev, struct device_attribute *attr, |
| 221 | const char *buf, size_t count) | 222 | const char *buf, size_t count) |
| 222 | { | 223 | { |
| 223 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 224 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 224 | void __iomem *base; | 225 | void __iomem *base; |
| 225 | bool clear; | 226 | bool clear; |
| 226 | 227 | ||
| 227 | if (kstrtobool(buf, &clear) || !clear) | 228 | if (kstrtobool(buf, &clear) || !clear) |
| 228 | return -EINVAL; | 229 | return -EINVAL; |
| 229 | 230 | ||
| 230 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 231 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 231 | 232 | ||
| 232 | mutex_lock(&pdata->lock); | 233 | mutex_lock(&fdata->lock); |
| 233 | writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); | 234 | writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); |
| 234 | mutex_unlock(&pdata->lock); | 235 | mutex_unlock(&fdata->lock); |
| 235 | 236 | ||
| 236 | return count; | 237 | return count; |
| 237 | } | 238 | } |
| @@ -241,15 +242,15 @@ static ssize_t · 3 unmodified lines | |||
| 241 | ap2_event_show(struct device *dev, struct device_attribute *attr, | 242 | ap2_event_show(struct device *dev, struct device_attribute *attr, |
| 242 | char *buf) | 243 | char *buf) |
| 243 | { | 244 | { |
| 244 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 245 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 245 | void __iomem *base; | 246 | void __iomem *base; |
| 246 | u64 v; | 247 | u64 v; |
| 247 | 248 | ||
| 248 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 249 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 249 | 250 | ||
| 250 | mutex_lock(&pdata->lock); | 251 | mutex_lock(&fdata->lock); |
| 251 | v = readq(base + PORT_HDR_STS); | 252 | v = readq(base + PORT_HDR_STS); |
| 252 | mutex_unlock(&pdata->lock); | 253 | mutex_unlock(&fdata->lock); |
| 253 | 254 | ||
| 254 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); | 255 | return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); |
| 255 | } | 256 | } |
| @@ -258,18 +259,18 @@ static ssize_t · 2 unmodified lines | |||
| 258 | ap2_event_store(struct device *dev, struct device_attribute *attr, | 259 | ap2_event_store(struct device *dev, struct device_attribute *attr, |
| 259 | const char *buf, size_t count) | 260 | const char *buf, size_t count) |
| 260 | { | 261 | { |
| 261 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 262 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 262 | void __iomem *base; | 263 | void __iomem *base; |
| 263 | bool clear; | 264 | bool clear; |
| 264 | 265 | ||
| 265 | if (kstrtobool(buf, &clear) || !clear) | 266 | if (kstrtobool(buf, &clear) || !clear) |
| 266 | return -EINVAL; | 267 | return -EINVAL; |
| 267 | 268 | ||
| 268 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 269 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 269 | 270 | ||
| 270 | mutex_lock(&pdata->lock); | 271 | mutex_lock(&fdata->lock); |
| 271 | writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); | 272 | writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); |
| 272 | mutex_unlock(&pdata->lock); | 273 | mutex_unlock(&fdata->lock); |
| 273 | 274 | ||
| 274 | return count; | 275 | return count; |
| 275 | } | 276 | } |
| @@ -278,15 +279,15 @@ static DEVICE_ATTR_RW(ap2_event); · 2 unmodified lines | |||
| 278 | static ssize_t | 279 | static ssize_t |
| 279 | power_state_show(struct device *dev, struct device_attribute *attr, char *buf) | 280 | power_state_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 280 | { | 281 | { |
| 281 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 282 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 282 | void __iomem *base; | 283 | void __iomem *base; |
| 283 | u64 v; | 284 | u64 v; |
| 284 | 285 | ||
| 285 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 286 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 286 | 287 | ||
| 287 | mutex_lock(&pdata->lock); | 288 | mutex_lock(&fdata->lock); |
| 288 | v = readq(base + PORT_HDR_STS); | 289 | v = readq(base + PORT_HDR_STS); |
| 289 | mutex_unlock(&pdata->lock); | 290 | mutex_unlock(&fdata->lock); |
| 290 | 291 | ||
| 291 | return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); | 292 | return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); |
| 292 | } | 293 | } |
| @@ -296,18 +297,18 @@ static ssize_t · 3 unmodified lines | |||
| 296 | userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, | 297 | userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, |
| 297 | const char *buf, size_t count) | 298 | const char *buf, size_t count) |
| 298 | { | 299 | { |
| 299 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 300 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 300 | u64 userclk_freq_cmd; | 301 | u64 userclk_freq_cmd; |
| 301 | void __iomem *base; | 302 | void __iomem *base; |
| 302 | 303 | ||
| 303 | if (kstrtou64(buf, 0, &userclk_freq_cmd)) | 304 | if (kstrtou64(buf, 0, &userclk_freq_cmd)) |
| 304 | return -EINVAL; | 305 | return -EINVAL; |
| 305 | 306 | ||
| 306 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 307 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 307 | 308 | ||
| 308 | mutex_lock(&pdata->lock); | 309 | mutex_lock(&fdata->lock); |
| 309 | writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); | 310 | writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); |
| 310 | mutex_unlock(&pdata->lock); | 311 | mutex_unlock(&fdata->lock); |
| 311 | 312 | ||
| 312 | return count; | 313 | return count; |
| 313 | } | 314 | } |
| @@ -317,18 +318,18 @@ static ssize_t · 3 unmodified lines | |||
| 317 | userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, | 318 | userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, |
| 318 | const char *buf, size_t count) | 319 | const char *buf, size_t count) |
| 319 | { | 320 | { |
| 320 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 321 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 321 | u64 userclk_freqcntr_cmd; | 322 | u64 userclk_freqcntr_cmd; |
| 322 | void __iomem *base; | 323 | void __iomem *base; |
| 323 | 324 | ||
| 324 | if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) | 325 | if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) |
| 325 | return -EINVAL; | 326 | return -EINVAL; |
| 326 | 327 | ||
| 327 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 328 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 328 | 329 | ||
| 329 | mutex_lock(&pdata->lock); | 330 | mutex_lock(&fdata->lock); |
| 330 | writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); | 331 | writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); |
| 331 | mutex_unlock(&pdata->lock); | 332 | mutex_unlock(&fdata->lock); |
| 332 | 333 | ||
| 333 | return count; | 334 | return count; |
| 334 | } | 335 | } |
| @@ -338,15 +339,15 @@ static ssize_t · 3 unmodified lines | |||
| 338 | userclk_freqsts_show(struct device *dev, struct device_attribute *attr, | 339 | userclk_freqsts_show(struct device *dev, struct device_attribute *attr, |
| 339 | char *buf) | 340 | char *buf) |
| 340 | { | 341 | { |
| 341 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 342 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 342 | u64 userclk_freqsts; | 343 | u64 userclk_freqsts; |
| 343 | void __iomem *base; | 344 | void __iomem *base; |
| 344 | 345 | ||
| 345 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 346 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 346 | 347 | ||
| 347 | mutex_lock(&pdata->lock); | 348 | mutex_lock(&fdata->lock); |
| 348 | userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); | 349 | userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); |
| 349 | mutex_unlock(&pdata->lock); | 350 | mutex_unlock(&fdata->lock); |
| 350 | 351 | ||
| 351 | return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); | 352 | return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); |
| 352 | } | 353 | } |
| @@ -356,15 +357,15 @@ static ssize_t · 3 unmodified lines | |||
| 356 | userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, | 357 | userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, |
| 357 | char *buf) | 358 | char *buf) |
| 358 | { | 359 | { |
| 359 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 360 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 360 | u64 userclk_freqcntrsts; | 361 | u64 userclk_freqcntrsts; |
| 361 | void __iomem *base; | 362 | void __iomem *base; |
| 362 | 363 | ||
| 363 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 364 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); |
| 364 | 365 | ||
| 365 | mutex_lock(&pdata->lock); | 366 | mutex_lock(&fdata->lock); |
| 366 | userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); | 367 | userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); |
| 367 | mutex_unlock(&pdata->lock); | 368 | mutex_unlock(&fdata->lock); |
| 368 | 369 | ||
| 369 | return sprintf(buf, "0x%llx\n", | 370 | return sprintf(buf, "0x%llx\n", |
| 370 | (unsigned long long)userclk_freqcntrsts); | 371 | (unsigned long long)userclk_freqcntrsts); |
| @@ -388,10 +389,12 @@ static umode_t port_hdr_attrs_visible(struct kobject *kobj, · 17 unmodified lines | |||
| 388 | struct attribute *attr, int n) | 389 | struct attribute *attr, int n) |
| 389 | { | 390 | { |
| 390 | struct device *dev = kobj_to_dev(kobj); | 391 | struct device *dev = kobj_to_dev(kobj); |
| 392 | struct dfl_feature_dev_data *fdata; | ||
| 391 | umode_t mode = attr->mode; | 393 | umode_t mode = attr->mode; |
| 392 | void __iomem *base; | 394 | void __iomem *base; |
| 393 | 395 | ||
| 394 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); | 396 | fdata = to_dfl_feature_dev_data(dev); |
| 397 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); | ||
| 395 | 398 | ||
| 396 | if (dfl_feature_revision(base) > 0) { | 399 | if (dfl_feature_revision(base) > 0) { |
| 397 | /* | 400 | /* |
| @@ -456,21 +459,21 @@ static const struct dfl_feature_ops port_hdr_ops = { · 58 unmodified lines | |||
| 456 | static ssize_t | 459 | static ssize_t |
| 457 | afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) | 460 | afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 458 | { | 461 | { |
| 459 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 462 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 460 | void __iomem *base; | 463 | void __iomem *base; |
| 461 | u64 guidl, guidh; | 464 | u64 guidl, guidh; |
| 462 | 465 | ||
| 463 | base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_AFU); | 466 | base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_AFU); |
| 464 | 467 | ||
| 465 | mutex_lock(&pdata->lock); | 468 | mutex_lock(&fdata->lock); |
| 466 | if (pdata->disable_count) { | 469 | if (fdata->disable_count) { |
| 467 | mutex_unlock(&pdata->lock); | 470 | mutex_unlock(&fdata->lock); |
| 468 | return -EBUSY; | 471 | return -EBUSY; |
| 469 | } | 472 | } |
| 470 | 473 | ||
| 471 | guidl = readq(base + GUID_L); | 474 | guidl = readq(base + GUID_L); |
| 472 | guidh = readq(base + GUID_H); | 475 | guidh = readq(base + GUID_H); |
| 473 | mutex_unlock(&pdata->lock); | 476 | mutex_unlock(&fdata->lock); |
| 474 | 477 | ||
| 475 | return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl); | 478 | return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl); |
| 476 | } | 479 | } |
| @@ -485,12 +488,14 @@ static umode_t port_afu_attrs_visible(struct kobject *kobj, · 8 unmodified lines | |||
| 485 | struct attribute *attr, int n) | 488 | struct attribute *attr, int n) |
| 486 | { | 489 | { |
| 487 | struct device *dev = kobj_to_dev(kobj); | 490 | struct device *dev = kobj_to_dev(kobj); |
| 491 | struct dfl_feature_dev_data *fdata; | ||
| 488 | 492 | ||
| 493 | fdata = to_dfl_feature_dev_data(dev); | ||
| 489 | /* | 494 | /* |
| 490 | * sysfs entries are visible only if related private feature is | 495 | * sysfs entries are visible only if related private feature is |
| 491 | * enumerated. | 496 | * enumerated. |
| 492 | */ | 497 | */ |
| 493 | if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) | 498 | if (!dfl_get_feature_by_id(fdata, PORT_FEATURE_ID_AFU)) |
| 494 | return 0; | 499 | return 0; |
| 495 | 500 | ||
| 496 | return attr->mode; | 501 | return attr->mode; |
| @@ -504,9 +509,10 @@ static const struct attribute_group port_afu_group = { · 7 unmodified lines | |||
| 504 | static int port_afu_init(struct platform_device *pdev, | 509 | static int port_afu_init(struct platform_device *pdev, |
| 505 | struct dfl_feature *feature) | 510 | struct dfl_feature *feature) |
| 506 | { | 511 | { |
| 512 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); | ||
| 507 | struct resource *res = &pdev->resource[feature->resource_index]; | 513 | struct resource *res = &pdev->resource[feature->resource_index]; |
| 508 | 514 | ||
| 509 | return afu_mmio_region_add(dev_get_platdata(&pdev->dev), | 515 | return afu_mmio_region_add(fdata, |
| 510 | DFL_PORT_REGION_INDEX_AFU, | 516 | DFL_PORT_REGION_INDEX_AFU, |
| 511 | resource_size(res), res->start, | 517 | resource_size(res), res->start, |
| 512 | DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | | 518 | DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | |
| @@ -525,9 +531,10 @@ static const struct dfl_feature_ops port_afu_ops = { · 12 unmodified lines | |||
| 525 | static int port_stp_init(struct platform_device *pdev, | 531 | static int port_stp_init(struct platform_device *pdev, |
| 526 | struct dfl_feature *feature) | 532 | struct dfl_feature *feature) |
| 527 | { | 533 | { |
| 534 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); | ||
| 528 | struct resource *res = &pdev->resource[feature->resource_index]; | 535 | struct resource *res = &pdev->resource[feature->resource_index]; |
| 529 | 536 | ||
| 530 | return afu_mmio_region_add(dev_get_platdata(&pdev->dev), | 537 | return afu_mmio_region_add(fdata, |
| 531 | DFL_PORT_REGION_INDEX_STP, | 538 | DFL_PORT_REGION_INDEX_STP, |
| 532 | resource_size(res), res->start, | 539 | resource_size(res), res->start, |
| 533 | DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | | 540 | DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | |
| @@ -595,22 +602,18 @@ static struct dfl_feature_driver port_feature_drvs[] = { · 61 unmodified lines | |||
| 595 | 602 | ||
| 596 | static int afu_open(struct inode *inode, struct file *filp) | 603 | static int afu_open(struct inode *inode, struct file *filp) |
| 597 | { | 604 | { |
| 598 | struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); | 605 | struct dfl_feature_dev_data *fdata = dfl_fpga_inode_to_feature_dev_data(inode); |
| 599 | struct dfl_feature_platform_data *pdata; | 606 | struct platform_device *fdev = fdata->dev; |
| 600 | int ret; | 607 | int ret; |
| 601 | 608 | ||
| 602 | pdata = dev_get_platdata(&fdev->dev); | 609 | mutex_lock(&fdata->lock); |
| 603 | if (WARN_ON(!pdata)) | 610 | ret = dfl_feature_dev_use_begin(fdata, filp->f_flags & O_EXCL); |
| 604 | return -ENODEV; | ||
| 605 | |||
| 606 | mutex_lock(&pdata->lock); | ||
| 607 | ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); | ||
| 608 | if (!ret) { | 611 | if (!ret) { |
| 609 | dev_dbg(&fdev->dev, "Device File Opened %d Times\n", | 612 | dev_dbg(&fdev->dev, "Device File Opened %d Times\n", |
| 610 | dfl_feature_dev_use_count(pdata)); | 613 | dfl_feature_dev_use_count(fdata)); |
| 611 | filp->private_data = fdev; | 614 | filp->private_data = fdev; |
| 612 | } | 615 | } |
| 613 | mutex_unlock(&pdata->lock); | 616 | mutex_unlock(&fdata->lock); |
| 614 | 617 | ||
| 615 | return ret; | 618 | return ret; |
| 616 | } | 619 | } |
| @@ -618,29 +621,29 @@ static int afu_open(struct inode *inode, struct file *filp) · 1 unmodified line | |||
| 618 | static int afu_release(struct inode *inode, struct file *filp) | 621 | static int afu_release(struct inode *inode, struct file *filp) |
| 619 | { | 622 | { |
| 620 | struct platform_device *pdev = filp->private_data; | 623 | struct platform_device *pdev = filp->private_data; |
| 621 | struct dfl_feature_platform_data *pdata; | 624 | struct dfl_feature_dev_data *fdata; |
| 622 | struct dfl_feature *feature; | 625 | struct dfl_feature *feature; |
| 623 | 626 | ||
| 624 | dev_dbg(&pdev->dev, "Device File Release\n"); | 627 | dev_dbg(&pdev->dev, "Device File Release\n"); |
| 625 | 628 | ||
| 626 | pdata = dev_get_platdata(&pdev->dev); | 629 | fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 627 | 630 | ||
| 628 | mutex_lock(&pdata->lock); | 631 | mutex_lock(&fdata->lock); |
| 629 | dfl_feature_dev_use_end(pdata); | 632 | dfl_feature_dev_use_end(fdata); |
| 630 | 633 | ||
| 631 | if (!dfl_feature_dev_use_count(pdata)) { | 634 | if (!dfl_feature_dev_use_count(fdata)) { |
| 632 | dfl_fpga_dev_for_each_feature(pdata, feature) | 635 | dfl_fpga_dev_for_each_feature(fdata, feature) |
| 633 | dfl_fpga_set_irq_triggers(feature, 0, | 636 | dfl_fpga_set_irq_triggers(feature, 0, |
| 634 | feature->nr_irqs, NULL); | 637 | feature->nr_irqs, NULL); |
| 635 | __port_reset(pdev); | 638 | __port_reset(fdata); |
| 636 | afu_dma_region_destroy(pdata); | 639 | afu_dma_region_destroy(fdata); |
| 637 | } | 640 | } |
| 638 | mutex_unlock(&pdata->lock); | 641 | mutex_unlock(&fdata->lock); |
| 639 | 642 | ||
| 640 | return 0; | 643 | return 0; |
| 641 | } | 644 | } |
| 642 | 645 | ||
| 643 | static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata, | 646 | static long afu_ioctl_check_extension(struct dfl_feature_dev_data *fdata, |
| 644 | unsigned long arg) | 647 | unsigned long arg) |
| 645 | { | 648 | { |
| 646 | /* No extension support for now */ | 649 | /* No extension support for now */ |
| @@ -648,7 +651,7 @@ static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata, · 1 unmodified line | |||
| 648 | } | 651 | } |
| 649 | 652 | ||
| 650 | static long | 653 | static long |
| 651 | afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) | 654 | afu_ioctl_get_info(struct dfl_feature_dev_data *fdata, void __user *arg) |
| 652 | { | 655 | { |
| 653 | struct dfl_fpga_port_info info; | 656 | struct dfl_fpga_port_info info; |
| 654 | struct dfl_afu *afu; | 657 | struct dfl_afu *afu; |
| @@ -662,12 +665,12 @@ afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) · 7 unmodified lines | |||
| 662 | if (info.argsz < minsz) | 665 | if (info.argsz < minsz) |
| 663 | return -EINVAL; | 666 | return -EINVAL; |
| 664 | 667 | ||
| 665 | mutex_lock(&pdata->lock); | 668 | mutex_lock(&fdata->lock); |
| 666 | afu = dfl_fpga_pdata_get_private(pdata); | 669 | afu = dfl_fpga_fdata_get_private(fdata); |
| 667 | info.flags = 0; | 670 | info.flags = 0; |
| 668 | info.num_regions = afu->num_regions; | 671 | info.num_regions = afu->num_regions; |
| 669 | info.num_umsgs = afu->num_umsgs; | 672 | info.num_umsgs = afu->num_umsgs; |
| 670 | mutex_unlock(&pdata->lock); | 673 | mutex_unlock(&fdata->lock); |
| 671 | 674 | ||
| 672 | if (copy_to_user(arg, &info, sizeof(info))) | 675 | if (copy_to_user(arg, &info, sizeof(info))) |
| 673 | return -EFAULT; | 676 | return -EFAULT; |
| @@ -675,7 +678,7 @@ afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) · 1 unmodified line | |||
| 675 | return 0; | 678 | return 0; |
| 676 | } | 679 | } |
| 677 | 680 | ||
| 678 | static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, | 681 | static long afu_ioctl_get_region_info(struct dfl_feature_dev_data *fdata, |
| 679 | void __user *arg) | 682 | void __user *arg) |
| 680 | { | 683 | { |
| 681 | struct dfl_fpga_port_region_info rinfo; | 684 | struct dfl_fpga_port_region_info rinfo; |
| @@ -691,7 +694,7 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, · 9 unmodified lines | |||
| 691 | if (rinfo.argsz < minsz || rinfo.padding) | 694 | if (rinfo.argsz < minsz || rinfo.padding) |
| 692 | return -EINVAL; | 695 | return -EINVAL; |
| 693 | 696 | ||
| 694 | ret = afu_mmio_region_get_by_index(pdata, rinfo.index, ®ion); | 697 | ret = afu_mmio_region_get_by_index(fdata, rinfo.index, ®ion); |
| 695 | if (ret) | 698 | if (ret) |
| 696 | return ret; | 699 | return ret; |
| 697 | 700 | ||
| @@ -706,7 +709,7 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, · 8 unmodified lines | |||
| 706 | } | 709 | } |
| 707 | 710 | ||
| 708 | static long | 711 | static long |
| 709 | afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) | 712 | afu_ioctl_dma_map(struct dfl_feature_dev_data *fdata, void __user *arg) |
| 710 | { | 713 | { |
| 711 | struct dfl_fpga_port_dma_map map; | 714 | struct dfl_fpga_port_dma_map map; |
| 712 | unsigned long minsz; | 715 | unsigned long minsz; |
| @@ -720,16 +723,16 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) · 7 unmodified lines | |||
| 720 | if (map.argsz < minsz || map.flags) | 723 | if (map.argsz < minsz || map.flags) |
| 721 | return -EINVAL; | 724 | return -EINVAL; |
| 722 | 725 | ||
| 723 | ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova); | 726 | ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova); |
| 724 | if (ret) | 727 | if (ret) |
| 725 | return ret; | 728 | return ret; |
| 726 | 729 | ||
| 727 | if (copy_to_user(arg, &map, sizeof(map))) { | 730 | if (copy_to_user(arg, &map, sizeof(map))) { |
| 728 | afu_dma_unmap_region(pdata, map.iova); | 731 | afu_dma_unmap_region(fdata, map.iova); |
| 729 | return -EFAULT; | 732 | return -EFAULT; |
| 730 | } | 733 | } |
| 731 | 734 | ||
| 732 | dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", | 735 | dev_dbg(&fdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", |
| 733 | (unsigned long long)map.user_addr, | 736 | (unsigned long long)map.user_addr, |
| 734 | (unsigned long long)map.length, | 737 | (unsigned long long)map.length, |
| 735 | (unsigned long long)map.iova); | 738 | (unsigned long long)map.iova); |
| @@ -738,7 +741,7 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) · 2 unmodified lines | |||
| 738 | } | 741 | } |
| 739 | 742 | ||
| 740 | static long | 743 | static long |
| 741 | afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) | 744 | afu_ioctl_dma_unmap(struct dfl_feature_dev_data *fdata, void __user *arg) |
| 742 | { | 745 | { |
| 743 | struct dfl_fpga_port_dma_unmap unmap; | 746 | struct dfl_fpga_port_dma_unmap unmap; |
| 744 | unsigned long minsz; | 747 | unsigned long minsz; |
| @@ -751,33 +754,33 @@ afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) · 6 unmodified lines | |||
| 751 | if (unmap.argsz < minsz || unmap.flags) | 754 | if (unmap.argsz < minsz || unmap.flags) |
| 752 | return -EINVAL; | 755 | return -EINVAL; |
| 753 | 756 | ||
| 754 | return afu_dma_unmap_region(pdata, unmap.iova); | 757 | return afu_dma_unmap_region(fdata, unmap.iova); |
| 755 | } | 758 | } |
| 756 | 759 | ||
| 757 | static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 760 | static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 758 | { | 761 | { |
| 759 | struct platform_device *pdev = filp->private_data; | 762 | struct platform_device *pdev = filp->private_data; |
| 760 | struct dfl_feature_platform_data *pdata; | 763 | struct dfl_feature_dev_data *fdata; |
| 761 | struct dfl_feature *f; | 764 | struct dfl_feature *f; |
| 762 | long ret; | 765 | long ret; |
| 763 | 766 | ||
| 764 | dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); | 767 | dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); |
| 765 | 768 | ||
| 766 | pdata = dev_get_platdata(&pdev->dev); | 769 | fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 767 | 770 | ||
| 768 | switch (cmd) { | 771 | switch (cmd) { |
| 769 | case DFL_FPGA_GET_API_VERSION: | 772 | case DFL_FPGA_GET_API_VERSION: |
| 770 | return DFL_FPGA_API_VERSION; | 773 | return DFL_FPGA_API_VERSION; |
| 771 | case DFL_FPGA_CHECK_EXTENSION: | 774 | case DFL_FPGA_CHECK_EXTENSION: |
| 772 | return afu_ioctl_check_extension(pdata, arg); | 775 | return afu_ioctl_check_extension(fdata, arg); |
| 773 | case DFL_FPGA_PORT_GET_INFO: | 776 | case DFL_FPGA_PORT_GET_INFO: |
| 774 | return afu_ioctl_get_info(pdata, (void __user *)arg); | 777 | return afu_ioctl_get_info(fdata, (void __user *)arg); |
| 775 | case DFL_FPGA_PORT_GET_REGION_INFO: | 778 | case DFL_FPGA_PORT_GET_REGION_INFO: |
| 776 | return afu_ioctl_get_region_info(pdata, (void __user *)arg); | 779 | return afu_ioctl_get_region_info(fdata, (void __user *)arg); |
| 777 | case DFL_FPGA_PORT_DMA_MAP: | 780 | case DFL_FPGA_PORT_DMA_MAP: |
| 778 | return afu_ioctl_dma_map(pdata, (void __user *)arg); | 781 | return afu_ioctl_dma_map(fdata, (void __user *)arg); |
| 779 | case DFL_FPGA_PORT_DMA_UNMAP: | 782 | case DFL_FPGA_PORT_DMA_UNMAP: |
| 780 | return afu_ioctl_dma_unmap(pdata, (void __user *)arg); | 783 | return afu_ioctl_dma_unmap(fdata, (void __user *)arg); |
| 781 | default: | 784 | default: |
| 782 | /* | 785 | /* |
| 783 | * Let sub-feature's ioctl function to handle the cmd | 786 | * Let sub-feature's ioctl function to handle the cmd |
| @@ -785,7 +788,7 @@ static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 1 unmodified line | |||
| 785 | * handled in this sub feature, and returns 0 and other | 788 | * handled in this sub feature, and returns 0 and other |
| 786 | * error code if cmd is handled. | 789 | * error code if cmd is handled. |
| 787 | */ | 790 | */ |
| 788 | dfl_fpga_dev_for_each_feature(pdata, f) | 791 | dfl_fpga_dev_for_each_feature(fdata, f) |
| 789 | if (f->ops && f->ops->ioctl) { | 792 | if (f->ops && f->ops->ioctl) { |
| 790 | ret = f->ops->ioctl(pdev, f, cmd, arg); | 793 | ret = f->ops->ioctl(pdev, f, cmd, arg); |
| 791 | if (ret != -ENODEV) | 794 | if (ret != -ENODEV) |
| @@ -805,8 +808,8 @@ static const struct vm_operations_struct afu_vma_ops = { · 13 unmodified lines | |||
| 805 | static int afu_mmap(struct file *filp, struct vm_area_struct *vma) | 808 | static int afu_mmap(struct file *filp, struct vm_area_struct *vma) |
| 806 | { | 809 | { |
| 807 | struct platform_device *pdev = filp->private_data; | 810 | struct platform_device *pdev = filp->private_data; |
| 808 | struct dfl_feature_platform_data *pdata; | ||
| 809 | u64 size = vma->vm_end - vma->vm_start; | 811 | u64 size = vma->vm_end - vma->vm_start; |
| 812 | struct dfl_feature_dev_data *fdata; | ||
| 810 | struct dfl_afu_mmio_region region; | 813 | struct dfl_afu_mmio_region region; |
| 811 | u64 offset; | 814 | u64 offset; |
| 812 | int ret; | 815 | int ret; |
| @@ -814,10 +817,10 @@ static int afu_mmap(struct file *filp, struct vm_area_struct *vma) · 1 unmodified line | |||
| 814 | if (!(vma->vm_flags & VM_SHARED)) | 817 | if (!(vma->vm_flags & VM_SHARED)) |
| 815 | return -EINVAL; | 818 | return -EINVAL; |
| 816 | 819 | ||
| 817 | pdata = dev_get_platdata(&pdev->dev); | 820 | fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 818 | 821 | ||
| 819 | offset = vma->vm_pgoff << PAGE_SHIFT; | 822 | offset = vma->vm_pgoff << PAGE_SHIFT; |
| 820 | ret = afu_mmio_region_get_by_offset(pdata, offset, size, ®ion); | 823 | ret = afu_mmio_region_get_by_offset(fdata, offset, size, ®ion); |
| 821 | if (ret) | 824 | if (ret) |
| 822 | return ret; | 825 | return ret; |
| 823 | 826 | ||
| @@ -851,46 +854,45 @@ static const struct file_operations afu_fops = { · 27 unmodified lines | |||
| 851 | 854 | ||
| 852 | static int afu_dev_init(struct platform_device *pdev) | 855 | static int afu_dev_init(struct platform_device *pdev) |
| 853 | { | 856 | { |
| 854 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 857 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 855 | struct dfl_afu *afu; | 858 | struct dfl_afu *afu; |
| 856 | 859 | ||
| 857 | afu = devm_kzalloc(&pdev->dev, sizeof(*afu), GFP_KERNEL); | 860 | afu = devm_kzalloc(&pdev->dev, sizeof(*afu), GFP_KERNEL); |
| 858 | if (!afu) | 861 | if (!afu) |
| 859 | return -ENOMEM; | 862 | return -ENOMEM; |
| 860 | 863 | ||
| 861 | mutex_lock(&pdata->lock); | 864 | mutex_lock(&fdata->lock); |
| 862 | dfl_fpga_pdata_set_private(pdata, afu); | 865 | dfl_fpga_fdata_set_private(fdata, afu); |
| 863 | afu_mmio_region_init(pdata); | 866 | afu_mmio_region_init(fdata); |
| 864 | afu_dma_region_init(pdata); | 867 | afu_dma_region_init(fdata); |
| 865 | mutex_unlock(&pdata->lock); | 868 | mutex_unlock(&fdata->lock); |
| 866 | 869 | ||
| 867 | return 0; | 870 | return 0; |
| 868 | } | 871 | } |
| 869 | 872 | ||
| 870 | static int afu_dev_destroy(struct platform_device *pdev) | 873 | static int afu_dev_destroy(struct platform_device *pdev) |
| 871 | { | 874 | { |
| 872 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 875 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 873 | 876 | ||
| 874 | mutex_lock(&pdata->lock); | 877 | mutex_lock(&fdata->lock); |
| 875 | afu_mmio_region_destroy(pdata); | 878 | afu_mmio_region_destroy(fdata); |
| 876 | afu_dma_region_destroy(pdata); | 879 | afu_dma_region_destroy(fdata); |
| 877 | dfl_fpga_pdata_set_private(pdata, NULL); | 880 | dfl_fpga_fdata_set_private(fdata, NULL); |
| 878 | mutex_unlock(&pdata->lock); | 881 | mutex_unlock(&fdata->lock); |
| 879 | 882 | ||
| 880 | return 0; | 883 | return 0; |
| 881 | } | 884 | } |
| 882 | 885 | ||
| 883 | static int port_enable_set(struct platform_device *pdev, bool enable) | 886 | static int port_enable_set(struct dfl_feature_dev_data *fdata, bool enable) |
| 884 | { | 887 | { |
| 885 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
| 886 | int ret; | 888 | int ret; |
| 887 | 889 | ||
| 888 | mutex_lock(&pdata->lock); | 890 | mutex_lock(&fdata->lock); |
| 889 | if (enable) | 891 | if (enable) |
| 890 | ret = __afu_port_enable(pdev); | 892 | ret = __afu_port_enable(fdata); |
| 891 | else | 893 | else |
| 892 | ret = __afu_port_disable(pdev); | 894 | ret = __afu_port_disable(fdata); |
| 893 | mutex_unlock(&pdata->lock); | 895 | mutex_unlock(&fdata->lock); |
| 894 | 896 | ||
| 895 | return ret; | 897 | return ret; |
| 896 | } | 898 | } |
| @@ -12,11 +12,11 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | /** | 13 | /** |
| 14 | * afu_mmio_region_init - init function for afu mmio region support | 14 | * afu_mmio_region_init - init function for afu mmio region support |
| 15 | * @pdata: afu platform device's pdata. | 15 | * @fdata: afu feature dev data |
| 16 | */ | 16 | */ |
| 17 | void afu_mmio_region_init(struct dfl_feature_platform_data *pdata) | 17 | void afu_mmio_region_init(struct dfl_feature_dev_data *fdata) |
| 18 | { | 18 | { |
| 19 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 19 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 20 | 20 | ||
| 21 | INIT_LIST_HEAD(&afu->regions); | 21 | INIT_LIST_HEAD(&afu->regions); |
| 22 | } | 22 | } |
| @@ -39,7 +39,7 @@ static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu, · 16 unmodified lines | |||
| 39 | /** | 39 | /** |
| 40 | * afu_mmio_region_add - add a mmio region to given feature dev. | 40 | * afu_mmio_region_add - add a mmio region to given feature dev. |
| 41 | * | 41 | * |
| 42 | * @pdata: afu platform device's pdata. | 42 | * @fdata: afu feature dev data |
| 43 | * @region_index: region index. | 43 | * @region_index: region index. |
| 44 | * @region_size: region size. | 44 | * @region_size: region size. |
| 45 | * @phys: region's physical address of this region. | 45 | * @phys: region's physical address of this region. |
| @@ -47,14 +47,15 @@ static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu, · 1 unmodified line | |||
| 47 | * | 47 | * |
| 48 | * Return: 0 on success, negative error code otherwise. | 48 | * Return: 0 on success, negative error code otherwise. |
| 49 | */ | 49 | */ |
| 50 | int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, | 50 | int afu_mmio_region_add(struct dfl_feature_dev_data *fdata, |
| 51 | u32 region_index, u64 region_size, u64 phys, u32 flags) | 51 | u32 region_index, u64 region_size, u64 phys, u32 flags) |
| 52 | { | 52 | { |
| 53 | struct device *dev = &fdata->dev->dev; | ||
| 53 | struct dfl_afu_mmio_region *region; | 54 | struct dfl_afu_mmio_region *region; |
| 54 | struct dfl_afu *afu; | 55 | struct dfl_afu *afu; |
| 55 | int ret = 0; | 56 | int ret = 0; |
| 56 | 57 | ||
| 57 | region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL); | 58 | region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); |
| 58 | if (!region) | 59 | if (!region) |
| 59 | return -ENOMEM; | 60 | return -ENOMEM; |
| 60 | 61 | ||
| @@ -63,13 +64,13 @@ int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, · 2 unmodified lines | |||
| 63 | region->phys = phys; | 64 | region->phys = phys; |
| 64 | region->flags = flags; | 65 | region->flags = flags; |
| 65 | 66 | ||
| 66 | mutex_lock(&pdata->lock); | 67 | mutex_lock(&fdata->lock); |
| 67 | 68 | ||
| 68 | afu = dfl_fpga_pdata_get_private(pdata); | 69 | afu = dfl_fpga_fdata_get_private(fdata); |
| 69 | 70 | ||
| 70 | /* check if @index already exists */ | 71 | /* check if @index already exists */ |
| 71 | if (get_region_by_index(afu, region_index)) { | 72 | if (get_region_by_index(afu, region_index)) { |
| 72 | mutex_unlock(&pdata->lock); | 73 | mutex_unlock(&fdata->lock); |
| 73 | ret = -EEXIST; | 74 | ret = -EEXIST; |
| 74 | goto exit; | 75 | goto exit; |
| 75 | } | 76 | } |
| @@ -80,37 +81,37 @@ int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, · 4 unmodified lines | |||
| 80 | 81 | ||
| 81 | afu->region_cur_offset += region_size; | 82 | afu->region_cur_offset += region_size; |
| 82 | afu->num_regions++; | 83 | afu->num_regions++; |
| 83 | mutex_unlock(&pdata->lock); | 84 | mutex_unlock(&fdata->lock); |
| 84 | 85 | ||
| 85 | return 0; | 86 | return 0; |
| 86 | 87 | ||
| 87 | exit: | 88 | exit: |
| 88 | devm_kfree(&pdata->dev->dev, region); | 89 | devm_kfree(dev, region); |
| 89 | return ret; | 90 | return ret; |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | /** | 93 | /** |
| 93 | * afu_mmio_region_destroy - destroy all mmio regions under given feature dev. | 94 | * afu_mmio_region_destroy - destroy all mmio regions under given feature dev. |
| 94 | * @pdata: afu platform device's pdata. | 95 | * @fdata: afu feature dev data |
| 95 | */ | 96 | */ |
| 96 | void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata) | 97 | void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata) |
| 97 | { | 98 | { |
| 98 | struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); | 99 | struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); |
| 99 | struct dfl_afu_mmio_region *tmp, *region; | 100 | struct dfl_afu_mmio_region *tmp, *region; |
| 100 | 101 | ||
| 101 | list_for_each_entry_safe(region, tmp, &afu->regions, node) | 102 | list_for_each_entry_safe(region, tmp, &afu->regions, node) |
| 102 | devm_kfree(&pdata->dev->dev, region); | 103 | devm_kfree(&fdata->dev->dev, region); |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | /** | 106 | /** |
| 106 | * afu_mmio_region_get_by_index - find an afu region by index. | 107 | * afu_mmio_region_get_by_index - find an afu region by index. |
| 107 | * @pdata: afu platform device's pdata. | 108 | * @fdata: afu feature dev data |
| 108 | * @region_index: region index. | 109 | * @region_index: region index. |
| 109 | * @pregion: ptr to region for result. | 110 | * @pregion: ptr to region for result. |
| 110 | * | 111 | * |
| 111 | * Return: 0 on success, negative error code otherwise. | 112 | * Return: 0 on success, negative error code otherwise. |
| 112 | */ | 113 | */ |
| 113 | int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, | 114 | int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata, |
| 114 | u32 region_index, | 115 | u32 region_index, |
| 115 | struct dfl_afu_mmio_region *pregion) | 116 | struct dfl_afu_mmio_region *pregion) |
| 116 | { | 117 | { |
| @@ -118,8 +119,8 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, · 1 unmodified line | |||
| 118 | struct dfl_afu *afu; | 119 | struct dfl_afu *afu; |
| 119 | int ret = 0; | 120 | int ret = 0; |
| 120 | 121 | ||
| 121 | mutex_lock(&pdata->lock); | 122 | mutex_lock(&fdata->lock); |
| 122 | afu = dfl_fpga_pdata_get_private(pdata); | 123 | afu = dfl_fpga_fdata_get_private(fdata); |
| 123 | region = get_region_by_index(afu, region_index); | 124 | region = get_region_by_index(afu, region_index); |
| 124 | if (!region) { | 125 | if (!region) { |
| 125 | ret = -EINVAL; | 126 | ret = -EINVAL; |
| @@ -127,14 +128,14 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, · 1 unmodified line | |||
| 127 | } | 128 | } |
| 128 | *pregion = *region; | 129 | *pregion = *region; |
| 129 | exit: | 130 | exit: |
| 130 | mutex_unlock(&pdata->lock); | 131 | mutex_unlock(&fdata->lock); |
| 131 | return ret; | 132 | return ret; |
| 132 | } | 133 | } |
| 133 | 134 | ||
| 134 | /** | 135 | /** |
| 135 | * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size | 136 | * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size |
| 136 | * | 137 | * |
| 137 | * @pdata: afu platform device's pdata. | 138 | * @fdata: afu feature dev data |
| 138 | * @offset: region offset from start of the device fd. | 139 | * @offset: region offset from start of the device fd. |
| 139 | * @size: region size. | 140 | * @size: region size. |
| 140 | * @pregion: ptr to region for result. | 141 | * @pregion: ptr to region for result. |
| @@ -144,7 +145,7 @@ exit: · 3 unmodified lines | |||
| 144 | * | 145 | * |
| 145 | * Return: 0 on success, negative error code otherwise. | 146 | * Return: 0 on success, negative error code otherwise. |
| 146 | */ | 147 | */ |
| 147 | int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, | 148 | int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata, |
| 148 | u64 offset, u64 size, | 149 | u64 offset, u64 size, |
| 149 | struct dfl_afu_mmio_region *pregion) | 150 | struct dfl_afu_mmio_region *pregion) |
| 150 | { | 151 | { |
| @@ -152,8 +153,8 @@ int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, · 1 unmodified line | |||
| 152 | struct dfl_afu *afu; | 153 | struct dfl_afu *afu; |
| 153 | int ret = 0; | 154 | int ret = 0; |
| 154 | 155 | ||
| 155 | mutex_lock(&pdata->lock); | 156 | mutex_lock(&fdata->lock); |
| 156 | afu = dfl_fpga_pdata_get_private(pdata); | 157 | afu = dfl_fpga_fdata_get_private(fdata); |
| 157 | for_each_region(region, afu) | 158 | for_each_region(region, afu) |
| 158 | if (region->offset <= offset && | 159 | if (region->offset <= offset && |
| 159 | region->offset + region->size >= offset + size) { | 160 | region->offset + region->size >= offset + size) { |
| @@ -162,6 +163,6 @@ int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, · 2 unmodified lines | |||
| 162 | } | 163 | } |
| 163 | ret = -EINVAL; | 164 | ret = -EINVAL; |
| 164 | exit: | 165 | exit: |
| 165 | mutex_unlock(&pdata->lock); | 166 | mutex_unlock(&fdata->lock); |
| 166 | return ret; | 167 | return ret; |
| 167 | } | 168 | } |
| @@ -76,27 +76,27 @@ struct dfl_afu { · 75 unmodified lines | |||
| 76 | struct rb_root dma_regions; | 76 | struct rb_root dma_regions; |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | /* hold pdata->lock when call __afu_port_enable/disable */ | 79 | /* hold fdata->lock when call __afu_port_enable/disable */ |
| 80 | int __afu_port_enable(struct platform_device *pdev); | 80 | int __afu_port_enable(struct dfl_feature_dev_data *fdata); |
| 81 | int __afu_port_disable(struct platform_device *pdev); | 81 | int __afu_port_disable(struct dfl_feature_dev_data *fdata); |
| 82 | 82 | ||
| 83 | void afu_mmio_region_init(struct dfl_feature_platform_data *pdata); | 83 | void afu_mmio_region_init(struct dfl_feature_dev_data *fdata); |
| 84 | int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, | 84 | int afu_mmio_region_add(struct dfl_feature_dev_data *fdata, |
| 85 | u32 region_index, u64 region_size, u64 phys, u32 flags); | 85 | u32 region_index, u64 region_size, u64 phys, u32 flags); |
| 86 | void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata); | 86 | void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata); |
| 87 | int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, | 87 | int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata, |
| 88 | u32 region_index, | 88 | u32 region_index, |
| 89 | struct dfl_afu_mmio_region *pregion); | 89 | struct dfl_afu_mmio_region *pregion); |
| 90 | int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, | 90 | int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata, |
| 91 | u64 offset, u64 size, | 91 | u64 offset, u64 size, |
| 92 | struct dfl_afu_mmio_region *pregion); | 92 | struct dfl_afu_mmio_region *pregion); |
| 93 | void afu_dma_region_init(struct dfl_feature_platform_data *pdata); | 93 | void afu_dma_region_init(struct dfl_feature_dev_data *fdata); |
| 94 | void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata); | 94 | void afu_dma_region_destroy(struct dfl_feature_dev_data *fdata); |
| 95 | int afu_dma_map_region(struct dfl_feature_platform_data *pdata, | 95 | int afu_dma_map_region(struct dfl_feature_dev_data *fdata, |
| 96 | u64 user_addr, u64 length, u64 *iova); | 96 | u64 user_addr, u64 length, u64 *iova); |
| 97 | int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova); | 97 | int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova); |
| 98 | struct dfl_afu_dma_region * | 98 | struct dfl_afu_dma_region * |
| 99 | afu_dma_region_find(struct dfl_feature_platform_data *pdata, | 99 | afu_dma_region_find(struct dfl_feature_dev_data *fdata, |
| 100 | u64 iova, u64 size); | 100 | u64 iova, u64 size); |
| 101 | 101 | ||
| 102 | extern const struct dfl_feature_ops port_err_ops; | 102 | extern const struct dfl_feature_ops port_err_ops; |
| @@ -22,34 +22,34 @@ · 21 unmodified lines | |||
| 22 | struct fme_br_priv { | 22 | struct fme_br_priv { |
| 23 | struct dfl_fme_br_pdata *pdata; | 23 | struct dfl_fme_br_pdata *pdata; |
| 24 | struct dfl_fpga_port_ops *port_ops; | 24 | struct dfl_fpga_port_ops *port_ops; |
| 25 | struct platform_device *port_pdev; | 25 | struct dfl_feature_dev_data *port_fdata; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | static int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) | 28 | static int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) |
| 29 | { | 29 | { |
| 30 | struct fme_br_priv *priv = bridge->priv; | 30 | struct fme_br_priv *priv = bridge->priv; |
| 31 | struct platform_device *port_pdev; | 31 | struct dfl_feature_dev_data *port_fdata; |
| 32 | struct dfl_fpga_port_ops *ops; | 32 | struct dfl_fpga_port_ops *ops; |
| 33 | 33 | ||
| 34 | if (!priv->port_pdev) { | 34 | if (!priv->port_fdata) { |
| 35 | port_pdev = dfl_fpga_cdev_find_port(priv->pdata->cdev, | 35 | port_fdata = dfl_fpga_cdev_find_port_data(priv->pdata->cdev, |
| 36 | &priv->pdata->port_id, | 36 | &priv->pdata->port_id, |
| 37 | dfl_fpga_check_port_id); | 37 | dfl_fpga_check_port_id); |
| 38 | if (!port_pdev) | 38 | if (!port_fdata) |
| 39 | return -ENODEV; | 39 | return -ENODEV; |
| 40 | 40 | ||
| 41 | priv->port_pdev = port_pdev; | 41 | priv->port_fdata = port_fdata; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | if (priv->port_pdev && !priv->port_ops) { | 44 | if (priv->port_fdata && !priv->port_ops) { |
| 45 | ops = dfl_fpga_port_ops_get(priv->port_pdev); | 45 | ops = dfl_fpga_port_ops_get(priv->port_fdata); |
| 46 | if (!ops || !ops->enable_set) | 46 | if (!ops || !ops->enable_set) |
| 47 | return -ENOENT; | 47 | return -ENOENT; |
| 48 | 48 | ||
| 49 | priv->port_ops = ops; | 49 | priv->port_ops = ops; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | return priv->port_ops->enable_set(priv->port_pdev, enable); | 52 | return priv->port_ops->enable_set(priv->port_fdata, enable); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static const struct fpga_bridge_ops fme_bridge_ops = { | 55 | static const struct fpga_bridge_ops fme_bridge_ops = { |
| @@ -85,8 +85,6 @@ static void fme_br_remove(struct platform_device *pdev) · 29 unmodified lines | |||
| 85 | 85 | ||
| 86 | fpga_bridge_unregister(br); | 86 | fpga_bridge_unregister(br); |
| 87 | 87 | ||
| 88 | if (priv->port_pdev) | ||
| 89 | put_device(&priv->port_pdev->dev); | ||
| 90 | if (priv->port_ops) | 88 | if (priv->port_ops) |
| 91 | dfl_fpga_port_ops_put(priv->port_ops); | 89 | dfl_fpga_port_ops_put(priv->port_ops); |
| 92 | } | 90 | } |
| @@ -42,15 +42,15 @@ · 41 unmodified lines | |||
| 42 | static ssize_t pcie0_errors_show(struct device *dev, | 42 | static ssize_t pcie0_errors_show(struct device *dev, |
| 43 | struct device_attribute *attr, char *buf) | 43 | struct device_attribute *attr, char *buf) |
| 44 | { | 44 | { |
| 45 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 45 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 46 | void __iomem *base; | 46 | void __iomem *base; |
| 47 | u64 value; | 47 | u64 value; |
| 48 | 48 | ||
| 49 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 49 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 50 | 50 | ||
| 51 | mutex_lock(&pdata->lock); | 51 | mutex_lock(&fdata->lock); |
| 52 | value = readq(base + PCIE0_ERROR); | 52 | value = readq(base + PCIE0_ERROR); |
| 53 | mutex_unlock(&pdata->lock); | 53 | mutex_unlock(&fdata->lock); |
| 54 | 54 | ||
| 55 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); | 55 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); |
| 56 | } | 56 | } |
| @@ -59,7 +59,7 @@ static ssize_t pcie0_errors_store(struct device *dev, · 2 unmodified lines | |||
| 59 | struct device_attribute *attr, | 59 | struct device_attribute *attr, |
| 60 | const char *buf, size_t count) | 60 | const char *buf, size_t count) |
| 61 | { | 61 | { |
| 62 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 62 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 63 | void __iomem *base; | 63 | void __iomem *base; |
| 64 | int ret = 0; | 64 | int ret = 0; |
| 65 | u64 v, val; | 65 | u64 v, val; |
| @@ -67,9 +67,9 @@ static ssize_t pcie0_errors_store(struct device *dev, · 1 unmodified line | |||
| 67 | if (kstrtou64(buf, 0, &val)) | 67 | if (kstrtou64(buf, 0, &val)) |
| 68 | return -EINVAL; | 68 | return -EINVAL; |
| 69 | 69 | ||
| 70 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 70 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 71 | 71 | ||
| 72 | mutex_lock(&pdata->lock); | 72 | mutex_lock(&fdata->lock); |
| 73 | writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK); | 73 | writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK); |
| 74 | 74 | ||
| 75 | v = readq(base + PCIE0_ERROR); | 75 | v = readq(base + PCIE0_ERROR); |
| @@ -79,7 +79,7 @@ static ssize_t pcie0_errors_store(struct device *dev, · 3 unmodified lines | |||
| 79 | ret = -EINVAL; | 79 | ret = -EINVAL; |
| 80 | 80 | ||
| 81 | writeq(0ULL, base + PCIE0_ERROR_MASK); | 81 | writeq(0ULL, base + PCIE0_ERROR_MASK); |
| 82 | mutex_unlock(&pdata->lock); | 82 | mutex_unlock(&fdata->lock); |
| 83 | return ret ? ret : count; | 83 | return ret ? ret : count; |
| 84 | } | 84 | } |
| 85 | static DEVICE_ATTR_RW(pcie0_errors); | 85 | static DEVICE_ATTR_RW(pcie0_errors); |
| @@ -87,15 +87,15 @@ static DEVICE_ATTR_RW(pcie0_errors); · 1 unmodified line | |||
| 87 | static ssize_t pcie1_errors_show(struct device *dev, | 87 | static ssize_t pcie1_errors_show(struct device *dev, |
| 88 | struct device_attribute *attr, char *buf) | 88 | struct device_attribute *attr, char *buf) |
| 89 | { | 89 | { |
| 90 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 90 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 91 | void __iomem *base; | 91 | void __iomem *base; |
| 92 | u64 value; | 92 | u64 value; |
| 93 | 93 | ||
| 94 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 94 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 95 | 95 | ||
| 96 | mutex_lock(&pdata->lock); | 96 | mutex_lock(&fdata->lock); |
| 97 | value = readq(base + PCIE1_ERROR); | 97 | value = readq(base + PCIE1_ERROR); |
| 98 | mutex_unlock(&pdata->lock); | 98 | mutex_unlock(&fdata->lock); |
| 99 | 99 | ||
| 100 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); | 100 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); |
| 101 | } | 101 | } |
| @@ -104,7 +104,7 @@ static ssize_t pcie1_errors_store(struct device *dev, · 2 unmodified lines | |||
| 104 | struct device_attribute *attr, | 104 | struct device_attribute *attr, |
| 105 | const char *buf, size_t count) | 105 | const char *buf, size_t count) |
| 106 | { | 106 | { |
| 107 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 107 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 108 | void __iomem *base; | 108 | void __iomem *base; |
| 109 | int ret = 0; | 109 | int ret = 0; |
| 110 | u64 v, val; | 110 | u64 v, val; |
| @@ -112,9 +112,9 @@ static ssize_t pcie1_errors_store(struct device *dev, · 1 unmodified line | |||
| 112 | if (kstrtou64(buf, 0, &val)) | 112 | if (kstrtou64(buf, 0, &val)) |
| 113 | return -EINVAL; | 113 | return -EINVAL; |
| 114 | 114 | ||
| 115 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 115 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 116 | 116 | ||
| 117 | mutex_lock(&pdata->lock); | 117 | mutex_lock(&fdata->lock); |
| 118 | writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK); | 118 | writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK); |
| 119 | 119 | ||
| 120 | v = readq(base + PCIE1_ERROR); | 120 | v = readq(base + PCIE1_ERROR); |
| @@ -124,7 +124,7 @@ static ssize_t pcie1_errors_store(struct device *dev, · 3 unmodified lines | |||
| 124 | ret = -EINVAL; | 124 | ret = -EINVAL; |
| 125 | 125 | ||
| 126 | writeq(0ULL, base + PCIE1_ERROR_MASK); | 126 | writeq(0ULL, base + PCIE1_ERROR_MASK); |
| 127 | mutex_unlock(&pdata->lock); | 127 | mutex_unlock(&fdata->lock); |
| 128 | return ret ? ret : count; | 128 | return ret ? ret : count; |
| 129 | } | 129 | } |
| 130 | static DEVICE_ATTR_RW(pcie1_errors); | 130 | static DEVICE_ATTR_RW(pcie1_errors); |
| @@ -132,9 +132,10 @@ static DEVICE_ATTR_RW(pcie1_errors); · 1 unmodified line | |||
| 132 | static ssize_t nonfatal_errors_show(struct device *dev, | 132 | static ssize_t nonfatal_errors_show(struct device *dev, |
| 133 | struct device_attribute *attr, char *buf) | 133 | struct device_attribute *attr, char *buf) |
| 134 | { | 134 | { |
| 135 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 135 | void __iomem *base; | 136 | void __iomem *base; |
| 136 | 137 | ||
| 137 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 138 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 138 | 139 | ||
| 139 | return sprintf(buf, "0x%llx\n", | 140 | return sprintf(buf, "0x%llx\n", |
| 140 | (unsigned long long)readq(base + RAS_NONFAT_ERROR)); | 141 | (unsigned long long)readq(base + RAS_NONFAT_ERROR)); |
| @@ -144,9 +145,10 @@ static DEVICE_ATTR_RO(nonfatal_errors); · 3 unmodified lines | |||
| 144 | static ssize_t catfatal_errors_show(struct device *dev, | 145 | static ssize_t catfatal_errors_show(struct device *dev, |
| 145 | struct device_attribute *attr, char *buf) | 146 | struct device_attribute *attr, char *buf) |
| 146 | { | 147 | { |
| 148 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 147 | void __iomem *base; | 149 | void __iomem *base; |
| 148 | 150 | ||
| 149 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 151 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 150 | 152 | ||
| 151 | return sprintf(buf, "0x%llx\n", | 153 | return sprintf(buf, "0x%llx\n", |
| 152 | (unsigned long long)readq(base + RAS_CATFAT_ERROR)); | 154 | (unsigned long long)readq(base + RAS_CATFAT_ERROR)); |
| @@ -156,15 +158,15 @@ static DEVICE_ATTR_RO(catfatal_errors); · 3 unmodified lines | |||
| 156 | static ssize_t inject_errors_show(struct device *dev, | 158 | static ssize_t inject_errors_show(struct device *dev, |
| 157 | struct device_attribute *attr, char *buf) | 159 | struct device_attribute *attr, char *buf) |
| 158 | { | 160 | { |
| 159 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 161 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 160 | void __iomem *base; | 162 | void __iomem *base; |
| 161 | u64 v; | 163 | u64 v; |
| 162 | 164 | ||
| 163 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 165 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 164 | 166 | ||
| 165 | mutex_lock(&pdata->lock); | 167 | mutex_lock(&fdata->lock); |
| 166 | v = readq(base + RAS_ERROR_INJECT); | 168 | v = readq(base + RAS_ERROR_INJECT); |
| 167 | mutex_unlock(&pdata->lock); | 169 | mutex_unlock(&fdata->lock); |
| 168 | 170 | ||
| 169 | return sprintf(buf, "0x%llx\n", | 171 | return sprintf(buf, "0x%llx\n", |
| 170 | (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v)); | 172 | (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v)); |
| @@ -174,7 +176,7 @@ static ssize_t inject_errors_store(struct device *dev, · 3 unmodified lines | |||
| 174 | struct device_attribute *attr, | 176 | struct device_attribute *attr, |
| 175 | const char *buf, size_t count) | 177 | const char *buf, size_t count) |
| 176 | { | 178 | { |
| 177 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 179 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 178 | void __iomem *base; | 180 | void __iomem *base; |
| 179 | u8 inject_error; | 181 | u8 inject_error; |
| 180 | u64 v; | 182 | u64 v; |
| @@ -185,14 +187,14 @@ static ssize_t inject_errors_store(struct device *dev, · 4 unmodified lines | |||
| 185 | if (inject_error & ~INJECT_ERROR_MASK) | 187 | if (inject_error & ~INJECT_ERROR_MASK) |
| 186 | return -EINVAL; | 188 | return -EINVAL; |
| 187 | 189 | ||
| 188 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 190 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 189 | 191 | ||
| 190 | mutex_lock(&pdata->lock); | 192 | mutex_lock(&fdata->lock); |
| 191 | v = readq(base + RAS_ERROR_INJECT); | 193 | v = readq(base + RAS_ERROR_INJECT); |
| 192 | v &= ~INJECT_ERROR_MASK; | 194 | v &= ~INJECT_ERROR_MASK; |
| 193 | v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error); | 195 | v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error); |
| 194 | writeq(v, base + RAS_ERROR_INJECT); | 196 | writeq(v, base + RAS_ERROR_INJECT); |
| 195 | mutex_unlock(&pdata->lock); | 197 | mutex_unlock(&fdata->lock); |
| 196 | 198 | ||
| 197 | return count; | 199 | return count; |
| 198 | } | 200 | } |
| @@ -201,15 +203,15 @@ static DEVICE_ATTR_RW(inject_errors); · 2 unmodified lines | |||
| 201 | static ssize_t fme_errors_show(struct device *dev, | 203 | static ssize_t fme_errors_show(struct device *dev, |
| 202 | struct device_attribute *attr, char *buf) | 204 | struct device_attribute *attr, char *buf) |
| 203 | { | 205 | { |
| 204 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 206 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 205 | void __iomem *base; | 207 | void __iomem *base; |
| 206 | u64 value; | 208 | u64 value; |
| 207 | 209 | ||
| 208 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 210 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 209 | 211 | ||
| 210 | mutex_lock(&pdata->lock); | 212 | mutex_lock(&fdata->lock); |
| 211 | value = readq(base + FME_ERROR); | 213 | value = readq(base + FME_ERROR); |
| 212 | mutex_unlock(&pdata->lock); | 214 | mutex_unlock(&fdata->lock); |
| 213 | 215 | ||
| 214 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); | 216 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); |
| 215 | } | 217 | } |
| @@ -218,7 +220,7 @@ static ssize_t fme_errors_store(struct device *dev, · 2 unmodified lines | |||
| 218 | struct device_attribute *attr, | 220 | struct device_attribute *attr, |
| 219 | const char *buf, size_t count) | 221 | const char *buf, size_t count) |
| 220 | { | 222 | { |
| 221 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 223 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 222 | void __iomem *base; | 224 | void __iomem *base; |
| 223 | u64 v, val; | 225 | u64 v, val; |
| 224 | int ret = 0; | 226 | int ret = 0; |
| @@ -226,9 +228,9 @@ static ssize_t fme_errors_store(struct device *dev, · 1 unmodified line | |||
| 226 | if (kstrtou64(buf, 0, &val)) | 228 | if (kstrtou64(buf, 0, &val)) |
| 227 | return -EINVAL; | 229 | return -EINVAL; |
| 228 | 230 | ||
| 229 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 231 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 230 | 232 | ||
| 231 | mutex_lock(&pdata->lock); | 233 | mutex_lock(&fdata->lock); |
| 232 | writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK); | 234 | writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK); |
| 233 | 235 | ||
| 234 | v = readq(base + FME_ERROR); | 236 | v = readq(base + FME_ERROR); |
| @@ -240,7 +242,7 @@ static ssize_t fme_errors_store(struct device *dev, · 5 unmodified lines | |||
| 240 | /* Workaround: disable MBP_ERROR if feature revision is 0 */ | 242 | /* Workaround: disable MBP_ERROR if feature revision is 0 */ |
| 241 | writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR, | 243 | writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR, |
| 242 | base + FME_ERROR_MASK); | 244 | base + FME_ERROR_MASK); |
| 243 | mutex_unlock(&pdata->lock); | 245 | mutex_unlock(&fdata->lock); |
| 244 | return ret ? ret : count; | 246 | return ret ? ret : count; |
| 245 | } | 247 | } |
| 246 | static DEVICE_ATTR_RW(fme_errors); | 248 | static DEVICE_ATTR_RW(fme_errors); |
| @@ -248,15 +250,15 @@ static DEVICE_ATTR_RW(fme_errors); · 1 unmodified line | |||
| 248 | static ssize_t first_error_show(struct device *dev, | 250 | static ssize_t first_error_show(struct device *dev, |
| 249 | struct device_attribute *attr, char *buf) | 251 | struct device_attribute *attr, char *buf) |
| 250 | { | 252 | { |
| 251 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 253 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 252 | void __iomem *base; | 254 | void __iomem *base; |
| 253 | u64 value; | 255 | u64 value; |
| 254 | 256 | ||
| 255 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 257 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 256 | 258 | ||
| 257 | mutex_lock(&pdata->lock); | 259 | mutex_lock(&fdata->lock); |
| 258 | value = readq(base + FME_FIRST_ERROR); | 260 | value = readq(base + FME_FIRST_ERROR); |
| 259 | mutex_unlock(&pdata->lock); | 261 | mutex_unlock(&fdata->lock); |
| 260 | 262 | ||
| 261 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); | 263 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); |
| 262 | } | 264 | } |
| @@ -265,15 +267,15 @@ static DEVICE_ATTR_RO(first_error); · 2 unmodified lines | |||
| 265 | static ssize_t next_error_show(struct device *dev, | 267 | static ssize_t next_error_show(struct device *dev, |
| 266 | struct device_attribute *attr, char *buf) | 268 | struct device_attribute *attr, char *buf) |
| 267 | { | 269 | { |
| 268 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 270 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 269 | void __iomem *base; | 271 | void __iomem *base; |
| 270 | u64 value; | 272 | u64 value; |
| 271 | 273 | ||
| 272 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 274 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 273 | 275 | ||
| 274 | mutex_lock(&pdata->lock); | 276 | mutex_lock(&fdata->lock); |
| 275 | value = readq(base + FME_NEXT_ERROR); | 277 | value = readq(base + FME_NEXT_ERROR); |
| 276 | mutex_unlock(&pdata->lock); | 278 | mutex_unlock(&fdata->lock); |
| 277 | 279 | ||
| 278 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); | 280 | return sprintf(buf, "0x%llx\n", (unsigned long long)value); |
| 279 | } | 281 | } |
| @@ -295,12 +297,14 @@ static umode_t fme_global_err_attrs_visible(struct kobject *kobj, · 15 unmodified lines | |||
| 295 | struct attribute *attr, int n) | 297 | struct attribute *attr, int n) |
| 296 | { | 298 | { |
| 297 | struct device *dev = kobj_to_dev(kobj); | 299 | struct device *dev = kobj_to_dev(kobj); |
| 300 | struct dfl_feature_dev_data *fdata; | ||
| 298 | 301 | ||
| 302 | fdata = to_dfl_feature_dev_data(dev); | ||
| 299 | /* | 303 | /* |
| 300 | * sysfs entries are visible only if related private feature is | 304 | * sysfs entries are visible only if related private feature is |
| 301 | * enumerated. | 305 | * enumerated. |
| 302 | */ | 306 | */ |
| 303 | if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR)) | 307 | if (!dfl_get_feature_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR)) |
| 304 | return 0; | 308 | return 0; |
| 305 | 309 | ||
| 306 | return attr->mode; | 310 | return attr->mode; |
| @@ -314,12 +318,12 @@ const struct attribute_group fme_global_err_group = { · 7 unmodified lines | |||
| 314 | 318 | ||
| 315 | static void fme_err_mask(struct device *dev, bool mask) | 319 | static void fme_err_mask(struct device *dev, bool mask) |
| 316 | { | 320 | { |
| 317 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | 321 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 318 | void __iomem *base; | 322 | void __iomem *base; |
| 319 | 323 | ||
| 320 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); | 324 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); |
| 321 | 325 | ||
| 322 | mutex_lock(&pdata->lock); | 326 | mutex_lock(&fdata->lock); |
| 323 | 327 | ||
| 324 | /* Workaround: keep MBP_ERROR always masked if revision is 0 */ | 328 | /* Workaround: keep MBP_ERROR always masked if revision is 0 */ |
| 325 | if (dfl_feature_revision(base)) | 329 | if (dfl_feature_revision(base)) |
| @@ -332,7 +336,7 @@ static void fme_err_mask(struct device *dev, bool mask) · 6 unmodified lines | |||
| 332 | writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK); | 336 | writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK); |
| 333 | writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK); | 337 | writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK); |
| 334 | 338 | ||
| 335 | mutex_unlock(&pdata->lock); | 339 | mutex_unlock(&fdata->lock); |
| 336 | } | 340 | } |
| 337 | 341 | ||
| 338 | static int fme_global_err_init(struct platform_device *pdev, | 342 | static int fme_global_err_init(struct platform_device *pdev, |
| @@ -28,10 +28,11 @@ · 27 unmodified lines | |||
| 28 | static ssize_t ports_num_show(struct device *dev, | 28 | static ssize_t ports_num_show(struct device *dev, |
| 29 | struct device_attribute *attr, char *buf) | 29 | struct device_attribute *attr, char *buf) |
| 30 | { | 30 | { |
| 31 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 31 | void __iomem *base; | 32 | void __iomem *base; |
| 32 | u64 v; | 33 | u64 v; |
| 33 | 34 | ||
| 34 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 35 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 35 | 36 | ||
| 36 | v = readq(base + FME_HDR_CAP); | 37 | v = readq(base + FME_HDR_CAP); |
| 37 | 38 | ||
| @@ -47,10 +48,11 @@ static DEVICE_ATTR_RO(ports_num); · 9 unmodified lines | |||
| 47 | static ssize_t bitstream_id_show(struct device *dev, | 48 | static ssize_t bitstream_id_show(struct device *dev, |
| 48 | struct device_attribute *attr, char *buf) | 49 | struct device_attribute *attr, char *buf) |
| 49 | { | 50 | { |
| 51 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 50 | void __iomem *base; | 52 | void __iomem *base; |
| 51 | u64 v; | 53 | u64 v; |
| 52 | 54 | ||
| 53 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 55 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 54 | 56 | ||
| 55 | v = readq(base + FME_HDR_BITSTREAM_ID); | 57 | v = readq(base + FME_HDR_BITSTREAM_ID); |
| 56 | 58 | ||
| @@ -65,10 +67,11 @@ static DEVICE_ATTR_RO(bitstream_id); · 8 unmodified lines | |||
| 65 | static ssize_t bitstream_metadata_show(struct device *dev, | 67 | static ssize_t bitstream_metadata_show(struct device *dev, |
| 66 | struct device_attribute *attr, char *buf) | 68 | struct device_attribute *attr, char *buf) |
| 67 | { | 69 | { |
| 70 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 68 | void __iomem *base; | 71 | void __iomem *base; |
| 69 | u64 v; | 72 | u64 v; |
| 70 | 73 | ||
| 71 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 74 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 72 | 75 | ||
| 73 | v = readq(base + FME_HDR_BITSTREAM_MD); | 76 | v = readq(base + FME_HDR_BITSTREAM_MD); |
| 74 | 77 | ||
| @@ -79,10 +82,11 @@ static DEVICE_ATTR_RO(bitstream_metadata); · 4 unmodified lines | |||
| 79 | static ssize_t cache_size_show(struct device *dev, | 82 | static ssize_t cache_size_show(struct device *dev, |
| 80 | struct device_attribute *attr, char *buf) | 83 | struct device_attribute *attr, char *buf) |
| 81 | { | 84 | { |
| 85 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 82 | void __iomem *base; | 86 | void __iomem *base; |
| 83 | u64 v; | 87 | u64 v; |
| 84 | 88 | ||
| 85 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 89 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 86 | 90 | ||
| 87 | v = readq(base + FME_HDR_CAP); | 91 | v = readq(base + FME_HDR_CAP); |
| 88 | 92 | ||
| @@ -94,10 +98,11 @@ static DEVICE_ATTR_RO(cache_size); · 5 unmodified lines | |||
| 94 | static ssize_t fabric_version_show(struct device *dev, | 98 | static ssize_t fabric_version_show(struct device *dev, |
| 95 | struct device_attribute *attr, char *buf) | 99 | struct device_attribute *attr, char *buf) |
| 96 | { | 100 | { |
| 101 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 97 | void __iomem *base; | 102 | void __iomem *base; |
| 98 | u64 v; | 103 | u64 v; |
| 99 | 104 | ||
| 100 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 105 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 101 | 106 | ||
| 102 | v = readq(base + FME_HDR_CAP); | 107 | v = readq(base + FME_HDR_CAP); |
| 103 | 108 | ||
| @@ -109,10 +114,11 @@ static DEVICE_ATTR_RO(fabric_version); · 5 unmodified lines | |||
| 109 | static ssize_t socket_id_show(struct device *dev, | 114 | static ssize_t socket_id_show(struct device *dev, |
| 110 | struct device_attribute *attr, char *buf) | 115 | struct device_attribute *attr, char *buf) |
| 111 | { | 116 | { |
| 117 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); | ||
| 112 | void __iomem *base; | 118 | void __iomem *base; |
| 113 | u64 v; | 119 | u64 v; |
| 114 | 120 | ||
| 115 | base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); | 121 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 116 | 122 | ||
| 117 | v = readq(base + FME_HDR_CAP); | 123 | v = readq(base + FME_HDR_CAP); |
| 118 | 124 | ||
| @@ -135,10 +141,10 @@ static const struct attribute_group fme_hdr_group = { · 16 unmodified lines | |||
| 135 | .attrs = fme_hdr_attrs, | 141 | .attrs = fme_hdr_attrs, |
| 136 | }; | 142 | }; |
| 137 | 143 | ||
| 138 | static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, | 144 | static long fme_hdr_ioctl_release_port(struct dfl_feature_dev_data *fdata, |
| 139 | unsigned long arg) | 145 | unsigned long arg) |
| 140 | { | 146 | { |
| 141 | struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; | 147 | struct dfl_fpga_cdev *cdev = fdata->dfl_cdev; |
| 142 | int port_id; | 148 | int port_id; |
| 143 | 149 | ||
| 144 | if (get_user(port_id, (int __user *)arg)) | 150 | if (get_user(port_id, (int __user *)arg)) |
| @@ -147,10 +153,10 @@ static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, · 2 unmodified lines | |||
| 147 | return dfl_fpga_cdev_release_port(cdev, port_id); | 153 | return dfl_fpga_cdev_release_port(cdev, port_id); |
| 148 | } | 154 | } |
| 149 | 155 | ||
| 150 | static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata, | 156 | static long fme_hdr_ioctl_assign_port(struct dfl_feature_dev_data *fdata, |
| 151 | unsigned long arg) | 157 | unsigned long arg) |
| 152 | { | 158 | { |
| 153 | struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; | 159 | struct dfl_fpga_cdev *cdev = fdata->dfl_cdev; |
| 154 | int port_id; | 160 | int port_id; |
| 155 | 161 | ||
| 156 | if (get_user(port_id, (int __user *)arg)) | 162 | if (get_user(port_id, (int __user *)arg)) |
| @@ -163,13 +169,13 @@ static long fme_hdr_ioctl(struct platform_device *pdev, · 6 unmodified lines | |||
| 163 | struct dfl_feature *feature, | 169 | struct dfl_feature *feature, |
| 164 | unsigned int cmd, unsigned long arg) | 170 | unsigned int cmd, unsigned long arg) |
| 165 | { | 171 | { |
| 166 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 172 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 167 | 173 | ||
| 168 | switch (cmd) { | 174 | switch (cmd) { |
| 169 | case DFL_FPGA_FME_PORT_RELEASE: | 175 | case DFL_FPGA_FME_PORT_RELEASE: |
| 170 | return fme_hdr_ioctl_release_port(pdata, arg); | 176 | return fme_hdr_ioctl_release_port(fdata, arg); |
| 171 | case DFL_FPGA_FME_PORT_ASSIGN: | 177 | case DFL_FPGA_FME_PORT_ASSIGN: |
| 172 | return fme_hdr_ioctl_assign_port(pdata, arg); | 178 | return fme_hdr_ioctl_assign_port(fdata, arg); |
| 173 | } | 179 | } |
| 174 | 180 | ||
| 175 | return -ENODEV; | 181 | return -ENODEV; |
| @@ -411,14 +417,14 @@ static int power_hwmon_read(struct device *dev, enum hwmon_sensor_types type, · 235 unmodified lines | |||
| 411 | static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type, | 417 | static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type, |
| 412 | u32 attr, int channel, long val) | 418 | u32 attr, int channel, long val) |
| 413 | { | 419 | { |
| 414 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev->parent); | 420 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev->parent); |
| 415 | struct dfl_feature *feature = dev_get_drvdata(dev); | 421 | struct dfl_feature *feature = dev_get_drvdata(dev); |
| 416 | int ret = 0; | 422 | int ret = 0; |
| 417 | u64 v; | 423 | u64 v; |
| 418 | 424 | ||
| 419 | val = clamp_val(val / MICRO, 0, PWR_THRESHOLD_MAX); | 425 | val = clamp_val(val / MICRO, 0, PWR_THRESHOLD_MAX); |
| 420 | 426 | ||
| 421 | mutex_lock(&pdata->lock); | 427 | mutex_lock(&fdata->lock); |
| 422 | 428 | ||
| 423 | switch (attr) { | 429 | switch (attr) { |
| 424 | case hwmon_power_max: | 430 | case hwmon_power_max: |
| @@ -438,7 +444,7 @@ static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type, · 13 unmodified lines | |||
| 438 | break; | 444 | break; |
| 439 | } | 445 | } |
| 440 | 446 | ||
| 441 | mutex_unlock(&pdata->lock); | 447 | mutex_unlock(&fdata->lock); |
| 442 | 448 | ||
| 443 | return ret; | 449 | return ret; |
| 444 | } | 450 | } |
| @@ -589,7 +595,7 @@ static struct dfl_feature_driver fme_feature_drvs[] = { · 144 unmodified lines | |||
| 589 | }, | 595 | }, |
| 590 | }; | 596 | }; |
| 591 | 597 | ||
| 592 | static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata, | 598 | static long fme_ioctl_check_extension(struct dfl_feature_dev_data *fdata, |
| 593 | unsigned long arg) | 599 | unsigned long arg) |
| 594 | { | 600 | { |
| 595 | /* No extension support for now */ | 601 | /* No extension support for now */ |
| @@ -598,49 +604,46 @@ static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata, · 2 unmodified lines | |||
| 598 | 604 | ||
| 599 | static int fme_open(struct inode *inode, struct file *filp) | 605 | static int fme_open(struct inode *inode, struct file *filp) |
| 600 | { | 606 | { |
| 601 | struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); | 607 | struct dfl_feature_dev_data *fdata = dfl_fpga_inode_to_feature_dev_data(inode); |
| 602 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev); | 608 | struct platform_device *fdev = fdata->dev; |
| 603 | int ret; | 609 | int ret; |
| 604 | 610 | ||
| 605 | if (WARN_ON(!pdata)) | 611 | mutex_lock(&fdata->lock); |
| 606 | return -ENODEV; | 612 | ret = dfl_feature_dev_use_begin(fdata, filp->f_flags & O_EXCL); |
| 607 | |||
| 608 | mutex_lock(&pdata->lock); | ||
| 609 | ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); | ||
| 610 | if (!ret) { | 613 | if (!ret) { |
| 611 | dev_dbg(&fdev->dev, "Device File Opened %d Times\n", | 614 | dev_dbg(&fdev->dev, "Device File Opened %d Times\n", |
| 612 | dfl_feature_dev_use_count(pdata)); | 615 | dfl_feature_dev_use_count(fdata)); |
| 613 | filp->private_data = pdata; | 616 | filp->private_data = fdata; |
| 614 | } | 617 | } |
| 615 | mutex_unlock(&pdata->lock); | 618 | mutex_unlock(&fdata->lock); |
| 616 | 619 | ||
| 617 | return ret; | 620 | return ret; |
| 618 | } | 621 | } |
| 619 | 622 | ||
| 620 | static int fme_release(struct inode *inode, struct file *filp) | 623 | static int fme_release(struct inode *inode, struct file *filp) |
| 621 | { | 624 | { |
| 622 | struct dfl_feature_platform_data *pdata = filp->private_data; | 625 | struct dfl_feature_dev_data *fdata = filp->private_data; |
| 623 | struct platform_device *pdev = pdata->dev; | 626 | struct platform_device *pdev = fdata->dev; |
| 624 | struct dfl_feature *feature; | 627 | struct dfl_feature *feature; |
| 625 | 628 | ||
| 626 | dev_dbg(&pdev->dev, "Device File Release\n"); | 629 | dev_dbg(&pdev->dev, "Device File Release\n"); |
| 627 | 630 | ||
| 628 | mutex_lock(&pdata->lock); | 631 | mutex_lock(&fdata->lock); |
| 629 | dfl_feature_dev_use_end(pdata); | 632 | dfl_feature_dev_use_end(fdata); |
| 630 | 633 | ||
| 631 | if (!dfl_feature_dev_use_count(pdata)) | 634 | if (!dfl_feature_dev_use_count(fdata)) |
| 632 | dfl_fpga_dev_for_each_feature(pdata, feature) | 635 | dfl_fpga_dev_for_each_feature(fdata, feature) |
| 633 | dfl_fpga_set_irq_triggers(feature, 0, | 636 | dfl_fpga_set_irq_triggers(feature, 0, |
| 634 | feature->nr_irqs, NULL); | 637 | feature->nr_irqs, NULL); |
| 635 | mutex_unlock(&pdata->lock); | 638 | mutex_unlock(&fdata->lock); |
| 636 | 639 | ||
| 637 | return 0; | 640 | return 0; |
| 638 | } | 641 | } |
| 639 | 642 | ||
| 640 | static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 643 | static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 641 | { | 644 | { |
| 642 | struct dfl_feature_platform_data *pdata = filp->private_data; | 645 | struct dfl_feature_dev_data *fdata = filp->private_data; |
| 643 | struct platform_device *pdev = pdata->dev; | 646 | struct platform_device *pdev = fdata->dev; |
| 644 | struct dfl_feature *f; | 647 | struct dfl_feature *f; |
| 645 | long ret; | 648 | long ret; |
| 646 | 649 | ||
| @@ -650,7 +653,7 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 3 unmodified lines | |||
| 650 | case DFL_FPGA_GET_API_VERSION: | 653 | case DFL_FPGA_GET_API_VERSION: |
| 651 | return DFL_FPGA_API_VERSION; | 654 | return DFL_FPGA_API_VERSION; |
| 652 | case DFL_FPGA_CHECK_EXTENSION: | 655 | case DFL_FPGA_CHECK_EXTENSION: |
| 653 | return fme_ioctl_check_extension(pdata, arg); | 656 | return fme_ioctl_check_extension(fdata, arg); |
| 654 | default: | 657 | default: |
| 655 | /* | 658 | /* |
| 656 | * Let sub-feature's ioctl function to handle the cmd. | 659 | * Let sub-feature's ioctl function to handle the cmd. |
| @@ -658,7 +661,7 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 1 unmodified line | |||
| 658 | * handled in this sub feature, and returns 0 or other | 661 | * handled in this sub feature, and returns 0 or other |
| 659 | * error code if cmd is handled. | 662 | * error code if cmd is handled. |
| 660 | */ | 663 | */ |
| 661 | dfl_fpga_dev_for_each_feature(pdata, f) { | 664 | dfl_fpga_dev_for_each_feature(fdata, f) { |
| 662 | if (f->ops && f->ops->ioctl) { | 665 | if (f->ops && f->ops->ioctl) { |
| 663 | ret = f->ops->ioctl(pdev, f, cmd, arg); | 666 | ret = f->ops->ioctl(pdev, f, cmd, arg); |
| 664 | if (ret != -ENODEV) | 667 | if (ret != -ENODEV) |
| @@ -672,27 +675,27 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 7 unmodified lines | |||
| 672 | 675 | ||
| 673 | static int fme_dev_init(struct platform_device *pdev) | 676 | static int fme_dev_init(struct platform_device *pdev) |
| 674 | { | 677 | { |
| 675 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 678 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 676 | struct dfl_fme *fme; | 679 | struct dfl_fme *fme; |
| 677 | 680 | ||
| 678 | fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL); | 681 | fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL); |
| 679 | if (!fme) | 682 | if (!fme) |
| 680 | return -ENOMEM; | 683 | return -ENOMEM; |
| 681 | 684 | ||
| 682 | mutex_lock(&pdata->lock); | 685 | mutex_lock(&fdata->lock); |
| 683 | dfl_fpga_pdata_set_private(pdata, fme); | 686 | dfl_fpga_fdata_set_private(fdata, fme); |
| 684 | mutex_unlock(&pdata->lock); | 687 | mutex_unlock(&fdata->lock); |
| 685 | 688 | ||
| 686 | return 0; | 689 | return 0; |
| 687 | } | 690 | } |
| 688 | 691 | ||
| 689 | static void fme_dev_destroy(struct platform_device *pdev) | 692 | static void fme_dev_destroy(struct platform_device *pdev) |
| 690 | { | 693 | { |
| 691 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 694 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 692 | 695 | ||
| 693 | mutex_lock(&pdata->lock); | 696 | mutex_lock(&fdata->lock); |
| 694 | dfl_fpga_pdata_set_private(pdata, NULL); | 697 | dfl_fpga_fdata_set_private(fdata, NULL); |
| 695 | mutex_unlock(&pdata->lock); | 698 | mutex_unlock(&fdata->lock); |
| 696 | } | 699 | } |
| 697 | 700 | ||
| 698 | static const struct file_operations fme_fops = { | 701 | static const struct file_operations fme_fops = { |
| @@ -65,7 +65,7 @@ static struct fpga_region *dfl_fme_region_find(struct dfl_fme *fme, int port_id) · 64 unmodified lines | |||
| 65 | 65 | ||
| 66 | static int fme_pr(struct platform_device *pdev, unsigned long arg) | 66 | static int fme_pr(struct platform_device *pdev, unsigned long arg) |
| 67 | { | 67 | { |
| 68 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 68 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 69 | void __user *argp = (void __user *)arg; | 69 | void __user *argp = (void __user *)arg; |
| 70 | struct dfl_fpga_fme_port_pr port_pr; | 70 | struct dfl_fpga_fme_port_pr port_pr; |
| 71 | struct fpga_image_info *info; | 71 | struct fpga_image_info *info; |
| @@ -87,8 +87,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) · 15 unmodified lines | |||
| 87 | return -EINVAL; | 87 | return -EINVAL; |
| 88 | 88 | ||
| 89 | /* get fme header region */ | 89 | /* get fme header region */ |
| 90 | fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev, | 90 | fme_hdr = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 91 | FME_FEATURE_ID_HEADER); | ||
| 92 | 91 | ||
| 93 | /* check port id */ | 92 | /* check port id */ |
| 94 | v = readq(fme_hdr + FME_HDR_CAP); | 93 | v = readq(fme_hdr + FME_HDR_CAP); |
| @@ -123,8 +122,8 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) · 28 unmodified lines | |||
| 123 | 122 | ||
| 124 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; | 123 | info->flags |= FPGA_MGR_PARTIAL_RECONFIG; |
| 125 | 124 | ||
| 126 | mutex_lock(&pdata->lock); | 125 | mutex_lock(&fdata->lock); |
| 127 | fme = dfl_fpga_pdata_get_private(pdata); | 126 | fme = dfl_fpga_fdata_get_private(fdata); |
| 128 | /* fme device has been unregistered. */ | 127 | /* fme device has been unregistered. */ |
| 129 | if (!fme) { | 128 | if (!fme) { |
| 130 | ret = -EINVAL; | 129 | ret = -EINVAL; |
| @@ -156,7 +155,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) · 25 unmodified lines | |||
| 156 | 155 | ||
| 157 | put_device(®ion->dev); | 156 | put_device(®ion->dev); |
| 158 | unlock_exit: | 157 | unlock_exit: |
| 159 | mutex_unlock(&pdata->lock); | 158 | mutex_unlock(&fdata->lock); |
| 160 | free_exit: | 159 | free_exit: |
| 161 | vfree(buf); | 160 | vfree(buf); |
| 162 | return ret; | 161 | return ret; |
| @@ -164,16 +163,16 @@ free_exit: · 1 unmodified line | |||
| 164 | 163 | ||
| 165 | /** | 164 | /** |
| 166 | * dfl_fme_create_mgr - create fpga mgr platform device as child device | 165 | * dfl_fme_create_mgr - create fpga mgr platform device as child device |
| 166 | * @fdata: fme feature dev data | ||
| 167 | * @feature: sub feature info | 167 | * @feature: sub feature info |
| 168 | * @pdata: fme platform_device's pdata | ||
| 169 | * | 168 | * |
| 170 | * Return: mgr platform device if successful, and error code otherwise. | 169 | * Return: mgr platform device if successful, and error code otherwise. |
| 171 | */ | 170 | */ |
| 172 | static struct platform_device * | 171 | static struct platform_device * |
| 173 | dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata, | 172 | dfl_fme_create_mgr(struct dfl_feature_dev_data *fdata, |
| 174 | struct dfl_feature *feature) | 173 | struct dfl_feature *feature) |
| 175 | { | 174 | { |
| 176 | struct platform_device *mgr, *fme = pdata->dev; | 175 | struct platform_device *mgr, *fme = fdata->dev; |
| 177 | struct dfl_fme_mgr_pdata mgr_pdata; | 176 | struct dfl_fme_mgr_pdata mgr_pdata; |
| 178 | int ret = -ENOMEM; | 177 | int ret = -ENOMEM; |
| 179 | 178 | ||
| @@ -209,11 +208,11 @@ create_mgr_err: · 29 unmodified lines | |||
| 209 | 208 | ||
| 210 | /** | 209 | /** |
| 211 | * dfl_fme_destroy_mgr - destroy fpga mgr platform device | 210 | * dfl_fme_destroy_mgr - destroy fpga mgr platform device |
| 212 | * @pdata: fme platform device's pdata | 211 | * @fdata: fme feature dev data |
| 213 | */ | 212 | */ |
| 214 | static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata) | 213 | static void dfl_fme_destroy_mgr(struct dfl_feature_dev_data *fdata) |
| 215 | { | 214 | { |
| 216 | struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); | 215 | struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); |
| 217 | 216 | ||
| 218 | platform_device_unregister(priv->mgr); | 217 | platform_device_unregister(priv->mgr); |
| 219 | } | 218 | } |
| @@ -221,15 +220,15 @@ static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata) · 1 unmodified line | |||
| 221 | /** | 220 | /** |
| 222 | * dfl_fme_create_bridge - create fme fpga bridge platform device as child | 221 | * dfl_fme_create_bridge - create fme fpga bridge platform device as child |
| 223 | * | 222 | * |
| 224 | * @pdata: fme platform device's pdata | 223 | * @fdata: fme feature dev data |
| 225 | * @port_id: port id for the bridge to be created. | 224 | * @port_id: port id for the bridge to be created. |
| 226 | * | 225 | * |
| 227 | * Return: bridge platform device if successful, and error code otherwise. | 226 | * Return: bridge platform device if successful, and error code otherwise. |
| 228 | */ | 227 | */ |
| 229 | static struct dfl_fme_bridge * | 228 | static struct dfl_fme_bridge * |
| 230 | dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id) | 229 | dfl_fme_create_bridge(struct dfl_feature_dev_data *fdata, int port_id) |
| 231 | { | 230 | { |
| 232 | struct device *dev = &pdata->dev->dev; | 231 | struct device *dev = &fdata->dev->dev; |
| 233 | struct dfl_fme_br_pdata br_pdata; | 232 | struct dfl_fme_br_pdata br_pdata; |
| 234 | struct dfl_fme_bridge *fme_br; | 233 | struct dfl_fme_bridge *fme_br; |
| 235 | int ret = -ENOMEM; | 234 | int ret = -ENOMEM; |
| @@ -238,7 +237,7 @@ dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id) · 2 unmodified lines | |||
| 238 | if (!fme_br) | 237 | if (!fme_br) |
| 239 | return ERR_PTR(ret); | 238 | return ERR_PTR(ret); |
| 240 | 239 | ||
| 241 | br_pdata.cdev = pdata->dfl_cdev; | 240 | br_pdata.cdev = fdata->dfl_cdev; |
| 242 | br_pdata.port_id = port_id; | 241 | br_pdata.port_id = port_id; |
| 243 | 242 | ||
| 244 | fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE, | 243 | fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE, |
| @@ -274,11 +273,11 @@ static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br) · 29 unmodified lines | |||
| 274 | 273 | ||
| 275 | /** | 274 | /** |
| 276 | * dfl_fme_destroy_bridges - destroy all fpga bridge platform device | 275 | * dfl_fme_destroy_bridges - destroy all fpga bridge platform device |
| 277 | * @pdata: fme platform device's pdata | 276 | * @fdata: fme feature dev data |
| 278 | */ | 277 | */ |
| 279 | static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) | 278 | static void dfl_fme_destroy_bridges(struct dfl_feature_dev_data *fdata) |
| 280 | { | 279 | { |
| 281 | struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); | 280 | struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); |
| 282 | struct dfl_fme_bridge *fbridge, *tmp; | 281 | struct dfl_fme_bridge *fbridge, *tmp; |
| 283 | 282 | ||
| 284 | list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) { | 283 | list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) { |
| @@ -290,7 +289,7 @@ static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) · 5 unmodified lines | |||
| 290 | /** | 289 | /** |
| 291 | * dfl_fme_create_region - create fpga region platform device as child | 290 | * dfl_fme_create_region - create fpga region platform device as child |
| 292 | * | 291 | * |
| 293 | * @pdata: fme platform device's pdata | 292 | * @fdata: fme feature dev data |
| 294 | * @mgr: mgr platform device needed for region | 293 | * @mgr: mgr platform device needed for region |
| 295 | * @br: br platform device needed for region | 294 | * @br: br platform device needed for region |
| 296 | * @port_id: port id | 295 | * @port_id: port id |
| @@ -298,12 +297,12 @@ static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) · 1 unmodified line | |||
| 298 | * Return: fme region if successful, and error code otherwise. | 297 | * Return: fme region if successful, and error code otherwise. |
| 299 | */ | 298 | */ |
| 300 | static struct dfl_fme_region * | 299 | static struct dfl_fme_region * |
| 301 | dfl_fme_create_region(struct dfl_feature_platform_data *pdata, | 300 | dfl_fme_create_region(struct dfl_feature_dev_data *fdata, |
| 302 | struct platform_device *mgr, | 301 | struct platform_device *mgr, |
| 303 | struct platform_device *br, int port_id) | 302 | struct platform_device *br, int port_id) |
| 304 | { | 303 | { |
| 305 | struct dfl_fme_region_pdata region_pdata; | 304 | struct dfl_fme_region_pdata region_pdata; |
| 306 | struct device *dev = &pdata->dev->dev; | 305 | struct device *dev = &fdata->dev->dev; |
| 307 | struct dfl_fme_region *fme_region; | 306 | struct dfl_fme_region *fme_region; |
| 308 | int ret = -ENOMEM; | 307 | int ret = -ENOMEM; |
| 309 | 308 | ||
| @@ -353,11 +352,11 @@ static void dfl_fme_destroy_region(struct dfl_fme_region *fme_region) · 43 unmodified lines | |||
| 353 | 352 | ||
| 354 | /** | 353 | /** |
| 355 | * dfl_fme_destroy_regions - destroy all fme regions | 354 | * dfl_fme_destroy_regions - destroy all fme regions |
| 356 | * @pdata: fme platform device's pdata | 355 | * @fdata: fme feature dev data |
| 357 | */ | 356 | */ |
| 358 | static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata) | 357 | static void dfl_fme_destroy_regions(struct dfl_feature_dev_data *fdata) |
| 359 | { | 358 | { |
| 360 | struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); | 359 | struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); |
| 361 | struct dfl_fme_region *fme_region, *tmp; | 360 | struct dfl_fme_region *fme_region, *tmp; |
| 362 | 361 | ||
| 363 | list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) { | 362 | list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) { |
| @@ -369,7 +368,7 @@ static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata) · 5 unmodified lines | |||
| 369 | static int pr_mgmt_init(struct platform_device *pdev, | 368 | static int pr_mgmt_init(struct platform_device *pdev, |
| 370 | struct dfl_feature *feature) | 369 | struct dfl_feature *feature) |
| 371 | { | 370 | { |
| 372 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 371 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 373 | struct dfl_fme_region *fme_region; | 372 | struct dfl_fme_region *fme_region; |
| 374 | struct dfl_fme_bridge *fme_br; | 373 | struct dfl_fme_bridge *fme_br; |
| 375 | struct platform_device *mgr; | 374 | struct platform_device *mgr; |
| @@ -378,18 +377,17 @@ static int pr_mgmt_init(struct platform_device *pdev, · 2 unmodified lines | |||
| 378 | int ret = -ENODEV, i = 0; | 377 | int ret = -ENODEV, i = 0; |
| 379 | u64 fme_cap, port_offset; | 378 | u64 fme_cap, port_offset; |
| 380 | 379 | ||
| 381 | fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev, | 380 | fme_hdr = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 382 | FME_FEATURE_ID_HEADER); | ||
| 383 | 381 | ||
| 384 | mutex_lock(&pdata->lock); | 382 | mutex_lock(&fdata->lock); |
| 385 | priv = dfl_fpga_pdata_get_private(pdata); | 383 | priv = dfl_fpga_fdata_get_private(fdata); |
| 386 | 384 | ||
| 387 | /* Initialize the region and bridge sub device list */ | 385 | /* Initialize the region and bridge sub device list */ |
| 388 | INIT_LIST_HEAD(&priv->region_list); | 386 | INIT_LIST_HEAD(&priv->region_list); |
| 389 | INIT_LIST_HEAD(&priv->bridge_list); | 387 | INIT_LIST_HEAD(&priv->bridge_list); |
| 390 | 388 | ||
| 391 | /* Create fpga mgr platform device */ | 389 | /* Create fpga mgr platform device */ |
| 392 | mgr = dfl_fme_create_mgr(pdata, feature); | 390 | mgr = dfl_fme_create_mgr(fdata, feature); |
| 393 | if (IS_ERR(mgr)) { | 391 | if (IS_ERR(mgr)) { |
| 394 | dev_err(&pdev->dev, "fail to create fpga mgr pdev\n"); | 392 | dev_err(&pdev->dev, "fail to create fpga mgr pdev\n"); |
| 395 | goto unlock; | 393 | goto unlock; |
| @@ -405,7 +403,7 @@ static int pr_mgmt_init(struct platform_device *pdev, · 9 unmodified lines | |||
| 405 | continue; | 403 | continue; |
| 406 | 404 | ||
| 407 | /* Create bridge for each port */ | 405 | /* Create bridge for each port */ |
| 408 | fme_br = dfl_fme_create_bridge(pdata, i); | 406 | fme_br = dfl_fme_create_bridge(fdata, i); |
| 409 | if (IS_ERR(fme_br)) { | 407 | if (IS_ERR(fme_br)) { |
| 410 | ret = PTR_ERR(fme_br); | 408 | ret = PTR_ERR(fme_br); |
| 411 | goto destroy_region; | 409 | goto destroy_region; |
| @@ -414,7 +412,7 @@ static int pr_mgmt_init(struct platform_device *pdev, · 2 unmodified lines | |||
| 414 | list_add(&fme_br->node, &priv->bridge_list); | 412 | list_add(&fme_br->node, &priv->bridge_list); |
| 415 | 413 | ||
| 416 | /* Create region for each port */ | 414 | /* Create region for each port */ |
| 417 | fme_region = dfl_fme_create_region(pdata, mgr, | 415 | fme_region = dfl_fme_create_region(fdata, mgr, |
| 418 | fme_br->br, i); | 416 | fme_br->br, i); |
| 419 | if (IS_ERR(fme_region)) { | 417 | if (IS_ERR(fme_region)) { |
| 420 | ret = PTR_ERR(fme_region); | 418 | ret = PTR_ERR(fme_region); |
| @@ -423,30 +421,30 @@ static int pr_mgmt_init(struct platform_device *pdev, · 2 unmodified lines | |||
| 423 | 421 | ||
| 424 | list_add(&fme_region->node, &priv->region_list); | 422 | list_add(&fme_region->node, &priv->region_list); |
| 425 | } | 423 | } |
| 426 | mutex_unlock(&pdata->lock); | 424 | mutex_unlock(&fdata->lock); |
| 427 | 425 | ||
| 428 | return 0; | 426 | return 0; |
| 429 | 427 | ||
| 430 | destroy_region: | 428 | destroy_region: |
| 431 | dfl_fme_destroy_regions(pdata); | 429 | dfl_fme_destroy_regions(fdata); |
| 432 | dfl_fme_destroy_bridges(pdata); | 430 | dfl_fme_destroy_bridges(fdata); |
| 433 | dfl_fme_destroy_mgr(pdata); | 431 | dfl_fme_destroy_mgr(fdata); |
| 434 | unlock: | 432 | unlock: |
| 435 | mutex_unlock(&pdata->lock); | 433 | mutex_unlock(&fdata->lock); |
| 436 | return ret; | 434 | return ret; |
| 437 | } | 435 | } |
| 438 | 436 | ||
| 439 | static void pr_mgmt_uinit(struct platform_device *pdev, | 437 | static void pr_mgmt_uinit(struct platform_device *pdev, |
| 440 | struct dfl_feature *feature) | 438 | struct dfl_feature *feature) |
| 441 | { | 439 | { |
| 442 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 440 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 443 | 441 | ||
| 444 | mutex_lock(&pdata->lock); | 442 | mutex_lock(&fdata->lock); |
| 445 | 443 | ||
| 446 | dfl_fme_destroy_regions(pdata); | 444 | dfl_fme_destroy_regions(fdata); |
| 447 | dfl_fme_destroy_bridges(pdata); | 445 | dfl_fme_destroy_bridges(fdata); |
| 448 | dfl_fme_destroy_mgr(pdata); | 446 | dfl_fme_destroy_mgr(fdata); |
| 449 | mutex_unlock(&pdata->lock); | 447 | mutex_unlock(&fdata->lock); |
| 450 | } | 448 | } |
| 451 | 449 | ||
| 452 | static long fme_pr_ioctl(struct platform_device *pdev, | 450 | static long fme_pr_ioctl(struct platform_device *pdev, |
| @@ -119,17 +119,6 @@ static void dfl_id_free(enum dfl_id_type type, int id) · 118 unmodified lines | |||
| 119 | mutex_unlock(&dfl_id_mutex); | 119 | mutex_unlock(&dfl_id_mutex); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | static enum dfl_id_type feature_dev_id_type(struct platform_device *pdev) | ||
| 123 | { | ||
| 124 | int i; | ||
| 125 | |||
| 126 | for (i = 0; i < ARRAY_SIZE(dfl_devs); i++) | ||
| 127 | if (!strcmp(dfl_devs[i].name, pdev->name)) | ||
| 128 | return i; | ||
| 129 | |||
| 130 | return DFL_ID_MAX; | ||
| 131 | } | ||
| 132 | |||
| 133 | static enum dfl_id_type dfh_id_to_type(u16 id) | 122 | static enum dfl_id_type dfh_id_to_type(u16 id) |
| 134 | { | 123 | { |
| 135 | int i; | 124 | int i; |
| @@ -156,12 +145,12 @@ static LIST_HEAD(dfl_port_ops_list); · 20 unmodified lines | |||
| 156 | 145 | ||
| 157 | /** | 146 | /** |
| 158 | * dfl_fpga_port_ops_get - get matched port ops from the global list | 147 | * dfl_fpga_port_ops_get - get matched port ops from the global list |
| 159 | * @pdev: platform device to match with associated port ops. | 148 | * @fdata: feature dev data to match with associated port ops. |
| 160 | * Return: matched port ops on success, NULL otherwise. | 149 | * Return: matched port ops on success, NULL otherwise. |
| 161 | * | 150 | * |
| 162 | * Please note that must dfl_fpga_port_ops_put after use the port_ops. | 151 | * Please note that must dfl_fpga_port_ops_put after use the port_ops. |
| 163 | */ | 152 | */ |
| 164 | struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev) | 153 | struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct dfl_feature_dev_data *fdata) |
| 165 | { | 154 | { |
| 166 | struct dfl_fpga_port_ops *ops = NULL; | 155 | struct dfl_fpga_port_ops *ops = NULL; |
| 167 | 156 | ||
| @@ -171,7 +160,7 @@ struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev) · 3 unmodified lines | |||
| 171 | 160 | ||
| 172 | list_for_each_entry(ops, &dfl_port_ops_list, node) { | 161 | list_for_each_entry(ops, &dfl_port_ops_list, node) { |
| 173 | /* match port_ops using the name of platform device */ | 162 | /* match port_ops using the name of platform device */ |
| 174 | if (!strcmp(pdev->name, ops->name)) { | 163 | if (!strcmp(fdata->pdev_name, ops->name)) { |
| 175 | if (!try_module_get(ops->owner)) | 164 | if (!try_module_get(ops->owner)) |
| 176 | ops = NULL; | 165 | ops = NULL; |
| 177 | goto done; | 166 | goto done; |
| @@ -222,27 +211,26 @@ EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del); · 44 unmodified lines | |||
| 222 | 211 | ||
| 223 | /** | 212 | /** |
| 224 | * dfl_fpga_check_port_id - check the port id | 213 | * dfl_fpga_check_port_id - check the port id |
| 225 | * @pdev: port platform device. | 214 | * @fdata: port feature dev data. |
| 226 | * @pport_id: port id to compare. | 215 | * @pport_id: port id to compare. |
| 227 | * | 216 | * |
| 228 | * Return: 1 if port device matches with given port id, otherwise 0. | 217 | * Return: 1 if port device matches with given port id, otherwise 0. |
| 229 | */ | 218 | */ |
| 230 | int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id) | 219 | int dfl_fpga_check_port_id(struct dfl_feature_dev_data *fdata, void *pport_id) |
| 231 | { | 220 | { |
| 232 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
| 233 | struct dfl_fpga_port_ops *port_ops; | 221 | struct dfl_fpga_port_ops *port_ops; |
| 234 | 222 | ||
| 235 | if (pdata->id != FEATURE_DEV_ID_UNUSED) | 223 | if (fdata->id != FEATURE_DEV_ID_UNUSED) |
| 236 | return pdata->id == *(int *)pport_id; | 224 | return fdata->id == *(int *)pport_id; |
| 237 | 225 | ||
| 238 | port_ops = dfl_fpga_port_ops_get(pdev); | 226 | port_ops = dfl_fpga_port_ops_get(fdata); |
| 239 | if (!port_ops || !port_ops->get_id) | 227 | if (!port_ops || !port_ops->get_id) |
| 240 | return 0; | 228 | return 0; |
| 241 | 229 | ||
| 242 | pdata->id = port_ops->get_id(pdev); | 230 | fdata->id = port_ops->get_id(fdata); |
| 243 | dfl_fpga_port_ops_put(port_ops); | 231 | dfl_fpga_port_ops_put(port_ops); |
| 244 | 232 | ||
| 245 | return pdata->id == *(int *)pport_id; | 233 | return fdata->id == *(int *)pport_id; |
| 246 | } | 234 | } |
| 247 | EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); | 235 | EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); |
| 248 | 236 | ||
| @@ -351,10 +339,10 @@ static void release_dfl_dev(struct device *dev) · 102 unmodified lines | |||
| 351 | } | 339 | } |
| 352 | 340 | ||
| 353 | static struct dfl_device * | 341 | static struct dfl_device * |
| 354 | dfl_dev_add(struct dfl_feature_platform_data *pdata, | 342 | dfl_dev_add(struct dfl_feature_dev_data *fdata, |
| 355 | struct dfl_feature *feature) | 343 | struct dfl_feature *feature) |
| 356 | { | 344 | { |
| 357 | struct platform_device *pdev = pdata->dev; | 345 | struct platform_device *pdev = fdata->dev; |
| 358 | struct resource *parent_res; | 346 | struct resource *parent_res; |
| 359 | struct dfl_device *ddev; | 347 | struct dfl_device *ddev; |
| 360 | int id, i, ret; | 348 | int id, i, ret; |
| @@ -380,11 +368,11 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata, · 19 unmodified lines | |||
| 380 | if (ret) | 368 | if (ret) |
| 381 | goto put_dev; | 369 | goto put_dev; |
| 382 | 370 | ||
| 383 | ddev->type = feature_dev_id_type(pdev); | 371 | ddev->type = fdata->type; |
| 384 | ddev->feature_id = feature->id; | 372 | ddev->feature_id = feature->id; |
| 385 | ddev->revision = feature->revision; | 373 | ddev->revision = feature->revision; |
| 386 | ddev->dfh_version = feature->dfh_version; | 374 | ddev->dfh_version = feature->dfh_version; |
| 387 | ddev->cdev = pdata->dfl_cdev; | 375 | ddev->cdev = fdata->dfl_cdev; |
| 388 | if (feature->param_size) { | 376 | if (feature->param_size) { |
| 389 | ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL); | 377 | ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL); |
| 390 | if (!ddev->params) { | 378 | if (!ddev->params) { |
| @@ -435,11 +423,11 @@ put_dev: · 44 unmodified lines | |||
| 435 | return ERR_PTR(ret); | 423 | return ERR_PTR(ret); |
| 436 | } | 424 | } |
| 437 | 425 | ||
| 438 | static void dfl_devs_remove(struct dfl_feature_platform_data *pdata) | 426 | static void dfl_devs_remove(struct dfl_feature_dev_data *fdata) |
| 439 | { | 427 | { |
| 440 | struct dfl_feature *feature; | 428 | struct dfl_feature *feature; |
| 441 | 429 | ||
| 442 | dfl_fpga_dev_for_each_feature(pdata, feature) { | 430 | dfl_fpga_dev_for_each_feature(fdata, feature) { |
| 443 | if (feature->ddev) { | 431 | if (feature->ddev) { |
| 444 | device_unregister(&feature->ddev->dev); | 432 | device_unregister(&feature->ddev->dev); |
| 445 | feature->ddev = NULL; | 433 | feature->ddev = NULL; |
| @@ -447,13 +435,13 @@ static void dfl_devs_remove(struct dfl_feature_platform_data *pdata) · 1 unmodified line | |||
| 447 | } | 435 | } |
| 448 | } | 436 | } |
| 449 | 437 | ||
| 450 | static int dfl_devs_add(struct dfl_feature_platform_data *pdata) | 438 | static int dfl_devs_add(struct dfl_feature_dev_data *fdata) |
| 451 | { | 439 | { |
| 452 | struct dfl_feature *feature; | 440 | struct dfl_feature *feature; |
| 453 | struct dfl_device *ddev; | 441 | struct dfl_device *ddev; |
| 454 | int ret; | 442 | int ret; |
| 455 | 443 | ||
| 456 | dfl_fpga_dev_for_each_feature(pdata, feature) { | 444 | dfl_fpga_dev_for_each_feature(fdata, feature) { |
| 457 | if (feature->ioaddr) | 445 | if (feature->ioaddr) |
| 458 | continue; | 446 | continue; |
| 459 | 447 | ||
| @@ -462,7 +450,7 @@ static int dfl_devs_add(struct dfl_feature_platform_data *pdata) · 2 unmodified lines | |||
| 462 | goto err; | 450 | goto err; |
| 463 | } | 451 | } |
| 464 | 452 | ||
| 465 | ddev = dfl_dev_add(pdata, feature); | 453 | ddev = dfl_dev_add(fdata, feature); |
| 466 | if (IS_ERR(ddev)) { | 454 | if (IS_ERR(ddev)) { |
| 467 | ret = PTR_ERR(ddev); | 455 | ret = PTR_ERR(ddev); |
| 468 | goto err; | 456 | goto err; |
| @@ -474,7 +462,7 @@ static int dfl_devs_add(struct dfl_feature_platform_data *pdata) · 5 unmodified lines | |||
| 474 | return 0; | 462 | return 0; |
| 475 | 463 | ||
| 476 | err: | 464 | err: |
| 477 | dfl_devs_remove(pdata); | 465 | dfl_devs_remove(fdata); |
| 478 | return ret; | 466 | return ret; |
| 479 | } | 467 | } |
| 480 | 468 | ||
| @@ -504,12 +492,12 @@ EXPORT_SYMBOL(dfl_driver_unregister); · 23 unmodified lines | |||
| 504 | */ | 492 | */ |
| 505 | void dfl_fpga_dev_feature_uinit(struct platform_device *pdev) | 493 | void dfl_fpga_dev_feature_uinit(struct platform_device *pdev) |
| 506 | { | 494 | { |
| 507 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 495 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 508 | struct dfl_feature *feature; | 496 | struct dfl_feature *feature; |
| 509 | 497 | ||
| 510 | dfl_devs_remove(pdata); | 498 | dfl_devs_remove(fdata); |
| 511 | 499 | ||
| 512 | dfl_fpga_dev_for_each_feature(pdata, feature) { | 500 | dfl_fpga_dev_for_each_feature(fdata, feature) { |
| 513 | if (feature->ops) { | 501 | if (feature->ops) { |
| 514 | if (feature->ops->uinit) | 502 | if (feature->ops->uinit) |
| 515 | feature->ops->uinit(pdev, feature); | 503 | feature->ops->uinit(pdev, feature); |
| @@ -520,7 +508,6 @@ void dfl_fpga_dev_feature_uinit(struct platform_device *pdev) · 4 unmodified lines | |||
| 520 | EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_uinit); | 508 | EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_uinit); |
| 521 | 509 | ||
| 522 | static int dfl_feature_instance_init(struct platform_device *pdev, | 510 | static int dfl_feature_instance_init(struct platform_device *pdev, |
| 523 | struct dfl_feature_platform_data *pdata, | ||
| 524 | struct dfl_feature *feature, | 511 | struct dfl_feature *feature, |
| 525 | struct dfl_feature_driver *drv) | 512 | struct dfl_feature_driver *drv) |
| 526 | { | 513 | { |
| @@ -579,16 +566,15 @@ static bool dfl_feature_drv_match(struct dfl_feature *feature, · 52 unmodified lines | |||
| 579 | int dfl_fpga_dev_feature_init(struct platform_device *pdev, | 566 | int dfl_fpga_dev_feature_init(struct platform_device *pdev, |
| 580 | struct dfl_feature_driver *feature_drvs) | 567 | struct dfl_feature_driver *feature_drvs) |
| 581 | { | 568 | { |
| 582 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 569 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 583 | struct dfl_feature_driver *drv = feature_drvs; | 570 | struct dfl_feature_driver *drv = feature_drvs; |
| 584 | struct dfl_feature *feature; | 571 | struct dfl_feature *feature; |
| 585 | int ret; | 572 | int ret; |
| 586 | 573 | ||
| 587 | while (drv->ops) { | 574 | while (drv->ops) { |
| 588 | dfl_fpga_dev_for_each_feature(pdata, feature) { | 575 | dfl_fpga_dev_for_each_feature(fdata, feature) { |
| 589 | if (dfl_feature_drv_match(feature, drv)) { | 576 | if (dfl_feature_drv_match(feature, drv)) { |
| 590 | ret = dfl_feature_instance_init(pdev, pdata, | 577 | ret = dfl_feature_instance_init(pdev, feature, drv); |
| 591 | feature, drv); | ||
| 592 | if (ret) | 578 | if (ret) |
| 593 | goto exit; | 579 | goto exit; |
| 594 | } | 580 | } |
| @@ -596,7 +582,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev, · 1 unmodified line | |||
| 596 | drv++; | 582 | drv++; |
| 597 | } | 583 | } |
| 598 | 584 | ||
| 599 | ret = dfl_devs_add(pdata); | 585 | ret = dfl_devs_add(fdata); |
| 600 | if (ret) | 586 | if (ret) |
| 601 | goto exit; | 587 | goto exit; |
| 602 | 588 | ||
| @@ -695,7 +681,7 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister); · 92 unmodified lines | |||
| 695 | * @nr_irqs: number of irqs for all feature devices. | 681 | * @nr_irqs: number of irqs for all feature devices. |
| 696 | * @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of | 682 | * @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of |
| 697 | * this device. | 683 | * this device. |
| 698 | * @feature_dev: current feature device. | 684 | * @type: the current FIU type. |
| 699 | * @ioaddr: header register region address of current FIU in enumeration. | 685 | * @ioaddr: header register region address of current FIU in enumeration. |
| 700 | * @start: register resource start of current FIU. | 686 | * @start: register resource start of current FIU. |
| 701 | * @len: max register resource length of current FIU. | 687 | * @len: max register resource length of current FIU. |
| @@ -708,7 +694,7 @@ struct build_feature_devs_info { · 6 unmodified lines | |||
| 708 | unsigned int nr_irqs; | 694 | unsigned int nr_irqs; |
| 709 | int *irq_table; | 695 | int *irq_table; |
| 710 | 696 | ||
| 711 | struct platform_device *feature_dev; | 697 | enum dfl_id_type type; |
| 712 | void __iomem *ioaddr; | 698 | void __iomem *ioaddr; |
| 713 | resource_size_t start; | 699 | resource_size_t start; |
| 714 | resource_size_t len; | 700 | resource_size_t len; |
| @@ -743,50 +729,62 @@ struct dfl_feature_info { · 28 unmodified lines | |||
| 743 | u64 params[]; | 729 | u64 params[]; |
| 744 | }; | 730 | }; |
| 745 | 731 | ||
| 746 | static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev, | 732 | static void dfl_fpga_cdev_add_port_data(struct dfl_fpga_cdev *cdev, |
| 747 | struct platform_device *port) | 733 | struct dfl_feature_dev_data *fdata) |
| 748 | { | 734 | { |
| 749 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&port->dev); | ||
| 750 | |||
| 751 | mutex_lock(&cdev->lock); | 735 | mutex_lock(&cdev->lock); |
| 752 | list_add(&pdata->node, &cdev->port_dev_list); | 736 | list_add(&fdata->node, &cdev->port_dev_list); |
| 753 | get_device(&pdata->dev->dev); | ||
| 754 | mutex_unlock(&cdev->lock); | 737 | mutex_unlock(&cdev->lock); |
| 755 | } | 738 | } |
| 756 | 739 | ||
| 757 | /* | 740 | static void dfl_id_free_action(void *arg) |
| 758 | * register current feature device, it is called when we need to switch to | 741 | { |
| 759 | * another feature parsing or we have parsed all features on given device | 742 | struct dfl_feature_dev_data *fdata = arg; |
| 760 | * feature list. | 743 | |
| 761 | */ | 744 | dfl_id_free(fdata->type, fdata->pdev_id); |
| 762 | static int build_info_commit_dev(struct build_feature_devs_info *binfo) | 745 | } |
| 746 | |||
| 747 | static struct dfl_feature_dev_data * | ||
| 748 | binfo_create_feature_dev_data(struct build_feature_devs_info *binfo) | ||
| 763 | { | 749 | { |
| 764 | struct platform_device *fdev = binfo->feature_dev; | 750 | enum dfl_id_type type = binfo->type; |
| 765 | struct dfl_feature_platform_data *pdata; | ||
| 766 | struct dfl_feature_info *finfo, *p; | 751 | struct dfl_feature_info *finfo, *p; |
| 767 | enum dfl_id_type type; | 752 | struct dfl_feature_dev_data *fdata; |
| 768 | int ret, index = 0, res_idx = 0; | 753 | int ret, index = 0, res_idx = 0; |
| 769 | 754 | ||
| 770 | type = feature_dev_id_type(fdev); | ||
| 771 | if (WARN_ON_ONCE(type >= DFL_ID_MAX)) | 755 | if (WARN_ON_ONCE(type >= DFL_ID_MAX)) |
| 772 | return -EINVAL; | 756 | return ERR_PTR(-EINVAL); |
| 773 | 757 | ||
| 774 | /* | 758 | fdata = devm_kzalloc(binfo->dev, sizeof(*fdata), GFP_KERNEL); |
| 775 | * we do not need to care for the memory which is associated with | 759 | if (!fdata) |
| 776 | * the platform device. After calling platform_device_unregister(), | 760 | return ERR_PTR(-ENOMEM); |
| 777 | * it will be automatically freed by device's release() callback, | 761 | |
| 778 | * platform_device_release(). | 762 | fdata->features = devm_kcalloc(binfo->dev, binfo->feature_num, |
| 779 | */ | 763 | sizeof(*fdata->features), GFP_KERNEL); |
| 780 | pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL); | 764 | if (!fdata->features) |
| 781 | if (!pdata) | 765 | return ERR_PTR(-ENOMEM); |
| 782 | return -ENOMEM; | 766 | |
| 767 | fdata->resources = devm_kcalloc(binfo->dev, binfo->feature_num, | ||
| 768 | sizeof(*fdata->resources), GFP_KERNEL); | ||
| 769 | if (!fdata->resources) | ||
| 770 | return ERR_PTR(-ENOMEM); | ||
| 771 | |||
| 772 | fdata->type = type; | ||
| 783 | 773 | ||
| 784 | pdata->dev = fdev; | 774 | fdata->pdev_id = dfl_id_alloc(type, binfo->dev); |
| 785 | pdata->num = binfo->feature_num; | 775 | if (fdata->pdev_id < 0) |
| 786 | pdata->dfl_cdev = binfo->cdev; | 776 | return ERR_PTR(fdata->pdev_id); |
| 787 | pdata->id = FEATURE_DEV_ID_UNUSED; | 777 | |
| 788 | mutex_init(&pdata->lock); | 778 | ret = devm_add_action_or_reset(binfo->dev, dfl_id_free_action, fdata); |
| 789 | lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], | 779 | if (ret) |
| 780 | return ERR_PTR(ret); | ||
| 781 | |||
| 782 | fdata->pdev_name = dfl_devs[type].name; | ||
| 783 | fdata->num = binfo->feature_num; | ||
| 784 | fdata->dfl_cdev = binfo->cdev; | ||
| 785 | fdata->id = FEATURE_DEV_ID_UNUSED; | ||
| 786 | mutex_init(&fdata->lock); | ||
| 787 | lockdep_set_class_and_name(&fdata->lock, &dfl_pdata_keys[type], | ||
| 790 | dfl_pdata_key_strings[type]); | 788 | dfl_pdata_key_strings[type]); |
| 791 | 789 | ||
| 792 | /* | 790 | /* |
| @@ -795,25 +793,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) · 2 unmodified lines | |||
| 795 | * works properly for port device. | 793 | * works properly for port device. |
| 796 | * and it should always be 0 for fme device. | 794 | * and it should always be 0 for fme device. |
| 797 | */ | 795 | */ |
| 798 | WARN_ON(pdata->disable_count); | 796 | WARN_ON(fdata->disable_count); |
| 799 | |||
| 800 | fdev->dev.platform_data = pdata; | ||
| 801 | |||
| 802 | /* each sub feature has one MMIO resource */ | ||
| 803 | fdev->num_resources = binfo->feature_num; | ||
| 804 | fdev->resource = kcalloc(binfo->feature_num, sizeof(*fdev->resource), | ||
| 805 | GFP_KERNEL); | ||
| 806 | if (!fdev->resource) | ||
| 807 | return -ENOMEM; | ||
| 808 | 797 | ||
| 809 | /* fill features and resource information for feature dev */ | 798 | /* fill features and resource information for feature dev */ |
| 810 | list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { | 799 | list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { |
| 811 | struct dfl_feature *feature = &pdata->features[index++]; | 800 | struct dfl_feature *feature = &fdata->features[index++]; |
| 812 | struct dfl_feature_irq_ctx *ctx; | 801 | struct dfl_feature_irq_ctx *ctx; |
| 813 | unsigned int i; | 802 | unsigned int i; |
| 814 | 803 | ||
| 815 | /* save resource information for each feature */ | 804 | /* save resource information for each feature */ |
| 816 | feature->dev = fdev; | ||
| 817 | feature->id = finfo->fid; | 805 | feature->id = finfo->fid; |
| 818 | feature->revision = finfo->revision; | 806 | feature->revision = finfo->revision; |
| 819 | feature->dfh_version = finfo->dfh_version; | 807 | feature->dfh_version = finfo->dfh_version; |
| @@ -823,7 +811,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) · 3 unmodified lines | |||
| 823 | finfo->params, finfo->param_size, | 811 | finfo->params, finfo->param_size, |
| 824 | GFP_KERNEL); | 812 | GFP_KERNEL); |
| 825 | if (!feature->params) | 813 | if (!feature->params) |
| 826 | return -ENOMEM; | 814 | return ERR_PTR(-ENOMEM); |
| 827 | 815 | ||
| 828 | feature->param_size = finfo->param_size; | 816 | feature->param_size = finfo->param_size; |
| 829 | } | 817 | } |
| @@ -840,17 +828,17 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) · 10 unmodified lines | |||
| 840 | devm_ioremap_resource(binfo->dev, | 828 | devm_ioremap_resource(binfo->dev, |
| 841 | &finfo->mmio_res); | 829 | &finfo->mmio_res); |
| 842 | if (IS_ERR(feature->ioaddr)) | 830 | if (IS_ERR(feature->ioaddr)) |
| 843 | return PTR_ERR(feature->ioaddr); | 831 | return ERR_CAST(feature->ioaddr); |
| 844 | } else { | 832 | } else { |
| 845 | feature->resource_index = res_idx; | 833 | feature->resource_index = res_idx; |
| 846 | fdev->resource[res_idx++] = finfo->mmio_res; | 834 | fdata->resources[res_idx++] = finfo->mmio_res; |
| 847 | } | 835 | } |
| 848 | 836 | ||
| 849 | if (finfo->nr_irqs) { | 837 | if (finfo->nr_irqs) { |
| 850 | ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs, | 838 | ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs, |
| 851 | sizeof(*ctx), GFP_KERNEL); | 839 | sizeof(*ctx), GFP_KERNEL); |
| 852 | if (!ctx) | 840 | if (!ctx) |
| 853 | return -ENOMEM; | 841 | return ERR_PTR(-ENOMEM); |
| 854 | 842 | ||
| 855 | for (i = 0; i < finfo->nr_irqs; i++) | 843 | for (i = 0; i < finfo->nr_irqs; i++) |
| 856 | ctx[i].irq = | 844 | ctx[i].irq = |
| @@ -864,55 +852,94 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) · 7 unmodified lines | |||
| 864 | kfree(finfo); | 852 | kfree(finfo); |
| 865 | } | 853 | } |
| 866 | 854 | ||
| 867 | ret = platform_device_add(binfo->feature_dev); | 855 | fdata->resource_num = res_idx; |
| 868 | if (!ret) { | ||
| 869 | if (type == PORT_ID) | ||
| 870 | dfl_fpga_cdev_add_port_dev(binfo->cdev, | ||
| 871 | binfo->feature_dev); | ||
| 872 | else | ||
| 873 | binfo->cdev->fme_dev = | ||
| 874 | get_device(&binfo->feature_dev->dev); | ||
| 875 | /* | ||
| 876 | * reset it to avoid build_info_free() freeing their resource. | ||
| 877 | * | ||
| 878 | * The resource of successfully registered feature devices | ||
| 879 | * will be freed by platform_device_unregister(). See the | ||
| 880 | * comments in build_info_create_dev(). | ||
| 881 | */ | ||
| 882 | binfo->feature_dev = NULL; | ||
| 883 | } | ||
| 884 | 856 | ||
| 885 | return ret; | 857 | return fdata; |
| 886 | } | 858 | } |
| 887 | 859 | ||
| 888 | static int | 860 | /* |
| 889 | build_info_create_dev(struct build_feature_devs_info *binfo, | 861 | * register current feature device, it is called when we need to switch to |
| 890 | enum dfl_id_type type) | 862 | * another feature parsing or we have parsed all features on given device |
| 863 | * feature list. | ||
| 864 | */ | ||
| 865 | static int feature_dev_register(struct dfl_feature_dev_data *fdata) | ||
| 891 | { | 866 | { |
| 867 | struct dfl_feature_platform_data pdata = {}; | ||
| 892 | struct platform_device *fdev; | 868 | struct platform_device *fdev; |
| 869 | struct dfl_feature *feature; | ||
| 870 | int ret; | ||
| 893 | 871 | ||
| 894 | if (type >= DFL_ID_MAX) | 872 | fdev = platform_device_alloc(fdata->pdev_name, fdata->pdev_id); |
| 895 | return -EINVAL; | ||
| 896 | |||
| 897 | /* | ||
| 898 | * we use -ENODEV as the initialization indicator which indicates | ||
| 899 | * whether the id need to be reclaimed | ||
| 900 | */ | ||
| 901 | fdev = platform_device_alloc(dfl_devs[type].name, -ENODEV); | ||
| 902 | if (!fdev) | 873 | if (!fdev) |
| 903 | return -ENOMEM; | 874 | return -ENOMEM; |
| 904 | 875 | ||
| 905 | binfo->feature_dev = fdev; | 876 | fdata->dev = fdev; |
| 906 | binfo->feature_num = 0; | ||
| 907 | 877 | ||
| 908 | INIT_LIST_HEAD(&binfo->sub_features); | 878 | fdev->dev.parent = &fdata->dfl_cdev->region->dev; |
| 879 | fdev->dev.devt = dfl_get_devt(dfl_devs[fdata->type].devt_type, fdev->id); | ||
| 909 | 880 | ||
| 910 | fdev->id = dfl_id_alloc(type, &fdev->dev); | 881 | dfl_fpga_dev_for_each_feature(fdata, feature) |
| 911 | if (fdev->id < 0) | 882 | feature->dev = fdev; |
| 912 | return fdev->id; | 883 | |
| 884 | ret = platform_device_add_resources(fdev, fdata->resources, | ||
| 885 | fdata->resource_num); | ||
| 886 | if (ret) | ||
| 887 | goto err_put_dev; | ||
| 888 | |||
| 889 | pdata.fdata = fdata; | ||
| 890 | ret = platform_device_add_data(fdev, &pdata, sizeof(pdata)); | ||
| 891 | if (ret) | ||
| 892 | goto err_put_dev; | ||
| 893 | |||
| 894 | ret = platform_device_add(fdev); | ||
| 895 | if (ret) | ||
| 896 | goto err_put_dev; | ||
| 897 | |||
| 898 | return 0; | ||
| 899 | |||
| 900 | err_put_dev: | ||
| 901 | platform_device_put(fdev); | ||
| 902 | |||
| 903 | fdata->dev = NULL; | ||
| 904 | |||
| 905 | dfl_fpga_dev_for_each_feature(fdata, feature) | ||
| 906 | feature->dev = NULL; | ||
| 907 | |||
| 908 | return ret; | ||
| 909 | } | ||
| 910 | |||
| 911 | static void feature_dev_unregister(struct dfl_feature_dev_data *fdata) | ||
| 912 | { | ||
| 913 | struct dfl_feature *feature; | ||
| 914 | |||
| 915 | platform_device_unregister(fdata->dev); | ||
| 916 | |||
| 917 | fdata->dev = NULL; | ||
| 918 | |||
| 919 | dfl_fpga_dev_for_each_feature(fdata, feature) | ||
| 920 | feature->dev = NULL; | ||
| 921 | } | ||
| 922 | |||
| 923 | static int build_info_commit_dev(struct build_feature_devs_info *binfo) | ||
| 924 | { | ||
| 925 | struct dfl_feature_dev_data *fdata; | ||
| 926 | int ret; | ||
| 927 | |||
| 928 | fdata = binfo_create_feature_dev_data(binfo); | ||
| 929 | if (IS_ERR(fdata)) | ||
| 930 | return PTR_ERR(fdata); | ||
| 931 | |||
| 932 | ret = feature_dev_register(fdata); | ||
| 933 | if (ret) | ||
| 934 | return ret; | ||
| 935 | |||
| 936 | if (binfo->type == PORT_ID) | ||
| 937 | dfl_fpga_cdev_add_port_data(binfo->cdev, fdata); | ||
| 938 | else | ||
| 939 | binfo->cdev->fme_dev = get_device(&fdata->dev->dev); | ||
| 913 | 940 | ||
| 914 | fdev->dev.parent = &binfo->cdev->region->dev; | 941 | /* reset the binfo for next FIU */ |
| 915 | fdev->dev.devt = dfl_get_devt(dfl_devs[type].devt_type, fdev->id); | 942 | binfo->type = DFL_ID_MAX; |
| 916 | 943 | ||
| 917 | return 0; | 944 | return 0; |
| 918 | } | 945 | } |
| @@ -921,22 +948,11 @@ static void build_info_free(struct build_feature_devs_info *binfo) · 2 unmodified lines | |||
| 921 | { | 948 | { |
| 922 | struct dfl_feature_info *finfo, *p; | 949 | struct dfl_feature_info *finfo, *p; |
| 923 | 950 | ||
| 924 | /* | 951 | list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { |
| 925 | * it is a valid id, free it. See comments in | 952 | list_del(&finfo->node); |
| 926 | * build_info_create_dev() | 953 | kfree(finfo); |
| 927 | */ | ||
| 928 | if (binfo->feature_dev && binfo->feature_dev->id >= 0) { | ||
| 929 | dfl_id_free(feature_dev_id_type(binfo->feature_dev), | ||
| 930 | binfo->feature_dev->id); | ||
| 931 | |||
| 932 | list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { | ||
| 933 | list_del(&finfo->node); | ||
| 934 | kfree(finfo); | ||
| 935 | } | ||
| 936 | } | 954 | } |
| 937 | 955 | ||
| 938 | platform_device_put(binfo->feature_dev); | ||
| 939 | |||
| 940 | devm_kfree(binfo->dev, binfo); | 956 | devm_kfree(binfo->dev, binfo); |
| 941 | } | 957 | } |
| 942 | 958 | ||
| @@ -1025,7 +1041,7 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo, · 82 unmodified lines | |||
| 1025 | * Instead, features with interrupt functionality provide | 1041 | * Instead, features with interrupt functionality provide |
| 1026 | * the information in feature specific registers. | 1042 | * the information in feature specific registers. |
| 1027 | */ | 1043 | */ |
| 1028 | type = feature_dev_id_type(binfo->feature_dev); | 1044 | type = binfo->type; |
| 1029 | if (type == PORT_ID) { | 1045 | if (type == PORT_ID) { |
| 1030 | switch (fid) { | 1046 | switch (fid) { |
| 1031 | case PORT_FEATURE_ID_UINT: | 1047 | case PORT_FEATURE_ID_UINT: |
| @@ -1217,7 +1233,7 @@ static int parse_feature_port_afu(struct build_feature_devs_info *binfo, · 185 unmodified lines | |||
| 1217 | return create_feature_instance(binfo, ofst, size, FEATURE_ID_AFU); | 1233 | return create_feature_instance(binfo, ofst, size, FEATURE_ID_AFU); |
| 1218 | } | 1234 | } |
| 1219 | 1235 | ||
| 1220 | #define is_feature_dev_detected(binfo) (!!(binfo)->feature_dev) | 1236 | #define is_feature_dev_detected(binfo) ((binfo)->type != DFL_ID_MAX) |
| 1221 | 1237 | ||
| 1222 | static int parse_feature_afu(struct build_feature_devs_info *binfo, | 1238 | static int parse_feature_afu(struct build_feature_devs_info *binfo, |
| 1223 | resource_size_t ofst) | 1239 | resource_size_t ofst) |
| @@ -1227,12 +1243,11 @@ static int parse_feature_afu(struct build_feature_devs_info *binfo, · 3 unmodified lines | |||
| 1227 | return -EINVAL; | 1243 | return -EINVAL; |
| 1228 | } | 1244 | } |
| 1229 | 1245 | ||
| 1230 | switch (feature_dev_id_type(binfo->feature_dev)) { | 1246 | switch (binfo->type) { |
| 1231 | case PORT_ID: | 1247 | case PORT_ID: |
| 1232 | return parse_feature_port_afu(binfo, ofst); | 1248 | return parse_feature_port_afu(binfo, ofst); |
| 1233 | default: | 1249 | default: |
| 1234 | dev_info(binfo->dev, "AFU belonging to FIU %s is not supported yet.\n", | 1250 | dev_info(binfo->dev, "AFU belonging to FIU is not supported yet.\n"); |
| 1235 | binfo->feature_dev->name); | ||
| 1236 | } | 1251 | } |
| 1237 | 1252 | ||
| 1238 | return 0; | 1253 | return 0; |
| @@ -1273,6 +1288,7 @@ static void build_info_complete(struct build_feature_devs_info *binfo) · 34 unmodified lines | |||
| 1273 | static int parse_feature_fiu(struct build_feature_devs_info *binfo, | 1288 | static int parse_feature_fiu(struct build_feature_devs_info *binfo, |
| 1274 | resource_size_t ofst) | 1289 | resource_size_t ofst) |
| 1275 | { | 1290 | { |
| 1291 | enum dfl_id_type type; | ||
| 1276 | int ret = 0; | 1292 | int ret = 0; |
| 1277 | u32 offset; | 1293 | u32 offset; |
| 1278 | u16 id; | 1294 | u16 id; |
| @@ -1294,10 +1310,13 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo, · 15 unmodified lines | |||
| 1294 | v = readq(binfo->ioaddr + DFH); | 1310 | v = readq(binfo->ioaddr + DFH); |
| 1295 | id = FIELD_GET(DFH_ID, v); | 1311 | id = FIELD_GET(DFH_ID, v); |
| 1296 | 1312 | ||
| 1297 | /* create platform device for dfl feature dev */ | 1313 | type = dfh_id_to_type(id); |
| 1298 | ret = build_info_create_dev(binfo, dfh_id_to_type(id)); | 1314 | if (type >= DFL_ID_MAX) |
| 1299 | if (ret) | 1315 | return -EINVAL; |
| 1300 | return ret; | 1316 | |
| 1317 | binfo->type = type; | ||
| 1318 | binfo->feature_num = 0; | ||
| 1319 | INIT_LIST_HEAD(&binfo->sub_features); | ||
| 1301 | 1320 | ||
| 1302 | ret = create_feature_instance(binfo, 0, 0, 0); | 1321 | ret = create_feature_instance(binfo, 0, 0, 0); |
| 1303 | if (ret) | 1322 | if (ret) |
| @@ -1515,13 +1534,9 @@ EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_irq); · 211 unmodified lines | |||
| 1515 | 1534 | ||
| 1516 | static int remove_feature_dev(struct device *dev, void *data) | 1535 | static int remove_feature_dev(struct device *dev, void *data) |
| 1517 | { | 1536 | { |
| 1518 | struct platform_device *pdev = to_platform_device(dev); | 1537 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); |
| 1519 | enum dfl_id_type type = feature_dev_id_type(pdev); | ||
| 1520 | int id = pdev->id; | ||
| 1521 | |||
| 1522 | platform_device_unregister(pdev); | ||
| 1523 | 1538 | ||
| 1524 | dfl_id_free(type, id); | 1539 | feature_dev_unregister(fdata); |
| 1525 | 1540 | ||
| 1526 | return 0; | 1541 | return 0; |
| 1527 | } | 1542 | } |
| @@ -1573,6 +1588,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) · 45 unmodified lines | |||
| 1573 | goto unregister_region_exit; | 1588 | goto unregister_region_exit; |
| 1574 | } | 1589 | } |
| 1575 | 1590 | ||
| 1591 | binfo->type = DFL_ID_MAX; | ||
| 1576 | binfo->dev = info->dev; | 1592 | binfo->dev = info->dev; |
| 1577 | binfo->cdev = cdev; | 1593 | binfo->cdev = cdev; |
| 1578 | 1594 | ||
| @@ -1614,25 +1630,10 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_enumerate); · 35 unmodified lines | |||
| 1614 | */ | 1630 | */ |
| 1615 | void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev) | 1631 | void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev) |
| 1616 | { | 1632 | { |
| 1617 | struct dfl_feature_platform_data *pdata, *ptmp; | ||
| 1618 | |||
| 1619 | mutex_lock(&cdev->lock); | 1633 | mutex_lock(&cdev->lock); |
| 1620 | if (cdev->fme_dev) | 1634 | if (cdev->fme_dev) |
| 1621 | put_device(cdev->fme_dev); | 1635 | put_device(cdev->fme_dev); |
| 1622 | 1636 | ||
| 1623 | list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { | ||
| 1624 | struct platform_device *port_dev = pdata->dev; | ||
| 1625 | |||
| 1626 | /* remove released ports */ | ||
| 1627 | if (!device_is_registered(&port_dev->dev)) { | ||
| 1628 | dfl_id_free(feature_dev_id_type(port_dev), | ||
| 1629 | port_dev->id); | ||
| 1630 | platform_device_put(port_dev); | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | list_del(&pdata->node); | ||
| 1634 | put_device(&port_dev->dev); | ||
| 1635 | } | ||
| 1636 | mutex_unlock(&cdev->lock); | 1637 | mutex_unlock(&cdev->lock); |
| 1637 | 1638 | ||
| 1638 | remove_feature_devs(cdev); | 1639 | remove_feature_devs(cdev); |
| @@ -1643,7 +1644,7 @@ void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev) · 4 unmodified lines | |||
| 1643 | EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove); | 1644 | EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove); |
| 1644 | 1645 | ||
| 1645 | /** | 1646 | /** |
| 1646 | * __dfl_fpga_cdev_find_port - find a port under given container device | 1647 | * __dfl_fpga_cdev_find_port_data - find a port under given container device |
| 1647 | * | 1648 | * |
| 1648 | * @cdev: container device | 1649 | * @cdev: container device |
| 1649 | * @data: data passed to match function | 1650 | * @data: data passed to match function |
| @@ -1656,23 +1657,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove); · 6 unmodified lines | |||
| 1656 | * | 1657 | * |
| 1657 | * NOTE: you will need to drop the device reference with put_device() after use. | 1658 | * NOTE: you will need to drop the device reference with put_device() after use. |
| 1658 | */ | 1659 | */ |
| 1659 | struct platform_device * | 1660 | struct dfl_feature_dev_data * |
| 1660 | __dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, | 1661 | __dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, |
| 1661 | int (*match)(struct platform_device *, void *)) | 1662 | int (*match)(struct dfl_feature_dev_data *, void *)) |
| 1662 | { | 1663 | { |
| 1663 | struct dfl_feature_platform_data *pdata; | 1664 | struct dfl_feature_dev_data *fdata; |
| 1664 | struct platform_device *port_dev; | ||
| 1665 | |||
| 1666 | list_for_each_entry(pdata, &cdev->port_dev_list, node) { | ||
| 1667 | port_dev = pdata->dev; | ||
| 1668 | 1665 | ||
| 1669 | if (match(port_dev, data) && get_device(&port_dev->dev)) | 1666 | list_for_each_entry(fdata, &cdev->port_dev_list, node) { |
| 1670 | return port_dev; | 1667 | if (match(fdata, data)) |
| 1668 | return fdata; | ||
| 1671 | } | 1669 | } |
| 1672 | 1670 | ||
| 1673 | return NULL; | 1671 | return NULL; |
| 1674 | } | 1672 | } |
| 1675 | EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port); | 1673 | EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port_data); |
| 1676 | 1674 | ||
| 1677 | static int __init dfl_fpga_init(void) | 1675 | static int __init dfl_fpga_init(void) |
| 1678 | { | 1676 | { |
| @@ -1706,33 +1704,28 @@ static int __init dfl_fpga_init(void) · 27 unmodified lines | |||
| 1706 | */ | 1704 | */ |
| 1707 | int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id) | 1705 | int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id) |
| 1708 | { | 1706 | { |
| 1709 | struct dfl_feature_platform_data *pdata; | 1707 | struct dfl_feature_dev_data *fdata; |
| 1710 | struct platform_device *port_pdev; | ||
| 1711 | int ret = -ENODEV; | 1708 | int ret = -ENODEV; |
| 1712 | 1709 | ||
| 1713 | mutex_lock(&cdev->lock); | 1710 | mutex_lock(&cdev->lock); |
| 1714 | port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, | 1711 | fdata = __dfl_fpga_cdev_find_port_data(cdev, &port_id, |
| 1715 | dfl_fpga_check_port_id); | 1712 | dfl_fpga_check_port_id); |
| 1716 | if (!port_pdev) | 1713 | if (!fdata) |
| 1717 | goto unlock_exit; | 1714 | goto unlock_exit; |
| 1718 | 1715 | ||
| 1719 | if (!device_is_registered(&port_pdev->dev)) { | 1716 | if (!fdata->dev) { |
| 1720 | ret = -EBUSY; | 1717 | ret = -EBUSY; |
| 1721 | goto put_dev_exit; | 1718 | goto unlock_exit; |
| 1722 | } | 1719 | } |
| 1723 | 1720 | ||
| 1724 | pdata = dev_get_platdata(&port_pdev->dev); | 1721 | mutex_lock(&fdata->lock); |
| 1725 | 1722 | ret = dfl_feature_dev_use_begin(fdata, true); | |
| 1726 | mutex_lock(&pdata->lock); | 1723 | mutex_unlock(&fdata->lock); |
| 1727 | ret = dfl_feature_dev_use_begin(pdata, true); | ||
| 1728 | mutex_unlock(&pdata->lock); | ||
| 1729 | if (ret) | 1724 | if (ret) |
| 1730 | goto put_dev_exit; | 1725 | goto unlock_exit; |
| 1731 | 1726 | ||
| 1732 | platform_device_del(port_pdev); | 1727 | feature_dev_unregister(fdata); |
| 1733 | cdev->released_port_num++; | 1728 | cdev->released_port_num++; |
| 1734 | put_dev_exit: | ||
| 1735 | put_device(&port_pdev->dev); | ||
| 1736 | unlock_exit: | 1729 | unlock_exit: |
| 1737 | mutex_unlock(&cdev->lock); | 1730 | mutex_unlock(&cdev->lock); |
| 1738 | return ret; | 1731 | return ret; |
| @@ -1752,34 +1745,29 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port); · 13 unmodified lines | |||
| 1752 | */ | 1745 | */ |
| 1753 | int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id) | 1746 | int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id) |
| 1754 | { | 1747 | { |
| 1755 | struct dfl_feature_platform_data *pdata; | 1748 | struct dfl_feature_dev_data *fdata; |
| 1756 | struct platform_device *port_pdev; | ||
| 1757 | int ret = -ENODEV; | 1749 | int ret = -ENODEV; |
| 1758 | 1750 | ||
| 1759 | mutex_lock(&cdev->lock); | 1751 | mutex_lock(&cdev->lock); |
| 1760 | port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, | 1752 | fdata = __dfl_fpga_cdev_find_port_data(cdev, &port_id, |
| 1761 | dfl_fpga_check_port_id); | 1753 | dfl_fpga_check_port_id); |
| 1762 | if (!port_pdev) | 1754 | if (!fdata) |
| 1763 | goto unlock_exit; | 1755 | goto unlock_exit; |
| 1764 | 1756 | ||
| 1765 | if (device_is_registered(&port_pdev->dev)) { | 1757 | if (fdata->dev) { |
| 1766 | ret = -EBUSY; | 1758 | ret = -EBUSY; |
| 1767 | goto put_dev_exit; | 1759 | goto unlock_exit; |
| 1768 | } | 1760 | } |
| 1769 | 1761 | ||
| 1770 | ret = platform_device_add(port_pdev); | 1762 | ret = feature_dev_register(fdata); |
| 1771 | if (ret) | 1763 | if (ret) |
| 1772 | goto put_dev_exit; | 1764 | goto unlock_exit; |
| 1773 | |||
| 1774 | pdata = dev_get_platdata(&port_pdev->dev); | ||
| 1775 | 1765 | ||
| 1776 | mutex_lock(&pdata->lock); | 1766 | mutex_lock(&fdata->lock); |
| 1777 | dfl_feature_dev_use_end(pdata); | 1767 | dfl_feature_dev_use_end(fdata); |
| 1778 | mutex_unlock(&pdata->lock); | 1768 | mutex_unlock(&fdata->lock); |
| 1779 | 1769 | ||
| 1780 | cdev->released_port_num--; | 1770 | cdev->released_port_num--; |
| 1781 | put_dev_exit: | ||
| 1782 | put_device(&port_pdev->dev); | ||
| 1783 | unlock_exit: | 1771 | unlock_exit: |
| 1784 | mutex_unlock(&cdev->lock); | 1772 | mutex_unlock(&cdev->lock); |
| 1785 | return ret; | 1773 | return ret; |
| @@ -1789,10 +1777,11 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port); · 3 unmodified lines | |||
| 1789 | static void config_port_access_mode(struct device *fme_dev, int port_id, | 1777 | static void config_port_access_mode(struct device *fme_dev, int port_id, |
| 1790 | bool is_vf) | 1778 | bool is_vf) |
| 1791 | { | 1779 | { |
| 1780 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(fme_dev); | ||
| 1792 | void __iomem *base; | 1781 | void __iomem *base; |
| 1793 | u64 v; | 1782 | u64 v; |
| 1794 | 1783 | ||
| 1795 | base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER); | 1784 | base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); |
| 1796 | 1785 | ||
| 1797 | v = readq(base + FME_HDR_PORT_OFST(port_id)); | 1786 | v = readq(base + FME_HDR_PORT_OFST(port_id)); |
| 1798 | 1787 | ||
| @@ -1816,14 +1805,14 @@ static void config_port_access_mode(struct device *fme_dev, int port_id, · 17 unmodified lines | |||
| 1816 | */ | 1805 | */ |
| 1817 | void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev) | 1806 | void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev) |
| 1818 | { | 1807 | { |
| 1819 | struct dfl_feature_platform_data *pdata; | 1808 | struct dfl_feature_dev_data *fdata; |
| 1820 | 1809 | ||
| 1821 | mutex_lock(&cdev->lock); | 1810 | mutex_lock(&cdev->lock); |
| 1822 | list_for_each_entry(pdata, &cdev->port_dev_list, node) { | 1811 | list_for_each_entry(fdata, &cdev->port_dev_list, node) { |
| 1823 | if (device_is_registered(&pdata->dev->dev)) | 1812 | if (fdata->dev) |
| 1824 | continue; | 1813 | continue; |
| 1825 | 1814 | ||
| 1826 | config_port_pf_mode(cdev->fme_dev, pdata->id); | 1815 | config_port_pf_mode(cdev->fme_dev, fdata->id); |
| 1827 | } | 1816 | } |
| 1828 | mutex_unlock(&cdev->lock); | 1817 | mutex_unlock(&cdev->lock); |
| 1829 | } | 1818 | } |
| @@ -1842,7 +1831,7 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf); · 12 unmodified lines | |||
| 1842 | */ | 1831 | */ |
| 1843 | int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) | 1832 | int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) |
| 1844 | { | 1833 | { |
| 1845 | struct dfl_feature_platform_data *pdata; | 1834 | struct dfl_feature_dev_data *fdata; |
| 1846 | int ret = 0; | 1835 | int ret = 0; |
| 1847 | 1836 | ||
| 1848 | mutex_lock(&cdev->lock); | 1837 | mutex_lock(&cdev->lock); |
| @@ -1856,11 +1845,11 @@ int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) · 7 unmodified lines | |||
| 1856 | goto done; | 1845 | goto done; |
| 1857 | } | 1846 | } |
| 1858 | 1847 | ||
| 1859 | list_for_each_entry(pdata, &cdev->port_dev_list, node) { | 1848 | list_for_each_entry(fdata, &cdev->port_dev_list, node) { |
| 1860 | if (device_is_registered(&pdata->dev->dev)) | 1849 | if (fdata->dev) |
| 1861 | continue; | 1850 | continue; |
| 1862 | 1851 | ||
| 1863 | config_port_vf_mode(cdev->fme_dev, pdata->id); | 1852 | config_port_vf_mode(cdev->fme_dev, fdata->id); |
| 1864 | } | 1853 | } |
| 1865 | done: | 1854 | done: |
| 1866 | mutex_unlock(&cdev->lock); | 1855 | mutex_unlock(&cdev->lock); |
| @@ -1993,7 +1982,7 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, · 126 unmodified lines | |||
| 1993 | struct dfl_feature *feature, | 1982 | struct dfl_feature *feature, |
| 1994 | unsigned long arg) | 1983 | unsigned long arg) |
| 1995 | { | 1984 | { |
| 1996 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); | 1985 | struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); |
| 1997 | struct dfl_fpga_irq_set hdr; | 1986 | struct dfl_fpga_irq_set hdr; |
| 1998 | s32 *fds; | 1987 | s32 *fds; |
| 1999 | long ret; | 1988 | long ret; |
| @@ -2013,9 +2002,9 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, · 13 unmodified lines | |||
| 2013 | if (IS_ERR(fds)) | 2002 | if (IS_ERR(fds)) |
| 2014 | return PTR_ERR(fds); | 2003 | return PTR_ERR(fds); |
| 2015 | 2004 | ||
| 2016 | mutex_lock(&pdata->lock); | 2005 | mutex_lock(&fdata->lock); |
| 2017 | ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds); | 2006 | ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds); |
| 2018 | mutex_unlock(&pdata->lock); | 2007 | mutex_unlock(&fdata->lock); |
| 2019 | 2008 | ||
| 2020 | kfree(fds); | 2009 | kfree(fds); |
| 2021 | return ret; | 2010 | return ret; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/bitfield.h> | 17 | #include <linux/bitfield.h> |
| 18 | #include <linux/cdev.h> | 18 | #include <linux/cdev.h> |
| 19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
| 20 | #include <linux/dfl.h> | ||
| 20 | #include <linux/eventfd.h> | 21 | #include <linux/eventfd.h> |
| 21 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
| 22 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
| @@ -206,6 +207,8 @@ · 183 unmodified lines | |||
| 206 | #define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */ | 207 | #define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */ |
| 207 | #define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */ | 208 | #define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */ |
| 208 | 209 | ||
| 210 | struct dfl_feature_dev_data; | ||
| 211 | |||
| 209 | /** | 212 | /** |
| 210 | * struct dfl_fpga_port_ops - port ops | 213 | * struct dfl_fpga_port_ops - port ops |
| 211 | * | 214 | * |
| @@ -219,15 +222,15 @@ struct dfl_fpga_port_ops { · 7 unmodified lines | |||
| 219 | const char *name; | 222 | const char *name; |
| 220 | struct module *owner; | 223 | struct module *owner; |
| 221 | struct list_head node; | 224 | struct list_head node; |
| 222 | int (*get_id)(struct platform_device *pdev); | 225 | int (*get_id)(struct dfl_feature_dev_data *fdata); |
| 223 | int (*enable_set)(struct platform_device *pdev, bool enable); | 226 | int (*enable_set)(struct dfl_feature_dev_data *fdata, bool enable); |
| 224 | }; | 227 | }; |
| 225 | 228 | ||
| 226 | void dfl_fpga_port_ops_add(struct dfl_fpga_port_ops *ops); | 229 | void dfl_fpga_port_ops_add(struct dfl_fpga_port_ops *ops); |
| 227 | void dfl_fpga_port_ops_del(struct dfl_fpga_port_ops *ops); | 230 | void dfl_fpga_port_ops_del(struct dfl_fpga_port_ops *ops); |
| 228 | struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev); | 231 | struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct dfl_feature_dev_data *fdata); |
| 229 | void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops); | 232 | void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops); |
| 230 | int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); | 233 | int dfl_fpga_check_port_id(struct dfl_feature_dev_data *fdata, void *pport_id); |
| 231 | 234 | ||
| 232 | /** | 235 | /** |
| 233 | * struct dfl_feature_id - dfl private feature id | 236 | * struct dfl_feature_id - dfl private feature id |
| @@ -300,26 +303,32 @@ struct dfl_feature { · 66 unmodified lines | |||
| 300 | #define FEATURE_DEV_ID_UNUSED (-1) | 303 | #define FEATURE_DEV_ID_UNUSED (-1) |
| 301 | 304 | ||
| 302 | /** | 305 | /** |
| 303 | * struct dfl_feature_platform_data - platform data for feature devices | 306 | * struct dfl_feature_dev_data - dfl enumeration data for dfl feature dev. |
| 304 | * | 307 | * |
| 305 | * @node: node to link feature devs to container device's port_dev_list. | 308 | * @node: node to link the data structure to container device's port_dev_list. |
| 306 | * @lock: mutex to protect platform data. | 309 | * @lock: mutex to protect feature dev data. |
| 307 | * @cdev: cdev of feature dev. | 310 | * @dev: ptr to the feature's platform device linked with this structure. |
| 308 | * @dev: ptr to platform device linked with this platform data. | 311 | * @type: type of DFL FIU for the feature dev. See enum dfl_id_type. |
| 312 | * @pdev_id: platform device id for the feature dev. | ||
| 313 | * @pdev_name: platform device name for the feature dev. | ||
| 309 | * @dfl_cdev: ptr to container device. | 314 | * @dfl_cdev: ptr to container device. |
| 310 | * @id: id used for this feature device. | 315 | * @id: id used for the feature device. |
| 311 | * @disable_count: count for port disable. | 316 | * @disable_count: count for port disable. |
| 312 | * @excl_open: set on feature device exclusive open. | 317 | * @excl_open: set on feature device exclusive open. |
| 313 | * @open_count: count for feature device open. | 318 | * @open_count: count for feature device open. |
| 314 | * @num: number for sub features. | 319 | * @num: number for sub features. |
| 315 | * @private: ptr to feature dev private data. | 320 | * @private: ptr to feature dev private data. |
| 316 | * @features: sub features of this feature dev. | 321 | * @features: sub features for the feature dev. |
| 322 | * @resource_num: number of resources for the feature dev. | ||
| 323 | * @resources: resources for the feature dev. | ||
| 317 | */ | 324 | */ |
| 318 | struct dfl_feature_platform_data { | 325 | struct dfl_feature_dev_data { |
| 319 | struct list_head node; | 326 | struct list_head node; |
| 320 | struct mutex lock; | 327 | struct mutex lock; |
| 321 | struct cdev cdev; | ||
| 322 | struct platform_device *dev; | 328 | struct platform_device *dev; |
| 329 | enum dfl_id_type type; | ||
| 330 | int pdev_id; | ||
| 331 | const char *pdev_name; | ||
| 323 | struct dfl_fpga_cdev *dfl_cdev; | 332 | struct dfl_fpga_cdev *dfl_cdev; |
| 324 | int id; | 333 | int id; |
| 325 | unsigned int disable_count; | 334 | unsigned int disable_count; |
| @@ -327,55 +336,68 @@ struct dfl_feature_platform_data { · 1 unmodified line | |||
| 327 | int open_count; | 336 | int open_count; |
| 328 | void *private; | 337 | void *private; |
| 329 | int num; | 338 | int num; |
| 330 | struct dfl_feature features[]; | 339 | struct dfl_feature *features; |
| 340 | int resource_num; | ||
| 341 | struct resource *resources; | ||
| 342 | }; | ||
| 343 | |||
| 344 | /** | ||
| 345 | * struct dfl_feature_platform_data - platform data for feature devices | ||
| 346 | * | ||
| 347 | * @cdev: cdev of feature dev. | ||
| 348 | * @fdata: dfl enumeration data for the dfl feature device. | ||
| 349 | */ | ||
| 350 | struct dfl_feature_platform_data { | ||
| 351 | struct cdev cdev; | ||
| 352 | struct dfl_feature_dev_data *fdata; | ||
| 331 | }; | 353 | }; |
| 332 | 354 | ||
| 333 | static inline | 355 | static inline |
| 334 | int dfl_feature_dev_use_begin(struct dfl_feature_platform_data *pdata, | 356 | int dfl_feature_dev_use_begin(struct dfl_feature_dev_data *fdata, |
| 335 | bool excl) | 357 | bool excl) |
| 336 | { | 358 | { |
| 337 | if (pdata->excl_open) | 359 | if (fdata->excl_open) |
| 338 | return -EBUSY; | 360 | return -EBUSY; |
| 339 | 361 | ||
| 340 | if (excl) { | 362 | if (excl) { |
| 341 | if (pdata->open_count) | 363 | if (fdata->open_count) |
| 342 | return -EBUSY; | 364 | return -EBUSY; |
| 343 | 365 | ||
| 344 | pdata->excl_open = true; | 366 | fdata->excl_open = true; |
| 345 | } | 367 | } |
| 346 | pdata->open_count++; | 368 | fdata->open_count++; |
| 347 | 369 | ||
| 348 | return 0; | 370 | return 0; |
| 349 | } | 371 | } |
| 350 | 372 | ||
| 351 | static inline | 373 | static inline |
| 352 | void dfl_feature_dev_use_end(struct dfl_feature_platform_data *pdata) | 374 | void dfl_feature_dev_use_end(struct dfl_feature_dev_data *fdata) |
| 353 | { | 375 | { |
| 354 | pdata->excl_open = false; | 376 | fdata->excl_open = false; |
| 355 | 377 | ||
| 356 | if (WARN_ON(pdata->open_count <= 0)) | 378 | if (WARN_ON(fdata->open_count <= 0)) |
| 357 | return; | 379 | return; |
| 358 | 380 | ||
| 359 | pdata->open_count--; | 381 | fdata->open_count--; |
| 360 | } | 382 | } |
| 361 | 383 | ||
| 362 | static inline | 384 | static inline |
| 363 | int dfl_feature_dev_use_count(struct dfl_feature_platform_data *pdata) | 385 | int dfl_feature_dev_use_count(struct dfl_feature_dev_data *fdata) |
| 364 | { | 386 | { |
| 365 | return pdata->open_count; | 387 | return fdata->open_count; |
| 366 | } | 388 | } |
| 367 | 389 | ||
| 368 | static inline | 390 | static inline |
| 369 | void dfl_fpga_pdata_set_private(struct dfl_feature_platform_data *pdata, | 391 | void dfl_fpga_fdata_set_private(struct dfl_feature_dev_data *fdata, |
| 370 | void *private) | 392 | void *private) |
| 371 | { | 393 | { |
| 372 | pdata->private = private; | 394 | fdata->private = private; |
| 373 | } | 395 | } |
| 374 | 396 | ||
| 375 | static inline | 397 | static inline |
| 376 | void *dfl_fpga_pdata_get_private(struct dfl_feature_platform_data *pdata) | 398 | void *dfl_fpga_fdata_get_private(struct dfl_feature_dev_data *fdata) |
| 377 | { | 399 | { |
| 378 | return pdata->private; | 400 | return fdata->private; |
| 379 | } | 401 | } |
| 380 | 402 | ||
| 381 | struct dfl_feature_ops { | 403 | struct dfl_feature_ops { |
| @@ -398,37 +420,36 @@ int dfl_fpga_dev_ops_register(struct platform_device *pdev, · 16 unmodified lines | |||
| 398 | struct module *owner); | 420 | struct module *owner); |
| 399 | void dfl_fpga_dev_ops_unregister(struct platform_device *pdev); | 421 | void dfl_fpga_dev_ops_unregister(struct platform_device *pdev); |
| 400 | 422 | ||
| 401 | static inline | 423 | static inline struct dfl_feature_dev_data * |
| 402 | struct platform_device *dfl_fpga_inode_to_feature_dev(struct inode *inode) | 424 | dfl_fpga_inode_to_feature_dev_data(struct inode *inode) |
| 403 | { | 425 | { |
| 404 | struct dfl_feature_platform_data *pdata; | 426 | struct dfl_feature_platform_data *pdata; |
| 405 | 427 | ||
| 406 | pdata = container_of(inode->i_cdev, struct dfl_feature_platform_data, | 428 | pdata = container_of(inode->i_cdev, struct dfl_feature_platform_data, |
| 407 | cdev); | 429 | cdev); |
| 408 | return pdata->dev; | 430 | return pdata->fdata; |
| 409 | } | 431 | } |
| 410 | 432 | ||
| 411 | #define dfl_fpga_dev_for_each_feature(pdata, feature) \ | 433 | #define dfl_fpga_dev_for_each_feature(fdata, feature) \ |
| 412 | for ((feature) = (pdata)->features; \ | 434 | for ((feature) = (fdata)->features; \ |
| 413 | (feature) < (pdata)->features + (pdata)->num; (feature)++) | 435 | (feature) < (fdata)->features + (fdata)->num; (feature)++) |
| 414 | 436 | ||
| 415 | static inline | 437 | static inline struct dfl_feature * |
| 416 | struct dfl_feature *dfl_get_feature_by_id(struct device *dev, u16 id) | 438 | dfl_get_feature_by_id(struct dfl_feature_dev_data *fdata, u16 id) |
| 417 | { | 439 | { |
| 418 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | ||
| 419 | struct dfl_feature *feature; | 440 | struct dfl_feature *feature; |
| 420 | 441 | ||
| 421 | dfl_fpga_dev_for_each_feature(pdata, feature) | 442 | dfl_fpga_dev_for_each_feature(fdata, feature) |
| 422 | if (feature->id == id) | 443 | if (feature->id == id) |
| 423 | return feature; | 444 | return feature; |
| 424 | 445 | ||
| 425 | return NULL; | 446 | return NULL; |
| 426 | } | 447 | } |
| 427 | 448 | ||
| 428 | static inline | 449 | static inline void __iomem * |
| 429 | void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) | 450 | dfl_get_feature_ioaddr_by_id(struct dfl_feature_dev_data *fdata, u16 id) |
| 430 | { | 451 | { |
| 431 | struct dfl_feature *feature = dfl_get_feature_by_id(dev, id); | 452 | struct dfl_feature *feature = dfl_get_feature_by_id(fdata, id); |
| 432 | 453 | ||
| 433 | if (feature && feature->ioaddr) | 454 | if (feature && feature->ioaddr) |
| 434 | return feature->ioaddr; | 455 | return feature->ioaddr; |
| @@ -437,10 +458,18 @@ void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) · 2 unmodified lines | |||
| 437 | return NULL; | 458 | return NULL; |
| 438 | } | 459 | } |
| 439 | 460 | ||
| 461 | static inline struct dfl_feature_dev_data * | ||
| 462 | to_dfl_feature_dev_data(struct device *dev) | ||
| 463 | { | ||
| 464 | struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); | ||
| 465 | |||
| 466 | return pdata->fdata; | ||
| 467 | } | ||
| 468 | |||
| 440 | static inline | 469 | static inline |
| 441 | struct device *dfl_fpga_pdata_to_parent(struct dfl_feature_platform_data *pdata) | 470 | struct device *dfl_fpga_fdata_to_parent(struct dfl_feature_dev_data *fdata) |
| 442 | { | 471 | { |
| 443 | return pdata->dev->dev.parent->parent; | 472 | return fdata->dev->dev.parent->parent; |
| 444 | } | 473 | } |
| 445 | 474 | ||
| 446 | static inline bool dfl_feature_is_fme(void __iomem *base) | 475 | static inline bool dfl_feature_is_fme(void __iomem *base) |
| @@ -522,26 +551,21 @@ struct dfl_fpga_cdev * · 75 unmodified lines | |||
| 522 | dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info); | 551 | dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info); |
| 523 | void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev); | 552 | void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev); |
| 524 | 553 | ||
| 525 | /* | 554 | struct dfl_feature_dev_data * |
| 526 | * need to drop the device reference with put_device() after use port platform | 555 | __dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, |
| 527 | * device returned by __dfl_fpga_cdev_find_port and dfl_fpga_cdev_find_port | 556 | int (*match)(struct dfl_feature_dev_data *, void *)); |
| 528 | * functions. | ||
| 529 | */ | ||
| 530 | struct platform_device * | ||
| 531 | __dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, | ||
| 532 | int (*match)(struct platform_device *, void *)); | ||
| 533 | 557 | ||
| 534 | static inline struct platform_device * | 558 | static inline struct dfl_feature_dev_data * |
| 535 | dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, | 559 | dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, |
| 536 | int (*match)(struct platform_device *, void *)) | 560 | int (*match)(struct dfl_feature_dev_data *, void *)) |
| 537 | { | 561 | { |
| 538 | struct platform_device *pdev; | 562 | struct dfl_feature_dev_data *fdata; |
| 539 | 563 | ||
| 540 | mutex_lock(&cdev->lock); | 564 | mutex_lock(&cdev->lock); |
| 541 | pdev = __dfl_fpga_cdev_find_port(cdev, data, match); | 565 | fdata = __dfl_fpga_cdev_find_port_data(cdev, data, match); |
| 542 | mutex_unlock(&cdev->lock); | 566 | mutex_unlock(&cdev->lock); |
| 543 | 567 | ||
| 544 | return pdev; | 568 | return fdata; |
| 545 | } | 569 | } |
| 546 | 570 | ||
| 547 | int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); | 571 | int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); |
| @@ -75,22 +75,54 @@ struct coresight_device *coresight_get_percpu_sink(int cpu) · 74 unmodified lines | |||
| 75 | } | 75 | } |
| 76 | EXPORT_SYMBOL_GPL(coresight_get_percpu_sink); | 76 | EXPORT_SYMBOL_GPL(coresight_get_percpu_sink); |
| 77 | 77 | ||
| 78 | static struct coresight_device *coresight_get_source(struct list_head *path) | ||
| 79 | { | ||
| 80 | struct coresight_device *csdev; | ||
| 81 | |||
| 82 | if (!path) | ||
| 83 | return NULL; | ||
| 84 | |||
| 85 | csdev = list_first_entry(path, struct coresight_node, link)->csdev; | ||
| 86 | if (!coresight_is_device_source(csdev)) | ||
| 87 | return NULL; | ||
| 88 | |||
| 89 | return csdev; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * coresight_blocks_source - checks whether the connection matches the source | ||
| 94 | * of path if connection is bound to specific source. | ||
| 95 | * @src: The source device of the trace path | ||
| 96 | * @conn: The connection of one outport | ||
| 97 | * | ||
| 98 | * Return false if the connection doesn't have a source binded or source of the | ||
| 99 | * path matches the source binds to connection. | ||
| 100 | */ | ||
| 101 | static bool coresight_blocks_source(struct coresight_device *src, | ||
| 102 | struct coresight_connection *conn) | ||
| 103 | { | ||
| 104 | return conn->filter_src_fwnode && (conn->filter_src_dev != src); | ||
| 105 | } | ||
| 106 | |||
| 78 | static struct coresight_connection * | 107 | static struct coresight_connection * |
| 79 | coresight_find_out_connection(struct coresight_device *src_dev, | 108 | coresight_find_out_connection(struct coresight_device *csdev, |
| 80 | struct coresight_device *dest_dev) | 109 | struct coresight_device *out_dev, |
| 110 | struct coresight_device *trace_src) | ||
| 81 | { | 111 | { |
| 82 | int i; | 112 | int i; |
| 83 | struct coresight_connection *conn; | 113 | struct coresight_connection *conn; |
| 84 | 114 | ||
| 85 | for (i = 0; i < src_dev->pdata->nr_outconns; i++) { | 115 | for (i = 0; i < csdev->pdata->nr_outconns; i++) { |
| 86 | conn = src_dev->pdata->out_conns[i]; | 116 | conn = csdev->pdata->out_conns[i]; |
| 87 | if (conn->dest_dev == dest_dev) | 117 | if (coresight_blocks_source(trace_src, conn)) |
| 118 | continue; | ||
| 119 | if (conn->dest_dev == out_dev) | ||
| 88 | return conn; | 120 | return conn; |
| 89 | } | 121 | } |
| 90 | 122 | ||
| 91 | dev_err(&src_dev->dev, | 123 | dev_err(&csdev->dev, |
| 92 | "couldn't find output connection, src_dev: %s, dest_dev: %s\n", | 124 | "couldn't find output connection, csdev: %s, out_dev: %s\n", |
| 93 | dev_name(&src_dev->dev), dev_name(&dest_dev->dev)); | 125 | dev_name(&csdev->dev), dev_name(&out_dev->dev)); |
| 94 | 126 | ||
| 95 | return ERR_PTR(-ENODEV); | 127 | return ERR_PTR(-ENODEV); |
| 96 | } | 128 | } |
| @@ -251,7 +283,8 @@ static void coresight_disable_sink(struct coresight_device *csdev) · 154 unmodified lines | |||
| 251 | 283 | ||
| 252 | static int coresight_enable_link(struct coresight_device *csdev, | 284 | static int coresight_enable_link(struct coresight_device *csdev, |
| 253 | struct coresight_device *parent, | 285 | struct coresight_device *parent, |
| 254 | struct coresight_device *child) | 286 | struct coresight_device *child, |
| 287 | struct coresight_device *source) | ||
| 255 | { | 288 | { |
| 256 | int link_subtype; | 289 | int link_subtype; |
| 257 | struct coresight_connection *inconn, *outconn; | 290 | struct coresight_connection *inconn, *outconn; |
| @@ -259,8 +292,8 @@ static int coresight_enable_link(struct coresight_device *csdev, · 1 unmodified line | |||
| 259 | if (!parent || !child) | 292 | if (!parent || !child) |
| 260 | return -EINVAL; | 293 | return -EINVAL; |
| 261 | 294 | ||
| 262 | inconn = coresight_find_out_connection(parent, csdev); | 295 | inconn = coresight_find_out_connection(parent, csdev, source); |
| 263 | outconn = coresight_find_out_connection(csdev, child); | 296 | outconn = coresight_find_out_connection(csdev, child, source); |
| 264 | link_subtype = csdev->subtype.link_subtype; | 297 | link_subtype = csdev->subtype.link_subtype; |
| 265 | 298 | ||
| 266 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn)) | 299 | if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn)) |
| @@ -273,15 +306,16 @@ static int coresight_enable_link(struct coresight_device *csdev, · 6 unmodified lines | |||
| 273 | 306 | ||
| 274 | static void coresight_disable_link(struct coresight_device *csdev, | 307 | static void coresight_disable_link(struct coresight_device *csdev, |
| 275 | struct coresight_device *parent, | 308 | struct coresight_device *parent, |
| 276 | struct coresight_device *child) | 309 | struct coresight_device *child, |
| 310 | struct coresight_device *source) | ||
| 277 | { | 311 | { |
| 278 | struct coresight_connection *inconn, *outconn; | 312 | struct coresight_connection *inconn, *outconn; |
| 279 | 313 | ||
| 280 | if (!parent || !child) | 314 | if (!parent || !child) |
| 281 | return; | 315 | return; |
| 282 | 316 | ||
| 283 | inconn = coresight_find_out_connection(parent, csdev); | 317 | inconn = coresight_find_out_connection(parent, csdev, source); |
| 284 | outconn = coresight_find_out_connection(csdev, child); | 318 | outconn = coresight_find_out_connection(csdev, child, source); |
| 285 | 319 | ||
| 286 | link_ops(csdev)->disable(csdev, inconn, outconn); | 320 | link_ops(csdev)->disable(csdev, inconn, outconn); |
| 287 | } | 321 | } |
| @@ -375,7 +409,8 @@ static void coresight_disable_path_from(struct list_head *path, · 87 unmodified lines | |||
| 375 | case CORESIGHT_DEV_TYPE_LINK: | 409 | case CORESIGHT_DEV_TYPE_LINK: |
| 376 | parent = list_prev_entry(nd, link)->csdev; | 410 | parent = list_prev_entry(nd, link)->csdev; |
| 377 | child = list_next_entry(nd, link)->csdev; | 411 | child = list_next_entry(nd, link)->csdev; |
| 378 | coresight_disable_link(csdev, parent, child); | 412 | coresight_disable_link(csdev, parent, child, |
| 413 | coresight_get_source(path)); | ||
| 379 | break; | 414 | break; |
| 380 | default: | 415 | default: |
| 381 | break; | 416 | break; |
| @@ -418,7 +453,9 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, · 36 unmodified lines | |||
| 418 | u32 type; | 453 | u32 type; |
| 419 | struct coresight_node *nd; | 454 | struct coresight_node *nd; |
| 420 | struct coresight_device *csdev, *parent, *child; | 455 | struct coresight_device *csdev, *parent, *child; |
| 456 | struct coresight_device *source; | ||
| 421 | 457 | ||
| 458 | source = coresight_get_source(path); | ||
| 422 | list_for_each_entry_reverse(nd, path, link) { | 459 | list_for_each_entry_reverse(nd, path, link) { |
| 423 | csdev = nd->csdev; | 460 | csdev = nd->csdev; |
| 424 | type = csdev->type; | 461 | type = csdev->type; |
| @@ -456,7 +493,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, · 31 unmodified lines | |||
| 456 | case CORESIGHT_DEV_TYPE_LINK: | 493 | case CORESIGHT_DEV_TYPE_LINK: |
| 457 | parent = list_prev_entry(nd, link)->csdev; | 494 | parent = list_prev_entry(nd, link)->csdev; |
| 458 | child = list_next_entry(nd, link)->csdev; | 495 | child = list_next_entry(nd, link)->csdev; |
| 459 | ret = coresight_enable_link(csdev, parent, child); | 496 | ret = coresight_enable_link(csdev, parent, child, source); |
| 460 | if (ret) | 497 | if (ret) |
| 461 | goto err; | 498 | goto err; |
| 462 | break; | 499 | break; |
| @@ -619,6 +656,7 @@ static void coresight_drop_device(struct coresight_device *csdev) · 156 unmodified lines | |||
| 619 | /** | 656 | /** |
| 620 | * _coresight_build_path - recursively build a path from a @csdev to a sink. | 657 | * _coresight_build_path - recursively build a path from a @csdev to a sink. |
| 621 | * @csdev: The device to start from. | 658 | * @csdev: The device to start from. |
| 659 | * @source: The trace source device of the path. | ||
| 622 | * @sink: The final sink we want in this path. | 660 | * @sink: The final sink we want in this path. |
| 623 | * @path: The list to add devices to. | 661 | * @path: The list to add devices to. |
| 624 | * | 662 | * |
| @@ -628,6 +666,7 @@ static void coresight_drop_device(struct coresight_device *csdev) · 3 unmodified lines | |||
| 628 | * the source is the first device and the sink the last one. | 666 | * the source is the first device and the sink the last one. |
| 629 | */ | 667 | */ |
| 630 | static int _coresight_build_path(struct coresight_device *csdev, | 668 | static int _coresight_build_path(struct coresight_device *csdev, |
| 669 | struct coresight_device *source, | ||
| 631 | struct coresight_device *sink, | 670 | struct coresight_device *sink, |
| 632 | struct list_head *path) | 671 | struct list_head *path) |
| 633 | { | 672 | { |
| @@ -641,7 +680,7 @@ static int _coresight_build_path(struct coresight_device *csdev, · 7 unmodified lines | |||
| 641 | 680 | ||
| 642 | if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) && | 681 | if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) && |
| 643 | sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) { | 682 | sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) { |
| 644 | if (_coresight_build_path(sink, sink, path) == 0) { | 683 | if (_coresight_build_path(sink, source, sink, path) == 0) { |
| 645 | found = true; | 684 | found = true; |
| 646 | goto out; | 685 | goto out; |
| 647 | } | 686 | } |
| @@ -652,8 +691,12 @@ static int _coresight_build_path(struct coresight_device *csdev, · 4 unmodified lines | |||
| 652 | struct coresight_device *child_dev; | 691 | struct coresight_device *child_dev; |
| 653 | 692 | ||
| 654 | child_dev = csdev->pdata->out_conns[i]->dest_dev; | 693 | child_dev = csdev->pdata->out_conns[i]->dest_dev; |
| 694 | |||
| 695 | if (coresight_blocks_source(source, csdev->pdata->out_conns[i])) | ||
| 696 | continue; | ||
| 697 | |||
| 655 | if (child_dev && | 698 | if (child_dev && |
| 656 | _coresight_build_path(child_dev, sink, path) == 0) { | 699 | _coresight_build_path(child_dev, source, sink, path) == 0) { |
| 657 | found = true; | 700 | found = true; |
| 658 | break; | 701 | break; |
| 659 | } | 702 | } |
| @@ -698,7 +741,7 @@ struct list_head *coresight_build_path(struct coresight_device *source, · 38 unmodified lines | |||
| 698 | 741 | ||
| 699 | INIT_LIST_HEAD(path); | 742 | INIT_LIST_HEAD(path); |
| 700 | 743 | ||
| 701 | rc = _coresight_build_path(source, sink, path); | 744 | rc = _coresight_build_path(source, source, sink, path); |
| 702 | if (rc) { | 745 | if (rc) { |
| 703 | kfree(path); | 746 | kfree(path); |
| 704 | return ERR_PTR(rc); | 747 | return ERR_PTR(rc); |
| @@ -927,6 +970,16 @@ static int coresight_orphan_match(struct device *dev, void *data) · 222 unmodified lines | |||
| 927 | for (i = 0; i < src_csdev->pdata->nr_outconns; i++) { | 970 | for (i = 0; i < src_csdev->pdata->nr_outconns; i++) { |
| 928 | conn = src_csdev->pdata->out_conns[i]; | 971 | conn = src_csdev->pdata->out_conns[i]; |
| 929 | 972 | ||
| 973 | /* Fix filter source device before skip the port */ | ||
| 974 | if (conn->filter_src_fwnode && !conn->filter_src_dev) { | ||
| 975 | if (dst_csdev && | ||
| 976 | (conn->filter_src_fwnode == dst_csdev->dev.fwnode) && | ||
| 977 | !WARN_ON_ONCE(!coresight_is_device_source(dst_csdev))) | ||
| 978 | conn->filter_src_dev = dst_csdev; | ||
| 979 | else | ||
| 980 | still_orphan = true; | ||
| 981 | } | ||
| 982 | |||
| 930 | /* Skip the port if it's already connected. */ | 983 | /* Skip the port if it's already connected. */ |
| 931 | if (conn->dest_dev) | 984 | if (conn->dest_dev) |
| 932 | continue; | 985 | continue; |
| @@ -977,18 +1030,40 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev) · 44 unmodified lines | |||
| 977 | csdev, coresight_orphan_match); | 1030 | csdev, coresight_orphan_match); |
| 978 | } | 1031 | } |
| 979 | 1032 | ||
| 1033 | static int coresight_clear_filter_source(struct device *dev, void *data) | ||
| 1034 | { | ||
| 1035 | int i; | ||
| 1036 | struct coresight_device *source = data; | ||
| 1037 | struct coresight_device *csdev = to_coresight_device(dev); | ||
| 1038 | |||
| 1039 | for (i = 0; i < csdev->pdata->nr_outconns; ++i) { | ||
| 1040 | if (csdev->pdata->out_conns[i]->filter_src_dev == source) | ||
| 1041 | csdev->pdata->out_conns[i]->filter_src_dev = NULL; | ||
| 1042 | } | ||
| 1043 | return 0; | ||
| 1044 | } | ||
| 1045 | |||
| 980 | /* coresight_remove_conns - Remove other device's references to this device */ | 1046 | /* coresight_remove_conns - Remove other device's references to this device */ |
| 981 | static void coresight_remove_conns(struct coresight_device *csdev) | 1047 | static void coresight_remove_conns(struct coresight_device *csdev) |
| 982 | { | 1048 | { |
| 983 | int i, j; | 1049 | int i, j; |
| 984 | struct coresight_connection *conn; | 1050 | struct coresight_connection *conn; |
| 985 | 1051 | ||
| 1052 | if (coresight_is_device_source(csdev)) | ||
| 1053 | bus_for_each_dev(&coresight_bustype, NULL, csdev, | ||
| 1054 | coresight_clear_filter_source); | ||
| 1055 | |||
| 986 | /* | 1056 | /* |
| 987 | * Remove the input connection references from the destination device | 1057 | * Remove the input connection references from the destination device |
| 988 | * for each output connection. | 1058 | * for each output connection. |
| 989 | */ | 1059 | */ |
| 990 | for (i = 0; i < csdev->pdata->nr_outconns; i++) { | 1060 | for (i = 0; i < csdev->pdata->nr_outconns; i++) { |
| 991 | conn = csdev->pdata->out_conns[i]; | 1061 | conn = csdev->pdata->out_conns[i]; |
| 1062 | if (conn->filter_src_fwnode) { | ||
| 1063 | conn->filter_src_dev = NULL; | ||
| 1064 | fwnode_handle_put(conn->filter_src_fwnode); | ||
| 1065 | } | ||
| 1066 | |||
| 992 | if (!conn->dest_dev) | 1067 | if (!conn->dest_dev) |
| 993 | continue; | 1068 | continue; |
| 994 | 1069 | ||
| @@ -11,10 +11,12 @@ · 10 unmodified lines | |||
| 11 | #include <linux/pm_runtime.h> | 11 | #include <linux/pm_runtime.h> |
| 12 | 12 | ||
| 13 | #include "coresight-priv.h" | 13 | #include "coresight-priv.h" |
| 14 | #include "coresight-trace-id.h" | ||
| 14 | 15 | ||
| 15 | struct dummy_drvdata { | 16 | struct dummy_drvdata { |
| 16 | struct device *dev; | 17 | struct device *dev; |
| 17 | struct coresight_device *csdev; | 18 | struct coresight_device *csdev; |
| 19 | u8 traceid; | ||
| 18 | }; | 20 | }; |
| 19 | 21 | ||
| 20 | DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source"); | 22 | DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source"); |
| @@ -72,6 +74,32 @@ static const struct coresight_ops dummy_sink_cs_ops = { · 51 unmodified lines | |||
| 72 | .sink_ops = &dummy_sink_ops, | 74 | .sink_ops = &dummy_sink_ops, |
| 73 | }; | 75 | }; |
| 74 | 76 | ||
| 77 | /* User can get the trace id of dummy source from this node. */ | ||
| 78 | static ssize_t traceid_show(struct device *dev, | ||
| 79 | struct device_attribute *attr, char *buf) | ||
| 80 | { | ||
| 81 | unsigned long val; | ||
| 82 | struct dummy_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||
| 83 | |||
| 84 | val = drvdata->traceid; | ||
| 85 | return sysfs_emit(buf, "%#lx\n", val); | ||
| 86 | } | ||
| 87 | static DEVICE_ATTR_RO(traceid); | ||
| 88 | |||
| 89 | static struct attribute *coresight_dummy_attrs[] = { | ||
| 90 | &dev_attr_traceid.attr, | ||
| 91 | NULL, | ||
| 92 | }; | ||
| 93 | |||
| 94 | static const struct attribute_group coresight_dummy_group = { | ||
| 95 | .attrs = coresight_dummy_attrs, | ||
| 96 | }; | ||
| 97 | |||
| 98 | static const struct attribute_group *coresight_dummy_groups[] = { | ||
| 99 | &coresight_dummy_group, | ||
| 100 | NULL, | ||
| 101 | }; | ||
| 102 | |||
| 75 | static int dummy_probe(struct platform_device *pdev) | 103 | static int dummy_probe(struct platform_device *pdev) |
| 76 | { | 104 | { |
| 77 | struct device *dev = &pdev->dev; | 105 | struct device *dev = &pdev->dev; |
| @@ -79,6 +107,11 @@ static int dummy_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 79 | struct coresight_platform_data *pdata; | 107 | struct coresight_platform_data *pdata; |
| 80 | struct dummy_drvdata *drvdata; | 108 | struct dummy_drvdata *drvdata; |
| 81 | struct coresight_desc desc = { 0 }; | 109 | struct coresight_desc desc = { 0 }; |
| 110 | int ret = 0, trace_id = 0; | ||
| 111 | |||
| 112 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
| 113 | if (!drvdata) | ||
| 114 | return -ENOMEM; | ||
| 82 | 115 | ||
| 83 | if (of_device_is_compatible(node, "arm,coresight-dummy-source")) { | 116 | if (of_device_is_compatible(node, "arm,coresight-dummy-source")) { |
| 84 | 117 | ||
| @@ -90,6 +123,26 @@ static int dummy_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 90 | desc.subtype.source_subtype = | 123 | desc.subtype.source_subtype = |
| 91 | CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS; | 124 | CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS; |
| 92 | desc.ops = &dummy_source_cs_ops; | 125 | desc.ops = &dummy_source_cs_ops; |
| 126 | desc.groups = coresight_dummy_groups; | ||
| 127 | |||
| 128 | ret = coresight_get_static_trace_id(dev, &trace_id); | ||
| 129 | if (!ret) { | ||
| 130 | /* Get the static id if id is set in device tree. */ | ||
| 131 | ret = coresight_trace_id_get_static_system_id(trace_id); | ||
| 132 | if (ret < 0) { | ||
| 133 | dev_err(dev, "Fail to get static id.\n"); | ||
| 134 | return ret; | ||
| 135 | } | ||
| 136 | } else { | ||
| 137 | /* Get next available id if id is not set in device tree. */ | ||
| 138 | trace_id = coresight_trace_id_get_system_id(); | ||
| 139 | if (trace_id < 0) { | ||
| 140 | ret = trace_id; | ||
| 141 | return ret; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | drvdata->traceid = (u8)trace_id; | ||
| 145 | |||
| 93 | } else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) { | 146 | } else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) { |
| 94 | desc.name = coresight_alloc_device_name(&sink_devs, dev); | 147 | desc.name = coresight_alloc_device_name(&sink_devs, dev); |
| 95 | if (!desc.name) | 148 | if (!desc.name) |
| @@ -104,27 +157,35 @@ static int dummy_probe(struct platform_device *pdev) · 8 unmodified lines | |||
| 104 | } | 157 | } |
| 105 | 158 | ||
| 106 | pdata = coresight_get_platform_data(dev); | 159 | pdata = coresight_get_platform_data(dev); |
| 107 | if (IS_ERR(pdata)) | 160 | if (IS_ERR(pdata)) { |
| 108 | return PTR_ERR(pdata); | 161 | ret = PTR_ERR(pdata); |
| 162 | goto free_id; | ||
| 163 | } | ||
| 109 | pdev->dev.platform_data = pdata; | 164 | pdev->dev.platform_data = pdata; |
| 110 | 165 | ||
| 111 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
| 112 | if (!drvdata) | ||
| 113 | return -ENOMEM; | ||
| 114 | |||
| 115 | drvdata->dev = &pdev->dev; | 166 | drvdata->dev = &pdev->dev; |
| 116 | platform_set_drvdata(pdev, drvdata); | 167 | platform_set_drvdata(pdev, drvdata); |
| 117 | 168 | ||
| 118 | desc.pdata = pdev->dev.platform_data; | 169 | desc.pdata = pdev->dev.platform_data; |
| 119 | desc.dev = &pdev->dev; | 170 | desc.dev = &pdev->dev; |
| 120 | drvdata->csdev = coresight_register(&desc); | 171 | drvdata->csdev = coresight_register(&desc); |
| 121 | if (IS_ERR(drvdata->csdev)) | 172 | if (IS_ERR(drvdata->csdev)) { |
| 122 | return PTR_ERR(drvdata->csdev); | 173 | ret = PTR_ERR(drvdata->csdev); |
| 174 | goto free_id; | ||
| 175 | } | ||
| 123 | 176 | ||
| 124 | pm_runtime_enable(dev); | 177 | pm_runtime_enable(dev); |
| 125 | dev_dbg(dev, "Dummy device initialized\n"); | 178 | dev_dbg(dev, "Dummy device initialized\n"); |
| 126 | 179 | ||
| 127 | return 0; | 180 | ret = 0; |
| 181 | goto out; | ||
| 182 | |||
| 183 | free_id: | ||
| 184 | if (IS_VALID_CS_TRACE_ID(drvdata->traceid)) | ||
| 185 | coresight_trace_id_put_system_id(drvdata->traceid); | ||
| 186 | |||
| 187 | out: | ||
| 188 | return ret; | ||
| 128 | } | 189 | } |
| 129 | 190 | ||
| 130 | static void dummy_remove(struct platform_device *pdev) | 191 | static void dummy_remove(struct platform_device *pdev) |
| @@ -132,6 +193,8 @@ static void dummy_remove(struct platform_device *pdev) · 1 unmodified line | |||
| 132 | struct dummy_drvdata *drvdata = platform_get_drvdata(pdev); | 193 | struct dummy_drvdata *drvdata = platform_get_drvdata(pdev); |
| 133 | struct device *dev = &pdev->dev; | 194 | struct device *dev = &pdev->dev; |
| 134 | 195 | ||
| 196 | if (IS_VALID_CS_TRACE_ID(drvdata->traceid)) | ||
| 197 | coresight_trace_id_put_system_id(drvdata->traceid); | ||
| 135 | pm_runtime_disable(dev); | 198 | pm_runtime_disable(dev); |
| 136 | coresight_unregister(drvdata->csdev); | 199 | coresight_unregister(drvdata->csdev); |
| 137 | } | 200 | } |
| @@ -86,14 +86,14 @@ static int funnel_enable(struct coresight_device *csdev, · 85 unmodified lines | |||
| 86 | bool first_enable = false; | 86 | bool first_enable = false; |
| 87 | 87 | ||
| 88 | spin_lock_irqsave(&drvdata->spinlock, flags); | 88 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 89 | if (atomic_read(&in->dest_refcnt) == 0) { | 89 | if (in->dest_refcnt == 0) { |
| 90 | if (drvdata->base) | 90 | if (drvdata->base) |
| 91 | rc = dynamic_funnel_enable_hw(drvdata, in->dest_port); | 91 | rc = dynamic_funnel_enable_hw(drvdata, in->dest_port); |
| 92 | if (!rc) | 92 | if (!rc) |
| 93 | first_enable = true; | 93 | first_enable = true; |
| 94 | } | 94 | } |
| 95 | if (!rc) | 95 | if (!rc) |
| 96 | atomic_inc(&in->dest_refcnt); | 96 | in->dest_refcnt++; |
| 97 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 97 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 98 | 98 | ||
| 99 | if (first_enable) | 99 | if (first_enable) |
| @@ -130,7 +130,7 @@ static void funnel_disable(struct coresight_device *csdev, · 30 unmodified lines | |||
| 130 | bool last_disable = false; | 130 | bool last_disable = false; |
| 131 | 131 | ||
| 132 | spin_lock_irqsave(&drvdata->spinlock, flags); | 132 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 133 | if (atomic_dec_return(&in->dest_refcnt) == 0) { | 133 | if (--in->dest_refcnt == 0) { |
| 134 | if (drvdata->base) | 134 | if (drvdata->base) |
| 135 | dynamic_funnel_disable_hw(drvdata, in->dest_port); | 135 | dynamic_funnel_disable_hw(drvdata, in->dest_port); |
| 136 | last_disable = true; | 136 | last_disable = true; |
| @@ -243,6 +243,27 @@ static int of_coresight_parse_endpoint(struct device *dev, · 242 unmodified lines | |||
| 243 | conn.dest_fwnode = fwnode_handle_get(rdev_fwnode); | 243 | conn.dest_fwnode = fwnode_handle_get(rdev_fwnode); |
| 244 | conn.dest_port = rendpoint.port; | 244 | conn.dest_port = rendpoint.port; |
| 245 | 245 | ||
| 246 | /* | ||
| 247 | * Get the firmware node of the filter source through the | ||
| 248 | * reference. This could be used to filter the source in | ||
| 249 | * building path. | ||
| 250 | */ | ||
| 251 | conn.filter_src_fwnode = | ||
| 252 | fwnode_find_reference(&ep->fwnode, "filter-source", 0); | ||
| 253 | if (IS_ERR(conn.filter_src_fwnode)) { | ||
| 254 | conn.filter_src_fwnode = NULL; | ||
| 255 | } else { | ||
| 256 | conn.filter_src_dev = | ||
| 257 | coresight_find_csdev_by_fwnode(conn.filter_src_fwnode); | ||
| 258 | if (conn.filter_src_dev && | ||
| 259 | !coresight_is_device_source(conn.filter_src_dev)) { | ||
| 260 | dev_warn(dev, "port %d: Filter handle is not a trace source : %s\n", | ||
| 261 | conn.src_port, dev_name(&conn.filter_src_dev->dev)); | ||
| 262 | conn.filter_src_dev = NULL; | ||
| 263 | conn.filter_src_fwnode = NULL; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 246 | new_conn = coresight_add_out_conn(dev, pdata, &conn); | 267 | new_conn = coresight_add_out_conn(dev, pdata, &conn); |
| 247 | if (IS_ERR_VALUE(new_conn)) { | 268 | if (IS_ERR_VALUE(new_conn)) { |
| 248 | fwnode_handle_put(conn.dest_fwnode); | 269 | fwnode_handle_put(conn.dest_fwnode); |
| @@ -796,6 +817,12 @@ int coresight_get_cpu(struct device *dev) · 547 unmodified lines | |||
| 796 | } | 817 | } |
| 797 | EXPORT_SYMBOL_GPL(coresight_get_cpu); | 818 | EXPORT_SYMBOL_GPL(coresight_get_cpu); |
| 798 | 819 | ||
| 820 | int coresight_get_static_trace_id(struct device *dev, u32 *id) | ||
| 821 | { | ||
| 822 | return fwnode_property_read_u32(dev_fwnode(dev), "arm,static-trace-id", id); | ||
| 823 | } | ||
| 824 | EXPORT_SYMBOL_GPL(coresight_get_static_trace_id); | ||
| 825 | |||
| 799 | struct coresight_platform_data * | 826 | struct coresight_platform_data * |
| 800 | coresight_get_platform_data(struct device *dev) | 827 | coresight_get_platform_data(struct device *dev) |
| 801 | { | 828 | { |
| @@ -126,7 +126,7 @@ static int replicator_enable(struct coresight_device *csdev, · 125 unmodified lines | |||
| 126 | bool first_enable = false; | 126 | bool first_enable = false; |
| 127 | 127 | ||
| 128 | spin_lock_irqsave(&drvdata->spinlock, flags); | 128 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 129 | if (atomic_read(&out->src_refcnt) == 0) { | 129 | if (out->src_refcnt == 0) { |
| 130 | if (drvdata->base) | 130 | if (drvdata->base) |
| 131 | rc = dynamic_replicator_enable(drvdata, in->dest_port, | 131 | rc = dynamic_replicator_enable(drvdata, in->dest_port, |
| 132 | out->src_port); | 132 | out->src_port); |
| @@ -134,7 +134,7 @@ static int replicator_enable(struct coresight_device *csdev, · 1 unmodified line | |||
| 134 | first_enable = true; | 134 | first_enable = true; |
| 135 | } | 135 | } |
| 136 | if (!rc) | 136 | if (!rc) |
| 137 | atomic_inc(&out->src_refcnt); | 137 | out->src_refcnt++; |
| 138 | spin_unlock_irqrestore(&drvdata->spinlock, flags); | 138 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
| 139 | 139 | ||
| 140 | if (first_enable) | 140 | if (first_enable) |
| @@ -180,7 +180,7 @@ static void replicator_disable(struct coresight_device *csdev, · 39 unmodified lines | |||
| 180 | bool last_disable = false; | 180 | bool last_disable = false; |
| 181 | 181 | ||
| 182 | spin_lock_irqsave(&drvdata->spinlock, flags); | 182 | spin_lock_irqsave(&drvdata->spinlock, flags); |
| 183 | if (atomic_dec_return(&out->src_refcnt) == 0) { | 183 | if (--out->src_refcnt == 0) { |
| 184 | if (drvdata->base) | 184 | if (drvdata->base) |
| 185 | dynamic_replicator_disable(drvdata, in->dest_port, | 185 | dynamic_replicator_disable(drvdata, in->dest_port, |
| 186 | out->src_port); | 186 | out->src_port); |
| @@ -24,7 +24,7 @@ DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | static bool coresight_device_is_tpdm(struct coresight_device *csdev) | 25 | static bool coresight_device_is_tpdm(struct coresight_device *csdev) |
| 26 | { | 26 | { |
| 27 | return (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) && | 27 | return (coresight_is_device_source(csdev)) && |
| 28 | (csdev->subtype.source_subtype == | 28 | (csdev->subtype.source_subtype == |
| 29 | CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); | 29 | CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); |
| 30 | } | 30 | } |
| @@ -110,6 +110,16 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata, · 79 unmodified lines | |||
| 110 | csdev->pdata->in_conns[i]->dest_port != inport) | 110 | csdev->pdata->in_conns[i]->dest_port != inport) |
| 111 | continue; | 111 | continue; |
| 112 | 112 | ||
| 113 | /* | ||
| 114 | * If this port has a hardcoded filter, use the source | ||
| 115 | * device directly. | ||
| 116 | */ | ||
| 117 | if (csdev->pdata->in_conns[i]->filter_src_fwnode) { | ||
| 118 | in = csdev->pdata->in_conns[i]->filter_src_dev; | ||
| 119 | if (!in) | ||
| 120 | continue; | ||
| 121 | } | ||
| 122 | |||
| 113 | if (coresight_device_is_tpdm(in)) { | 123 | if (coresight_device_is_tpdm(in)) { |
| 114 | if (drvdata->dsb_esize || drvdata->cmb_esize) | 124 | if (drvdata->dsb_esize || drvdata->cmb_esize) |
| 115 | return -EEXIST; | 125 | return -EEXIST; |
| @@ -124,7 +134,6 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata, · 8 unmodified lines | |||
| 124 | } | 134 | } |
| 125 | } | 135 | } |
| 126 | 136 | ||
| 127 | |||
| 128 | return rc; | 137 | return rc; |
| 129 | } | 138 | } |
| 130 | 139 | ||
| @@ -190,10 +199,10 @@ static int tpda_enable(struct coresight_device *csdev, · 59 unmodified lines | |||
| 190 | int ret = 0; | 199 | int ret = 0; |
| 191 | 200 | ||
| 192 | spin_lock(&drvdata->spinlock); | 201 | spin_lock(&drvdata->spinlock); |
| 193 | if (atomic_read(&in->dest_refcnt) == 0) { | 202 | if (in->dest_refcnt == 0) { |
| 194 | ret = __tpda_enable(drvdata, in->dest_port); | 203 | ret = __tpda_enable(drvdata, in->dest_port); |
| 195 | if (!ret) { | 204 | if (!ret) { |
| 196 | atomic_inc(&in->dest_refcnt); | 205 | in->dest_refcnt++; |
| 197 | csdev->refcnt++; | 206 | csdev->refcnt++; |
| 198 | dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); | 207 | dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); |
| 199 | } | 208 | } |
| @@ -223,7 +232,7 @@ static void tpda_disable(struct coresight_device *csdev, · 23 unmodified lines | |||
| 223 | struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 232 | struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
| 224 | 233 | ||
| 225 | spin_lock(&drvdata->spinlock); | 234 | spin_lock(&drvdata->spinlock); |
| 226 | if (atomic_dec_return(&in->dest_refcnt) == 0) { | 235 | if (--in->dest_refcnt == 0) { |
| 227 | __tpda_disable(drvdata, in->dest_port); | 236 | __tpda_disable(drvdata, in->dest_port); |
| 228 | csdev->refcnt--; | 237 | csdev->refcnt--; |
| 229 | } | 238 | } |
| @@ -640,8 +640,7 @@ static ssize_t dsb_mode_store(struct device *dev, · 639 unmodified lines | |||
| 640 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 640 | struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); |
| 641 | unsigned long val; | 641 | unsigned long val; |
| 642 | 642 | ||
| 643 | if ((kstrtoul(buf, 0, &val)) || (val < 0) || | 643 | if ((kstrtoul(buf, 0, &val)) || (val & ~TPDM_DSB_MODE_MASK)) |
| 644 | (val & ~TPDM_DSB_MODE_MASK)) | ||
| 645 | return -EINVAL; | 644 | return -EINVAL; |
| 646 | 645 | ||
| 647 | spin_lock(&drvdata->spinlock); | 646 | spin_lock(&drvdata->spinlock); |
| @@ -1308,8 +1307,8 @@ static void tpdm_remove(struct amba_device *adev) · 660 unmodified lines | |||
| 1308 | */ | 1307 | */ |
| 1309 | static struct amba_id tpdm_ids[] = { | 1308 | static struct amba_id tpdm_ids[] = { |
| 1310 | { | 1309 | { |
| 1311 | .id = 0x000f0e00, | 1310 | .id = 0x001f0e00, |
| 1312 | .mask = 0x000fff00, | 1311 | .mask = 0x00ffff00, |
| 1313 | }, | 1312 | }, |
| 1314 | { 0, 0, NULL }, | 1313 | { 0, 0, NULL }, |
| 1315 | }; | 1314 | }; |
| @@ -12,6 +12,12 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | #include "coresight-trace-id.h" | 13 | #include "coresight-trace-id.h" |
| 14 | 14 | ||
| 15 | enum trace_id_flags { | ||
| 16 | TRACE_ID_ANY = 0x0, | ||
| 17 | TRACE_ID_PREFER_ODD = 0x1, | ||
| 18 | TRACE_ID_REQ_STATIC = 0x2, | ||
| 19 | }; | ||
| 20 | |||
| 15 | /* Default trace ID map. Used in sysfs mode and for system sources */ | 21 | /* Default trace ID map. Used in sysfs mode and for system sources */ |
| 16 | static DEFINE_PER_CPU(atomic_t, id_map_default_cpu_ids) = ATOMIC_INIT(0); | 22 | static DEFINE_PER_CPU(atomic_t, id_map_default_cpu_ids) = ATOMIC_INIT(0); |
| 17 | static struct coresight_trace_id_map id_map_default = { | 23 | static struct coresight_trace_id_map id_map_default = { |
| @@ -74,21 +80,25 @@ static int coresight_trace_id_find_odd_id(struct coresight_trace_id_map *id_map) · 56 unmodified lines | |||
| 74 | * Otherwise allocate next available ID. | 80 | * Otherwise allocate next available ID. |
| 75 | */ | 81 | */ |
| 76 | static int coresight_trace_id_alloc_new_id(struct coresight_trace_id_map *id_map, | 82 | static int coresight_trace_id_alloc_new_id(struct coresight_trace_id_map *id_map, |
| 77 | int preferred_id, bool prefer_odd_id) | 83 | int preferred_id, unsigned int flags) |
| 78 | { | 84 | { |
| 79 | int id = 0; | 85 | int id = 0; |
| 80 | 86 | ||
| 81 | /* for backwards compatibility, cpu IDs may use preferred value */ | 87 | /* for backwards compatibility, cpu IDs may use preferred value */ |
| 82 | if (IS_VALID_CS_TRACE_ID(preferred_id) && | 88 | if (IS_VALID_CS_TRACE_ID(preferred_id)) { |
| 83 | !test_bit(preferred_id, id_map->used_ids)) { | 89 | if (!test_bit(preferred_id, id_map->used_ids)) { |
| 84 | id = preferred_id; | 90 | id = preferred_id; |
| 85 | goto trace_id_allocated; | 91 | goto trace_id_allocated; |
| 86 | } else if (prefer_odd_id) { | 92 | } else if (flags & TRACE_ID_REQ_STATIC) |
| 93 | return -EBUSY; | ||
| 94 | } else if (flags & TRACE_ID_PREFER_ODD) { | ||
| 87 | /* may use odd ids to avoid preferred legacy cpu IDs */ | 95 | /* may use odd ids to avoid preferred legacy cpu IDs */ |
| 88 | id = coresight_trace_id_find_odd_id(id_map); | 96 | id = coresight_trace_id_find_odd_id(id_map); |
| 89 | if (id) | 97 | if (id) |
| 90 | goto trace_id_allocated; | 98 | goto trace_id_allocated; |
| 91 | } | 99 | } else if (!IS_VALID_CS_TRACE_ID(preferred_id) && |
| 100 | (flags & TRACE_ID_REQ_STATIC)) | ||
| 101 | return -EINVAL; | ||
| 92 | 102 | ||
| 93 | /* | 103 | /* |
| 94 | * skip reserved bit 0, look at bitmap length of | 104 | * skip reserved bit 0, look at bitmap length of |
| @@ -153,7 +163,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map · 58 unmodified lines | |||
| 153 | */ | 163 | */ |
| 154 | id = coresight_trace_id_alloc_new_id(id_map, | 164 | id = coresight_trace_id_alloc_new_id(id_map, |
| 155 | CORESIGHT_LEGACY_CPU_TRACE_ID(cpu), | 165 | CORESIGHT_LEGACY_CPU_TRACE_ID(cpu), |
| 156 | false); | 166 | TRACE_ID_ANY); |
| 157 | if (!IS_VALID_CS_TRACE_ID(id)) | 167 | if (!IS_VALID_CS_TRACE_ID(id)) |
| 158 | goto get_cpu_id_out_unlock; | 168 | goto get_cpu_id_out_unlock; |
| 159 | 169 | ||
| @@ -188,14 +198,14 @@ static void _coresight_trace_id_put_cpu_id(int cpu, struct coresight_trace_id_ma · 28 unmodified lines | |||
| 188 | DUMP_ID_MAP(id_map); | 198 | DUMP_ID_MAP(id_map); |
| 189 | } | 199 | } |
| 190 | 200 | ||
| 191 | static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *id_map) | 201 | static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *id_map, |
| 202 | int preferred_id, unsigned int traceid_flags) | ||
| 192 | { | 203 | { |
| 193 | unsigned long flags; | 204 | unsigned long flags; |
| 194 | int id; | 205 | int id; |
| 195 | 206 | ||
| 196 | spin_lock_irqsave(&id_map->lock, flags); | 207 | spin_lock_irqsave(&id_map->lock, flags); |
| 197 | /* prefer odd IDs for system components to avoid legacy CPU IDS */ | 208 | id = coresight_trace_id_alloc_new_id(id_map, preferred_id, traceid_flags); |
| 198 | id = coresight_trace_id_alloc_new_id(id_map, 0, true); | ||
| 199 | spin_unlock_irqrestore(&id_map->lock, flags); | 209 | spin_unlock_irqrestore(&id_map->lock, flags); |
| 200 | 210 | ||
| 201 | DUMP_ID(id); | 211 | DUMP_ID(id); |
| @@ -255,10 +265,19 @@ EXPORT_SYMBOL_GPL(coresight_trace_id_read_cpu_id_map); · 53 unmodified lines | |||
| 255 | 265 | ||
| 256 | int coresight_trace_id_get_system_id(void) | 266 | int coresight_trace_id_get_system_id(void) |
| 257 | { | 267 | { |
| 258 | return coresight_trace_id_map_get_system_id(&id_map_default); | 268 | /* prefer odd IDs for system components to avoid legacy CPU IDS */ |
| 269 | return coresight_trace_id_map_get_system_id(&id_map_default, 0, | ||
| 270 | TRACE_ID_PREFER_ODD); | ||
| 259 | } | 271 | } |
| 260 | EXPORT_SYMBOL_GPL(coresight_trace_id_get_system_id); | 272 | EXPORT_SYMBOL_GPL(coresight_trace_id_get_system_id); |
| 261 | 273 | ||
| 274 | int coresight_trace_id_get_static_system_id(int trace_id) | ||
| 275 | { | ||
| 276 | return coresight_trace_id_map_get_system_id(&id_map_default, | ||
| 277 | trace_id, TRACE_ID_REQ_STATIC); | ||
| 278 | } | ||
| 279 | EXPORT_SYMBOL_GPL(coresight_trace_id_get_static_system_id); | ||
| 280 | |||
| 262 | void coresight_trace_id_put_system_id(int id) | 281 | void coresight_trace_id_put_system_id(int id) |
| 263 | { | 282 | { |
| 264 | coresight_trace_id_map_put_system_id(&id_map_default, id); | 283 | coresight_trace_id_map_put_system_id(&id_map_default, id); |
| @@ -116,6 +116,15 @@ int coresight_trace_id_read_cpu_id_map(int cpu, struct coresight_trace_id_map *i · 115 unmodified lines | |||
| 116 | */ | 116 | */ |
| 117 | int coresight_trace_id_get_system_id(void); | 117 | int coresight_trace_id_get_system_id(void); |
| 118 | 118 | ||
| 119 | /** | ||
| 120 | * Allocate a CoreSight static trace ID for a system component. | ||
| 121 | * | ||
| 122 | * Used to allocate static IDs for system trace sources such as dummy source. | ||
| 123 | * | ||
| 124 | * return: Trace ID or -EINVAL if allocation is impossible. | ||
| 125 | */ | ||
| 126 | int coresight_trace_id_get_static_system_id(int id); | ||
| 127 | |||
| 119 | /** | 128 | /** |
| 120 | * Release an allocated system trace ID. | 129 | * Release an allocated system trace ID. |
| 121 | * | 130 | * |
| @@ -857,8 +857,9 @@ static irqreturn_t intel_th_irq(int irq, void *data) · 856 unmodified lines | |||
| 857 | /** | 857 | /** |
| 858 | * intel_th_alloc() - allocate a new Intel TH device and its subdevices | 858 | * intel_th_alloc() - allocate a new Intel TH device and its subdevices |
| 859 | * @dev: parent device | 859 | * @dev: parent device |
| 860 | * @drvdata: data private to the driver | ||
| 860 | * @devres: resources indexed by th_mmio_idx | 861 | * @devres: resources indexed by th_mmio_idx |
| 861 | * @irq: irq number | 862 | * @ndevres: number of entries in the @devres resources |
| 862 | */ | 863 | */ |
| 863 | struct intel_th * | 864 | struct intel_th * |
| 864 | intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, | 865 | intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, |
| @@ -9,37 +9,93 @@ · 8 unmodified lines | |||
| 9 | #define _ADXL345_H_ | 9 | #define _ADXL345_H_ |
| 10 | 10 | ||
| 11 | #define ADXL345_REG_DEVID 0x00 | 11 | #define ADXL345_REG_DEVID 0x00 |
| 12 | #define ADXL345_REG_THRESH_TAP 0x1D | ||
| 12 | #define ADXL345_REG_OFSX 0x1E | 13 | #define ADXL345_REG_OFSX 0x1E |
| 13 | #define ADXL345_REG_OFSY 0x1F | 14 | #define ADXL345_REG_OFSY 0x1F |
| 14 | #define ADXL345_REG_OFSZ 0x20 | 15 | #define ADXL345_REG_OFSZ 0x20 |
| 15 | #define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) | 16 | #define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) |
| 17 | |||
| 18 | /* Tap duration */ | ||
| 19 | #define ADXL345_REG_DUR 0x21 | ||
| 20 | /* Tap latency */ | ||
| 21 | #define ADXL345_REG_LATENT 0x22 | ||
| 22 | /* Tap window */ | ||
| 23 | #define ADXL345_REG_WINDOW 0x23 | ||
| 24 | /* Activity threshold */ | ||
| 25 | #define ADXL345_REG_THRESH_ACT 0x24 | ||
| 26 | /* Inactivity threshold */ | ||
| 27 | #define ADXL345_REG_THRESH_INACT 0x25 | ||
| 28 | /* Inactivity time */ | ||
| 29 | #define ADXL345_REG_TIME_INACT 0x26 | ||
| 30 | /* Axis enable control for activity and inactivity detection */ | ||
| 31 | #define ADXL345_REG_ACT_INACT_CTRL 0x27 | ||
| 32 | /* Free-fall threshold */ | ||
| 33 | #define ADXL345_REG_THRESH_FF 0x28 | ||
| 34 | /* Free-fall time */ | ||
| 35 | #define ADXL345_REG_TIME_FF 0x29 | ||
| 36 | /* Axis control for single tap or double tap */ | ||
| 37 | #define ADXL345_REG_TAP_AXIS 0x2A | ||
| 38 | /* Source of single tap or double tap */ | ||
| 39 | #define ADXL345_REG_ACT_TAP_STATUS 0x2B | ||
| 40 | /* Data rate and power mode control */ | ||
| 16 | #define ADXL345_REG_BW_RATE 0x2C | 41 | #define ADXL345_REG_BW_RATE 0x2C |
| 17 | #define ADXL345_REG_POWER_CTL 0x2D | 42 | #define ADXL345_REG_POWER_CTL 0x2D |
| 43 | #define ADXL345_REG_INT_ENABLE 0x2E | ||
| 44 | #define ADXL345_REG_INT_MAP 0x2F | ||
| 45 | #define ADXL345_REG_INT_SOURCE 0x30 | ||
| 46 | #define ADXL345_REG_INT_SOURCE_MSK 0xFF | ||
| 18 | #define ADXL345_REG_DATA_FORMAT 0x31 | 47 | #define ADXL345_REG_DATA_FORMAT 0x31 |
| 19 | #define ADXL345_REG_DATAX0 0x32 | 48 | #define ADXL345_REG_XYZ_BASE 0x32 |
| 20 | #define ADXL345_REG_DATAY0 0x34 | 49 | #define ADXL345_REG_DATA_AXIS(index) \ |
| 21 | #define ADXL345_REG_DATAZ0 0x36 | 50 | (ADXL345_REG_XYZ_BASE + (index) * sizeof(__le16)) |
| 22 | #define ADXL345_REG_DATA_AXIS(index) \ | 51 | |
| 23 | (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) | 52 | #define ADXL345_REG_FIFO_CTL 0x38 |
| 53 | #define ADXL345_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0) | ||
| 54 | /* 0: INT1, 1: INT2 */ | ||
| 55 | #define ADXL345_FIFO_CTL_TRIGGER_MSK BIT(5) | ||
| 56 | #define ADXL345_FIFO_CTL_MODE_MSK GENMASK(7, 6) | ||
| 57 | #define ADXL345_REG_FIFO_STATUS 0x39 | ||
| 58 | #define ADXL345_REG_FIFO_STATUS_MSK 0x3F | ||
| 24 | 59 | ||
| 60 | #define ADXL345_INT_OVERRUN BIT(0) | ||
| 61 | #define ADXL345_INT_WATERMARK BIT(1) | ||
| 62 | #define ADXL345_INT_FREE_FALL BIT(2) | ||
| 63 | #define ADXL345_INT_INACTIVITY BIT(3) | ||
| 64 | #define ADXL345_INT_ACTIVITY BIT(4) | ||
| 65 | #define ADXL345_INT_DOUBLE_TAP BIT(5) | ||
| 66 | #define ADXL345_INT_SINGLE_TAP BIT(6) | ||
| 67 | #define ADXL345_INT_DATA_READY BIT(7) | ||
| 68 | |||
| 69 | /* | ||
| 70 | * BW_RATE bits - Bandwidth and output data rate. The default value is | ||
| 71 | * 0x0A, which translates to a 100 Hz output data rate | ||
| 72 | */ | ||
| 25 | #define ADXL345_BW_RATE GENMASK(3, 0) | 73 | #define ADXL345_BW_RATE GENMASK(3, 0) |
| 74 | #define ADXL345_BW_LOW_POWER BIT(4) | ||
| 26 | #define ADXL345_BASE_RATE_NANO_HZ 97656250LL | 75 | #define ADXL345_BASE_RATE_NANO_HZ 97656250LL |
| 27 | 76 | ||
| 28 | #define ADXL345_POWER_CTL_MEASURE BIT(3) | ||
| 29 | #define ADXL345_POWER_CTL_STANDBY 0x00 | 77 | #define ADXL345_POWER_CTL_STANDBY 0x00 |
| 78 | #define ADXL345_POWER_CTL_WAKEUP GENMASK(1, 0) | ||
| 79 | #define ADXL345_POWER_CTL_SLEEP BIT(2) | ||
| 80 | #define ADXL345_POWER_CTL_MEASURE BIT(3) | ||
| 81 | #define ADXL345_POWER_CTL_AUTO_SLEEP BIT(4) | ||
| 82 | #define ADXL345_POWER_CTL_LINK BIT(5) | ||
| 30 | 83 | ||
| 31 | #define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */ | 84 | /* Set the g range */ |
| 32 | #define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */ | 85 | #define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) |
| 33 | #define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ | 86 | /* Data is left justified */ |
| 34 | #define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6) /* 3-wire SPI mode */ | 87 | #define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) |
| 35 | #define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */ | 88 | /* Up to 13-bits resolution */ |
| 36 | 89 | #define ADXL345_DATA_FORMAT_FULL_RES BIT(3) | |
| 90 | #define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6) | ||
| 91 | #define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) | ||
| 37 | #define ADXL345_DATA_FORMAT_2G 0 | 92 | #define ADXL345_DATA_FORMAT_2G 0 |
| 38 | #define ADXL345_DATA_FORMAT_4G 1 | 93 | #define ADXL345_DATA_FORMAT_4G 1 |
| 39 | #define ADXL345_DATA_FORMAT_8G 2 | 94 | #define ADXL345_DATA_FORMAT_8G 2 |
| 40 | #define ADXL345_DATA_FORMAT_16G 3 | 95 | #define ADXL345_DATA_FORMAT_16G 3 |
| 41 | 96 | ||
| 42 | #define ADXL345_DEVID 0xE5 | 97 | #define ADXL345_DEVID 0xE5 |
| 98 | #define ADXL345_FIFO_SIZE 32 | ||
| 43 | 99 | ||
| 44 | /* | 100 | /* |
| 45 | * In full-resolution mode, scale factor is maintained at ~4 mg/LSB | 101 | * In full-resolution mode, scale factor is maintained at ~4 mg/LSB |
| @@ -62,6 +118,7 @@ struct adxl345_chip_info { · 16 unmodified lines | |||
| 62 | }; | 118 | }; |
| 63 | 119 | ||
| 64 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, | 120 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, |
| 121 | bool fifo_delay_default, | ||
| 65 | int (*setup)(struct device*, struct regmap*)); | 122 | int (*setup)(struct device*, struct regmap*)); |
| 66 | 123 | ||
| 67 | #endif /* _ADXL345_H_ */ | 124 | #endif /* _ADXL345_H_ */ |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf | 7 | * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/bitfield.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 11 | #include <linux/property.h> | 13 | #include <linux/property.h> |
| 12 | #include <linux/regmap.h> | 14 | #include <linux/regmap.h> |
| @@ -14,36 +16,92 @@ · 1 unmodified line | |||
| 14 | 16 | ||
| 15 | #include <linux/iio/iio.h> | 17 | #include <linux/iio/iio.h> |
| 16 | #include <linux/iio/sysfs.h> | 18 | #include <linux/iio/sysfs.h> |
| 19 | #include <linux/iio/buffer.h> | ||
| 20 | #include <linux/iio/kfifo_buf.h> | ||
| 17 | 21 | ||
| 18 | #include "adxl345.h" | 22 | #include "adxl345.h" |
| 19 | 23 | ||
| 20 | struct adxl345_data { | 24 | #define ADXL345_FIFO_BYPASS 0 |
| 25 | #define ADXL345_FIFO_FIFO 1 | ||
| 26 | #define ADXL345_FIFO_STREAM 2 | ||
| 27 | |||
| 28 | #define ADXL345_DIRS 3 | ||
| 29 | |||
| 30 | #define ADXL345_INT_NONE 0xff | ||
| 31 | #define ADXL345_INT1 0 | ||
| 32 | #define ADXL345_INT2 1 | ||
| 33 | |||
| 34 | struct adxl345_state { | ||
| 21 | const struct adxl345_chip_info *info; | 35 | const struct adxl345_chip_info *info; |
| 22 | struct regmap *regmap; | 36 | struct regmap *regmap; |
| 37 | bool fifo_delay; /* delay: delay is needed for SPI */ | ||
| 38 | int irq; | ||
| 39 | u8 intio; | ||
| 40 | u8 int_map; | ||
| 41 | u8 watermark; | ||
| 42 | u8 fifo_mode; | ||
| 43 | __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN); | ||
| 23 | }; | 44 | }; |
| 24 | 45 | ||
| 25 | #define ADXL345_CHANNEL(index, axis) { \ | 46 | #define ADXL345_CHANNEL(index, reg, axis) { \ |
| 26 | .type = IIO_ACCEL, \ | 47 | .type = IIO_ACCEL, \ |
| 27 | .modified = 1, \ | 48 | .modified = 1, \ |
| 28 | .channel2 = IIO_MOD_##axis, \ | 49 | .channel2 = IIO_MOD_##axis, \ |
| 29 | .address = index, \ | 50 | .address = (reg), \ |
| 30 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | 51 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
| 31 | BIT(IIO_CHAN_INFO_CALIBBIAS), \ | 52 | BIT(IIO_CHAN_INFO_CALIBBIAS), \ |
| 32 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | 53 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
| 33 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | 54 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
| 55 | .scan_index = (index), \ | ||
| 56 | .scan_type = { \ | ||
| 57 | .sign = 's', \ | ||
| 58 | .realbits = 13, \ | ||
| 59 | .storagebits = 16, \ | ||
| 60 | .endianness = IIO_LE, \ | ||
| 61 | }, \ | ||
| 34 | } | 62 | } |
| 35 | 63 | ||
| 64 | enum adxl345_chans { | ||
| 65 | chan_x, chan_y, chan_z, | ||
| 66 | }; | ||
| 67 | |||
| 36 | static const struct iio_chan_spec adxl345_channels[] = { | 68 | static const struct iio_chan_spec adxl345_channels[] = { |
| 37 | ADXL345_CHANNEL(0, X), | 69 | ADXL345_CHANNEL(0, chan_x, X), |
| 38 | ADXL345_CHANNEL(1, Y), | 70 | ADXL345_CHANNEL(1, chan_y, Y), |
| 39 | ADXL345_CHANNEL(2, Z), | 71 | ADXL345_CHANNEL(2, chan_z, Z), |
| 40 | }; | 72 | }; |
| 41 | 73 | ||
| 74 | static const unsigned long adxl345_scan_masks[] = { | ||
| 75 | BIT(chan_x) | BIT(chan_y) | BIT(chan_z), | ||
| 76 | 0 | ||
| 77 | }; | ||
| 78 | |||
| 79 | static int adxl345_set_interrupts(struct adxl345_state *st) | ||
| 80 | { | ||
| 81 | int ret; | ||
| 82 | unsigned int int_enable = st->int_map; | ||
| 83 | unsigned int int_map; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Any bits set to 0 in the INT map register send their respective | ||
| 87 | * interrupts to the INT1 pin, whereas bits set to 1 send their respective | ||
| 88 | * interrupts to the INT2 pin. The intio shall convert this accordingly. | ||
| 89 | */ | ||
| 90 | int_map = FIELD_GET(ADXL345_REG_INT_SOURCE_MSK, | ||
| 91 | st->intio ? st->int_map : ~st->int_map); | ||
| 92 | |||
| 93 | ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, int_map); | ||
| 94 | if (ret) | ||
| 95 | return ret; | ||
| 96 | |||
| 97 | return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, int_enable); | ||
| 98 | } | ||
| 99 | |||
| 42 | static int adxl345_read_raw(struct iio_dev *indio_dev, | 100 | static int adxl345_read_raw(struct iio_dev *indio_dev, |
| 43 | struct iio_chan_spec const *chan, | 101 | struct iio_chan_spec const *chan, |
| 44 | int *val, int *val2, long mask) | 102 | int *val, int *val2, long mask) |
| 45 | { | 103 | { |
| 46 | struct adxl345_data *data = iio_priv(indio_dev); | 104 | struct adxl345_state *st = iio_priv(indio_dev); |
| 47 | __le16 accel; | 105 | __le16 accel; |
| 48 | long long samp_freq_nhz; | 106 | long long samp_freq_nhz; |
| 49 | unsigned int regval; | 107 | unsigned int regval; |
| @@ -56,7 +114,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 56 | * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte | 114 | * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte |
| 57 | * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte | 115 | * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte |
| 58 | */ | 116 | */ |
| 59 | ret = regmap_bulk_read(data->regmap, | 117 | ret = regmap_bulk_read(st->regmap, |
| 60 | ADXL345_REG_DATA_AXIS(chan->address), | 118 | ADXL345_REG_DATA_AXIS(chan->address), |
| 61 | &accel, sizeof(accel)); | 119 | &accel, sizeof(accel)); |
| 62 | if (ret < 0) | 120 | if (ret < 0) |
| @@ -66,10 +124,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 66 | return IIO_VAL_INT; | 124 | return IIO_VAL_INT; |
| 67 | case IIO_CHAN_INFO_SCALE: | 125 | case IIO_CHAN_INFO_SCALE: |
| 68 | *val = 0; | 126 | *val = 0; |
| 69 | *val2 = data->info->uscale; | 127 | *val2 = st->info->uscale; |
| 70 | return IIO_VAL_INT_PLUS_MICRO; | 128 | return IIO_VAL_INT_PLUS_MICRO; |
| 71 | case IIO_CHAN_INFO_CALIBBIAS: | 129 | case IIO_CHAN_INFO_CALIBBIAS: |
| 72 | ret = regmap_read(data->regmap, | 130 | ret = regmap_read(st->regmap, |
| 73 | ADXL345_REG_OFS_AXIS(chan->address), ®val); | 131 | ADXL345_REG_OFS_AXIS(chan->address), ®val); |
| 74 | if (ret < 0) | 132 | if (ret < 0) |
| 75 | return ret; | 133 | return ret; |
| @@ -81,7 +139,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, · 5 unmodified lines | |||
| 81 | 139 | ||
| 82 | return IIO_VAL_INT; | 140 | return IIO_VAL_INT; |
| 83 | case IIO_CHAN_INFO_SAMP_FREQ: | 141 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 84 | ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val); | 142 | ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); |
| 85 | if (ret < 0) | 143 | if (ret < 0) |
| 86 | return ret; | 144 | return ret; |
| 87 | 145 | ||
| @@ -99,7 +157,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, · 11 unmodified lines | |||
| 99 | struct iio_chan_spec const *chan, | 157 | struct iio_chan_spec const *chan, |
| 100 | int val, int val2, long mask) | 158 | int val, int val2, long mask) |
| 101 | { | 159 | { |
| 102 | struct adxl345_data *data = iio_priv(indio_dev); | 160 | struct adxl345_state *st = iio_priv(indio_dev); |
| 103 | s64 n; | 161 | s64 n; |
| 104 | 162 | ||
| 105 | switch (mask) { | 163 | switch (mask) { |
| @@ -108,14 +166,14 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 108 | * 8-bit resolution at +/- 2g, that is 4x accel data scale | 166 | * 8-bit resolution at +/- 2g, that is 4x accel data scale |
| 109 | * factor | 167 | * factor |
| 110 | */ | 168 | */ |
| 111 | return regmap_write(data->regmap, | 169 | return regmap_write(st->regmap, |
| 112 | ADXL345_REG_OFS_AXIS(chan->address), | 170 | ADXL345_REG_OFS_AXIS(chan->address), |
| 113 | val / 4); | 171 | val / 4); |
| 114 | case IIO_CHAN_INFO_SAMP_FREQ: | 172 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 115 | n = div_s64(val * NANOHZ_PER_HZ + val2, | 173 | n = div_s64(val * NANOHZ_PER_HZ + val2, |
| 116 | ADXL345_BASE_RATE_NANO_HZ); | 174 | ADXL345_BASE_RATE_NANO_HZ); |
| 117 | 175 | ||
| 118 | return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE, | 176 | return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, |
| 119 | ADXL345_BW_RATE, | 177 | ADXL345_BW_RATE, |
| 120 | clamp_val(ilog2(n), 0, | 178 | clamp_val(ilog2(n), 0, |
| 121 | ADXL345_BW_RATE)); | 179 | ADXL345_BW_RATE)); |
| @@ -124,6 +182,24 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 124 | return -EINVAL; | 182 | return -EINVAL; |
| 125 | } | 183 | } |
| 126 | 184 | ||
| 185 | static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value) | ||
| 186 | { | ||
| 187 | struct adxl345_state *st = iio_priv(indio_dev); | ||
| 188 | unsigned int fifo_mask = 0x1F; | ||
| 189 | int ret; | ||
| 190 | |||
| 191 | value = min(value, ADXL345_FIFO_SIZE - 1); | ||
| 192 | |||
| 193 | ret = regmap_update_bits(st->regmap, ADXL345_REG_FIFO_CTL, fifo_mask, value); | ||
| 194 | if (ret) | ||
| 195 | return ret; | ||
| 196 | |||
| 197 | st->watermark = value; | ||
| 198 | st->int_map |= ADXL345_INT_WATERMARK; | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 127 | static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, | 203 | static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, |
| 128 | struct iio_chan_spec const *chan, | 204 | struct iio_chan_spec const *chan, |
| 129 | long mask) | 205 | long mask) |
| @@ -138,6 +214,33 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, · 8 unmodified lines | |||
| 138 | } | 214 | } |
| 139 | } | 215 | } |
| 140 | 216 | ||
| 217 | /** | ||
| 218 | * adxl345_set_measure_en() - Enable and disable measuring. | ||
| 219 | * | ||
| 220 | * @st: The device data. | ||
| 221 | * @en: Enable measurements, else standby mode. | ||
| 222 | * | ||
| 223 | * For lowest power operation, standby mode can be used. In standby mode, | ||
| 224 | * current consumption is supposed to be reduced to 0.1uA (typical). In this | ||
| 225 | * mode no measurements are made. Placing the device into standby mode | ||
| 226 | * preserves the contents of FIFO. | ||
| 227 | * | ||
| 228 | * Return: Returns 0 if successful, or a negative error value. | ||
| 229 | */ | ||
| 230 | static int adxl345_set_measure_en(struct adxl345_state *st, bool en) | ||
| 231 | { | ||
| 232 | unsigned int val = en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_STANDBY; | ||
| 233 | |||
| 234 | return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val); | ||
| 235 | } | ||
| 236 | |||
| 237 | static void adxl345_powerdown(void *ptr) | ||
| 238 | { | ||
| 239 | struct adxl345_state *st = ptr; | ||
| 240 | |||
| 241 | adxl345_set_measure_en(st, false); | ||
| 242 | } | ||
| 243 | |||
| 141 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( | 244 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( |
| 142 | "0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200" | 245 | "0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200" |
| 143 | ); | 246 | ); |
| @@ -151,37 +254,244 @@ static const struct attribute_group adxl345_attrs_group = { · 7 unmodified lines | |||
| 151 | .attrs = adxl345_attrs, | 254 | .attrs = adxl345_attrs, |
| 152 | }; | 255 | }; |
| 153 | 256 | ||
| 154 | static const struct iio_info adxl345_info = { | 257 | static int adxl345_set_fifo(struct adxl345_state *st) |
| 155 | .attrs = &adxl345_attrs_group, | 258 | { |
| 156 | .read_raw = adxl345_read_raw, | 259 | int ret; |
| 157 | .write_raw = adxl345_write_raw, | 260 | |
| 158 | .write_raw_get_fmt = adxl345_write_raw_get_fmt, | 261 | /* FIFO should only be configured while in standby mode */ |
| 262 | ret = adxl345_set_measure_en(st, false); | ||
| 263 | if (ret < 0) | ||
| 264 | return ret; | ||
| 265 | |||
| 266 | ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, | ||
| 267 | FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK, | ||
| 268 | st->watermark) | | ||
| 269 | FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, | ||
| 270 | st->intio) | | ||
| 271 | FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, | ||
| 272 | st->fifo_mode)); | ||
| 273 | if (ret < 0) | ||
| 274 | return ret; | ||
| 275 | |||
| 276 | return adxl345_set_measure_en(st, true); | ||
| 277 | } | ||
| 278 | |||
| 279 | /** | ||
| 280 | * adxl345_get_samples() - Read number of FIFO entries. | ||
| 281 | * @st: The initialized state instance of this driver. | ||
| 282 | * | ||
| 283 | * The sensor does not support treating any axis individually, or exclude them | ||
| 284 | * from measuring. | ||
| 285 | * | ||
| 286 | * Return: negative error, or value. | ||
| 287 | */ | ||
| 288 | static int adxl345_get_samples(struct adxl345_state *st) | ||
| 289 | { | ||
| 290 | unsigned int regval = 0; | ||
| 291 | int ret; | ||
| 292 | |||
| 293 | ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, ®val); | ||
| 294 | if (ret < 0) | ||
| 295 | return ret; | ||
| 296 | |||
| 297 | return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval); | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * adxl345_fifo_transfer() - Read samples number of elements. | ||
| 302 | * @st: The instance of the state object of this sensor. | ||
| 303 | * @samples: The number of lines in the FIFO referred to as fifo_entry. | ||
| 304 | * | ||
| 305 | * It is recommended that a multiple-byte read of all registers be performed to | ||
| 306 | * prevent a change in data between reads of sequential registers. That is to | ||
| 307 | * read out the data registers X0, X1, Y0, Y1, Z0, Z1, i.e. 6 bytes at once. | ||
| 308 | * | ||
| 309 | * Return: 0 or error value. | ||
| 310 | */ | ||
| 311 | static int adxl345_fifo_transfer(struct adxl345_state *st, int samples) | ||
| 312 | { | ||
| 313 | size_t count; | ||
| 314 | int i, ret = 0; | ||
| 315 | |||
| 316 | /* count is the 3x the fifo_buf element size, hence 6B */ | ||
| 317 | count = sizeof(st->fifo_buf[0]) * ADXL345_DIRS; | ||
| 318 | for (i = 0; i < samples; i++) { | ||
| 319 | /* read 3x 2 byte elements from base address into next fifo_buf position */ | ||
| 320 | ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE, | ||
| 321 | st->fifo_buf + (i * count / 2), count); | ||
| 322 | if (ret < 0) | ||
| 323 | return ret; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * To ensure that the FIFO has completely popped, there must be at least 5 | ||
| 327 | * us between the end of reading the data registers, signified by the | ||
| 328 | * transition to register 0x38 from 0x37 or the CS pin going high, and the | ||
| 329 | * start of new reads of the FIFO or reading the FIFO_STATUS register. For | ||
| 330 | * SPI operation at 1.5 MHz or lower, the register addressing portion of the | ||
| 331 | * transmission is sufficient delay to ensure the FIFO has completely | ||
| 332 | * popped. It is necessary for SPI operation greater than 1.5 MHz to | ||
| 333 | * de-assert the CS pin to ensure a total of 5 us, which is at most 3.4 us | ||
| 334 | * at 5 MHz operation. | ||
| 335 | */ | ||
| 336 | if (st->fifo_delay && samples > 1) | ||
| 337 | udelay(3); | ||
| 338 | } | ||
| 339 | return ret; | ||
| 340 | } | ||
| 341 | |||
| 342 | /** | ||
| 343 | * adxl345_fifo_reset() - Empty the FIFO in error condition. | ||
| 344 | * @st: The instance to the state object of the sensor. | ||
| 345 | * | ||
| 346 | * Read all elements of the FIFO. Reading the interrupt source register | ||
| 347 | * resets the sensor. | ||
| 348 | */ | ||
| 349 | static void adxl345_fifo_reset(struct adxl345_state *st) | ||
| 350 | { | ||
| 351 | int regval; | ||
| 352 | int samples; | ||
| 353 | |||
| 354 | adxl345_set_measure_en(st, false); | ||
| 355 | |||
| 356 | samples = adxl345_get_samples(st); | ||
| 357 | if (samples > 0) | ||
| 358 | adxl345_fifo_transfer(st, samples); | ||
| 359 | |||
| 360 | regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val); | ||
| 361 | |||
| 362 | adxl345_set_measure_en(st, true); | ||
| 363 | } | ||
| 364 | |||
| 365 | static int adxl345_buffer_postenable(struct iio_dev *indio_dev) | ||
| 366 | { | ||
| 367 | struct adxl345_state *st = iio_priv(indio_dev); | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | ret = adxl345_set_interrupts(st); | ||
| 371 | if (ret < 0) | ||
| 372 | return ret; | ||
| 373 | |||
| 374 | st->fifo_mode = ADXL345_FIFO_STREAM; | ||
| 375 | return adxl345_set_fifo(st); | ||
| 376 | } | ||
| 377 | |||
| 378 | static int adxl345_buffer_predisable(struct iio_dev *indio_dev) | ||
| 379 | { | ||
| 380 | struct adxl345_state *st = iio_priv(indio_dev); | ||
| 381 | int ret; | ||
| 382 | |||
| 383 | st->fifo_mode = ADXL345_FIFO_BYPASS; | ||
| 384 | ret = adxl345_set_fifo(st); | ||
| 385 | if (ret < 0) | ||
| 386 | return ret; | ||
| 387 | |||
| 388 | st->int_map = 0x00; | ||
| 389 | return adxl345_set_interrupts(st); | ||
| 390 | } | ||
| 391 | |||
| 392 | static const struct iio_buffer_setup_ops adxl345_buffer_ops = { | ||
| 393 | .postenable = adxl345_buffer_postenable, | ||
| 394 | .predisable = adxl345_buffer_predisable, | ||
| 159 | }; | 395 | }; |
| 160 | 396 | ||
| 161 | static int adxl345_powerup(void *regmap) | 397 | static int adxl345_get_status(struct adxl345_state *st) |
| 162 | { | 398 | { |
| 163 | return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE); | 399 | int ret; |
| 400 | unsigned int regval; | ||
| 401 | |||
| 402 | ret = regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val); | ||
| 403 | if (ret < 0) | ||
| 404 | return ret; | ||
| 405 | |||
| 406 | return FIELD_GET(ADXL345_REG_INT_SOURCE_MSK, regval); | ||
| 164 | } | 407 | } |
| 165 | 408 | ||
| 166 | static void adxl345_powerdown(void *regmap) | 409 | static int adxl345_fifo_push(struct iio_dev *indio_dev, |
| 410 | int samples) | ||
| 167 | { | 411 | { |
| 168 | regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); | 412 | struct adxl345_state *st = iio_priv(indio_dev); |
| 413 | int i, ret; | ||
| 414 | |||
| 415 | if (samples <= 0) | ||
| 416 | return -EINVAL; | ||
| 417 | |||
| 418 | ret = adxl345_fifo_transfer(st, samples); | ||
| 419 | if (ret) | ||
| 420 | return ret; | ||
| 421 | |||
| 422 | for (i = 0; i < ADXL345_DIRS * samples; i += ADXL345_DIRS) | ||
| 423 | iio_push_to_buffers(indio_dev, &st->fifo_buf[i]); | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | /** | ||
| 429 | * adxl345_irq_handler() - Handle irqs of the ADXL345. | ||
| 430 | * @irq: The irq being handled. | ||
| 431 | * @p: The struct iio_device pointer for the device. | ||
| 432 | * | ||
| 433 | * Return: The interrupt was handled. | ||
| 434 | */ | ||
| 435 | static irqreturn_t adxl345_irq_handler(int irq, void *p) | ||
| 436 | { | ||
| 437 | struct iio_dev *indio_dev = p; | ||
| 438 | struct adxl345_state *st = iio_priv(indio_dev); | ||
| 439 | int int_stat; | ||
| 440 | int samples; | ||
| 441 | |||
| 442 | int_stat = adxl345_get_status(st); | ||
| 443 | if (int_stat <= 0) | ||
| 444 | return IRQ_NONE; | ||
| 445 | |||
| 446 | if (int_stat & ADXL345_INT_OVERRUN) | ||
| 447 | goto err; | ||
| 448 | |||
| 449 | if (int_stat & ADXL345_INT_WATERMARK) { | ||
| 450 | samples = adxl345_get_samples(st); | ||
| 451 | if (samples < 0) | ||
| 452 | goto err; | ||
| 453 | |||
| 454 | if (adxl345_fifo_push(indio_dev, samples) < 0) | ||
| 455 | goto err; | ||
| 456 | } | ||
| 457 | return IRQ_HANDLED; | ||
| 458 | |||
| 459 | err: | ||
| 460 | adxl345_fifo_reset(st); | ||
| 461 | |||
| 462 | return IRQ_HANDLED; | ||
| 169 | } | 463 | } |
| 170 | 464 | ||
| 465 | static const struct iio_info adxl345_info = { | ||
| 466 | .attrs = &adxl345_attrs_group, | ||
| 467 | .read_raw = adxl345_read_raw, | ||
| 468 | .write_raw = adxl345_write_raw, | ||
| 469 | .write_raw_get_fmt = adxl345_write_raw_get_fmt, | ||
| 470 | .hwfifo_set_watermark = adxl345_set_watermark, | ||
| 471 | }; | ||
| 472 | |||
| 171 | /** | 473 | /** |
| 172 | * adxl345_core_probe() - probe and setup for the adxl345 accelerometer, | 474 | * adxl345_core_probe() - Probe and setup for the accelerometer. |
| 173 | * also covers the adlx375 accelerometer | ||
| 174 | * @dev: Driver model representation of the device | 475 | * @dev: Driver model representation of the device |
| 175 | * @regmap: Regmap instance for the device | 476 | * @regmap: Regmap instance for the device |
| 477 | * @fifo_delay_default: Using FIFO with SPI needs delay | ||
| 176 | * @setup: Setup routine to be executed right before the standard device | 478 | * @setup: Setup routine to be executed right before the standard device |
| 177 | * setup | 479 | * setup |
| 178 | * | 480 | * |
| 481 | * For SPI operation greater than 1.6 MHz, it is necessary to deassert the CS | ||
| 482 | * pin to ensure a total delay of 5 us; otherwise, the delay is not sufficient. | ||
| 483 | * The total delay necessary for 5 MHz operation is at most 3.4 us. This is not | ||
| 484 | * a concern when using I2C mode because the communication rate is low enough | ||
| 485 | * to ensure a sufficient delay between FIFO reads. | ||
| 486 | * Ref: "Retrieving Data from FIFO", p. 21 of 36, Data Sheet ADXL345 Rev. G | ||
| 487 | * | ||
| 179 | * Return: 0 on success, negative errno on error | 488 | * Return: 0 on success, negative errno on error |
| 180 | */ | 489 | */ |
| 181 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, | 490 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, |
| 491 | bool fifo_delay_default, | ||
| 182 | int (*setup)(struct device*, struct regmap*)) | 492 | int (*setup)(struct device*, struct regmap*)) |
| 183 | { | 493 | { |
| 184 | struct adxl345_data *data; | 494 | struct adxl345_state *st; |
| 185 | struct iio_dev *indio_dev; | 495 | struct iio_dev *indio_dev; |
| 186 | u32 regval; | 496 | u32 regval; |
| 187 | unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE | | 497 | unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE | |
| @@ -190,30 +500,32 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, · 2 unmodified lines | |||
| 190 | ADXL345_DATA_FORMAT_SELF_TEST); | 500 | ADXL345_DATA_FORMAT_SELF_TEST); |
| 191 | int ret; | 501 | int ret; |
| 192 | 502 | ||
| 193 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | 503 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
| 194 | if (!indio_dev) | 504 | if (!indio_dev) |
| 195 | return -ENOMEM; | 505 | return -ENOMEM; |
| 196 | 506 | ||
| 197 | data = iio_priv(indio_dev); | 507 | st = iio_priv(indio_dev); |
| 198 | data->regmap = regmap; | 508 | st->regmap = regmap; |
| 199 | data->info = device_get_match_data(dev); | 509 | st->info = device_get_match_data(dev); |
| 200 | if (!data->info) | 510 | if (!st->info) |
| 201 | return -ENODEV; | 511 | return -ENODEV; |
| 512 | st->fifo_delay = fifo_delay_default; | ||
| 202 | 513 | ||
| 203 | indio_dev->name = data->info->name; | 514 | indio_dev->name = st->info->name; |
| 204 | indio_dev->info = &adxl345_info; | 515 | indio_dev->info = &adxl345_info; |
| 205 | indio_dev->modes = INDIO_DIRECT_MODE; | 516 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 206 | indio_dev->channels = adxl345_channels; | 517 | indio_dev->channels = adxl345_channels; |
| 207 | indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); | 518 | indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); |
| 519 | indio_dev->available_scan_masks = adxl345_scan_masks; | ||
| 208 | 520 | ||
| 209 | if (setup) { | 521 | if (setup) { |
| 210 | /* Perform optional initial bus specific configuration */ | 522 | /* Perform optional initial bus specific configuration */ |
| 211 | ret = setup(dev, data->regmap); | 523 | ret = setup(dev, st->regmap); |
| 212 | if (ret) | 524 | if (ret) |
| 213 | return ret; | 525 | return ret; |
| 214 | 526 | ||
| 215 | /* Enable full-resolution mode */ | 527 | /* Enable full-resolution mode */ |
| 216 | ret = regmap_update_bits(data->regmap, ADXL345_REG_DATA_FORMAT, | 528 | ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, |
| 217 | data_format_mask, | 529 | data_format_mask, |
| 218 | ADXL345_DATA_FORMAT_FULL_RES); | 530 | ADXL345_DATA_FORMAT_FULL_RES); |
| 219 | if (ret) | 531 | if (ret) |
| @@ -222,14 +534,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, · 2 unmodified lines | |||
| 222 | 534 | ||
| 223 | } else { | 535 | } else { |
| 224 | /* Enable full-resolution mode (init all data_format bits) */ | 536 | /* Enable full-resolution mode (init all data_format bits) */ |
| 225 | ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, | 537 | ret = regmap_write(st->regmap, ADXL345_REG_DATA_FORMAT, |
| 226 | ADXL345_DATA_FORMAT_FULL_RES); | 538 | ADXL345_DATA_FORMAT_FULL_RES); |
| 227 | if (ret) | 539 | if (ret) |
| 228 | return dev_err_probe(dev, ret, | 540 | return dev_err_probe(dev, ret, |
| 229 | "Failed to set data range\n"); | 541 | "Failed to set data range\n"); |
| 230 | } | 542 | } |
| 231 | 543 | ||
| 232 | ret = regmap_read(data->regmap, ADXL345_REG_DEVID, ®val); | 544 | ret = regmap_read(st->regmap, ADXL345_REG_DEVID, ®val); |
| 233 | if (ret < 0) | 545 | if (ret < 0) |
| 234 | return dev_err_probe(dev, ret, "Error reading device ID\n"); | 546 | return dev_err_probe(dev, ret, "Error reading device ID\n"); |
| 235 | 547 | ||
| @@ -238,14 +550,43 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, · 2 unmodified lines | |||
| 238 | regval, ADXL345_DEVID); | 550 | regval, ADXL345_DEVID); |
| 239 | 551 | ||
| 240 | /* Enable measurement mode */ | 552 | /* Enable measurement mode */ |
| 241 | ret = adxl345_powerup(data->regmap); | 553 | ret = adxl345_set_measure_en(st, true); |
| 242 | if (ret < 0) | 554 | if (ret < 0) |
| 243 | return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); | 555 | return dev_err_probe(dev, ret, "Failed to enable measurement mode\n"); |
| 244 | 556 | ||
| 245 | ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap); | 557 | ret = devm_add_action_or_reset(dev, adxl345_powerdown, st); |
| 246 | if (ret < 0) | 558 | if (ret < 0) |
| 247 | return ret; | 559 | return ret; |
| 248 | 560 | ||
| 561 | st->intio = ADXL345_INT1; | ||
| 562 | st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); | ||
| 563 | if (st->irq < 0) { | ||
| 564 | st->intio = ADXL345_INT2; | ||
| 565 | st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); | ||
| 566 | if (st->irq < 0) | ||
| 567 | st->intio = ADXL345_INT_NONE; | ||
| 568 | } | ||
| 569 | |||
| 570 | if (st->intio != ADXL345_INT_NONE) { | ||
| 571 | /* FIFO_STREAM mode is going to be activated later */ | ||
| 572 | ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops); | ||
| 573 | if (ret) | ||
| 574 | return ret; | ||
| 575 | |||
| 576 | ret = devm_request_threaded_irq(dev, st->irq, NULL, | ||
| 577 | &adxl345_irq_handler, | ||
| 578 | IRQF_SHARED | IRQF_ONESHOT, | ||
| 579 | indio_dev->name, indio_dev); | ||
| 580 | if (ret) | ||
| 581 | return ret; | ||
| 582 | } else { | ||
| 583 | ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL, | ||
| 584 | FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK, | ||
| 585 | ADXL345_FIFO_BYPASS)); | ||
| 586 | if (ret < 0) | ||
| 587 | return ret; | ||
| 588 | } | ||
| 589 | |||
| 249 | return devm_iio_device_register(dev, indio_dev); | 590 | return devm_iio_device_register(dev, indio_dev); |
| 250 | } | 591 | } |
| 251 | EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345"); | 592 | EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345"); |
| @@ -27,7 +27,7 @@ static int adxl345_i2c_probe(struct i2c_client *client) · 26 unmodified lines | |||
| 27 | if (IS_ERR(regmap)) | 27 | if (IS_ERR(regmap)) |
| 28 | return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); | 28 | return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); |
| 29 | 29 | ||
| 30 | return adxl345_core_probe(&client->dev, regmap, NULL); | 30 | return adxl345_core_probe(&client->dev, regmap, false, NULL); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static const struct adxl345_chip_info adxl345_i2c_info = { | 33 | static const struct adxl345_chip_info adxl345_i2c_info = { |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include "adxl345.h" | 12 | #include "adxl345.h" |
| 13 | 13 | ||
| 14 | #define ADXL345_MAX_SPI_FREQ_HZ 5000000 | 14 | #define ADXL345_MAX_SPI_FREQ_HZ 5000000 |
| 15 | #define ADXL345_MAX_FREQ_NO_FIFO_DELAY 1500000 | ||
| 15 | 16 | ||
| 16 | static const struct regmap_config adxl345_spi_regmap_config = { | 17 | static const struct regmap_config adxl345_spi_regmap_config = { |
| 17 | .reg_bits = 8, | 18 | .reg_bits = 8, |
| @@ -28,6 +29,7 @@ static int adxl345_spi_setup(struct device *dev, struct regmap *regmap) · 10 unmodified lines | |||
| 28 | static int adxl345_spi_probe(struct spi_device *spi) | 29 | static int adxl345_spi_probe(struct spi_device *spi) |
| 29 | { | 30 | { |
| 30 | struct regmap *regmap; | 31 | struct regmap *regmap; |
| 32 | bool needs_delay; | ||
| 31 | 33 | ||
| 32 | /* Bail out if max_speed_hz exceeds 5 MHz */ | 34 | /* Bail out if max_speed_hz exceeds 5 MHz */ |
| 33 | if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) | 35 | if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) |
| @@ -38,10 +40,11 @@ static int adxl345_spi_probe(struct spi_device *spi) · 4 unmodified lines | |||
| 38 | if (IS_ERR(regmap)) | 40 | if (IS_ERR(regmap)) |
| 39 | return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); | 41 | return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); |
| 40 | 42 | ||
| 43 | needs_delay = spi->max_speed_hz > ADXL345_MAX_FREQ_NO_FIFO_DELAY; | ||
| 41 | if (spi->mode & SPI_3WIRE) | 44 | if (spi->mode & SPI_3WIRE) |
| 42 | return adxl345_core_probe(&spi->dev, regmap, adxl345_spi_setup); | 45 | return adxl345_core_probe(&spi->dev, regmap, needs_delay, adxl345_spi_setup); |
| 43 | else | 46 | else |
| 44 | return adxl345_core_probe(&spi->dev, regmap, NULL); | 47 | return adxl345_core_probe(&spi->dev, regmap, needs_delay, NULL); |
| 45 | } | 48 | } |
| 46 | 49 | ||
| 47 | static const struct adxl345_chip_info adxl345_spi_info = { | 50 | static const struct adxl345_chip_info adxl345_spi_info = { |
| @@ -66,7 +66,7 @@ struct bma220_data { · 65 unmodified lines | |||
| 66 | struct { | 66 | struct { |
| 67 | s8 chans[3]; | 67 | s8 chans[3]; |
| 68 | /* Ensure timestamp is naturally aligned. */ | 68 | /* Ensure timestamp is naturally aligned. */ |
| 69 | s64 timestamp __aligned(8); | 69 | aligned_s64 timestamp; |
| 70 | } scan; | 70 | } scan; |
| 71 | u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN); | 71 | u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN); |
| 72 | }; | 72 | }; |
| @@ -129,6 +129,8 @@ · 128 unmodified lines | |||
| 129 | 129 | ||
| 130 | #define FXLS8962AF_DEVICE_ID 0x62 | 130 | #define FXLS8962AF_DEVICE_ID 0x62 |
| 131 | #define FXLS8964AF_DEVICE_ID 0x84 | 131 | #define FXLS8964AF_DEVICE_ID 0x84 |
| 132 | #define FXLS8974CF_DEVICE_ID 0x86 | ||
| 133 | #define FXLS8967AF_DEVICE_ID 0x87 | ||
| 132 | 134 | ||
| 133 | /* Raw temp channel offset */ | 135 | /* Raw temp channel offset */ |
| 134 | #define FXLS8962AF_TEMP_CENTER_VAL 25 | 136 | #define FXLS8962AF_TEMP_CENTER_VAL 25 |
| @@ -766,6 +768,18 @@ static const struct fxls8962af_chip_info fxls_chip_info_table[] = { · 631 unmodified lines | |||
| 766 | .channels = fxls8962af_channels, | 768 | .channels = fxls8962af_channels, |
| 767 | .num_channels = ARRAY_SIZE(fxls8962af_channels), | 769 | .num_channels = ARRAY_SIZE(fxls8962af_channels), |
| 768 | }, | 770 | }, |
| 771 | [fxls8967af] = { | ||
| 772 | .chip_id = FXLS8967AF_DEVICE_ID, | ||
| 773 | .name = "fxls8967af", | ||
| 774 | .channels = fxls8962af_channels, | ||
| 775 | .num_channels = ARRAY_SIZE(fxls8962af_channels), | ||
| 776 | }, | ||
| 777 | [fxls8974cf] = { | ||
| 778 | .chip_id = FXLS8974CF_DEVICE_ID, | ||
| 779 | .name = "fxls8974cf", | ||
| 780 | .channels = fxls8962af_channels, | ||
| 781 | .num_channels = ARRAY_SIZE(fxls8962af_channels), | ||
| 782 | }, | ||
| 769 | }; | 783 | }; |
| 770 | 784 | ||
| 771 | static const struct iio_info fxls8962af_info = { | 785 | static const struct iio_info fxls8962af_info = { |
| @@ -30,6 +30,8 @@ static int fxls8962af_probe(struct i2c_client *client) · 29 unmodified lines | |||
| 30 | static const struct i2c_device_id fxls8962af_id[] = { | 30 | static const struct i2c_device_id fxls8962af_id[] = { |
| 31 | { "fxls8962af", fxls8962af }, | 31 | { "fxls8962af", fxls8962af }, |
| 32 | { "fxls8964af", fxls8964af }, | 32 | { "fxls8964af", fxls8964af }, |
| 33 | { "fxls8967af", fxls8967af }, | ||
| 34 | { "fxls8974cf", fxls8974cf }, | ||
| 33 | {} | 35 | {} |
| 34 | }; | 36 | }; |
| 35 | MODULE_DEVICE_TABLE(i2c, fxls8962af_id); | 37 | MODULE_DEVICE_TABLE(i2c, fxls8962af_id); |
| @@ -11,6 +11,8 @@ struct device; · 10 unmodified lines | |||
| 11 | enum { | 11 | enum { |
| 12 | fxls8962af, | 12 | fxls8962af, |
| 13 | fxls8964af, | 13 | fxls8964af, |
| 14 | fxls8967af, | ||
| 15 | fxls8974cf, | ||
| 14 | }; | 16 | }; |
| 15 | 17 | ||
| 16 | int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); | 18 | int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); |
| @@ -38,7 +38,9 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) · 37 unmodified lines | |||
| 38 | static const struct i2c_device_id kx022a_i2c_id[] = { | 38 | static const struct i2c_device_id kx022a_i2c_id[] = { |
| 39 | { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, | 39 | { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, |
| 40 | { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, | 40 | { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, |
| 41 | { .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info }, | ||
| 41 | { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, | 42 | { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, |
| 43 | { .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info }, | ||
| 42 | { } | 44 | { } |
| 43 | }; | 45 | }; |
| 44 | MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); | 46 | MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); |
| @@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); · 1 unmodified line | |||
| 46 | static const struct of_device_id kx022a_of_match[] = { | 48 | static const struct of_device_id kx022a_of_match[] = { |
| 47 | { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, | 49 | { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, |
| 48 | { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, | 50 | { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, |
| 51 | { .compatible = "kionix,kx134-1211", .data = &kx134_chip_info }, | ||
| 49 | { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, | 52 | { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, |
| 53 | { .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info }, | ||
| 50 | { } | 54 | { } |
| 51 | }; | 55 | }; |
| 52 | MODULE_DEVICE_TABLE(of, kx022a_of_match); | 56 | MODULE_DEVICE_TABLE(of, kx022a_of_match); |
| @@ -38,7 +38,9 @@ static int kx022a_spi_probe(struct spi_device *spi) · 37 unmodified lines | |||
| 38 | static const struct spi_device_id kx022a_id[] = { | 38 | static const struct spi_device_id kx022a_id[] = { |
| 39 | { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, | 39 | { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, |
| 40 | { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, | 40 | { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, |
| 41 | { .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info }, | ||
| 41 | { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, | 42 | { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, |
| 43 | { .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info }, | ||
| 42 | { } | 44 | { } |
| 43 | }; | 45 | }; |
| 44 | MODULE_DEVICE_TABLE(spi, kx022a_id); | 46 | MODULE_DEVICE_TABLE(spi, kx022a_id); |
| @@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(spi, kx022a_id); · 1 unmodified line | |||
| 46 | static const struct of_device_id kx022a_of_match[] = { | 48 | static const struct of_device_id kx022a_of_match[] = { |
| 47 | { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, | 49 | { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, |
| 48 | { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, | 50 | { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, |
| 51 | { .compatible = "kionix,kx134-1211", .data = &kx134_chip_info }, | ||
| 49 | { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, | 52 | { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, |
| 53 | { .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info }, | ||
| 50 | { } | 54 | { } |
| 51 | }; | 55 | }; |
| 52 | MODULE_DEVICE_TABLE(of, kx022a_of_match); | 56 | MODULE_DEVICE_TABLE(of, kx022a_of_match); |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | * ROHM/KIONIX accelerometer driver | 5 | * ROHM/KIONIX accelerometer driver |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/cleanup.h> | ||
| 8 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 9 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 10 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| @@ -407,11 +408,21 @@ static const int kx022a_scale_table[][2] = { · 396 unmodified lines | |||
| 407 | { 0, 4788403 }, | 408 | { 0, 4788403 }, |
| 408 | }; | 409 | }; |
| 409 | 410 | ||
| 411 | /* KX134ACR-LBZ ranges are (+/-) 8, 16, 32, 64 G */ | ||
| 412 | static const int kx134acr_lbz_scale_table[][2] = { | ||
| 413 | { 0, 2394202 }, | ||
| 414 | { 0, 4788403 }, | ||
| 415 | { 0, 9576807 }, | ||
| 416 | { 0, 19153613 }, | ||
| 417 | }; | ||
| 418 | |||
| 410 | static int kx022a_read_avail(struct iio_dev *indio_dev, | 419 | static int kx022a_read_avail(struct iio_dev *indio_dev, |
| 411 | struct iio_chan_spec const *chan, | 420 | struct iio_chan_spec const *chan, |
| 412 | const int **vals, int *type, int *length, | 421 | const int **vals, int *type, int *length, |
| 413 | long mask) | 422 | long mask) |
| 414 | { | 423 | { |
| 424 | struct kx022a_data *data = iio_priv(indio_dev); | ||
| 425 | |||
| 415 | switch (mask) { | 426 | switch (mask) { |
| 416 | case IIO_CHAN_INFO_SAMP_FREQ: | 427 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 417 | *vals = (const int *)kx022a_accel_samp_freq_table; | 428 | *vals = (const int *)kx022a_accel_samp_freq_table; |
| @@ -420,9 +431,8 @@ static int kx022a_read_avail(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 420 | *type = IIO_VAL_INT_PLUS_MICRO; | 431 | *type = IIO_VAL_INT_PLUS_MICRO; |
| 421 | return IIO_AVAIL_LIST; | 432 | return IIO_AVAIL_LIST; |
| 422 | case IIO_CHAN_INFO_SCALE: | 433 | case IIO_CHAN_INFO_SCALE: |
| 423 | *vals = (const int *)kx022a_scale_table; | 434 | *vals = (const int *)data->chip_info->scale_table; |
| 424 | *length = ARRAY_SIZE(kx022a_scale_table) * | 435 | *length = data->chip_info->scale_table_size; |
| 425 | ARRAY_SIZE(kx022a_scale_table[0]); | ||
| 426 | *type = IIO_VAL_INT_PLUS_NANO; | 436 | *type = IIO_VAL_INT_PLUS_NANO; |
| 427 | return IIO_AVAIL_LIST; | 437 | return IIO_AVAIL_LIST; |
| 428 | default: | 438 | default: |
| @@ -438,17 +448,17 @@ static void kx022a_reg2freq(unsigned int val, int *val1, int *val2) · 9 unmodified lines | |||
| 438 | *val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1]; | 448 | *val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1]; |
| 439 | } | 449 | } |
| 440 | 450 | ||
| 441 | static void kx022a_reg2scale(unsigned int val, unsigned int *val1, | 451 | static void kx022a_reg2scale(struct kx022a_data *data, unsigned int val, |
| 442 | unsigned int *val2) | 452 | unsigned int *val1, unsigned int *val2) |
| 443 | { | 453 | { |
| 444 | val &= KX022A_MASK_GSEL; | 454 | val &= KX022A_MASK_GSEL; |
| 445 | val >>= KX022A_GSEL_SHIFT; | 455 | val >>= KX022A_GSEL_SHIFT; |
| 446 | 456 | ||
| 447 | *val1 = kx022a_scale_table[val][0]; | 457 | *val1 = data->chip_info->scale_table[val][0]; |
| 448 | *val2 = kx022a_scale_table[val][1]; | 458 | *val2 = data->chip_info->scale_table[val][1]; |
| 449 | } | 459 | } |
| 450 | 460 | ||
| 451 | static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on) | 461 | static int __kx022a_turn_on_off(struct kx022a_data *data, bool on) |
| 452 | { | 462 | { |
| 453 | int ret; | 463 | int ret; |
| 454 | 464 | ||
| @@ -469,7 +479,7 @@ static int kx022a_turn_off_lock(struct kx022a_data *data) · 14 unmodified lines | |||
| 469 | int ret; | 479 | int ret; |
| 470 | 480 | ||
| 471 | mutex_lock(&data->mutex); | 481 | mutex_lock(&data->mutex); |
| 472 | ret = kx022a_turn_on_off_unlocked(data, false); | 482 | ret = __kx022a_turn_on_off(data, false); |
| 473 | if (ret) | 483 | if (ret) |
| 474 | mutex_unlock(&data->mutex); | 484 | mutex_unlock(&data->mutex); |
| 475 | 485 | ||
| @@ -480,7 +490,7 @@ static int kx022a_turn_on_unlock(struct kx022a_data *data) · 4 unmodified lines | |||
| 480 | { | 490 | { |
| 481 | int ret; | 491 | int ret; |
| 482 | 492 | ||
| 483 | ret = kx022a_turn_on_off_unlocked(data, true); | 493 | ret = __kx022a_turn_on_off(data, true); |
| 484 | mutex_unlock(&data->mutex); | 494 | mutex_unlock(&data->mutex); |
| 485 | 495 | ||
| 486 | return ret; | 496 | return ret; |
| @@ -543,11 +553,11 @@ static int kx022a_write_raw(struct iio_dev *idev, · 56 unmodified lines | |||
| 543 | kx022a_turn_on_unlock(data); | 553 | kx022a_turn_on_unlock(data); |
| 544 | break; | 554 | break; |
| 545 | case IIO_CHAN_INFO_SCALE: | 555 | case IIO_CHAN_INFO_SCALE: |
| 546 | n = ARRAY_SIZE(kx022a_scale_table); | 556 | n = data->chip_info->scale_table_size / 2; |
| 547 | 557 | ||
| 548 | while (n-- > 0) | 558 | while (n-- > 0) |
| 549 | if (val == kx022a_scale_table[n][0] && | 559 | if (val == data->chip_info->scale_table[n][0] && |
| 550 | val2 == kx022a_scale_table[n][1]) | 560 | val2 == data->chip_info->scale_table[n][1]) |
| 551 | break; | 561 | break; |
| 552 | if (n < 0) { | 562 | if (n < 0) { |
| 553 | ret = -EINVAL; | 563 | ret = -EINVAL; |
| @@ -642,7 +652,7 @@ static int kx022a_read_raw(struct iio_dev *idev, · 88 unmodified lines | |||
| 642 | if (ret < 0) | 652 | if (ret < 0) |
| 643 | return ret; | 653 | return ret; |
| 644 | 654 | ||
| 645 | kx022a_reg2scale(regval, val, val2); | 655 | kx022a_reg2scale(data, regval, val, val2); |
| 646 | 656 | ||
| 647 | return IIO_VAL_INT_PLUS_NANO; | 657 | return IIO_VAL_INT_PLUS_NANO; |
| 648 | } | 658 | } |
| @@ -912,18 +922,19 @@ static int kx022a_fifo_disable(struct kx022a_data *data) · 263 unmodified lines | |||
| 912 | { | 922 | { |
| 913 | int ret = 0; | 923 | int ret = 0; |
| 914 | 924 | ||
| 915 | ret = kx022a_turn_off_lock(data); | 925 | guard(mutex)(&data->mutex); |
| 926 | ret = __kx022a_turn_on_off(data, false); | ||
| 916 | if (ret) | 927 | if (ret) |
| 917 | return ret; | 928 | return ret; |
| 918 | 929 | ||
| 919 | ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI); | 930 | ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI); |
| 920 | if (ret) | 931 | if (ret) |
| 921 | goto unlock_out; | 932 | return ret; |
| 922 | 933 | ||
| 923 | ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, | 934 | ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, |
| 924 | KX022A_MASK_BUF_EN); | 935 | KX022A_MASK_BUF_EN); |
| 925 | if (ret) | 936 | if (ret) |
| 926 | goto unlock_out; | 937 | return ret; |
| 927 | 938 | ||
| 928 | data->state &= ~KX022A_STATE_FIFO; | 939 | data->state &= ~KX022A_STATE_FIFO; |
| 929 | 940 | ||
| @@ -931,12 +942,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data) · 1 unmodified line | |||
| 931 | 942 | ||
| 932 | kfree(data->fifo_buffer); | 943 | kfree(data->fifo_buffer); |
| 933 | 944 | ||
| 934 | return kx022a_turn_on_unlock(data); | 945 | return __kx022a_turn_on_off(data, true); |
| 935 | |||
| 936 | unlock_out: | ||
| 937 | mutex_unlock(&data->mutex); | ||
| 938 | |||
| 939 | return ret; | ||
| 940 | } | 946 | } |
| 941 | 947 | ||
| 942 | static int kx022a_buffer_predisable(struct iio_dev *idev) | 948 | static int kx022a_buffer_predisable(struct iio_dev *idev) |
| @@ -959,33 +965,29 @@ static int kx022a_fifo_enable(struct kx022a_data *data) · 16 unmodified lines | |||
| 959 | if (!data->fifo_buffer) | 965 | if (!data->fifo_buffer) |
| 960 | return -ENOMEM; | 966 | return -ENOMEM; |
| 961 | 967 | ||
| 962 | ret = kx022a_turn_off_lock(data); | 968 | guard(mutex)(&data->mutex); |
| 969 | ret = __kx022a_turn_on_off(data, false); | ||
| 963 | if (ret) | 970 | if (ret) |
| 964 | return ret; | 971 | return ret; |
| 965 | 972 | ||
| 966 | /* Update watermark to HW */ | 973 | /* Update watermark to HW */ |
| 967 | ret = kx022a_fifo_set_wmi(data); | 974 | ret = kx022a_fifo_set_wmi(data); |
| 968 | if (ret) | 975 | if (ret) |
| 969 | goto unlock_out; | 976 | return ret; |
| 970 | 977 | ||
| 971 | /* Enable buffer */ | 978 | /* Enable buffer */ |
| 972 | ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, | 979 | ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, |
| 973 | KX022A_MASK_BUF_EN); | 980 | KX022A_MASK_BUF_EN); |
| 974 | if (ret) | 981 | if (ret) |
| 975 | goto unlock_out; | 982 | return ret; |
| 976 | 983 | ||
| 977 | data->state |= KX022A_STATE_FIFO; | 984 | data->state |= KX022A_STATE_FIFO; |
| 978 | ret = regmap_set_bits(data->regmap, data->ien_reg, | 985 | ret = regmap_set_bits(data->regmap, data->ien_reg, |
| 979 | KX022A_MASK_WMI); | 986 | KX022A_MASK_WMI); |
| 980 | if (ret) | 987 | if (ret) |
| 981 | goto unlock_out; | 988 | return ret; |
| 982 | |||
| 983 | return kx022a_turn_on_unlock(data); | ||
| 984 | |||
| 985 | unlock_out: | ||
| 986 | mutex_unlock(&data->mutex); | ||
| 987 | 989 | ||
| 988 | return ret; | 990 | return __kx022a_turn_on_off(data, true); |
| 989 | } | 991 | } |
| 990 | 992 | ||
| 991 | static int kx022a_buffer_postenable(struct iio_dev *idev) | 993 | static int kx022a_buffer_postenable(struct iio_dev *idev) |
| @@ -1053,7 +1055,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) · 61 unmodified lines | |||
| 1053 | struct kx022a_data *data = iio_priv(idev); | 1055 | struct kx022a_data *data = iio_priv(idev); |
| 1054 | irqreturn_t ret = IRQ_NONE; | 1056 | irqreturn_t ret = IRQ_NONE; |
| 1055 | 1057 | ||
| 1056 | mutex_lock(&data->mutex); | 1058 | guard(mutex)(&data->mutex); |
| 1057 | 1059 | ||
| 1058 | if (data->trigger_enabled) { | 1060 | if (data->trigger_enabled) { |
| 1059 | iio_trigger_poll_nested(data->trig); | 1061 | iio_trigger_poll_nested(data->trig); |
| @@ -1068,8 +1070,6 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) · 8 unmodified lines | |||
| 1068 | ret = IRQ_HANDLED; | 1070 | ret = IRQ_HANDLED; |
| 1069 | } | 1071 | } |
| 1070 | 1072 | ||
| 1071 | mutex_unlock(&data->mutex); | ||
| 1072 | |||
| 1073 | return ret; | 1073 | return ret; |
| 1074 | } | 1074 | } |
| 1075 | 1075 | ||
| @@ -1079,32 +1079,26 @@ static int kx022a_trigger_set_state(struct iio_trigger *trig, · 3 unmodified lines | |||
| 1079 | struct kx022a_data *data = iio_trigger_get_drvdata(trig); | 1079 | struct kx022a_data *data = iio_trigger_get_drvdata(trig); |
| 1080 | int ret = 0; | 1080 | int ret = 0; |
| 1081 | 1081 | ||
| 1082 | mutex_lock(&data->mutex); | 1082 | guard(mutex)(&data->mutex); |
| 1083 | 1083 | ||
| 1084 | if (data->trigger_enabled == state) | 1084 | if (data->trigger_enabled == state) |
| 1085 | goto unlock_out; | 1085 | return 0; |
| 1086 | 1086 | ||
| 1087 | if (data->state & KX022A_STATE_FIFO) { | 1087 | if (data->state & KX022A_STATE_FIFO) { |
| 1088 | dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); | 1088 | dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); |
| 1089 | ret = -EBUSY; | 1089 | return -EBUSY; |
| 1090 | goto unlock_out; | ||
| 1091 | } | 1090 | } |
| 1092 | 1091 | ||
| 1093 | ret = kx022a_turn_on_off_unlocked(data, false); | 1092 | ret = __kx022a_turn_on_off(data, false); |
| 1094 | if (ret) | 1093 | if (ret) |
| 1095 | goto unlock_out; | 1094 | return ret; |
| 1096 | 1095 | ||
| 1097 | data->trigger_enabled = state; | 1096 | data->trigger_enabled = state; |
| 1098 | ret = kx022a_set_drdy_irq(data, state); | 1097 | ret = kx022a_set_drdy_irq(data, state); |
| 1099 | if (ret) | 1098 | if (ret) |
| 1100 | goto unlock_out; | 1099 | return ret; |
| 1101 | |||
| 1102 | ret = kx022a_turn_on_off_unlocked(data, true); | ||
| 1103 | |||
| 1104 | unlock_out: | ||
| 1105 | mutex_unlock(&data->mutex); | ||
| 1106 | 1100 | ||
| 1107 | return ret; | 1101 | return __kx022a_turn_on_off(data, true); |
| 1108 | } | 1102 | } |
| 1109 | 1103 | ||
| 1110 | static const struct iio_trigger_ops kx022a_trigger_ops = { | 1104 | static const struct iio_trigger_ops kx022a_trigger_ops = { |
| @@ -1121,10 +1115,15 @@ static int kx022a_chip_init(struct kx022a_data *data) · 10 unmodified lines | |||
| 1121 | return ret; | 1115 | return ret; |
| 1122 | 1116 | ||
| 1123 | /* | 1117 | /* |
| 1124 | * I've seen I2C read failures if we poll too fast after the sensor | 1118 | * According to the power-on procedure documents, there is (at least) |
| 1125 | * reset. Slight delay gives I2C block the time to recover. | 1119 | * 2ms delay required after the software reset. This should be same for |
| 1120 | * all, KX022ACR-Z, KX132-1211, KX132ACR-LBZ and KX134ACR-LBZ. | ||
| 1121 | * | ||
| 1122 | * https://fscdn.rohm.com/kionix/en/document/AN010_KX022ACR-Z_Power-on_Procedure_E.pdf | ||
| 1123 | * https://fscdn.rohm.com/kionix/en/document/TN027-Power-On-Procedure.pdf | ||
| 1124 | * https://fscdn.rohm.com/kionix/en/document/AN011_KX134ACR-LBZ_Power-on_Procedure_E.pdf | ||
| 1126 | */ | 1125 | */ |
| 1127 | msleep(1); | 1126 | msleep(2); |
| 1128 | 1127 | ||
| 1129 | ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val, | 1128 | ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val, |
| 1130 | !(val & KX022A_MASK_SRST), | 1129 | !(val & KX022A_MASK_SRST), |
| @@ -1158,6 +1157,9 @@ const struct kx022a_chip_info kx022a_chip_info = { · 27 unmodified lines | |||
| 1158 | .regmap_config = &kx022a_regmap_config, | 1157 | .regmap_config = &kx022a_regmap_config, |
| 1159 | .channels = kx022a_channels, | 1158 | .channels = kx022a_channels, |
| 1160 | .num_channels = ARRAY_SIZE(kx022a_channels), | 1159 | .num_channels = ARRAY_SIZE(kx022a_channels), |
| 1160 | .scale_table = kx022a_scale_table, | ||
| 1161 | .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * | ||
| 1162 | ARRAY_SIZE(kx022a_scale_table[0]), | ||
| 1161 | .fifo_length = KX022A_FIFO_LENGTH, | 1163 | .fifo_length = KX022A_FIFO_LENGTH, |
| 1162 | .who = KX022A_REG_WHO, | 1164 | .who = KX022A_REG_WHO, |
| 1163 | .id = KX022A_ID, | 1165 | .id = KX022A_ID, |
| @@ -1183,6 +1185,9 @@ const struct kx022a_chip_info kx132_chip_info = { · 19 unmodified lines | |||
| 1183 | .regmap_config = &kx132_regmap_config, | 1185 | .regmap_config = &kx132_regmap_config, |
| 1184 | .channels = kx132_channels, | 1186 | .channels = kx132_channels, |
| 1185 | .num_channels = ARRAY_SIZE(kx132_channels), | 1187 | .num_channels = ARRAY_SIZE(kx132_channels), |
| 1188 | .scale_table = kx022a_scale_table, | ||
| 1189 | .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * | ||
| 1190 | ARRAY_SIZE(kx022a_scale_table[0]), | ||
| 1186 | .fifo_length = KX132_FIFO_LENGTH, | 1191 | .fifo_length = KX132_FIFO_LENGTH, |
| 1187 | .who = KX132_REG_WHO, | 1192 | .who = KX132_REG_WHO, |
| 1188 | .id = KX132_ID, | 1193 | .id = KX132_ID, |
| @@ -1204,6 +1209,35 @@ const struct kx022a_chip_info kx132_chip_info = { · 15 unmodified lines | |||
| 1204 | }; | 1209 | }; |
| 1205 | EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A"); | 1210 | EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A"); |
| 1206 | 1211 | ||
| 1212 | const struct kx022a_chip_info kx134_chip_info = { | ||
| 1213 | .name = "kx134-1211", | ||
| 1214 | .regmap_config = &kx132_regmap_config, | ||
| 1215 | .channels = kx132_channels, | ||
| 1216 | .num_channels = ARRAY_SIZE(kx132_channels), | ||
| 1217 | .scale_table = kx134acr_lbz_scale_table, | ||
| 1218 | .scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) * | ||
| 1219 | ARRAY_SIZE(kx134acr_lbz_scale_table[0]), | ||
| 1220 | .fifo_length = KX132_FIFO_LENGTH, | ||
| 1221 | .who = KX132_REG_WHO, | ||
| 1222 | .id = KX134_1211_ID, | ||
| 1223 | .cntl = KX132_REG_CNTL, | ||
| 1224 | .cntl2 = KX132_REG_CNTL2, | ||
| 1225 | .odcntl = KX132_REG_ODCNTL, | ||
| 1226 | .buf_cntl1 = KX132_REG_BUF_CNTL1, | ||
| 1227 | .buf_cntl2 = KX132_REG_BUF_CNTL2, | ||
| 1228 | .buf_clear = KX132_REG_BUF_CLEAR, | ||
| 1229 | .buf_status1 = KX132_REG_BUF_STATUS_1, | ||
| 1230 | .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL, | ||
| 1231 | .buf_read = KX132_REG_BUF_READ, | ||
| 1232 | .inc1 = KX132_REG_INC1, | ||
| 1233 | .inc4 = KX132_REG_INC4, | ||
| 1234 | .inc5 = KX132_REG_INC5, | ||
| 1235 | .inc6 = KX132_REG_INC6, | ||
| 1236 | .xout_l = KX132_REG_XOUT_L, | ||
| 1237 | .get_fifo_bytes_available = kx132_get_fifo_bytes_available, | ||
| 1238 | }; | ||
| 1239 | EXPORT_SYMBOL_NS_GPL(kx134_chip_info, "IIO_KX022A"); | ||
| 1240 | |||
| 1207 | /* | 1241 | /* |
| 1208 | * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is | 1242 | * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is |
| 1209 | * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial | 1243 | * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial |
| @@ -1216,6 +1250,9 @@ const struct kx022a_chip_info kx132acr_chip_info = { · 6 unmodified lines | |||
| 1216 | .regmap_config = &kx022a_regmap_config, | 1250 | .regmap_config = &kx022a_regmap_config, |
| 1217 | .channels = kx022a_channels, | 1251 | .channels = kx022a_channels, |
| 1218 | .num_channels = ARRAY_SIZE(kx022a_channels), | 1252 | .num_channels = ARRAY_SIZE(kx022a_channels), |
| 1253 | .scale_table = kx022a_scale_table, | ||
| 1254 | .scale_table_size = ARRAY_SIZE(kx022a_scale_table) * | ||
| 1255 | ARRAY_SIZE(kx022a_scale_table[0]), | ||
| 1219 | .fifo_length = KX022A_FIFO_LENGTH, | 1256 | .fifo_length = KX022A_FIFO_LENGTH, |
| 1220 | .who = KX022A_REG_WHO, | 1257 | .who = KX022A_REG_WHO, |
| 1221 | .id = KX132ACR_LBZ_ID, | 1258 | .id = KX132ACR_LBZ_ID, |
| @@ -1236,6 +1273,34 @@ const struct kx022a_chip_info kx132acr_chip_info = { · 14 unmodified lines | |||
| 1236 | }; | 1273 | }; |
| 1237 | EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A"); | 1274 | EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A"); |
| 1238 | 1275 | ||
| 1276 | const struct kx022a_chip_info kx134acr_chip_info = { | ||
| 1277 | .name = "kx134acr-lbz", | ||
| 1278 | .regmap_config = &kx022a_regmap_config, | ||
| 1279 | .channels = kx022a_channels, | ||
| 1280 | .num_channels = ARRAY_SIZE(kx022a_channels), | ||
| 1281 | .scale_table = kx134acr_lbz_scale_table, | ||
| 1282 | .scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) * | ||
| 1283 | ARRAY_SIZE(kx134acr_lbz_scale_table[0]), | ||
| 1284 | .fifo_length = KX022A_FIFO_LENGTH, | ||
| 1285 | .who = KX022A_REG_WHO, | ||
| 1286 | .id = KX134ACR_LBZ_ID, | ||
| 1287 | .cntl = KX022A_REG_CNTL, | ||
| 1288 | .cntl2 = KX022A_REG_CNTL2, | ||
| 1289 | .odcntl = KX022A_REG_ODCNTL, | ||
| 1290 | .buf_cntl1 = KX022A_REG_BUF_CNTL1, | ||
| 1291 | .buf_cntl2 = KX022A_REG_BUF_CNTL2, | ||
| 1292 | .buf_clear = KX022A_REG_BUF_CLEAR, | ||
| 1293 | .buf_status1 = KX022A_REG_BUF_STATUS_1, | ||
| 1294 | .buf_read = KX022A_REG_BUF_READ, | ||
| 1295 | .inc1 = KX022A_REG_INC1, | ||
| 1296 | .inc4 = KX022A_REG_INC4, | ||
| 1297 | .inc5 = KX022A_REG_INC5, | ||
| 1298 | .inc6 = KX022A_REG_INC6, | ||
| 1299 | .xout_l = KX022A_REG_XOUT_L, | ||
| 1300 | .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, | ||
| 1301 | }; | ||
| 1302 | EXPORT_SYMBOL_NS_GPL(kx134acr_chip_info, "IIO_KX022A"); | ||
| 1303 | |||
| 1239 | int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) | 1304 | int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) |
| 1240 | { | 1305 | { |
| 1241 | static const char * const regulator_names[] = {"io-vdd", "vdd"}; | 1306 | static const char * const regulator_names[] = {"io-vdd", "vdd"}; |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #define KX022A_REG_WHO 0x0f | 14 | #define KX022A_REG_WHO 0x0f |
| 15 | #define KX022A_ID 0xc8 | 15 | #define KX022A_ID 0xc8 |
| 16 | #define KX132ACR_LBZ_ID 0xd8 | 16 | #define KX132ACR_LBZ_ID 0xd8 |
| 17 | #define KX134ACR_LBZ_ID 0xcc | ||
| 17 | 18 | ||
| 18 | #define KX022A_REG_CNTL2 0x19 | 19 | #define KX022A_REG_CNTL2 0x19 |
| 19 | #define KX022A_MASK_SRST BIT(7) | 20 | #define KX022A_MASK_SRST BIT(7) |
| @@ -77,6 +78,7 @@ · 57 unmodified lines | |||
| 77 | 78 | ||
| 78 | #define KX132_REG_WHO 0x13 | 79 | #define KX132_REG_WHO 0x13 |
| 79 | #define KX132_ID 0x3d | 80 | #define KX132_ID 0x3d |
| 81 | #define KX134_1211_ID 0x46 | ||
| 80 | 82 | ||
| 81 | #define KX132_FIFO_LENGTH 86 | 83 | #define KX132_FIFO_LENGTH 86 |
| 82 | 84 | ||
| @@ -135,6 +137,14 @@ struct kx022a_data; · 52 unmodified lines | |||
| 135 | * | 137 | * |
| 136 | * @name: name of the device | 138 | * @name: name of the device |
| 137 | * @regmap_config: pointer to register map configuration | 139 | * @regmap_config: pointer to register map configuration |
| 140 | * @scale_table: An array of tables of scaling factors for | ||
| 141 | * a supported acceleration measurement range. | ||
| 142 | * Each table containing a single scaling | ||
| 143 | * factor consisting of two integers. The first | ||
| 144 | * value in a table is the integer part, and | ||
| 145 | * the second value is the fractional part as | ||
| 146 | * parts per billion. | ||
| 147 | * @scale_table_size: Amount of values in tables. | ||
| 138 | * @channels: pointer to iio_chan_spec array | 148 | * @channels: pointer to iio_chan_spec array |
| 139 | * @num_channels: number of iio_chan_spec channels | 149 | * @num_channels: number of iio_chan_spec channels |
| 140 | * @fifo_length: number of 16-bit samples in a full buffer | 150 | * @fifo_length: number of 16-bit samples in a full buffer |
| @@ -161,6 +171,8 @@ struct kx022a_data; · 20 unmodified lines | |||
| 161 | struct kx022a_chip_info { | 171 | struct kx022a_chip_info { |
| 162 | const char *name; | 172 | const char *name; |
| 163 | const struct regmap_config *regmap_config; | 173 | const struct regmap_config *regmap_config; |
| 174 | const int (*scale_table)[2]; | ||
| 175 | const int scale_table_size; | ||
| 164 | const struct iio_chan_spec *channels; | 176 | const struct iio_chan_spec *channels; |
| 165 | unsigned int num_channels; | 177 | unsigned int num_channels; |
| 166 | unsigned int fifo_length; | 178 | unsigned int fifo_length; |
| @@ -187,6 +199,8 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi · 20 unmodified lines | |||
| 187 | 199 | ||
| 188 | extern const struct kx022a_chip_info kx022a_chip_info; | 200 | extern const struct kx022a_chip_info kx022a_chip_info; |
| 189 | extern const struct kx022a_chip_info kx132_chip_info; | 201 | extern const struct kx022a_chip_info kx132_chip_info; |
| 202 | extern const struct kx022a_chip_info kx134_chip_info; | ||
| 190 | extern const struct kx022a_chip_info kx132acr_chip_info; | 203 | extern const struct kx022a_chip_info kx132acr_chip_info; |
| 204 | extern const struct kx022a_chip_info kx134acr_chip_info; | ||
| 191 | 205 | ||
| 192 | #endif | 206 | #endif |
| @@ -35,10 +35,6 @@ · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | #define AD4000_SCALE_OPTIONS 2 | 36 | #define AD4000_SCALE_OPTIONS 2 |
| 37 | 37 | ||
| 38 | #define AD4000_TQUIET1_NS 190 | ||
| 39 | #define AD4000_TQUIET2_NS 60 | ||
| 40 | #define AD4000_TCONV_NS 320 | ||
| 41 | |||
| 42 | #define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \ | 38 | #define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \ |
| 43 | { \ | 39 | { \ |
| 44 | .type = IIO_VOLTAGE, \ | 40 | .type = IIO_VOLTAGE, \ |
| @@ -49,6 +45,7 @@ · 4 unmodified lines | |||
| 49 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | 45 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
| 50 | BIT(IIO_CHAN_INFO_SCALE), \ | 46 | BIT(IIO_CHAN_INFO_SCALE), \ |
| 51 | .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ | 47 | .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ |
| 48 | .scan_index = 0, \ | ||
| 52 | .scan_type = { \ | 49 | .scan_type = { \ |
| 53 | .sign = _sign, \ | 50 | .sign = _sign, \ |
| 54 | .realbits = _real_bits, \ | 51 | .realbits = _real_bits, \ |
| @@ -62,6 +59,12 @@ · 7 unmodified lines | |||
| 62 | __AD4000_DIFF_CHANNEL((_sign), (_real_bits), \ | 59 | __AD4000_DIFF_CHANNEL((_sign), (_real_bits), \ |
| 63 | ((_real_bits) > 16 ? 32 : 16), (_reg_access)) | 60 | ((_real_bits) > 16 ? 32 : 16), (_reg_access)) |
| 64 | 61 | ||
| 62 | #define AD4000_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \ | ||
| 63 | { \ | ||
| 64 | AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \ | ||
| 65 | IIO_CHAN_SOFT_TIMESTAMP(1), \ | ||
| 66 | } | ||
| 67 | |||
| 65 | #define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\ | 68 | #define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\ |
| 66 | { \ | 69 | { \ |
| 67 | .type = IIO_VOLTAGE, \ | 70 | .type = IIO_VOLTAGE, \ |
| @@ -71,6 +74,7 @@ · 3 unmodified lines | |||
| 71 | BIT(IIO_CHAN_INFO_SCALE) | \ | 74 | BIT(IIO_CHAN_INFO_SCALE) | \ |
| 72 | BIT(IIO_CHAN_INFO_OFFSET), \ | 75 | BIT(IIO_CHAN_INFO_OFFSET), \ |
| 73 | .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ | 76 | .info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\ |
| 77 | .scan_index = 0, \ | ||
| 74 | .scan_type = { \ | 78 | .scan_type = { \ |
| 75 | .sign = _sign, \ | 79 | .sign = _sign, \ |
| 76 | .realbits = _real_bits, \ | 80 | .realbits = _real_bits, \ |
| @@ -84,6 +88,12 @@ · 7 unmodified lines | |||
| 84 | __AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \ | 88 | __AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \ |
| 85 | ((_real_bits) > 16 ? 32 : 16), (_reg_access)) | 89 | ((_real_bits) > 16 ? 32 : 16), (_reg_access)) |
| 86 | 90 | ||
| 91 | #define AD4000_PSEUDO_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \ | ||
| 92 | { \ | ||
| 93 | AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \ | ||
| 94 | IIO_CHAN_SOFT_TIMESTAMP(1), \ | ||
| 95 | } | ||
| 96 | |||
| 87 | static const char * const ad4000_power_supplies[] = { | 97 | static const char * const ad4000_power_supplies[] = { |
| 88 | "vdd", "vio" | 98 | "vdd", "vio" |
| 89 | }; | 99 | }; |
| @@ -108,111 +118,280 @@ static const int ad4000_gains[] = { · 18 unmodified lines | |||
| 108 | 454, 909, 1000, 1900, | 118 | 454, 909, 1000, 1900, |
| 109 | }; | 119 | }; |
| 110 | 120 | ||
| 121 | struct ad4000_time_spec { | ||
| 122 | int t_conv_ns; | ||
| 123 | int t_quiet2_ns; | ||
| 124 | }; | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Same timing specifications for all of AD4000, AD4001, ..., AD4008, AD4010, | ||
| 128 | * ADAQ4001, and ADAQ4003. | ||
| 129 | */ | ||
| 130 | static const struct ad4000_time_spec ad4000_t_spec = { | ||
| 131 | .t_conv_ns = 320, | ||
| 132 | .t_quiet2_ns = 60, | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* AD4020, AD4021, AD4022 */ | ||
| 136 | static const struct ad4000_time_spec ad4020_t_spec = { | ||
| 137 | .t_conv_ns = 350, | ||
| 138 | .t_quiet2_ns = 60, | ||
| 139 | }; | ||
| 140 | |||
| 141 | /* AD7983, AD7984 */ | ||
| 142 | static const struct ad4000_time_spec ad7983_t_spec = { | ||
| 143 | .t_conv_ns = 500, | ||
| 144 | .t_quiet2_ns = 0, | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* AD7980, AD7982 */ | ||
| 148 | static const struct ad4000_time_spec ad7980_t_spec = { | ||
| 149 | .t_conv_ns = 800, | ||
| 150 | .t_quiet2_ns = 0, | ||
| 151 | }; | ||
| 152 | |||
| 153 | /* AD7946, AD7686, AD7688, AD7988-5, AD7693 */ | ||
| 154 | static const struct ad4000_time_spec ad7686_t_spec = { | ||
| 155 | .t_conv_ns = 1600, | ||
| 156 | .t_quiet2_ns = 0, | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* AD7690 */ | ||
| 160 | static const struct ad4000_time_spec ad7690_t_spec = { | ||
| 161 | .t_conv_ns = 2100, | ||
| 162 | .t_quiet2_ns = 0, | ||
| 163 | }; | ||
| 164 | |||
| 165 | /* AD7942, AD7685, AD7687 */ | ||
| 166 | static const struct ad4000_time_spec ad7687_t_spec = { | ||
| 167 | .t_conv_ns = 3200, | ||
| 168 | .t_quiet2_ns = 0, | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* AD7691 */ | ||
| 172 | static const struct ad4000_time_spec ad7691_t_spec = { | ||
| 173 | .t_conv_ns = 3700, | ||
| 174 | .t_quiet2_ns = 0, | ||
| 175 | }; | ||
| 176 | |||
| 177 | /* AD7988-1 */ | ||
| 178 | static const struct ad4000_time_spec ad7988_1_t_spec = { | ||
| 179 | .t_conv_ns = 9500, | ||
| 180 | .t_quiet2_ns = 0, | ||
| 181 | }; | ||
| 182 | |||
| 111 | struct ad4000_chip_info { | 183 | struct ad4000_chip_info { |
| 112 | const char *dev_name; | 184 | const char *dev_name; |
| 113 | struct iio_chan_spec chan_spec; | 185 | struct iio_chan_spec chan_spec[2]; |
| 114 | struct iio_chan_spec reg_access_chan_spec; | 186 | struct iio_chan_spec reg_access_chan_spec[2]; |
| 187 | const struct ad4000_time_spec *time_spec; | ||
| 115 | bool has_hardware_gain; | 188 | bool has_hardware_gain; |
| 116 | }; | 189 | }; |
| 117 | 190 | ||
| 118 | static const struct ad4000_chip_info ad4000_chip_info = { | 191 | static const struct ad4000_chip_info ad4000_chip_info = { |
| 119 | .dev_name = "ad4000", | 192 | .dev_name = "ad4000", |
| 120 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0), | 193 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), |
| 121 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1), | 194 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), |
| 195 | .time_spec = &ad4000_t_spec, | ||
| 122 | }; | 196 | }; |
| 123 | 197 | ||
| 124 | static const struct ad4000_chip_info ad4001_chip_info = { | 198 | static const struct ad4000_chip_info ad4001_chip_info = { |
| 125 | .dev_name = "ad4001", | 199 | .dev_name = "ad4001", |
| 126 | .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0), | 200 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), |
| 127 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1), | 201 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), |
| 202 | .time_spec = &ad4000_t_spec, | ||
| 128 | }; | 203 | }; |
| 129 | 204 | ||
| 130 | static const struct ad4000_chip_info ad4002_chip_info = { | 205 | static const struct ad4000_chip_info ad4002_chip_info = { |
| 131 | .dev_name = "ad4002", | 206 | .dev_name = "ad4002", |
| 132 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0), | 207 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), |
| 133 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1), | 208 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), |
| 209 | .time_spec = &ad4000_t_spec, | ||
| 134 | }; | 210 | }; |
| 135 | 211 | ||
| 136 | static const struct ad4000_chip_info ad4003_chip_info = { | 212 | static const struct ad4000_chip_info ad4003_chip_info = { |
| 137 | .dev_name = "ad4003", | 213 | .dev_name = "ad4003", |
| 138 | .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0), | 214 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), |
| 139 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1), | 215 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), |
| 216 | .time_spec = &ad4000_t_spec, | ||
| 140 | }; | 217 | }; |
| 141 | 218 | ||
| 142 | static const struct ad4000_chip_info ad4004_chip_info = { | 219 | static const struct ad4000_chip_info ad4004_chip_info = { |
| 143 | .dev_name = "ad4004", | 220 | .dev_name = "ad4004", |
| 144 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0), | 221 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), |
| 145 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1), | 222 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), |
| 223 | .time_spec = &ad4000_t_spec, | ||
| 146 | }; | 224 | }; |
| 147 | 225 | ||
| 148 | static const struct ad4000_chip_info ad4005_chip_info = { | 226 | static const struct ad4000_chip_info ad4005_chip_info = { |
| 149 | .dev_name = "ad4005", | 227 | .dev_name = "ad4005", |
| 150 | .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0), | 228 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), |
| 151 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1), | 229 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), |
| 230 | .time_spec = &ad4000_t_spec, | ||
| 152 | }; | 231 | }; |
| 153 | 232 | ||
| 154 | static const struct ad4000_chip_info ad4006_chip_info = { | 233 | static const struct ad4000_chip_info ad4006_chip_info = { |
| 155 | .dev_name = "ad4006", | 234 | .dev_name = "ad4006", |
| 156 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0), | 235 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), |
| 157 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1), | 236 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), |
| 237 | .time_spec = &ad4000_t_spec, | ||
| 158 | }; | 238 | }; |
| 159 | 239 | ||
| 160 | static const struct ad4000_chip_info ad4007_chip_info = { | 240 | static const struct ad4000_chip_info ad4007_chip_info = { |
| 161 | .dev_name = "ad4007", | 241 | .dev_name = "ad4007", |
| 162 | .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0), | 242 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), |
| 163 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1), | 243 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), |
| 244 | .time_spec = &ad4000_t_spec, | ||
| 164 | }; | 245 | }; |
| 165 | 246 | ||
| 166 | static const struct ad4000_chip_info ad4008_chip_info = { | 247 | static const struct ad4000_chip_info ad4008_chip_info = { |
| 167 | .dev_name = "ad4008", | 248 | .dev_name = "ad4008", |
| 168 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0), | 249 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), |
| 169 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1), | 250 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1), |
| 251 | .time_spec = &ad4000_t_spec, | ||
| 170 | }; | 252 | }; |
| 171 | 253 | ||
| 172 | static const struct ad4000_chip_info ad4010_chip_info = { | 254 | static const struct ad4000_chip_info ad4010_chip_info = { |
| 173 | .dev_name = "ad4010", | 255 | .dev_name = "ad4010", |
| 174 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0), | 256 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0), |
| 175 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1), | 257 | .reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1), |
| 258 | .time_spec = &ad4000_t_spec, | ||
| 176 | }; | 259 | }; |
| 177 | 260 | ||
| 178 | static const struct ad4000_chip_info ad4011_chip_info = { | 261 | static const struct ad4000_chip_info ad4011_chip_info = { |
| 179 | .dev_name = "ad4011", | 262 | .dev_name = "ad4011", |
| 180 | .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0), | 263 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), |
| 181 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1), | 264 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), |
| 265 | .time_spec = &ad4000_t_spec, | ||
| 182 | }; | 266 | }; |
| 183 | 267 | ||
| 184 | static const struct ad4000_chip_info ad4020_chip_info = { | 268 | static const struct ad4000_chip_info ad4020_chip_info = { |
| 185 | .dev_name = "ad4020", | 269 | .dev_name = "ad4020", |
| 186 | .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0), | 270 | .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), |
| 187 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1), | 271 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), |
| 272 | .time_spec = &ad4020_t_spec, | ||
| 188 | }; | 273 | }; |
| 189 | 274 | ||
| 190 | static const struct ad4000_chip_info ad4021_chip_info = { | 275 | static const struct ad4000_chip_info ad4021_chip_info = { |
| 191 | .dev_name = "ad4021", | 276 | .dev_name = "ad4021", |
| 192 | .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0), | 277 | .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), |
| 193 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1), | 278 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), |
| 279 | .time_spec = &ad4020_t_spec, | ||
| 194 | }; | 280 | }; |
| 195 | 281 | ||
| 196 | static const struct ad4000_chip_info ad4022_chip_info = { | 282 | static const struct ad4000_chip_info ad4022_chip_info = { |
| 197 | .dev_name = "ad4022", | 283 | .dev_name = "ad4022", |
| 198 | .chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0), | 284 | .chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0), |
| 199 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1), | 285 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1), |
| 286 | .time_spec = &ad4020_t_spec, | ||
| 200 | }; | 287 | }; |
| 201 | 288 | ||
| 202 | static const struct ad4000_chip_info adaq4001_chip_info = { | 289 | static const struct ad4000_chip_info adaq4001_chip_info = { |
| 203 | .dev_name = "adaq4001", | 290 | .dev_name = "adaq4001", |
| 204 | .chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0), | 291 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), |
| 205 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1), | 292 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1), |
| 293 | .time_spec = &ad4000_t_spec, | ||
| 206 | .has_hardware_gain = true, | 294 | .has_hardware_gain = true, |
| 207 | }; | 295 | }; |
| 208 | 296 | ||
| 209 | static const struct ad4000_chip_info adaq4003_chip_info = { | 297 | static const struct ad4000_chip_info adaq4003_chip_info = { |
| 210 | .dev_name = "adaq4003", | 298 | .dev_name = "adaq4003", |
| 211 | .chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0), | 299 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), |
| 212 | .reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1), | 300 | .reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1), |
| 301 | .time_spec = &ad4000_t_spec, | ||
| 213 | .has_hardware_gain = true, | 302 | .has_hardware_gain = true, |
| 214 | }; | 303 | }; |
| 215 | 304 | ||
| 305 | static const struct ad4000_chip_info ad7685_chip_info = { | ||
| 306 | .dev_name = "ad7685", | ||
| 307 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 308 | .time_spec = &ad7687_t_spec, | ||
| 309 | }; | ||
| 310 | |||
| 311 | static const struct ad4000_chip_info ad7686_chip_info = { | ||
| 312 | .dev_name = "ad7686", | ||
| 313 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 314 | .time_spec = &ad7686_t_spec, | ||
| 315 | }; | ||
| 316 | |||
| 317 | static const struct ad4000_chip_info ad7687_chip_info = { | ||
| 318 | .dev_name = "ad7687", | ||
| 319 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), | ||
| 320 | .time_spec = &ad7687_t_spec, | ||
| 321 | }; | ||
| 322 | |||
| 323 | static const struct ad4000_chip_info ad7688_chip_info = { | ||
| 324 | .dev_name = "ad7688", | ||
| 325 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), | ||
| 326 | .time_spec = &ad7686_t_spec, | ||
| 327 | }; | ||
| 328 | |||
| 329 | static const struct ad4000_chip_info ad7690_chip_info = { | ||
| 330 | .dev_name = "ad7690", | ||
| 331 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), | ||
| 332 | .time_spec = &ad7690_t_spec, | ||
| 333 | }; | ||
| 334 | |||
| 335 | static const struct ad4000_chip_info ad7691_chip_info = { | ||
| 336 | .dev_name = "ad7691", | ||
| 337 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), | ||
| 338 | .time_spec = &ad7691_t_spec, | ||
| 339 | }; | ||
| 340 | |||
| 341 | static const struct ad4000_chip_info ad7693_chip_info = { | ||
| 342 | .dev_name = "ad7693", | ||
| 343 | .chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0), | ||
| 344 | .time_spec = &ad7686_t_spec, | ||
| 345 | }; | ||
| 346 | |||
| 347 | static const struct ad4000_chip_info ad7942_chip_info = { | ||
| 348 | .dev_name = "ad7942", | ||
| 349 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0), | ||
| 350 | .time_spec = &ad7687_t_spec, | ||
| 351 | }; | ||
| 352 | |||
| 353 | static const struct ad4000_chip_info ad7946_chip_info = { | ||
| 354 | .dev_name = "ad7946", | ||
| 355 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0), | ||
| 356 | .time_spec = &ad7686_t_spec, | ||
| 357 | }; | ||
| 358 | |||
| 359 | static const struct ad4000_chip_info ad7980_chip_info = { | ||
| 360 | .dev_name = "ad7980", | ||
| 361 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 362 | .time_spec = &ad7980_t_spec, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static const struct ad4000_chip_info ad7982_chip_info = { | ||
| 366 | .dev_name = "ad7982", | ||
| 367 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), | ||
| 368 | .time_spec = &ad7980_t_spec, | ||
| 369 | }; | ||
| 370 | |||
| 371 | static const struct ad4000_chip_info ad7983_chip_info = { | ||
| 372 | .dev_name = "ad7983", | ||
| 373 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 374 | .time_spec = &ad7983_t_spec, | ||
| 375 | }; | ||
| 376 | |||
| 377 | static const struct ad4000_chip_info ad7984_chip_info = { | ||
| 378 | .dev_name = "ad7984", | ||
| 379 | .chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0), | ||
| 380 | .time_spec = &ad7983_t_spec, | ||
| 381 | }; | ||
| 382 | |||
| 383 | static const struct ad4000_chip_info ad7988_1_chip_info = { | ||
| 384 | .dev_name = "ad7988-1", | ||
| 385 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 386 | .time_spec = &ad7988_1_t_spec, | ||
| 387 | }; | ||
| 388 | |||
| 389 | static const struct ad4000_chip_info ad7988_5_chip_info = { | ||
| 390 | .dev_name = "ad7988-5", | ||
| 391 | .chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0), | ||
| 392 | .time_spec = &ad7686_t_spec, | ||
| 393 | }; | ||
| 394 | |||
| 216 | struct ad4000_state { | 395 | struct ad4000_state { |
| 217 | struct spi_device *spi; | 396 | struct spi_device *spi; |
| 218 | struct gpio_desc *cnv_gpio; | 397 | struct gpio_desc *cnv_gpio; |
| @@ -224,6 +403,7 @@ struct ad4000_state { · 5 unmodified lines | |||
| 224 | bool span_comp; | 403 | bool span_comp; |
| 225 | u16 gain_milli; | 404 | u16 gain_milli; |
| 226 | int scale_tbl[AD4000_SCALE_OPTIONS][2]; | 405 | int scale_tbl[AD4000_SCALE_OPTIONS][2]; |
| 406 | const struct ad4000_time_spec *time_spec; | ||
| 227 | 407 | ||
| 228 | /* | 408 | /* |
| 229 | * DMA (thus cache coherency maintenance) requires the transfer buffers | 409 | * DMA (thus cache coherency maintenance) requires the transfer buffers |
| @@ -234,7 +414,7 @@ struct ad4000_state { · 4 unmodified lines | |||
| 234 | __be16 sample_buf16; | 414 | __be16 sample_buf16; |
| 235 | __be32 sample_buf32; | 415 | __be32 sample_buf32; |
| 236 | } data; | 416 | } data; |
| 237 | s64 timestamp __aligned(8); | 417 | aligned_s64 timestamp; |
| 238 | } scan __aligned(IIO_DMA_MINALIGN); | 418 | } scan __aligned(IIO_DMA_MINALIGN); |
| 239 | u8 tx_buf[2]; | 419 | u8 tx_buf[2]; |
| 240 | u8 rx_buf[2]; | 420 | u8 rx_buf[2]; |
| @@ -488,16 +668,15 @@ static const struct iio_info ad4000_info = { · 247 unmodified lines | |||
| 488 | static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st, | 668 | static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st, |
| 489 | const struct iio_chan_spec *chan) | 669 | const struct iio_chan_spec *chan) |
| 490 | { | 670 | { |
| 491 | unsigned int cnv_pulse_time = AD4000_TCONV_NS; | ||
| 492 | struct spi_transfer *xfers = st->xfers; | 671 | struct spi_transfer *xfers = st->xfers; |
| 493 | 672 | ||
| 494 | xfers[0].cs_change = 1; | 673 | xfers[0].cs_change = 1; |
| 495 | xfers[0].cs_change_delay.value = cnv_pulse_time; | 674 | xfers[0].cs_change_delay.value = st->time_spec->t_conv_ns; |
| 496 | xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; | 675 | xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; |
| 497 | 676 | ||
| 498 | xfers[1].rx_buf = &st->scan.data; | 677 | xfers[1].rx_buf = &st->scan.data; |
| 499 | xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits); | 678 | xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits); |
| 500 | xfers[1].delay.value = AD4000_TQUIET2_NS; | 679 | xfers[1].delay.value = st->time_spec->t_quiet2_ns; |
| 501 | xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS; | 680 | xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS; |
| 502 | 681 | ||
| 503 | spi_message_init_with_transfers(&st->msg, st->xfers, 2); | 682 | spi_message_init_with_transfers(&st->msg, st->xfers, 2); |
| @@ -515,7 +694,6 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st, · 11 unmodified lines | |||
| 515 | static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st, | 694 | static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st, |
| 516 | const struct iio_chan_spec *chan) | 695 | const struct iio_chan_spec *chan) |
| 517 | { | 696 | { |
| 518 | unsigned int cnv_to_sdi_time = AD4000_TCONV_NS; | ||
| 519 | struct spi_transfer *xfers = st->xfers; | 697 | struct spi_transfer *xfers = st->xfers; |
| 520 | 698 | ||
| 521 | /* | 699 | /* |
| @@ -523,7 +701,7 @@ static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st, · 1 unmodified line | |||
| 523 | * going low. | 701 | * going low. |
| 524 | */ | 702 | */ |
| 525 | xfers[0].cs_off = 1; | 703 | xfers[0].cs_off = 1; |
| 526 | xfers[0].delay.value = cnv_to_sdi_time; | 704 | xfers[0].delay.value = st->time_spec->t_conv_ns; |
| 527 | xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; | 705 | xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; |
| 528 | 706 | ||
| 529 | xfers[1].rx_buf = &st->scan.data; | 707 | xfers[1].rx_buf = &st->scan.data; |
| @@ -562,6 +740,7 @@ static int ad4000_probe(struct spi_device *spi) · 32 unmodified lines | |||
| 562 | 740 | ||
| 563 | st = iio_priv(indio_dev); | 741 | st = iio_priv(indio_dev); |
| 564 | st->spi = spi; | 742 | st->spi = spi; |
| 743 | st->time_spec = chip->time_spec; | ||
| 565 | 744 | ||
| 566 | ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies), | 745 | ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies), |
| 567 | ad4000_power_supplies); | 746 | ad4000_power_supplies); |
| @@ -591,7 +770,7 @@ static int ad4000_probe(struct spi_device *spi) · 23 unmodified lines | |||
| 591 | switch (st->sdi_pin) { | 770 | switch (st->sdi_pin) { |
| 592 | case AD4000_SDI_MOSI: | 771 | case AD4000_SDI_MOSI: |
| 593 | indio_dev->info = &ad4000_reg_access_info; | 772 | indio_dev->info = &ad4000_reg_access_info; |
| 594 | indio_dev->channels = &chip->reg_access_chan_spec; | 773 | indio_dev->channels = chip->reg_access_chan_spec; |
| 595 | 774 | ||
| 596 | /* | 775 | /* |
| 597 | * In "3-wire mode", the ADC SDI line must be kept high when | 776 | * In "3-wire mode", the ADC SDI line must be kept high when |
| @@ -603,7 +782,7 @@ static int ad4000_probe(struct spi_device *spi) · 5 unmodified lines | |||
| 603 | if (ret < 0) | 782 | if (ret < 0) |
| 604 | return ret; | 783 | return ret; |
| 605 | 784 | ||
| 606 | ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels); | 785 | ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]); |
| 607 | if (ret) | 786 | if (ret) |
| 608 | return ret; | 787 | return ret; |
| 609 | 788 | ||
| @@ -614,16 +793,16 @@ static int ad4000_probe(struct spi_device *spi) · 4 unmodified lines | |||
| 614 | break; | 793 | break; |
| 615 | case AD4000_SDI_VIO: | 794 | case AD4000_SDI_VIO: |
| 616 | indio_dev->info = &ad4000_info; | 795 | indio_dev->info = &ad4000_info; |
| 617 | indio_dev->channels = &chip->chan_spec; | 796 | indio_dev->channels = chip->chan_spec; |
| 618 | ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels); | 797 | ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]); |
| 619 | if (ret) | 798 | if (ret) |
| 620 | return ret; | 799 | return ret; |
| 621 | 800 | ||
| 622 | break; | 801 | break; |
| 623 | case AD4000_SDI_CS: | 802 | case AD4000_SDI_CS: |
| 624 | indio_dev->info = &ad4000_info; | 803 | indio_dev->info = &ad4000_info; |
| 625 | indio_dev->channels = &chip->chan_spec; | 804 | indio_dev->channels = chip->chan_spec; |
| 626 | ret = ad4000_prepare_4wire_mode_message(st, indio_dev->channels); | 805 | ret = ad4000_prepare_4wire_mode_message(st, &indio_dev->channels[0]); |
| 627 | if (ret) | 806 | if (ret) |
| 628 | return ret; | 807 | return ret; |
| 629 | 808 | ||
| @@ -637,7 +816,7 @@ static int ad4000_probe(struct spi_device *spi) · 7 unmodified lines | |||
| 637 | } | 816 | } |
| 638 | 817 | ||
| 639 | indio_dev->name = chip->dev_name; | 818 | indio_dev->name = chip->dev_name; |
| 640 | indio_dev->num_channels = 1; | 819 | indio_dev->num_channels = 2; |
| 641 | 820 | ||
| 642 | ret = devm_mutex_init(dev, &st->lock); | 821 | ret = devm_mutex_init(dev, &st->lock); |
| 643 | if (ret) | 822 | if (ret) |
| @@ -658,7 +837,7 @@ static int ad4000_probe(struct spi_device *spi) · 14 unmodified lines | |||
| 658 | } | 837 | } |
| 659 | } | 838 | } |
| 660 | 839 | ||
| 661 | ad4000_fill_scale_tbl(st, indio_dev->channels); | 840 | ad4000_fill_scale_tbl(st, &indio_dev->channels[0]); |
| 662 | 841 | ||
| 663 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, | 842 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, |
| 664 | &iio_pollfunc_store_time, | 843 | &iio_pollfunc_store_time, |
| @@ -686,6 +865,21 @@ static const struct spi_device_id ad4000_id[] = { · 21 unmodified lines | |||
| 686 | { "ad4022", (kernel_ulong_t)&ad4022_chip_info }, | 865 | { "ad4022", (kernel_ulong_t)&ad4022_chip_info }, |
| 687 | { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info }, | 866 | { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info }, |
| 688 | { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info }, | 867 | { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info }, |
| 868 | { "ad7685", (kernel_ulong_t)&ad7685_chip_info }, | ||
| 869 | { "ad7686", (kernel_ulong_t)&ad7686_chip_info }, | ||
| 870 | { "ad7687", (kernel_ulong_t)&ad7687_chip_info }, | ||
| 871 | { "ad7688", (kernel_ulong_t)&ad7688_chip_info }, | ||
| 872 | { "ad7690", (kernel_ulong_t)&ad7690_chip_info }, | ||
| 873 | { "ad7691", (kernel_ulong_t)&ad7691_chip_info }, | ||
| 874 | { "ad7693", (kernel_ulong_t)&ad7693_chip_info }, | ||
| 875 | { "ad7942", (kernel_ulong_t)&ad7942_chip_info }, | ||
| 876 | { "ad7946", (kernel_ulong_t)&ad7946_chip_info }, | ||
| 877 | { "ad7980", (kernel_ulong_t)&ad7980_chip_info }, | ||
| 878 | { "ad7982", (kernel_ulong_t)&ad7982_chip_info }, | ||
| 879 | { "ad7983", (kernel_ulong_t)&ad7983_chip_info }, | ||
| 880 | { "ad7984", (kernel_ulong_t)&ad7984_chip_info }, | ||
| 881 | { "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info }, | ||
| 882 | { "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info }, | ||
| 689 | { } | 883 | { } |
| 690 | }; | 884 | }; |
| 691 | MODULE_DEVICE_TABLE(spi, ad4000_id); | 885 | MODULE_DEVICE_TABLE(spi, ad4000_id); |
| @@ -707,6 +901,21 @@ static const struct of_device_id ad4000_of_match[] = { · 15 unmodified lines | |||
| 707 | { .compatible = "adi,ad4022", .data = &ad4022_chip_info }, | 901 | { .compatible = "adi,ad4022", .data = &ad4022_chip_info }, |
| 708 | { .compatible = "adi,adaq4001", .data = &adaq4001_chip_info }, | 902 | { .compatible = "adi,adaq4001", .data = &adaq4001_chip_info }, |
| 709 | { .compatible = "adi,adaq4003", .data = &adaq4003_chip_info }, | 903 | { .compatible = "adi,adaq4003", .data = &adaq4003_chip_info }, |
| 904 | { .compatible = "adi,ad7685", .data = &ad7685_chip_info }, | ||
| 905 | { .compatible = "adi,ad7686", .data = &ad7686_chip_info }, | ||
| 906 | { .compatible = "adi,ad7687", .data = &ad7687_chip_info }, | ||
| 907 | { .compatible = "adi,ad7688", .data = &ad7688_chip_info }, | ||
| 908 | { .compatible = "adi,ad7690", .data = &ad7690_chip_info }, | ||
| 909 | { .compatible = "adi,ad7691", .data = &ad7691_chip_info }, | ||
| 910 | { .compatible = "adi,ad7693", .data = &ad7693_chip_info }, | ||
| 911 | { .compatible = "adi,ad7942", .data = &ad7942_chip_info }, | ||
| 912 | { .compatible = "adi,ad7946", .data = &ad7946_chip_info }, | ||
| 913 | { .compatible = "adi,ad7980", .data = &ad7980_chip_info }, | ||
| 914 | { .compatible = "adi,ad7982", .data = &ad7982_chip_info }, | ||
| 915 | { .compatible = "adi,ad7983", .data = &ad7983_chip_info }, | ||
| 916 | { .compatible = "adi,ad7984", .data = &ad7984_chip_info }, | ||
| 917 | { .compatible = "adi,ad7988-1", .data = &ad7988_1_chip_info }, | ||
| 918 | { .compatible = "adi,ad7988-5", .data = &ad7988_5_chip_info }, | ||
| 710 | { } | 919 | { } |
| 711 | }; | 920 | }; |
| 712 | MODULE_DEVICE_TABLE(of, ad4000_of_match); | 921 | MODULE_DEVICE_TABLE(of, ad4000_of_match); |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include <linux/spi/spi.h> | 30 | #include <linux/spi/spi.h> |
| 31 | #include <linux/units.h> | 31 | #include <linux/units.h> |
| 32 | 32 | ||
| 33 | #include <dt-bindings/iio/adi,ad4695.h> | 33 | #include <dt-bindings/iio/adc/adi,ad4695.h> |
| 34 | 34 | ||
| 35 | /* AD4695 registers */ | 35 | /* AD4695 registers */ |
| 36 | #define AD4695_REG_SPI_CONFIG_A 0x0000 | 36 | #define AD4695_REG_SPI_CONFIG_A 0x0000 |
| @@ -95,6 +95,10 @@ · 94 unmodified lines | |||
| 95 | #define AD7124_MAX_CONFIGS 8 | 95 | #define AD7124_MAX_CONFIGS 8 |
| 96 | #define AD7124_MAX_CHANNELS 16 | 96 | #define AD7124_MAX_CHANNELS 16 |
| 97 | 97 | ||
| 98 | /* AD7124 input sources */ | ||
| 99 | #define AD7124_INPUT_TEMPSENSOR 16 | ||
| 100 | #define AD7124_INPUT_AVSS 17 | ||
| 101 | |||
| 98 | enum ad7124_ids { | 102 | enum ad7124_ids { |
| 99 | ID_AD7124_4, | 103 | ID_AD7124_4, |
| 100 | ID_AD7124_8, | 104 | ID_AD7124_8, |
| @@ -360,20 +364,21 @@ static int ad7124_find_free_config_slot(struct ad7124_state *st) · 259 unmodified lines | |||
| 360 | return free_cfg_slot; | 364 | return free_cfg_slot; |
| 361 | } | 365 | } |
| 362 | 366 | ||
| 367 | /* Only called during probe, so dev_err_probe() can be used */ | ||
| 363 | static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg) | 368 | static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg) |
| 364 | { | 369 | { |
| 370 | struct device *dev = &st->sd.spi->dev; | ||
| 365 | unsigned int refsel = cfg->refsel; | 371 | unsigned int refsel = cfg->refsel; |
| 366 | 372 | ||
| 367 | switch (refsel) { | 373 | switch (refsel) { |
| 368 | case AD7124_REFIN1: | 374 | case AD7124_REFIN1: |
| 369 | case AD7124_REFIN2: | 375 | case AD7124_REFIN2: |
| 370 | case AD7124_AVDD_REF: | 376 | case AD7124_AVDD_REF: |
| 371 | if (IS_ERR(st->vref[refsel])) { | 377 | if (IS_ERR(st->vref[refsel])) |
| 372 | dev_err(&st->sd.spi->dev, | 378 | return dev_err_probe(dev, PTR_ERR(st->vref[refsel]), |
| 373 | "Error, trying to use external voltage reference without a %s regulator.\n", | 379 | "Error, trying to use external voltage reference without a %s regulator.\n", |
| 374 | ad7124_ref_names[refsel]); | 380 | ad7124_ref_names[refsel]); |
| 375 | return PTR_ERR(st->vref[refsel]); | 381 | |
| 376 | } | ||
| 377 | cfg->vref_mv = regulator_get_voltage(st->vref[refsel]); | 382 | cfg->vref_mv = regulator_get_voltage(st->vref[refsel]); |
| 378 | /* Conversion from uV to mV */ | 383 | /* Conversion from uV to mV */ |
| 379 | cfg->vref_mv /= 1000; | 384 | cfg->vref_mv /= 1000; |
| @@ -384,8 +389,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe · 4 unmodified lines | |||
| 384 | st->adc_control |= AD7124_ADC_CTRL_REF_EN(1); | 389 | st->adc_control |= AD7124_ADC_CTRL_REF_EN(1); |
| 385 | return 0; | 390 | return 0; |
| 386 | default: | 391 | default: |
| 387 | dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel); | 392 | return dev_err_probe(dev, -EINVAL, "Invalid reference %d\n", refsel); |
| 388 | return -EINVAL; | ||
| 389 | } | 393 | } |
| 390 | } | 394 | } |
| 391 | 395 | ||
| @@ -571,6 +575,7 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { · 179 unmodified lines | |||
| 571 | .data_reg = AD7124_DATA, | 575 | .data_reg = AD7124_DATA, |
| 572 | .num_slots = 8, | 576 | .num_slots = 8, |
| 573 | .irq_flags = IRQF_TRIGGER_FALLING, | 577 | .irq_flags = IRQF_TRIGGER_FALLING, |
| 578 | .num_resetclks = 64, | ||
| 574 | }; | 579 | }; |
| 575 | 580 | ||
| 576 | static int ad7124_read_raw(struct iio_dev *indio_dev, | 581 | static int ad7124_read_raw(struct iio_dev *indio_dev, |
| @@ -588,26 +593,59 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, · 11 unmodified lines | |||
| 588 | 593 | ||
| 589 | return IIO_VAL_INT; | 594 | return IIO_VAL_INT; |
| 590 | case IIO_CHAN_INFO_SCALE: | 595 | case IIO_CHAN_INFO_SCALE: |
| 591 | mutex_lock(&st->cfgs_lock); | 596 | switch (chan->type) { |
| 597 | case IIO_VOLTAGE: | ||
| 598 | mutex_lock(&st->cfgs_lock); | ||
| 592 | 599 | ||
| 593 | idx = st->channels[chan->address].cfg.pga_bits; | 600 | idx = st->channels[chan->address].cfg.pga_bits; |
| 594 | *val = st->channels[chan->address].cfg.vref_mv; | 601 | *val = st->channels[chan->address].cfg.vref_mv; |
| 595 | if (st->channels[chan->address].cfg.bipolar) | 602 | if (st->channels[chan->address].cfg.bipolar) |
| 596 | *val2 = chan->scan_type.realbits - 1 + idx; | 603 | *val2 = chan->scan_type.realbits - 1 + idx; |
| 597 | else | 604 | else |
| 598 | *val2 = chan->scan_type.realbits + idx; | 605 | *val2 = chan->scan_type.realbits + idx; |
| 606 | |||
| 607 | mutex_unlock(&st->cfgs_lock); | ||
| 608 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 609 | |||
| 610 | case IIO_TEMP: | ||
| 611 | /* | ||
| 612 | * According to the data sheet | ||
| 613 | * Temperature (°C) | ||
| 614 | * = ((Conversion − 0x800000)/13584) − 272.5 | ||
| 615 | * = (Conversion − 0x800000 - 13584 * 272.5) / 13584 | ||
| 616 | * = (Conversion − 12090248) / 13584 | ||
| 617 | * So scale with 1000/13584 to yield °mC. Reduce by 8 to | ||
| 618 | * 125/1698. | ||
| 619 | */ | ||
| 620 | *val = 125; | ||
| 621 | *val2 = 1698; | ||
| 622 | return IIO_VAL_FRACTIONAL; | ||
| 623 | |||
| 624 | default: | ||
| 625 | return -EINVAL; | ||
| 626 | } | ||
| 599 | 627 | ||
| 600 | mutex_unlock(&st->cfgs_lock); | ||
| 601 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 602 | case IIO_CHAN_INFO_OFFSET: | 628 | case IIO_CHAN_INFO_OFFSET: |
| 603 | mutex_lock(&st->cfgs_lock); | 629 | switch (chan->type) { |
| 604 | if (st->channels[chan->address].cfg.bipolar) | 630 | case IIO_VOLTAGE: |
| 605 | *val = -(1 << (chan->scan_type.realbits - 1)); | 631 | mutex_lock(&st->cfgs_lock); |
| 606 | else | 632 | if (st->channels[chan->address].cfg.bipolar) |
| 607 | *val = 0; | 633 | *val = -(1 << (chan->scan_type.realbits - 1)); |
| 634 | else | ||
| 635 | *val = 0; | ||
| 636 | |||
| 637 | mutex_unlock(&st->cfgs_lock); | ||
| 638 | return IIO_VAL_INT; | ||
| 639 | |||
| 640 | case IIO_TEMP: | ||
| 641 | /* see calculation above */ | ||
| 642 | *val = -12090248; | ||
| 643 | return IIO_VAL_INT; | ||
| 644 | |||
| 645 | default: | ||
| 646 | return -EINVAL; | ||
| 647 | } | ||
| 608 | 648 | ||
| 609 | mutex_unlock(&st->cfgs_lock); | ||
| 610 | return IIO_VAL_INT; | ||
| 611 | case IIO_CHAN_INFO_SAMP_FREQ: | 649 | case IIO_CHAN_INFO_SAMP_FREQ: |
| 612 | mutex_lock(&st->cfgs_lock); | 650 | mutex_lock(&st->cfgs_lock); |
| 613 | *val = st->channels[chan->address].cfg.odr; | 651 | *val = st->channels[chan->address].cfg.odr; |
| @@ -751,12 +789,14 @@ static const struct iio_info ad7124_info = { · 137 unmodified lines | |||
| 751 | .attrs = &ad7124_attrs_group, | 789 | .attrs = &ad7124_attrs_group, |
| 752 | }; | 790 | }; |
| 753 | 791 | ||
| 792 | /* Only called during probe, so dev_err_probe() can be used */ | ||
| 754 | static int ad7124_soft_reset(struct ad7124_state *st) | 793 | static int ad7124_soft_reset(struct ad7124_state *st) |
| 755 | { | 794 | { |
| 795 | struct device *dev = &st->sd.spi->dev; | ||
| 756 | unsigned int readval, timeout; | 796 | unsigned int readval, timeout; |
| 757 | int ret; | 797 | int ret; |
| 758 | 798 | ||
| 759 | ret = ad_sd_reset(&st->sd, 64); | 799 | ret = ad_sd_reset(&st->sd); |
| 760 | if (ret < 0) | 800 | if (ret < 0) |
| 761 | return ret; | 801 | return ret; |
| 762 | 802 | ||
| @@ -765,7 +805,7 @@ static int ad7124_soft_reset(struct ad7124_state *st) · 2 unmodified lines | |||
| 765 | do { | 805 | do { |
| 766 | ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval); | 806 | ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval); |
| 767 | if (ret < 0) | 807 | if (ret < 0) |
| 768 | return ret; | 808 | return dev_err_probe(dev, ret, "Error reading status register\n"); |
| 769 | 809 | ||
| 770 | if (!(readval & AD7124_STATUS_POR_FLAG_MSK)) | 810 | if (!(readval & AD7124_STATUS_POR_FLAG_MSK)) |
| 771 | return 0; | 811 | return 0; |
| @@ -774,39 +814,47 @@ static int ad7124_soft_reset(struct ad7124_state *st) · 2 unmodified lines | |||
| 774 | usleep_range(100, 2000); | 814 | usleep_range(100, 2000); |
| 775 | } while (--timeout); | 815 | } while (--timeout); |
| 776 | 816 | ||
| 777 | dev_err(&st->sd.spi->dev, "Soft reset failed\n"); | 817 | return dev_err_probe(dev, -EIO, "Soft reset failed\n"); |
| 778 | |||
| 779 | return -EIO; | ||
| 780 | } | 818 | } |
| 781 | 819 | ||
| 782 | static int ad7124_check_chip_id(struct ad7124_state *st) | 820 | static int ad7124_check_chip_id(struct ad7124_state *st) |
| 783 | { | 821 | { |
| 822 | struct device *dev = &st->sd.spi->dev; | ||
| 784 | unsigned int readval, chip_id, silicon_rev; | 823 | unsigned int readval, chip_id, silicon_rev; |
| 785 | int ret; | 824 | int ret; |
| 786 | 825 | ||
| 787 | ret = ad_sd_read_reg(&st->sd, AD7124_ID, 1, &readval); | 826 | ret = ad_sd_read_reg(&st->sd, AD7124_ID, 1, &readval); |
| 788 | if (ret < 0) | 827 | if (ret < 0) |
| 789 | return ret; | 828 | return dev_err_probe(dev, ret, "Failure to read ID register\n"); |
| 790 | 829 | ||
| 791 | chip_id = AD7124_DEVICE_ID_GET(readval); | 830 | chip_id = AD7124_DEVICE_ID_GET(readval); |
| 792 | silicon_rev = AD7124_SILICON_REV_GET(readval); | 831 | silicon_rev = AD7124_SILICON_REV_GET(readval); |
| 793 | 832 | ||
| 794 | if (chip_id != st->chip_info->chip_id) { | 833 | if (chip_id != st->chip_info->chip_id) |
| 795 | dev_err(&st->sd.spi->dev, | 834 | return dev_err_probe(dev, -ENODEV, |
| 796 | "Chip ID mismatch: expected %u, got %u\n", | 835 | "Chip ID mismatch: expected %u, got %u\n", |
| 797 | st->chip_info->chip_id, chip_id); | 836 | st->chip_info->chip_id, chip_id); |
| 798 | return -ENODEV; | ||
| 799 | } | ||
| 800 | 837 | ||
| 801 | if (silicon_rev == 0) { | 838 | if (silicon_rev == 0) |
| 802 | dev_err(&st->sd.spi->dev, | 839 | return dev_err_probe(dev, -ENODEV, |
| 803 | "Silicon revision empty. Chip may not be present\n"); | 840 | "Silicon revision empty. Chip may not be present\n"); |
| 804 | return -ENODEV; | ||
| 805 | } | ||
| 806 | 841 | ||
| 807 | return 0; | 842 | return 0; |
| 808 | } | 843 | } |
| 809 | 844 | ||
| 845 | /* | ||
| 846 | * Input specifiers 8 - 15 are explicitly reserved for ad7124-4 | ||
| 847 | * while they are fine for ad7124-8. Values above 31 don't fit | ||
| 848 | * into the register field and so are invalid for sure. | ||
| 849 | */ | ||
| 850 | static bool ad7124_valid_input_select(unsigned int ain, const struct ad7124_chip_info *info) | ||
| 851 | { | ||
| 852 | if (ain >= info->num_inputs && ain < 16) | ||
| 853 | return false; | ||
| 854 | |||
| 855 | return ain <= FIELD_MAX(AD7124_CHANNEL_AINM_MSK); | ||
| 856 | } | ||
| 857 | |||
| 810 | static int ad7124_parse_channel_config(struct iio_dev *indio_dev, | 858 | static int ad7124_parse_channel_config(struct iio_dev *indio_dev, |
| 811 | struct device *dev) | 859 | struct device *dev) |
| 812 | { | 860 | { |
| @@ -815,11 +863,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 815 | struct ad7124_channel *channels; | 863 | struct ad7124_channel *channels; |
| 816 | struct iio_chan_spec *chan; | 864 | struct iio_chan_spec *chan; |
| 817 | unsigned int ain[2], channel = 0, tmp; | 865 | unsigned int ain[2], channel = 0, tmp; |
| 866 | unsigned int num_channels; | ||
| 818 | int ret; | 867 | int ret; |
| 819 | 868 | ||
| 820 | st->num_channels = device_get_child_node_count(dev); | 869 | num_channels = device_get_child_node_count(dev); |
| 821 | if (!st->num_channels) | 870 | |
| 822 | return dev_err_probe(dev, -ENODEV, "no channel children\n"); | 871 | /* |
| 872 | * The driver assigns each logical channel defined in the device tree | ||
| 873 | * statically one channel register. So only accept 16 such logical | ||
| 874 | * channels to not treat CONFIG_0 (i.e. the register following | ||
| 875 | * CHANNEL_15) as an additional channel register. The driver could be | ||
| 876 | * improved to lift this limitation. | ||
| 877 | */ | ||
| 878 | if (num_channels > AD7124_MAX_CHANNELS) | ||
| 879 | return dev_err_probe(dev, -EINVAL, "Too many channels defined\n"); | ||
| 880 | |||
| 881 | /* Add one for temperature */ | ||
| 882 | st->num_channels = min(num_channels + 1, AD7124_MAX_CHANNELS); | ||
| 823 | 883 | ||
| 824 | chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels, | 884 | chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels, |
| 825 | sizeof(*chan), GFP_KERNEL); | 885 | sizeof(*chan), GFP_KERNEL); |
| @@ -838,16 +898,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, · 12 unmodified lines | |||
| 838 | device_for_each_child_node_scoped(dev, child) { | 898 | device_for_each_child_node_scoped(dev, child) { |
| 839 | ret = fwnode_property_read_u32(child, "reg", &channel); | 899 | ret = fwnode_property_read_u32(child, "reg", &channel); |
| 840 | if (ret) | 900 | if (ret) |
| 841 | return ret; | 901 | return dev_err_probe(dev, ret, |
| 902 | "Failed to parse reg property of %pfwP\n", child); | ||
| 842 | 903 | ||
| 843 | if (channel >= indio_dev->num_channels) | 904 | if (channel >= num_channels) |
| 844 | return dev_err_probe(dev, -EINVAL, | 905 | return dev_err_probe(dev, -EINVAL, |
| 845 | "Channel index >= number of channels\n"); | 906 | "Channel index >= number of channels in %pfwP\n", child); |
| 846 | 907 | ||
| 847 | ret = fwnode_property_read_u32_array(child, "diff-channels", | 908 | ret = fwnode_property_read_u32_array(child, "diff-channels", |
| 848 | ain, 2); | 909 | ain, 2); |
| 849 | if (ret) | 910 | if (ret) |
| 850 | return ret; | 911 | return dev_err_probe(dev, ret, |
| 912 | "Failed to parse diff-channels property of %pfwP\n", child); | ||
| 913 | |||
| 914 | if (!ad7124_valid_input_select(ain[0], st->chip_info) || | ||
| 915 | !ad7124_valid_input_select(ain[1], st->chip_info)) | ||
| 916 | return dev_err_probe(dev, -EINVAL, | ||
| 917 | "diff-channels property of %pfwP contains invalid data\n", child); | ||
| 851 | 918 | ||
| 852 | st->channels[channel].nr = channel; | 919 | st->channels[channel].nr = channel; |
| 853 | st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | | 920 | st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | |
| @@ -874,17 +941,49 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, · 20 unmodified lines | |||
| 874 | chan[channel].channel2 = ain[1]; | 941 | chan[channel].channel2 = ain[1]; |
| 875 | } | 942 | } |
| 876 | 943 | ||
| 944 | if (num_channels < AD7124_MAX_CHANNELS) { | ||
| 945 | st->channels[num_channels] = (struct ad7124_channel) { | ||
| 946 | .nr = num_channels, | ||
| 947 | .ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) | | ||
| 948 | AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS), | ||
| 949 | .cfg = { | ||
| 950 | .bipolar = true, | ||
| 951 | }, | ||
| 952 | }; | ||
| 953 | |||
| 954 | chan[num_channels] = (struct iio_chan_spec) { | ||
| 955 | .type = IIO_TEMP, | ||
| 956 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 957 | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) | | ||
| 958 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 959 | .scan_type = { | ||
| 960 | /* | ||
| 961 | * You might find it strange that a bipolar | ||
| 962 | * measurement yields an unsigned value, but | ||
| 963 | * this matches the device's manual. | ||
| 964 | */ | ||
| 965 | .sign = 'u', | ||
| 966 | .realbits = 24, | ||
| 967 | .storagebits = 32, | ||
| 968 | .endianness = IIO_BE, | ||
| 969 | }, | ||
| 970 | .address = num_channels, | ||
| 971 | .scan_index = num_channels, | ||
| 972 | }; | ||
| 973 | } | ||
| 974 | |||
| 877 | return 0; | 975 | return 0; |
| 878 | } | 976 | } |
| 879 | 977 | ||
| 880 | static int ad7124_setup(struct ad7124_state *st) | 978 | static int ad7124_setup(struct ad7124_state *st) |
| 881 | { | 979 | { |
| 980 | struct device *dev = &st->sd.spi->dev; | ||
| 882 | unsigned int fclk, power_mode; | 981 | unsigned int fclk, power_mode; |
| 883 | int i, ret; | 982 | int i, ret; |
| 884 | 983 | ||
| 885 | fclk = clk_get_rate(st->mclk); | 984 | fclk = clk_get_rate(st->mclk); |
| 886 | if (!fclk) | 985 | if (!fclk) |
| 887 | return -EINVAL; | 986 | return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n"); |
| 888 | 987 | ||
| 889 | /* The power mode changes the master clock frequency */ | 988 | /* The power mode changes the master clock frequency */ |
| 890 | power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz, | 989 | power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz, |
| @@ -893,7 +992,7 @@ static int ad7124_setup(struct ad7124_state *st) · 2 unmodified lines | |||
| 893 | if (fclk != ad7124_master_clk_freq_hz[power_mode]) { | 992 | if (fclk != ad7124_master_clk_freq_hz[power_mode]) { |
| 894 | ret = clk_set_rate(st->mclk, fclk); | 993 | ret = clk_set_rate(st->mclk, fclk); |
| 895 | if (ret) | 994 | if (ret) |
| 896 | return ret; | 995 | return dev_err_probe(dev, ret, "Failed to set mclk rate\n"); |
| 897 | } | 996 | } |
| 898 | 997 | ||
| 899 | /* Set the power mode */ | 998 | /* Set the power mode */ |
| @@ -924,7 +1023,7 @@ static int ad7124_setup(struct ad7124_state *st) · 24 unmodified lines | |||
| 924 | 1023 | ||
| 925 | ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); | 1024 | ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); |
| 926 | if (ret < 0) | 1025 | if (ret < 0) |
| 927 | return ret; | 1026 | return dev_err_probe(dev, ret, "Failed to setup CONTROL register\n"); |
| 928 | 1027 | ||
| 929 | return ret; | 1028 | return ret; |
| 930 | } | 1029 | } |
| @@ -937,13 +1036,14 @@ static void ad7124_reg_disable(void *r) · 6 unmodified lines | |||
| 937 | static int ad7124_probe(struct spi_device *spi) | 1036 | static int ad7124_probe(struct spi_device *spi) |
| 938 | { | 1037 | { |
| 939 | const struct ad7124_chip_info *info; | 1038 | const struct ad7124_chip_info *info; |
| 1039 | struct device *dev = &spi->dev; | ||
| 940 | struct ad7124_state *st; | 1040 | struct ad7124_state *st; |
| 941 | struct iio_dev *indio_dev; | 1041 | struct iio_dev *indio_dev; |
| 942 | int i, ret; | 1042 | int i, ret; |
| 943 | 1043 | ||
| 944 | info = spi_get_device_match_data(spi); | 1044 | info = spi_get_device_match_data(spi); |
| 945 | if (!info) | 1045 | if (!info) |
| 946 | return -ENODEV; | 1046 | return dev_err_probe(dev, -ENODEV, "Failed to get match data\n"); |
| 947 | 1047 | ||
| 948 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | 1048 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
| 949 | if (!indio_dev) | 1049 | if (!indio_dev) |
| @@ -978,17 +1078,17 @@ static int ad7124_probe(struct spi_device *spi) · 28 unmodified lines | |||
| 978 | 1078 | ||
| 979 | ret = regulator_enable(st->vref[i]); | 1079 | ret = regulator_enable(st->vref[i]); |
| 980 | if (ret) | 1080 | if (ret) |
| 981 | return ret; | 1081 | return dev_err_probe(dev, ret, "Failed to enable regulator #%d\n", i); |
| 982 | 1082 | ||
| 983 | ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable, | 1083 | ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable, |
| 984 | st->vref[i]); | 1084 | st->vref[i]); |
| 985 | if (ret) | 1085 | if (ret) |
| 986 | return ret; | 1086 | return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i); |
| 987 | } | 1087 | } |
| 988 | 1088 | ||
| 989 | st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); | 1089 | st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); |
| 990 | if (IS_ERR(st->mclk)) | 1090 | if (IS_ERR(st->mclk)) |
| 991 | return PTR_ERR(st->mclk); | 1091 | return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n"); |
| 992 | 1092 | ||
| 993 | ret = ad7124_soft_reset(st); | 1093 | ret = ad7124_soft_reset(st); |
| 994 | if (ret < 0) | 1094 | if (ret < 0) |
| @@ -1004,10 +1104,13 @@ static int ad7124_probe(struct spi_device *spi) · 9 unmodified lines | |||
| 1004 | 1104 | ||
| 1005 | ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); | 1105 | ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); |
| 1006 | if (ret < 0) | 1106 | if (ret < 0) |
| 1007 | return ret; | 1107 | return dev_err_probe(dev, ret, "Failed to setup triggers\n"); |
| 1008 | 1108 | ||
| 1009 | return devm_iio_device_register(&spi->dev, indio_dev); | 1109 | ret = devm_iio_device_register(&spi->dev, indio_dev); |
| 1110 | if (ret < 0) | ||
| 1111 | return dev_err_probe(dev, ret, "Failed to register iio device\n"); | ||
| 1010 | 1112 | ||
| 1113 | return 0; | ||
| 1011 | } | 1114 | } |
| 1012 | 1115 | ||
| 1013 | static const struct of_device_id ad7124_of_match[] = { | 1116 | static const struct of_device_id ad7124_of_match[] = { |
| @@ -150,6 +150,11 @@ · 149 unmodified lines | |||
| 150 | #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) | 150 | #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) |
| 151 | #define AD7173_MAX_CONFIGS 8 | 151 | #define AD7173_MAX_CONFIGS 8 |
| 152 | 152 | ||
| 153 | #define AD7173_MODE_CAL_INT_ZERO 0x4 /* Internal Zero-Scale Calibration */ | ||
| 154 | #define AD7173_MODE_CAL_INT_FULL 0x5 /* Internal Full-Scale Calibration */ | ||
| 155 | #define AD7173_MODE_CAL_SYS_ZERO 0x6 /* System Zero-Scale Calibration */ | ||
| 156 | #define AD7173_MODE_CAL_SYS_FULL 0x7 /* System Full-Scale Calibration */ | ||
| 157 | |||
| 153 | struct ad7173_device_info { | 158 | struct ad7173_device_info { |
| 154 | const unsigned int *sinc5_data_rates; | 159 | const unsigned int *sinc5_data_rates; |
| 155 | unsigned int num_sinc5_data_rates; | 160 | unsigned int num_sinc5_data_rates; |
| @@ -175,6 +180,7 @@ struct ad7173_device_info { · 19 unmodified lines | |||
| 175 | bool has_input_buf; | 180 | bool has_input_buf; |
| 176 | bool has_int_ref; | 181 | bool has_int_ref; |
| 177 | bool has_ref2; | 182 | bool has_ref2; |
| 183 | bool has_internal_fs_calibration; | ||
| 178 | bool higher_gpio_bits; | 184 | bool higher_gpio_bits; |
| 179 | u8 num_gpios; | 185 | u8 num_gpios; |
| 180 | }; | 186 | }; |
| @@ -193,9 +199,9 @@ struct ad7173_channel_config { · 12 unmodified lines | |||
| 193 | }; | 199 | }; |
| 194 | 200 | ||
| 195 | struct ad7173_channel { | 201 | struct ad7173_channel { |
| 196 | unsigned int chan_reg; | ||
| 197 | unsigned int ain; | 202 | unsigned int ain; |
| 198 | struct ad7173_channel_config cfg; | 203 | struct ad7173_channel_config cfg; |
| 204 | u8 syscalib_mode; | ||
| 199 | }; | 205 | }; |
| 200 | 206 | ||
| 201 | struct ad7173_state { | 207 | struct ad7173_state { |
| @@ -273,6 +279,7 @@ static const struct ad7173_device_info ad4111_device_info = { · 71 unmodified lines | |||
| 273 | .has_input_buf = true, | 279 | .has_input_buf = true, |
| 274 | .has_current_inputs = true, | 280 | .has_current_inputs = true, |
| 275 | .has_int_ref = true, | 281 | .has_int_ref = true, |
| 282 | .has_internal_fs_calibration = true, | ||
| 276 | .clock = 2 * HZ_PER_MHZ, | 283 | .clock = 2 * HZ_PER_MHZ, |
| 277 | .sinc5_data_rates = ad7173_sinc5_data_rates, | 284 | .sinc5_data_rates = ad7173_sinc5_data_rates, |
| 278 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), | 285 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), |
| @@ -292,6 +299,7 @@ static const struct ad7173_device_info ad4112_device_info = { · 13 unmodified lines | |||
| 292 | .has_input_buf = true, | 299 | .has_input_buf = true, |
| 293 | .has_current_inputs = true, | 300 | .has_current_inputs = true, |
| 294 | .has_int_ref = true, | 301 | .has_int_ref = true, |
| 302 | .has_internal_fs_calibration = true, | ||
| 295 | .clock = 2 * HZ_PER_MHZ, | 303 | .clock = 2 * HZ_PER_MHZ, |
| 296 | .sinc5_data_rates = ad7173_sinc5_data_rates, | 304 | .sinc5_data_rates = ad7173_sinc5_data_rates, |
| 297 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), | 305 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), |
| @@ -327,6 +335,7 @@ static const struct ad7173_device_info ad4114_device_info = { · 29 unmodified lines | |||
| 327 | .has_temp = true, | 335 | .has_temp = true, |
| 328 | .has_input_buf = true, | 336 | .has_input_buf = true, |
| 329 | .has_int_ref = true, | 337 | .has_int_ref = true, |
| 338 | .has_internal_fs_calibration = true, | ||
| 330 | .clock = 2 * HZ_PER_MHZ, | 339 | .clock = 2 * HZ_PER_MHZ, |
| 331 | .sinc5_data_rates = ad7173_sinc5_data_rates, | 340 | .sinc5_data_rates = ad7173_sinc5_data_rates, |
| 332 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), | 341 | .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), |
| @@ -344,6 +353,7 @@ static const struct ad7173_device_info ad4115_device_info = { · 11 unmodified lines | |||
| 344 | .has_temp = true, | 353 | .has_temp = true, |
| 345 | .has_input_buf = true, | 354 | .has_input_buf = true, |
| 346 | .has_int_ref = true, | 355 | .has_int_ref = true, |
| 356 | .has_internal_fs_calibration = true, | ||
| 347 | .clock = 8 * HZ_PER_MHZ, | 357 | .clock = 8 * HZ_PER_MHZ, |
| 348 | .sinc5_data_rates = ad4115_sinc5_data_rates, | 358 | .sinc5_data_rates = ad4115_sinc5_data_rates, |
| 349 | .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates), | 359 | .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates), |
| @@ -361,6 +371,7 @@ static const struct ad7173_device_info ad4116_device_info = { · 11 unmodified lines | |||
| 361 | .has_temp = true, | 371 | .has_temp = true, |
| 362 | .has_input_buf = true, | 372 | .has_input_buf = true, |
| 363 | .has_int_ref = true, | 373 | .has_int_ref = true, |
| 374 | .has_internal_fs_calibration = true, | ||
| 364 | .clock = 4 * HZ_PER_MHZ, | 375 | .clock = 4 * HZ_PER_MHZ, |
| 365 | .sinc5_data_rates = ad4116_sinc5_data_rates, | 376 | .sinc5_data_rates = ad4116_sinc5_data_rates, |
| 366 | .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates), | 377 | .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates), |
| @@ -506,6 +517,105 @@ static const struct regmap_config ad7173_regmap_config = { · 139 unmodified lines | |||
| 506 | .read_flag_mask = BIT(6), | 517 | .read_flag_mask = BIT(6), |
| 507 | }; | 518 | }; |
| 508 | 519 | ||
| 520 | enum { | ||
| 521 | AD7173_SYSCALIB_ZERO_SCALE, | ||
| 522 | AD7173_SYSCALIB_FULL_SCALE, | ||
| 523 | }; | ||
| 524 | |||
| 525 | static const char * const ad7173_syscalib_modes[] = { | ||
| 526 | [AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale", | ||
| 527 | [AD7173_SYSCALIB_FULL_SCALE] = "full_scale", | ||
| 528 | }; | ||
| 529 | |||
| 530 | static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev, | ||
| 531 | const struct iio_chan_spec *chan, | ||
| 532 | unsigned int mode) | ||
| 533 | { | ||
| 534 | struct ad7173_state *st = iio_priv(indio_dev); | ||
| 535 | |||
| 536 | st->channels[chan->channel].syscalib_mode = mode; | ||
| 537 | |||
| 538 | return 0; | ||
| 539 | } | ||
| 540 | |||
| 541 | static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev, | ||
| 542 | const struct iio_chan_spec *chan) | ||
| 543 | { | ||
| 544 | struct ad7173_state *st = iio_priv(indio_dev); | ||
| 545 | |||
| 546 | return st->channels[chan->channel].syscalib_mode; | ||
| 547 | } | ||
| 548 | |||
| 549 | static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev, | ||
| 550 | uintptr_t private, | ||
| 551 | const struct iio_chan_spec *chan, | ||
| 552 | const char *buf, size_t len) | ||
| 553 | { | ||
| 554 | struct ad7173_state *st = iio_priv(indio_dev); | ||
| 555 | bool sys_calib; | ||
| 556 | int ret, mode; | ||
| 557 | |||
| 558 | ret = kstrtobool(buf, &sys_calib); | ||
| 559 | if (ret) | ||
| 560 | return ret; | ||
| 561 | |||
| 562 | mode = st->channels[chan->channel].syscalib_mode; | ||
| 563 | if (sys_calib) { | ||
| 564 | if (mode == AD7173_SYSCALIB_ZERO_SCALE) | ||
| 565 | ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO, | ||
| 566 | chan->address); | ||
| 567 | else | ||
| 568 | ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL, | ||
| 569 | chan->address); | ||
| 570 | } | ||
| 571 | |||
| 572 | return ret ? : len; | ||
| 573 | } | ||
| 574 | |||
| 575 | static const struct iio_enum ad7173_syscalib_mode_enum = { | ||
| 576 | .items = ad7173_syscalib_modes, | ||
| 577 | .num_items = ARRAY_SIZE(ad7173_syscalib_modes), | ||
| 578 | .set = ad7173_set_syscalib_mode, | ||
| 579 | .get = ad7173_get_syscalib_mode | ||
| 580 | }; | ||
| 581 | |||
| 582 | static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = { | ||
| 583 | { | ||
| 584 | .name = "sys_calibration", | ||
| 585 | .write = ad7173_write_syscalib, | ||
| 586 | .shared = IIO_SEPARATE, | ||
| 587 | }, | ||
| 588 | IIO_ENUM("sys_calibration_mode", IIO_SEPARATE, | ||
| 589 | &ad7173_syscalib_mode_enum), | ||
| 590 | IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE, | ||
| 591 | &ad7173_syscalib_mode_enum), | ||
| 592 | { } | ||
| 593 | }; | ||
| 594 | |||
| 595 | static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev) | ||
| 596 | { | ||
| 597 | int ret; | ||
| 598 | int i; | ||
| 599 | |||
| 600 | for (i = 0; i < st->num_channels; i++) { | ||
| 601 | if (indio_dev->channels[i].type != IIO_VOLTAGE) | ||
| 602 | continue; | ||
| 603 | |||
| 604 | ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain); | ||
| 605 | if (ret < 0) | ||
| 606 | return ret; | ||
| 607 | |||
| 608 | if (st->info->has_internal_fs_calibration) { | ||
| 609 | ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL, | ||
| 610 | st->channels[i].ain); | ||
| 611 | if (ret < 0) | ||
| 612 | return ret; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 509 | static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, | 619 | static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, |
| 510 | unsigned int offset, unsigned int *reg, | 620 | unsigned int offset, unsigned int *reg, |
| 511 | unsigned int *mask) | 621 | unsigned int *mask) |
| @@ -765,6 +875,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info = { · 253 unmodified lines | |||
| 765 | .read_mask = BIT(6), | 875 | .read_mask = BIT(6), |
| 766 | .status_ch_mask = GENMASK(3, 0), | 876 | .status_ch_mask = GENMASK(3, 0), |
| 767 | .data_reg = AD7173_REG_DATA, | 877 | .data_reg = AD7173_REG_DATA, |
| 878 | .num_resetclks = 64, | ||
| 768 | }; | 879 | }; |
| 769 | 880 | ||
| 770 | static int ad7173_setup(struct iio_dev *indio_dev) | 881 | static int ad7173_setup(struct iio_dev *indio_dev) |
| @@ -802,6 +913,10 @@ static int ad7173_setup(struct iio_dev *indio_dev) · 31 unmodified lines | |||
| 802 | if (!st->config_cnts) | 913 | if (!st->config_cnts) |
| 803 | return -ENOMEM; | 914 | return -ENOMEM; |
| 804 | 915 | ||
| 916 | ret = ad7173_calibrate_all(st, indio_dev); | ||
| 917 | if (ret) | ||
| 918 | return ret; | ||
| 919 | |||
| 805 | /* All channels are enabled by default after a reset */ | 920 | /* All channels are enabled by default after a reset */ |
| 806 | return ad7173_disable_all(&st->sd); | 921 | return ad7173_disable_all(&st->sd); |
| 807 | } | 922 | } |
| @@ -1024,6 +1139,7 @@ static const struct iio_chan_spec ad7173_channel_template = { · 216 unmodified lines | |||
| 1024 | .storagebits = 32, | 1139 | .storagebits = 32, |
| 1025 | .endianness = IIO_BE, | 1140 | .endianness = IIO_BE, |
| 1026 | }, | 1141 | }, |
| 1142 | .ext_info = ad7173_calibsys_ext_info, | ||
| 1027 | }; | 1143 | }; |
| 1028 | 1144 | ||
| 1029 | static const struct iio_chan_spec ad7173_temp_iio_channel_template = { | 1145 | static const struct iio_chan_spec ad7173_temp_iio_channel_template = { |
| @@ -1317,7 +1433,6 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) · 287 unmodified lines | |||
| 1317 | chan->address = chan_index; | 1433 | chan->address = chan_index; |
| 1318 | chan->scan_index = chan_index; | 1434 | chan->scan_index = chan_index; |
| 1319 | chan->channel = ain[0]; | 1435 | chan->channel = ain[0]; |
| 1320 | chan_st_priv->chan_reg = chan_index; | ||
| 1321 | chan_st_priv->cfg.input_buf = st->info->has_input_buf; | 1436 | chan_st_priv->cfg.input_buf = st->info->has_input_buf; |
| 1322 | chan_st_priv->cfg.odr = 0; | 1437 | chan_st_priv->cfg.odr = 0; |
| 1323 | 1438 | ||
| @@ -361,6 +361,7 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = { · 360 unmodified lines | |||
| 361 | .status_ch_mask = GENMASK(3, 0), | 361 | .status_ch_mask = GENMASK(3, 0), |
| 362 | .num_slots = 4, | 362 | .num_slots = 4, |
| 363 | .irq_flags = IRQF_TRIGGER_FALLING, | 363 | .irq_flags = IRQF_TRIGGER_FALLING, |
| 364 | .num_resetclks = 40, | ||
| 364 | }; | 365 | }; |
| 365 | 366 | ||
| 366 | static const struct ad_sigma_delta_info ad7194_sigma_delta_info = { | 367 | static const struct ad_sigma_delta_info ad7194_sigma_delta_info = { |
| @@ -373,6 +374,7 @@ static const struct ad_sigma_delta_info ad7194_sigma_delta_info = { · 6 unmodified lines | |||
| 373 | .read_mask = BIT(6), | 374 | .read_mask = BIT(6), |
| 374 | .status_ch_mask = GENMASK(3, 0), | 375 | .status_ch_mask = GENMASK(3, 0), |
| 375 | .irq_flags = IRQF_TRIGGER_FALLING, | 376 | .irq_flags = IRQF_TRIGGER_FALLING, |
| 377 | .num_resetclks = 40, | ||
| 376 | }; | 378 | }; |
| 377 | 379 | ||
| 378 | static const struct ad_sd_calib_data ad7192_calib_arr[8] = { | 380 | static const struct ad_sd_calib_data ad7192_calib_arr[8] = { |
| @@ -565,7 +567,7 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev) · 186 unmodified lines | |||
| 565 | int i, ret, id; | 567 | int i, ret, id; |
| 566 | 568 | ||
| 567 | /* reset the serial interface */ | 569 | /* reset the serial interface */ |
| 568 | ret = ad_sd_reset(&st->sd, 48); | 570 | ret = ad_sd_reset(&st->sd); |
| 569 | if (ret < 0) | 571 | if (ret < 0) |
| 570 | return ret; | 572 | return ret; |
| 571 | usleep_range(500, 1000); /* Wait for at least 500us */ | 573 | usleep_range(500, 1000); /* Wait for at least 500us */ |
| @@ -175,17 +175,17 @@ static const struct iio_chan_spec ad7616_channels[] = { · 174 unmodified lines | |||
| 175 | AD7606_CHANNEL(15, 16), | 175 | AD7606_CHANNEL(15, 16), |
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, | 178 | static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 179 | struct iio_chan_spec *chan, int ch); | 179 | struct iio_chan_spec *chan, int ch); |
| 180 | static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, | 180 | static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 181 | struct iio_chan_spec *chan, int ch); | 181 | struct iio_chan_spec *chan, int ch); |
| 182 | static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, | 182 | static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 183 | struct iio_chan_spec *chan, int ch); | 183 | struct iio_chan_spec *chan, int ch); |
| 184 | static int ad7607_chan_scale_setup(struct ad7606_state *st, | 184 | static int ad7607_chan_scale_setup(struct iio_dev *indio_dev, |
| 185 | struct iio_chan_spec *chan, int ch); | 185 | struct iio_chan_spec *chan, int ch); |
| 186 | static int ad7608_chan_scale_setup(struct ad7606_state *st, | 186 | static int ad7608_chan_scale_setup(struct iio_dev *indio_dev, |
| 187 | struct iio_chan_spec *chan, int ch); | 187 | struct iio_chan_spec *chan, int ch); |
| 188 | static int ad7609_chan_scale_setup(struct ad7606_state *st, | 188 | static int ad7609_chan_scale_setup(struct iio_dev *indio_dev, |
| 189 | struct iio_chan_spec *chan, int ch); | 189 | struct iio_chan_spec *chan, int ch); |
| 190 | 190 | ||
| 191 | const struct ad7606_chip_info ad7605_4_info = { | 191 | const struct ad7606_chip_info ad7605_4_info = { |
| @@ -323,9 +323,10 @@ int ad7606_reset(struct ad7606_state *st) · 131 unmodified lines | |||
| 323 | } | 323 | } |
| 324 | EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606"); | 324 | EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606"); |
| 325 | 325 | ||
| 326 | static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, | 326 | static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 327 | struct iio_chan_spec *chan, int ch) | 327 | struct iio_chan_spec *chan, int ch) |
| 328 | { | 328 | { |
| 329 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 329 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 330 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 330 | 331 | ||
| 331 | if (!st->sw_mode_en) { | 332 | if (!st->sw_mode_en) { |
| @@ -345,10 +346,12 @@ static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, · 13 unmodified lines | |||
| 345 | return 0; | 346 | return 0; |
| 346 | } | 347 | } |
| 347 | 348 | ||
| 348 | static int ad7606_get_chan_config(struct ad7606_state *st, int ch, | 349 | static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch, |
| 349 | bool *bipolar, bool *differential) | 350 | bool *bipolar, bool *differential) |
| 350 | { | 351 | { |
| 351 | unsigned int num_channels = st->chip_info->num_channels - 1; | 352 | struct ad7606_state *st = iio_priv(indio_dev); |
| 353 | unsigned int num_channels = st->chip_info->num_adc_channels; | ||
| 354 | unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels; | ||
| 352 | struct device *dev = st->dev; | 355 | struct device *dev = st->dev; |
| 353 | int ret; | 356 | int ret; |
| 354 | 357 | ||
| @@ -364,7 +367,7 @@ static int ad7606_get_chan_config(struct ad7606_state *st, int ch, · 9 unmodified lines | |||
| 364 | continue; | 367 | continue; |
| 365 | 368 | ||
| 366 | /* channel number (here) is from 1 to num_channels */ | 369 | /* channel number (here) is from 1 to num_channels */ |
| 367 | if (reg == 0 || reg > num_channels) { | 370 | if (reg < offset || reg > num_channels) { |
| 368 | dev_warn(dev, | 371 | dev_warn(dev, |
| 369 | "Invalid channel number (ignoring): %d\n", reg); | 372 | "Invalid channel number (ignoring): %d\n", reg); |
| 370 | continue; | 373 | continue; |
| @@ -399,9 +402,10 @@ static int ad7606_get_chan_config(struct ad7606_state *st, int ch, · 28 unmodified lines | |||
| 399 | return 0; | 402 | return 0; |
| 400 | } | 403 | } |
| 401 | 404 | ||
| 402 | static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, | 405 | static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 403 | struct iio_chan_spec *chan, int ch) | 406 | struct iio_chan_spec *chan, int ch) |
| 404 | { | 407 | { |
| 408 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 405 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 409 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 406 | bool bipolar, differential; | 410 | bool bipolar, differential; |
| 407 | int ret; | 411 | int ret; |
| @@ -413,7 +417,7 @@ static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, · 5 unmodified lines | |||
| 413 | return 0; | 417 | return 0; |
| 414 | } | 418 | } |
| 415 | 419 | ||
| 416 | ret = ad7606_get_chan_config(st, ch, &bipolar, &differential); | 420 | ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential); |
| 417 | if (ret) | 421 | if (ret) |
| 418 | return ret; | 422 | return ret; |
| 419 | 423 | ||
| @@ -455,9 +459,10 @@ static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, · 35 unmodified lines | |||
| 455 | return 0; | 459 | return 0; |
| 456 | } | 460 | } |
| 457 | 461 | ||
| 458 | static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, | 462 | static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev, |
| 459 | struct iio_chan_spec *chan, int ch) | 463 | struct iio_chan_spec *chan, int ch) |
| 460 | { | 464 | { |
| 465 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 461 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 466 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 462 | bool bipolar, differential; | 467 | bool bipolar, differential; |
| 463 | int ret; | 468 | int ret; |
| @@ -469,7 +474,7 @@ static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, · 5 unmodified lines | |||
| 469 | return 0; | 474 | return 0; |
| 470 | } | 475 | } |
| 471 | 476 | ||
| 472 | ret = ad7606_get_chan_config(st, ch, &bipolar, &differential); | 477 | ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential); |
| 473 | if (ret) | 478 | if (ret) |
| 474 | return ret; | 479 | return ret; |
| 475 | 480 | ||
| @@ -512,9 +517,10 @@ static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, · 36 unmodified lines | |||
| 512 | return 0; | 517 | return 0; |
| 513 | } | 518 | } |
| 514 | 519 | ||
| 515 | static int ad7607_chan_scale_setup(struct ad7606_state *st, | 520 | static int ad7607_chan_scale_setup(struct iio_dev *indio_dev, |
| 516 | struct iio_chan_spec *chan, int ch) | 521 | struct iio_chan_spec *chan, int ch) |
| 517 | { | 522 | { |
| 523 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 518 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 524 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 519 | 525 | ||
| 520 | cs->range = 0; | 526 | cs->range = 0; |
| @@ -523,9 +529,10 @@ static int ad7607_chan_scale_setup(struct ad7606_state *st, · 2 unmodified lines | |||
| 523 | return 0; | 529 | return 0; |
| 524 | } | 530 | } |
| 525 | 531 | ||
| 526 | static int ad7608_chan_scale_setup(struct ad7606_state *st, | 532 | static int ad7608_chan_scale_setup(struct iio_dev *indio_dev, |
| 527 | struct iio_chan_spec *chan, int ch) | 533 | struct iio_chan_spec *chan, int ch) |
| 528 | { | 534 | { |
| 535 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 529 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 536 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 530 | 537 | ||
| 531 | cs->range = 0; | 538 | cs->range = 0; |
| @@ -534,9 +541,10 @@ static int ad7608_chan_scale_setup(struct ad7606_state *st, · 2 unmodified lines | |||
| 534 | return 0; | 541 | return 0; |
| 535 | } | 542 | } |
| 536 | 543 | ||
| 537 | static int ad7609_chan_scale_setup(struct ad7606_state *st, | 544 | static int ad7609_chan_scale_setup(struct iio_dev *indio_dev, |
| 538 | struct iio_chan_spec *chan, int ch) | 545 | struct iio_chan_spec *chan, int ch) |
| 539 | { | 546 | { |
| 547 | struct ad7606_state *st = iio_priv(indio_dev); | ||
| 540 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; | 548 | struct ad7606_chan_scale *cs = &st->chan_scales[ch]; |
| 541 | 549 | ||
| 542 | cs->range = 0; | 550 | cs->range = 0; |
| @@ -1146,8 +1154,8 @@ static int ad7606_sw_mode_setup(struct iio_dev *indio_dev) · 603 unmodified lines | |||
| 1146 | 1154 | ||
| 1147 | static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) | 1155 | static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) |
| 1148 | { | 1156 | { |
| 1149 | unsigned int num_channels = indio_dev->num_channels - 1; | ||
| 1150 | struct ad7606_state *st = iio_priv(indio_dev); | 1157 | struct ad7606_state *st = iio_priv(indio_dev); |
| 1158 | unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels; | ||
| 1151 | struct iio_chan_spec *chans; | 1159 | struct iio_chan_spec *chans; |
| 1152 | size_t size; | 1160 | size_t size; |
| 1153 | int ch, ret; | 1161 | int ch, ret; |
| @@ -1161,8 +1169,8 @@ static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) · 7 unmodified lines | |||
| 1161 | memcpy(chans, indio_dev->channels, size); | 1169 | memcpy(chans, indio_dev->channels, size); |
| 1162 | indio_dev->channels = chans; | 1170 | indio_dev->channels = chans; |
| 1163 | 1171 | ||
| 1164 | for (ch = 0; ch < num_channels; ch++) { | 1172 | for (ch = 0; ch < st->chip_info->num_adc_channels; ch++) { |
| 1165 | ret = st->chip_info->scale_setup_cb(st, &chans[ch + 1], ch); | 1173 | ret = st->chip_info->scale_setup_cb(indio_dev, &chans[ch + offset], ch); |
| 1166 | if (ret) | 1174 | if (ret) |
| 1167 | return ret; | 1175 | return ret; |
| 1168 | } | 1176 | } |
| @@ -69,7 +69,7 @@ · 68 unmodified lines | |||
| 69 | 69 | ||
| 70 | struct ad7606_state; | 70 | struct ad7606_state; |
| 71 | 71 | ||
| 72 | typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st, | 72 | typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev, |
| 73 | struct iio_chan_spec *chan, int ch); | 73 | struct iio_chan_spec *chan, int ch); |
| 74 | 74 | ||
| 75 | /** | 75 | /** |
| @@ -477,12 +477,12 @@ static int devm_ad7625_pwm_get(struct device *dev, · 476 unmodified lines | |||
| 477 | ref_clk = devm_clk_get_enabled(dev, NULL); | 477 | ref_clk = devm_clk_get_enabled(dev, NULL); |
| 478 | if (IS_ERR(ref_clk)) | 478 | if (IS_ERR(ref_clk)) |
| 479 | return dev_err_probe(dev, PTR_ERR(ref_clk), | 479 | return dev_err_probe(dev, PTR_ERR(ref_clk), |
| 480 | "failed to get ref_clk"); | 480 | "failed to get ref_clk\n"); |
| 481 | 481 | ||
| 482 | ref_clk_rate_hz = clk_get_rate(ref_clk); | 482 | ref_clk_rate_hz = clk_get_rate(ref_clk); |
| 483 | if (!ref_clk_rate_hz) | 483 | if (!ref_clk_rate_hz) |
| 484 | return dev_err_probe(dev, -EINVAL, | 484 | return dev_err_probe(dev, -EINVAL, |
| 485 | "failed to get ref_clk rate"); | 485 | "failed to get ref_clk rate\n"); |
| 486 | 486 | ||
| 487 | st->ref_clk_rate_hz = ref_clk_rate_hz; | 487 | st->ref_clk_rate_hz = ref_clk_rate_hz; |
| 488 | 488 | ||
| @@ -533,7 +533,7 @@ static int devm_ad7625_regulator_setup(struct device *dev, · 44 unmodified lines | |||
| 533 | 533 | ||
| 534 | if (!st->info->has_internal_vref && !st->have_refin && !ref_mv) | 534 | if (!st->info->has_internal_vref && !st->have_refin && !ref_mv) |
| 535 | return dev_err_probe(dev, -EINVAL, | 535 | return dev_err_probe(dev, -EINVAL, |
| 536 | "Need either REFIN or REF"); | 536 | "Need either REFIN or REF\n"); |
| 537 | 537 | ||
| 538 | if (st->have_refin && ref_mv) | 538 | if (st->have_refin && ref_mv) |
| 539 | return dev_err_probe(dev, -EINVAL, | 539 | return dev_err_probe(dev, -EINVAL, |
| @@ -623,7 +623,7 @@ static int ad7625_probe(struct platform_device *pdev) · 83 unmodified lines | |||
| 623 | st->back = devm_iio_backend_get(dev, NULL); | 623 | st->back = devm_iio_backend_get(dev, NULL); |
| 624 | if (IS_ERR(st->back)) | 624 | if (IS_ERR(st->back)) |
| 625 | return dev_err_probe(dev, PTR_ERR(st->back), | 625 | return dev_err_probe(dev, PTR_ERR(st->back), |
| 626 | "failed to get IIO backend"); | 626 | "failed to get IIO backend\n"); |
| 627 | 627 | ||
| 628 | ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); | 628 | ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); |
| 629 | if (ret) | 629 | if (ret) |
| @@ -254,6 +254,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = { · 253 unmodified lines | |||
| 254 | .addr_shift = 4, | 254 | .addr_shift = 4, |
| 255 | .read_mask = BIT(3), | 255 | .read_mask = BIT(3), |
| 256 | .irq_flags = IRQF_TRIGGER_FALLING, | 256 | .irq_flags = IRQF_TRIGGER_FALLING, |
| 257 | .num_resetclks = 32, | ||
| 257 | }; | 258 | }; |
| 258 | 259 | ||
| 259 | static int ad7791_read_raw(struct iio_dev *indio_dev, | 260 | static int ad7791_read_raw(struct iio_dev *indio_dev, |
| @@ -206,6 +206,7 @@ static const struct ad_sigma_delta_info ad7793_sigma_delta_info = { · 205 unmodified lines | |||
| 206 | .addr_shift = 3, | 206 | .addr_shift = 3, |
| 207 | .read_mask = BIT(6), | 207 | .read_mask = BIT(6), |
| 208 | .irq_flags = IRQF_TRIGGER_FALLING, | 208 | .irq_flags = IRQF_TRIGGER_FALLING, |
| 209 | .num_resetclks = 32, | ||
| 209 | }; | 210 | }; |
| 210 | 211 | ||
| 211 | static const struct ad_sd_calib_data ad7793_calib_arr[6] = { | 212 | static const struct ad_sd_calib_data ad7793_calib_arr[6] = { |
| @@ -265,7 +266,7 @@ static int ad7793_setup(struct iio_dev *indio_dev, · 53 unmodified lines | |||
| 265 | return ret; | 266 | return ret; |
| 266 | 267 | ||
| 267 | /* reset the serial interface */ | 268 | /* reset the serial interface */ |
| 268 | ret = ad_sd_reset(&st->sd, 32); | 269 | ret = ad_sd_reset(&st->sd); |
| 269 | if (ret < 0) | 270 | if (ret < 0) |
| 270 | goto out; | 271 | goto out; |
| 271 | usleep_range(500, 2000); /* Wait for at least 500us */ | 272 | usleep_range(500, 2000); /* Wait for at least 500us */ |
| @@ -75,7 +75,7 @@ struct ad7944_adc { · 74 unmodified lines | |||
| 75 | u16 u16; | 75 | u16 u16; |
| 76 | u32 u32; | 76 | u32 u32; |
| 77 | } raw; | 77 | } raw; |
| 78 | u64 timestamp __aligned(8); | 78 | aligned_s64 timestamp; |
| 79 | } sample __aligned(IIO_DMA_MINALIGN); | 79 | } sample __aligned(IIO_DMA_MINALIGN); |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| @@ -29,8 +29,11 @@ · 28 unmodified lines | |||
| 29 | #define AD_SD_COMM_CHAN_MASK 0x3 | 29 | #define AD_SD_COMM_CHAN_MASK 0x3 |
| 30 | 30 | ||
| 31 | #define AD_SD_REG_COMM 0x00 | 31 | #define AD_SD_REG_COMM 0x00 |
| 32 | #define AD_SD_REG_STATUS 0x00 | ||
| 32 | #define AD_SD_REG_DATA 0x03 | 33 | #define AD_SD_REG_DATA 0x03 |
| 33 | 34 | ||
| 35 | #define AD_SD_REG_STATUS_RDY 0x80 | ||
| 36 | |||
| 34 | /** | 37 | /** |
| 35 | * ad_sd_set_comm() - Set communications register | 38 | * ad_sd_set_comm() - Set communications register |
| 36 | * | 39 | * |
| @@ -109,7 +112,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, · 72 unmodified lines | |||
| 109 | }, { | 112 | }, { |
| 110 | .rx_buf = val, | 113 | .rx_buf = val, |
| 111 | .len = size, | 114 | .len = size, |
| 112 | .cs_change = sigma_delta->bus_locked, | 115 | .cs_change = sigma_delta->keep_cs_asserted, |
| 113 | }, | 116 | }, |
| 114 | }; | 117 | }; |
| 115 | struct spi_message m; | 118 | struct spi_message m; |
| @@ -178,13 +181,12 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA"); · 62 unmodified lines | |||
| 178 | * ad_sd_reset() - Reset the serial interface | 181 | * ad_sd_reset() - Reset the serial interface |
| 179 | * | 182 | * |
| 180 | * @sigma_delta: The sigma delta device | 183 | * @sigma_delta: The sigma delta device |
| 181 | * @reset_length: Number of SCLKs with DIN = 1 | ||
| 182 | * | 184 | * |
| 183 | * Returns 0 on success, an error code otherwise. | 185 | * Returns 0 on success, an error code otherwise. |
| 184 | **/ | 186 | **/ |
| 185 | int ad_sd_reset(struct ad_sigma_delta *sigma_delta, | 187 | int ad_sd_reset(struct ad_sigma_delta *sigma_delta) |
| 186 | unsigned int reset_length) | ||
| 187 | { | 188 | { |
| 189 | unsigned int reset_length = sigma_delta->info->num_resetclks; | ||
| 188 | uint8_t *buf; | 190 | uint8_t *buf; |
| 189 | unsigned int size; | 191 | unsigned int size; |
| 190 | int ret; | 192 | int ret; |
| @@ -202,6 +204,107 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta, · 11 unmodified lines | |||
| 202 | } | 204 | } |
| 203 | EXPORT_SYMBOL_NS_GPL(ad_sd_reset, "IIO_AD_SIGMA_DELTA"); | 205 | EXPORT_SYMBOL_NS_GPL(ad_sd_reset, "IIO_AD_SIGMA_DELTA"); |
| 204 | 206 | ||
| 207 | static bool ad_sd_disable_irq(struct ad_sigma_delta *sigma_delta) | ||
| 208 | { | ||
| 209 | guard(spinlock_irqsave)(&sigma_delta->irq_lock); | ||
| 210 | |||
| 211 | /* It's already off, return false to indicate nothing was changed */ | ||
| 212 | if (sigma_delta->irq_dis) | ||
| 213 | return false; | ||
| 214 | |||
| 215 | sigma_delta->irq_dis = true; | ||
| 216 | disable_irq_nosync(sigma_delta->irq_line); | ||
| 217 | return true; | ||
| 218 | } | ||
| 219 | |||
| 220 | static void ad_sd_enable_irq(struct ad_sigma_delta *sigma_delta) | ||
| 221 | { | ||
| 222 | guard(spinlock_irqsave)(&sigma_delta->irq_lock); | ||
| 223 | |||
| 224 | sigma_delta->irq_dis = false; | ||
| 225 | enable_irq(sigma_delta->irq_line); | ||
| 226 | } | ||
| 227 | |||
| 228 | #define AD_SD_CLEAR_DATA_BUFLEN 9 | ||
| 229 | |||
| 230 | /* Called with `sigma_delta->bus_locked == true` only. */ | ||
| 231 | static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta) | ||
| 232 | { | ||
| 233 | bool pending_event; | ||
| 234 | unsigned int data_read_len = BITS_TO_BYTES(sigma_delta->info->num_resetclks); | ||
| 235 | u8 *data; | ||
| 236 | struct spi_transfer t[] = { | ||
| 237 | { | ||
| 238 | .len = 1, | ||
| 239 | }, { | ||
| 240 | .len = data_read_len, | ||
| 241 | } | ||
| 242 | }; | ||
| 243 | struct spi_message m; | ||
| 244 | int ret; | ||
| 245 | |||
| 246 | /* | ||
| 247 | * Read R̅D̅Y̅ pin (if possible) or status register to check if there is an | ||
| 248 | * old event. | ||
| 249 | */ | ||
| 250 | if (sigma_delta->rdy_gpiod) { | ||
| 251 | pending_event = gpiod_get_value(sigma_delta->rdy_gpiod); | ||
| 252 | } else { | ||
| 253 | unsigned int status_reg; | ||
| 254 | |||
| 255 | ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg); | ||
| 256 | if (ret) | ||
| 257 | return ret; | ||
| 258 | |||
| 259 | pending_event = !(status_reg & AD_SD_REG_STATUS_RDY); | ||
| 260 | } | ||
| 261 | |||
| 262 | if (!pending_event) | ||
| 263 | return 0; | ||
| 264 | |||
| 265 | /* | ||
| 266 | * In general the size of the data register is unknown. It varies from | ||
| 267 | * device to device, might be one byte longer if CONTROL.DATA_STATUS is | ||
| 268 | * set and even varies on some devices depending on which input is | ||
| 269 | * selected. So send one byte to start reading the data register and | ||
| 270 | * then just clock for some bytes with DIN (aka MOSI) high to not | ||
| 271 | * confuse the register access state machine after the data register was | ||
| 272 | * completely read. Note however that the sequence length must be | ||
| 273 | * shorter than the reset procedure. | ||
| 274 | */ | ||
| 275 | |||
| 276 | data = kzalloc(data_read_len + 1, GFP_KERNEL); | ||
| 277 | if (!data) | ||
| 278 | return -ENOMEM; | ||
| 279 | |||
| 280 | spi_message_init(&m); | ||
| 281 | if (sigma_delta->info->has_registers) { | ||
| 282 | unsigned int data_reg = sigma_delta->info->data_reg ?: AD_SD_REG_DATA; | ||
| 283 | |||
| 284 | data[0] = data_reg << sigma_delta->info->addr_shift; | ||
| 285 | data[0] |= sigma_delta->info->read_mask; | ||
| 286 | data[0] |= sigma_delta->comm; | ||
| 287 | t[0].tx_buf = data; | ||
| 288 | spi_message_add_tail(&t[0], &m); | ||
| 289 | } | ||
| 290 | |||
| 291 | /* | ||
| 292 | * The first transferred byte is part of the real data register, | ||
| 293 | * so this doesn't need to be 0xff. In the remaining | ||
| 294 | * `data_read_len - 1` bytes are less than $num_resetclks ones. | ||
| 295 | */ | ||
| 296 | t[1].tx_buf = data + 1; | ||
| 297 | data[1] = 0x00; | ||
| 298 | memset(data + 2, 0xff, data_read_len - 1); | ||
| 299 | spi_message_add_tail(&t[1], &m); | ||
| 300 | |||
| 301 | ret = spi_sync_locked(sigma_delta->spi, &m); | ||
| 302 | |||
| 303 | kfree(data); | ||
| 304 | |||
| 305 | return ret; | ||
| 306 | } | ||
| 307 | |||
| 205 | int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, | 308 | int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, |
| 206 | unsigned int mode, unsigned int channel) | 309 | unsigned int mode, unsigned int channel) |
| 207 | { | 310 | { |
| @@ -217,16 +320,18 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, · 9 unmodified lines | |||
| 217 | sigma_delta->keep_cs_asserted = true; | 320 | sigma_delta->keep_cs_asserted = true; |
| 218 | reinit_completion(&sigma_delta->completion); | 321 | reinit_completion(&sigma_delta->completion); |
| 219 | 322 | ||
| 323 | ret = ad_sigma_delta_clear_pending_event(sigma_delta); | ||
| 324 | if (ret) | ||
| 325 | goto out; | ||
| 326 | |||
| 220 | ret = ad_sigma_delta_set_mode(sigma_delta, mode); | 327 | ret = ad_sigma_delta_set_mode(sigma_delta, mode); |
| 221 | if (ret < 0) | 328 | if (ret < 0) |
| 222 | goto out; | 329 | goto out; |
| 223 | 330 | ||
| 224 | sigma_delta->irq_dis = false; | 331 | ad_sd_enable_irq(sigma_delta); |
| 225 | enable_irq(sigma_delta->irq_line); | ||
| 226 | time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); | 332 | time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); |
| 227 | if (time_left == 0) { | 333 | if (time_left == 0) { |
| 228 | sigma_delta->irq_dis = true; | 334 | ad_sd_disable_irq(sigma_delta); |
| 229 | disable_irq_nosync(sigma_delta->irq_line); | ||
| 230 | ret = -EIO; | 335 | ret = -EIO; |
| 231 | } else { | 336 | } else { |
| 232 | ret = 0; | 337 | ret = 0; |
| @@ -292,10 +397,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, · 59 unmodified lines | |||
| 292 | sigma_delta->keep_cs_asserted = true; | 397 | sigma_delta->keep_cs_asserted = true; |
| 293 | reinit_completion(&sigma_delta->completion); | 398 | reinit_completion(&sigma_delta->completion); |
| 294 | 399 | ||
| 400 | ret = ad_sigma_delta_clear_pending_event(sigma_delta); | ||
| 401 | if (ret) | ||
| 402 | goto out_unlock; | ||
| 403 | |||
| 295 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); | 404 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); |
| 296 | 405 | ||
| 297 | sigma_delta->irq_dis = false; | 406 | ad_sd_enable_irq(sigma_delta); |
| 298 | enable_irq(sigma_delta->irq_line); | ||
| 299 | ret = wait_for_completion_interruptible_timeout( | 407 | ret = wait_for_completion_interruptible_timeout( |
| 300 | &sigma_delta->completion, HZ); | 408 | &sigma_delta->completion, HZ); |
| 301 | 409 | ||
| @@ -314,14 +422,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, · 12 unmodified lines | |||
| 314 | &raw_sample); | 422 | &raw_sample); |
| 315 | 423 | ||
| 316 | out: | 424 | out: |
| 317 | if (!sigma_delta->irq_dis) { | 425 | ad_sd_disable_irq(sigma_delta); |
| 318 | disable_irq_nosync(sigma_delta->irq_line); | ||
| 319 | sigma_delta->irq_dis = true; | ||
| 320 | } | ||
| 321 | 426 | ||
| 322 | sigma_delta->keep_cs_asserted = false; | ||
| 323 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | 427 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); |
| 324 | ad_sigma_delta_disable_one(sigma_delta, chan->address); | 428 | ad_sigma_delta_disable_one(sigma_delta, chan->address); |
| 429 | |||
| 430 | out_unlock: | ||
| 431 | sigma_delta->keep_cs_asserted = false; | ||
| 325 | sigma_delta->bus_locked = false; | 432 | sigma_delta->bus_locked = false; |
| 326 | spi_bus_unlock(sigma_delta->spi->controller); | 433 | spi_bus_unlock(sigma_delta->spi->controller); |
| 327 | iio_device_release_direct_mode(indio_dev); | 434 | iio_device_release_direct_mode(indio_dev); |
| @@ -392,12 +499,15 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) · 64 unmodified lines | |||
| 392 | sigma_delta->bus_locked = true; | 499 | sigma_delta->bus_locked = true; |
| 393 | sigma_delta->keep_cs_asserted = true; | 500 | sigma_delta->keep_cs_asserted = true; |
| 394 | 501 | ||
| 502 | ret = ad_sigma_delta_clear_pending_event(sigma_delta); | ||
| 503 | if (ret) | ||
| 504 | goto err_unlock; | ||
| 505 | |||
| 395 | ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); | 506 | ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); |
| 396 | if (ret) | 507 | if (ret) |
| 397 | goto err_unlock; | 508 | goto err_unlock; |
| 398 | 509 | ||
| 399 | sigma_delta->irq_dis = false; | 510 | ad_sd_enable_irq(sigma_delta); |
| 400 | enable_irq(sigma_delta->irq_line); | ||
| 401 | 511 | ||
| 402 | return 0; | 512 | return 0; |
| 403 | 513 | ||
| @@ -414,10 +524,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) · 10 unmodified lines | |||
| 414 | reinit_completion(&sigma_delta->completion); | 524 | reinit_completion(&sigma_delta->completion); |
| 415 | wait_for_completion_timeout(&sigma_delta->completion, HZ); | 525 | wait_for_completion_timeout(&sigma_delta->completion, HZ); |
| 416 | 526 | ||
| 417 | if (!sigma_delta->irq_dis) { | 527 | ad_sd_disable_irq(sigma_delta); |
| 418 | disable_irq_nosync(sigma_delta->irq_line); | ||
| 419 | sigma_delta->irq_dis = true; | ||
| 420 | } | ||
| 421 | 528 | ||
| 422 | sigma_delta->keep_cs_asserted = false; | 529 | sigma_delta->keep_cs_asserted = false; |
| 423 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); | 530 | ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); |
| @@ -516,8 +623,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) · 92 unmodified lines | |||
| 516 | 623 | ||
| 517 | irq_handled: | 624 | irq_handled: |
| 518 | iio_trigger_notify_done(indio_dev->trig); | 625 | iio_trigger_notify_done(indio_dev->trig); |
| 519 | sigma_delta->irq_dis = false; | 626 | ad_sd_enable_irq(sigma_delta); |
| 520 | enable_irq(sigma_delta->irq_line); | ||
| 521 | 627 | ||
| 522 | return IRQ_HANDLED; | 628 | return IRQ_HANDLED; |
| 523 | } | 629 | } |
| @@ -539,12 +645,31 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private) · 15 unmodified lines | |||
| 539 | { | 645 | { |
| 540 | struct ad_sigma_delta *sigma_delta = private; | 646 | struct ad_sigma_delta *sigma_delta = private; |
| 541 | 647 | ||
| 542 | complete(&sigma_delta->completion); | 648 | /* |
| 543 | disable_irq_nosync(irq); | 649 | * AD7124 and a few others use the same physical line for interrupt |
| 544 | sigma_delta->irq_dis = true; | 650 | * reporting (R̅D̅Y̅) and MISO. |
| 545 | iio_trigger_poll(sigma_delta->trig); | 651 | * As MISO toggles when reading a register, this likely results in a |
| 652 | * pending interrupt. This has two consequences: a) The irq might | ||
| 653 | * trigger immediately after it's enabled even though the conversion | ||
| 654 | * isn't done yet; and b) checking the STATUS register's R̅D̅Y̅ flag is | ||
| 655 | * off-limits as reading that would trigger another irq event. | ||
| 656 | * | ||
| 657 | * So read the MOSI line as GPIO (if available) and only trigger the irq | ||
| 658 | * if the line is active. Without such a GPIO assume this is a valid | ||
| 659 | * interrupt. | ||
| 660 | * | ||
| 661 | * Also as disable_irq_nosync() is used to disable the irq, only act if | ||
| 662 | * the irq wasn't disabled before. | ||
| 663 | */ | ||
| 664 | if ((!sigma_delta->rdy_gpiod || gpiod_get_value(sigma_delta->rdy_gpiod)) && | ||
| 665 | ad_sd_disable_irq(sigma_delta)) { | ||
| 666 | complete(&sigma_delta->completion); | ||
| 667 | iio_trigger_poll(sigma_delta->trig); | ||
| 546 | 668 | ||
| 547 | return IRQ_HANDLED; | 669 | return IRQ_HANDLED; |
| 670 | } | ||
| 671 | |||
| 672 | return IRQ_NONE; | ||
| 548 | } | 673 | } |
| 549 | 674 | ||
| 550 | /** | 675 | /** |
| @@ -674,11 +799,24 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, · 123 unmodified lines | |||
| 674 | } | 799 | } |
| 675 | } | 800 | } |
| 676 | 801 | ||
| 802 | spin_lock_init(&sigma_delta->irq_lock); | ||
| 803 | |||
| 677 | if (info->irq_line) | 804 | if (info->irq_line) |
| 678 | sigma_delta->irq_line = info->irq_line; | 805 | sigma_delta->irq_line = info->irq_line; |
| 679 | else | 806 | else |
| 680 | sigma_delta->irq_line = spi->irq; | 807 | sigma_delta->irq_line = spi->irq; |
| 681 | 808 | ||
| 809 | sigma_delta->rdy_gpiod = devm_gpiod_get_optional(&spi->dev, "rdy", GPIOD_IN); | ||
| 810 | if (IS_ERR(sigma_delta->rdy_gpiod)) | ||
| 811 | return dev_err_probe(&spi->dev, PTR_ERR(sigma_delta->rdy_gpiod), | ||
| 812 | "Failed to find rdy gpio\n"); | ||
| 813 | |||
| 814 | if (sigma_delta->rdy_gpiod && !sigma_delta->irq_line) { | ||
| 815 | sigma_delta->irq_line = gpiod_to_irq(sigma_delta->rdy_gpiod); | ||
| 816 | if (sigma_delta->irq_line < 0) | ||
| 817 | return sigma_delta->irq_line; | ||
| 818 | } | ||
| 819 | |||
| 682 | iio_device_set_drvdata(indio_dev, sigma_delta); | 820 | iio_device_set_drvdata(indio_dev, sigma_delta); |
| 683 | 821 | ||
| 684 | return 0; | 822 | return 0; |
| @@ -66,8 +66,6 @@ struct dln2_adc { · 65 unmodified lines | |||
| 66 | /* Demux table */ | 66 | /* Demux table */ |
| 67 | unsigned int demux_count; | 67 | unsigned int demux_count; |
| 68 | struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS]; | 68 | struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS]; |
| 69 | /* Precomputed timestamp padding offset and length */ | ||
| 70 | unsigned int ts_pad_offset, ts_pad_length; | ||
| 71 | }; | 69 | }; |
| 72 | 70 | ||
| 73 | struct dln2_adc_port_chan { | 71 | struct dln2_adc_port_chan { |
| @@ -111,8 +109,6 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2) · 37 unmodified lines | |||
| 111 | if (iio_get_masklength(indio_dev) && | 109 | if (iio_get_masklength(indio_dev) && |
| 112 | (*indio_dev->active_scan_mask & 0xff) == 0xff) { | 110 | (*indio_dev->active_scan_mask & 0xff) == 0xff) { |
| 113 | dln2_adc_add_demux(dln2, 0, 0, 16); | 111 | dln2_adc_add_demux(dln2, 0, 0, 16); |
| 114 | dln2->ts_pad_offset = 0; | ||
| 115 | dln2->ts_pad_length = 0; | ||
| 116 | return; | 112 | return; |
| 117 | } | 113 | } |
| 118 | 114 | ||
| @@ -127,16 +123,6 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2) · 8 unmodified lines | |||
| 127 | out_loc += 2; | 123 | out_loc += 2; |
| 128 | in_loc += 2; | 124 | in_loc += 2; |
| 129 | } | 125 | } |
| 130 | |||
| 131 | if (indio_dev->scan_timestamp) { | ||
| 132 | size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1; | ||
| 133 | |||
| 134 | dln2->ts_pad_offset = out_loc; | ||
| 135 | dln2->ts_pad_length = ts_offset * sizeof(int64_t) - out_loc; | ||
| 136 | } else { | ||
| 137 | dln2->ts_pad_offset = 0; | ||
| 138 | dln2->ts_pad_length = 0; | ||
| 139 | } | ||
| 140 | } | 126 | } |
| 141 | 127 | ||
| 142 | static int dln2_adc_get_chan_count(struct dln2_adc *dln2) | 128 | static int dln2_adc_get_chan_count(struct dln2_adc *dln2) |
| @@ -494,6 +480,8 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p) · 351 unmodified lines | |||
| 494 | if (ret < 0) | 480 | if (ret < 0) |
| 495 | goto done; | 481 | goto done; |
| 496 | 482 | ||
| 483 | memset(&data, 0, sizeof(data)); | ||
| 484 | |||
| 497 | /* Demux operation */ | 485 | /* Demux operation */ |
| 498 | for (i = 0; i < dln2->demux_count; ++i) { | 486 | for (i = 0; i < dln2->demux_count; ++i) { |
| 499 | t = &dln2->demux[i]; | 487 | t = &dln2->demux[i]; |
| @@ -501,11 +489,6 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p) · 1 unmodified line | |||
| 501 | (void *)dev_data.values + t->from, t->length); | 489 | (void *)dev_data.values + t->from, t->length); |
| 502 | } | 490 | } |
| 503 | 491 | ||
| 504 | /* Zero padding space between values and timestamp */ | ||
| 505 | if (dln2->ts_pad_length) | ||
| 506 | memset((void *)data.values + dln2->ts_pad_offset, | ||
| 507 | 0, dln2->ts_pad_length); | ||
| 508 | |||
| 509 | iio_push_to_buffers_with_timestamp(indio_dev, &data, | 492 | iio_push_to_buffers_with_timestamp(indio_dev, &data, |
| 510 | iio_get_time_ns(indio_dev)); | 493 | iio_get_time_ns(indio_dev)); |
| 511 | 494 | ||
| @@ -150,7 +150,7 @@ struct ina2xx_chip_info { · 149 unmodified lines | |||
| 150 | /* data buffer needs space for channel data and timestamp */ | 150 | /* data buffer needs space for channel data and timestamp */ |
| 151 | struct { | 151 | struct { |
| 152 | u16 chan[4]; | 152 | u16 chan[4]; |
| 153 | u64 ts __aligned(8); | 153 | aligned_s64 ts; |
| 154 | } scan; | 154 | } scan; |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| @@ -39,7 +39,7 @@ struct max1118 { · 38 unmodified lines | |||
| 39 | /* Ensure natural alignment of buffer elements */ | 39 | /* Ensure natural alignment of buffer elements */ |
| 40 | struct { | 40 | struct { |
| 41 | u8 channels[2]; | 41 | u8 channels[2]; |
| 42 | s64 ts __aligned(8); | 42 | aligned_s64 ts; |
| 43 | } scan; | 43 | } scan; |
| 44 | 44 | ||
| 45 | u8 data __aligned(IIO_DMA_MINALIGN); | 45 | u8 data __aligned(IIO_DMA_MINALIGN); |
| @@ -143,7 +143,7 @@ struct max11410_state { · 142 unmodified lines | |||
| 143 | int irq; | 143 | int irq; |
| 144 | struct { | 144 | struct { |
| 145 | u32 data __aligned(IIO_DMA_MINALIGN); | 145 | u32 data __aligned(IIO_DMA_MINALIGN); |
| 146 | s64 ts __aligned(8); | 146 | aligned_s64 ts; |
| 147 | } scan; | 147 | } scan; |
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| @@ -161,6 +161,7 @@ struct max1363_chip_info { · 160 unmodified lines | |||
| 161 | * @vref_uv: Actual (external or internal) reference voltage | 161 | * @vref_uv: Actual (external or internal) reference voltage |
| 162 | * @send: function used to send data to the chip | 162 | * @send: function used to send data to the chip |
| 163 | * @recv: function used to receive data from the chip | 163 | * @recv: function used to receive data from the chip |
| 164 | * @data: buffer to store channel data and timestamp | ||
| 164 | */ | 165 | */ |
| 165 | struct max1363_state { | 166 | struct max1363_state { |
| 166 | struct i2c_client *client; | 167 | struct i2c_client *client; |
| @@ -186,6 +187,10 @@ struct max1363_state { · 19 unmodified lines | |||
| 186 | const char *buf, int count); | 187 | const char *buf, int count); |
| 187 | int (*recv)(const struct i2c_client *client, | 188 | int (*recv)(const struct i2c_client *client, |
| 188 | char *buf, int count); | 189 | char *buf, int count); |
| 190 | struct { | ||
| 191 | u8 buf[MAX1363_MAX_CHANNELS * 2]; | ||
| 192 | aligned_s64 ts; | ||
| 193 | } data; | ||
| 189 | }; | 194 | }; |
| 190 | 195 | ||
| 191 | #define MAX1363_MODE_SINGLE(_num, _mask) { \ | 196 | #define MAX1363_MODE_SINGLE(_num, _mask) { \ |
| @@ -1462,22 +1467,10 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) · 1270 unmodified lines | |||
| 1462 | struct iio_poll_func *pf = p; | 1467 | struct iio_poll_func *pf = p; |
| 1463 | struct iio_dev *indio_dev = pf->indio_dev; | 1468 | struct iio_dev *indio_dev = pf->indio_dev; |
| 1464 | struct max1363_state *st = iio_priv(indio_dev); | 1469 | struct max1363_state *st = iio_priv(indio_dev); |
| 1465 | __u8 *rxbuf; | ||
| 1466 | int b_sent; | 1470 | int b_sent; |
| 1467 | size_t d_size; | ||
| 1468 | unsigned long numvals = bitmap_weight(st->current_mode->modemask, | 1471 | unsigned long numvals = bitmap_weight(st->current_mode->modemask, |
| 1469 | MAX1363_MAX_CHANNELS); | 1472 | MAX1363_MAX_CHANNELS); |
| 1470 | 1473 | ||
| 1471 | /* Ensure the timestamp is 8 byte aligned */ | ||
| 1472 | if (st->chip_info->bits != 8) | ||
| 1473 | d_size = numvals*2; | ||
| 1474 | else | ||
| 1475 | d_size = numvals; | ||
| 1476 | if (indio_dev->scan_timestamp) { | ||
| 1477 | d_size += sizeof(s64); | ||
| 1478 | if (d_size % sizeof(s64)) | ||
| 1479 | d_size += sizeof(s64) - (d_size % sizeof(s64)); | ||
| 1480 | } | ||
| 1481 | /* Monitor mode prevents reading. Whilst not currently implemented | 1474 | /* Monitor mode prevents reading. Whilst not currently implemented |
| 1482 | * might as well have this test in here in the meantime as it does | 1475 | * might as well have this test in here in the meantime as it does |
| 1483 | * no harm. | 1476 | * no harm. |
| @@ -1485,21 +1478,16 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) · 1 unmodified line | |||
| 1485 | if (numvals == 0) | 1478 | if (numvals == 0) |
| 1486 | goto done; | 1479 | goto done; |
| 1487 | 1480 | ||
| 1488 | rxbuf = kmalloc(d_size, GFP_KERNEL); | ||
| 1489 | if (rxbuf == NULL) | ||
| 1490 | goto done; | ||
| 1491 | if (st->chip_info->bits != 8) | 1481 | if (st->chip_info->bits != 8) |
| 1492 | b_sent = st->recv(st->client, rxbuf, numvals * 2); | 1482 | b_sent = st->recv(st->client, st->data.buf, numvals * 2); |
| 1493 | else | 1483 | else |
| 1494 | b_sent = st->recv(st->client, rxbuf, numvals); | 1484 | b_sent = st->recv(st->client, st->data.buf, numvals); |
| 1495 | if (b_sent < 0) | 1485 | if (b_sent < 0) |
| 1496 | goto done_free; | 1486 | goto done; |
| 1497 | 1487 | ||
| 1498 | iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, | 1488 | iio_push_to_buffers_with_timestamp(indio_dev, &st->data, |
| 1499 | iio_get_time_ns(indio_dev)); | 1489 | iio_get_time_ns(indio_dev)); |
| 1500 | 1490 | ||
| 1501 | done_free: | ||
| 1502 | kfree(rxbuf); | ||
| 1503 | done: | 1491 | done: |
| 1504 | iio_trigger_notify_done(indio_dev->trig); | 1492 | iio_trigger_notify_done(indio_dev->trig); |
| 1505 | 1493 | ||
| @@ -122,7 +122,7 @@ struct mcp3911 { · 121 unmodified lines | |||
| 122 | const struct mcp3911_chip_info *chip; | 122 | const struct mcp3911_chip_info *chip; |
| 123 | struct { | 123 | struct { |
| 124 | u32 channels[MCP39XX_MAX_NUM_CHANNELS]; | 124 | u32 channels[MCP39XX_MAX_NUM_CHANNELS]; |
| 125 | s64 ts __aligned(8); | 125 | aligned_s64 ts; |
| 126 | } scan; | 126 | } scan; |
| 127 | 127 | ||
| 128 | u8 tx_buf __aligned(IIO_DMA_MINALIGN); | 128 | u8 tx_buf __aligned(IIO_DMA_MINALIGN); |
| @@ -155,10 +155,10 @@ · 154 unmodified lines | |||
| 155 | */ | 155 | */ |
| 156 | #define MESON_SAR_ADC_REG11 0x2c | 156 | #define MESON_SAR_ADC_REG11 0x2c |
| 157 | #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) | 157 | #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) |
| 158 | #define MESON_SAR_ADC_REG11_CMV_SEL BIT(6) | 158 | #define MESON_SAR_ADC_REG11_CMV_SEL BIT(6) |
| 159 | #define MESON_SAR_ADC_REG11_VREF_VOLTAGE BIT(5) | 159 | #define MESON_SAR_ADC_REG11_VREF_VOLTAGE BIT(5) |
| 160 | #define MESON_SAR_ADC_REG11_EOC BIT(1) | 160 | #define MESON_SAR_ADC_REG11_EOC BIT(1) |
| 161 | #define MESON_SAR_ADC_REG11_VREF_SEL BIT(0) | 161 | #define MESON_SAR_ADC_REG11_VREF_SEL BIT(0) |
| 162 | 162 | ||
| 163 | #define MESON_SAR_ADC_REG13 0x34 | 163 | #define MESON_SAR_ADC_REG13 0x34 |
| 164 | #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) | 164 | #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) |
| @@ -315,19 +315,17 @@ static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = { · 150 unmodified lines | |||
| 315 | struct meson_sar_adc_param { | 315 | struct meson_sar_adc_param { |
| 316 | bool has_bl30_integration; | 316 | bool has_bl30_integration; |
| 317 | unsigned long clock_rate; | 317 | unsigned long clock_rate; |
| 318 | u32 bandgap_reg; | ||
| 319 | unsigned int resolution; | 318 | unsigned int resolution; |
| 320 | const struct regmap_config *regmap_config; | 319 | const struct regmap_config *regmap_config; |
| 321 | u8 temperature_trimming_bits; | 320 | u8 temperature_trimming_bits; |
| 322 | unsigned int temperature_multiplier; | 321 | unsigned int temperature_multiplier; |
| 323 | unsigned int temperature_divider; | 322 | unsigned int temperature_divider; |
| 324 | u8 disable_ring_counter; | 323 | u8 disable_ring_counter; |
| 325 | bool has_reg11; | ||
| 326 | bool has_vref_select; | 324 | bool has_vref_select; |
| 327 | u8 vref_select; | 325 | u8 vref_select; |
| 328 | u8 cmv_select; | 326 | u8 cmv_select; |
| 329 | u8 adc_eoc; | 327 | u8 adc_eoc; |
| 330 | enum meson_sar_adc_vref_sel vref_volatge; | 328 | enum meson_sar_adc_vref_sel vref_voltage; |
| 331 | }; | 329 | }; |
| 332 | 330 | ||
| 333 | struct meson_sar_adc_data { | 331 | struct meson_sar_adc_data { |
| @@ -976,7 +974,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) · 642 unmodified lines | |||
| 976 | MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, | 974 | MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, |
| 977 | regval); | 975 | regval); |
| 978 | 976 | ||
| 979 | if (priv->param->has_reg11) { | 977 | if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11) { |
| 980 | regval = FIELD_PREP(MESON_SAR_ADC_REG11_EOC, priv->param->adc_eoc); | 978 | regval = FIELD_PREP(MESON_SAR_ADC_REG11_EOC, priv->param->adc_eoc); |
| 981 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, | 979 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, |
| 982 | MESON_SAR_ADC_REG11_EOC, regval); | 980 | MESON_SAR_ADC_REG11_EOC, regval); |
| @@ -989,7 +987,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) · 6 unmodified lines | |||
| 989 | } | 987 | } |
| 990 | 988 | ||
| 991 | regval = FIELD_PREP(MESON_SAR_ADC_REG11_VREF_VOLTAGE, | 989 | regval = FIELD_PREP(MESON_SAR_ADC_REG11_VREF_VOLTAGE, |
| 992 | priv->param->vref_volatge); | 990 | priv->param->vref_voltage); |
| 993 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, | 991 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, |
| 994 | MESON_SAR_ADC_REG11_VREF_VOLTAGE, regval); | 992 | MESON_SAR_ADC_REG11_VREF_VOLTAGE, regval); |
| 995 | 993 | ||
| @@ -1013,16 +1011,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) · 17 unmodified lines | |||
| 1013 | static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) | 1011 | static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) |
| 1014 | { | 1012 | { |
| 1015 | struct meson_sar_adc_priv *priv = iio_priv(indio_dev); | 1013 | struct meson_sar_adc_priv *priv = iio_priv(indio_dev); |
| 1016 | const struct meson_sar_adc_param *param = priv->param; | ||
| 1017 | u32 enable_mask; | ||
| 1018 | 1014 | ||
| 1019 | if (param->bandgap_reg == MESON_SAR_ADC_REG11) | 1015 | if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11) |
| 1020 | enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN; | 1016 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, |
| 1017 | MESON_SAR_ADC_REG11_BANDGAP_EN, | ||
| 1018 | on_off ? MESON_SAR_ADC_REG11_BANDGAP_EN : 0); | ||
| 1021 | else | 1019 | else |
| 1022 | enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN; | 1020 | regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, |
| 1023 | 1021 | MESON_SAR_ADC_DELTA_10_TS_VBG_EN, | |
| 1024 | regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask, | 1022 | on_off ? MESON_SAR_ADC_DELTA_10_TS_VBG_EN : 0); |
| 1025 | on_off ? enable_mask : 0); | ||
| 1026 | } | 1023 | } |
| 1027 | 1024 | ||
| 1028 | static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) | 1025 | static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) |
| @@ -1186,7 +1183,6 @@ static const struct iio_info meson_sar_adc_iio_info = { · 157 unmodified lines | |||
| 1186 | static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { | 1183 | static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { |
| 1187 | .has_bl30_integration = false, | 1184 | .has_bl30_integration = false, |
| 1188 | .clock_rate = 1150000, | 1185 | .clock_rate = 1150000, |
| 1189 | .bandgap_reg = MESON_SAR_ADC_DELTA_10, | ||
| 1190 | .regmap_config = &meson_sar_adc_regmap_config_meson8, | 1186 | .regmap_config = &meson_sar_adc_regmap_config_meson8, |
| 1191 | .resolution = 10, | 1187 | .resolution = 10, |
| 1192 | .temperature_trimming_bits = 4, | 1188 | .temperature_trimming_bits = 4, |
| @@ -1197,7 +1193,6 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { · 4 unmodified lines | |||
| 1197 | static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = { | 1193 | static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = { |
| 1198 | .has_bl30_integration = false, | 1194 | .has_bl30_integration = false, |
| 1199 | .clock_rate = 1150000, | 1195 | .clock_rate = 1150000, |
| 1200 | .bandgap_reg = MESON_SAR_ADC_DELTA_10, | ||
| 1201 | .regmap_config = &meson_sar_adc_regmap_config_meson8, | 1196 | .regmap_config = &meson_sar_adc_regmap_config_meson8, |
| 1202 | .resolution = 10, | 1197 | .resolution = 10, |
| 1203 | .temperature_trimming_bits = 5, | 1198 | .temperature_trimming_bits = 5, |
| @@ -1208,35 +1203,29 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = { · 4 unmodified lines | |||
| 1208 | static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { | 1203 | static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { |
| 1209 | .has_bl30_integration = true, | 1204 | .has_bl30_integration = true, |
| 1210 | .clock_rate = 1200000, | 1205 | .clock_rate = 1200000, |
| 1211 | .bandgap_reg = MESON_SAR_ADC_REG11, | ||
| 1212 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, | 1206 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, |
| 1213 | .resolution = 10, | 1207 | .resolution = 10, |
| 1214 | .has_reg11 = true, | 1208 | .vref_voltage = 1, |
| 1215 | .vref_volatge = 1, | ||
| 1216 | .cmv_select = 1, | 1209 | .cmv_select = 1, |
| 1217 | }; | 1210 | }; |
| 1218 | 1211 | ||
| 1219 | static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { | 1212 | static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { |
| 1220 | .has_bl30_integration = true, | 1213 | .has_bl30_integration = true, |
| 1221 | .clock_rate = 1200000, | 1214 | .clock_rate = 1200000, |
| 1222 | .bandgap_reg = MESON_SAR_ADC_REG11, | ||
| 1223 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, | 1215 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, |
| 1224 | .resolution = 12, | 1216 | .resolution = 12, |
| 1225 | .disable_ring_counter = 1, | 1217 | .disable_ring_counter = 1, |
| 1226 | .has_reg11 = true, | 1218 | .vref_voltage = 1, |
| 1227 | .vref_volatge = 1, | ||
| 1228 | .cmv_select = 1, | 1219 | .cmv_select = 1, |
| 1229 | }; | 1220 | }; |
| 1230 | 1221 | ||
| 1231 | static const struct meson_sar_adc_param meson_sar_adc_axg_param = { | 1222 | static const struct meson_sar_adc_param meson_sar_adc_axg_param = { |
| 1232 | .has_bl30_integration = true, | 1223 | .has_bl30_integration = true, |
| 1233 | .clock_rate = 1200000, | 1224 | .clock_rate = 1200000, |
| 1234 | .bandgap_reg = MESON_SAR_ADC_REG11, | ||
| 1235 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, | 1225 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, |
| 1236 | .resolution = 12, | 1226 | .resolution = 12, |
| 1237 | .disable_ring_counter = 1, | 1227 | .disable_ring_counter = 1, |
| 1238 | .has_reg11 = true, | 1228 | .vref_voltage = 1, |
| 1239 | .vref_volatge = 1, | ||
| 1240 | .has_vref_select = true, | 1229 | .has_vref_select = true, |
| 1241 | .vref_select = VREF_VDDA, | 1230 | .vref_select = VREF_VDDA, |
| 1242 | .cmv_select = 1, | 1231 | .cmv_select = 1, |
| @@ -1245,11 +1234,9 @@ static const struct meson_sar_adc_param meson_sar_adc_axg_param = { · 2 unmodified lines | |||
| 1245 | static const struct meson_sar_adc_param meson_sar_adc_g12a_param = { | 1234 | static const struct meson_sar_adc_param meson_sar_adc_g12a_param = { |
| 1246 | .has_bl30_integration = false, | 1235 | .has_bl30_integration = false, |
| 1247 | .clock_rate = 1200000, | 1236 | .clock_rate = 1200000, |
| 1248 | .bandgap_reg = MESON_SAR_ADC_REG11, | ||
| 1249 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, | 1237 | .regmap_config = &meson_sar_adc_regmap_config_gxbb, |
| 1250 | .resolution = 12, | 1238 | .resolution = 12, |
| 1251 | .disable_ring_counter = 1, | 1239 | .disable_ring_counter = 1, |
| 1252 | .has_reg11 = true, | ||
| 1253 | .adc_eoc = 1, | 1240 | .adc_eoc = 1, |
| 1254 | .has_vref_select = true, | 1241 | .has_vref_select = true, |
| 1255 | .vref_select = VREF_VDDA, | 1242 | .vref_select = VREF_VDDA, |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/iio/iio.h> | 12 | #include <linux/iio/iio.h> |
| 13 | #include <linux/iio/trigger_consumer.h> | 13 | #include <linux/iio/trigger_consumer.h> |
| 14 | #include <linux/iio/triggered_buffer.h> | 14 | #include <linux/iio/triggered_buffer.h> |
| 15 | #include <linux/limits.h> | ||
| 15 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
| 16 | #include <linux/units.h> | 17 | #include <linux/units.h> |
| 17 | 18 | ||
| @@ -67,6 +68,14 @@ enum pac1921_mxsl { · 49 unmodified lines | |||
| 67 | #define PAC1921_DEFAULT_DI_GAIN 0 /* 2^(value): 1x gain (HW default) */ | 68 | #define PAC1921_DEFAULT_DI_GAIN 0 /* 2^(value): 1x gain (HW default) */ |
| 68 | #define PAC1921_DEFAULT_NUM_SAMPLES 0 /* 2^(value): 1 sample (HW default) */ | 69 | #define PAC1921_DEFAULT_NUM_SAMPLES 0 /* 2^(value): 1 sample (HW default) */ |
| 69 | 70 | ||
| 71 | #define PAC1921_ACPI_GET_uOHMS_VALS 0 | ||
| 72 | #define PAC1921_ACPI_GET_LABEL 1 | ||
| 73 | |||
| 74 | /* f7bb9932-86ee-4516-a236-7a7a742e55cb */ | ||
| 75 | static const guid_t pac1921_guid = | ||
| 76 | GUID_INIT(0xf7bb9932, 0x86ee, 0x4516, 0xa2, | ||
| 77 | 0x36, 0x7a, 0x7a, 0x74, 0x2e, 0x55, 0xcb); | ||
| 78 | |||
| 70 | /* | 79 | /* |
| 71 | * Pre-computed scale factors for BUS voltage | 80 | * Pre-computed scale factors for BUS voltage |
| 72 | * format: IIO_VAL_INT_PLUS_NANO | 81 | * format: IIO_VAL_INT_PLUS_NANO |
| @@ -200,7 +209,7 @@ struct pac1921_priv { · 127 unmodified lines | |||
| 200 | 209 | ||
| 201 | struct { | 210 | struct { |
| 202 | u16 chan[PAC1921_NUM_MEAS_CHANS]; | 211 | u16 chan[PAC1921_NUM_MEAS_CHANS]; |
| 203 | s64 timestamp __aligned(8); | 212 | aligned_s64 timestamp; |
| 204 | } scan; | 213 | } scan; |
| 205 | }; | 214 | }; |
| 206 | 215 | ||
| @@ -782,7 +791,7 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev, · 575 unmodified lines | |||
| 782 | const char *buf, size_t len) | 791 | const char *buf, size_t len) |
| 783 | { | 792 | { |
| 784 | struct pac1921_priv *priv = iio_priv(indio_dev); | 793 | struct pac1921_priv *priv = iio_priv(indio_dev); |
| 785 | u64 rshunt_uohm; | 794 | u32 rshunt_uohm; |
| 786 | int val, val_fract; | 795 | int val, val_fract; |
| 787 | int ret; | 796 | int ret; |
| 788 | 797 | ||
| @@ -793,10 +802,17 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev, · 4 unmodified lines | |||
| 793 | if (ret) | 802 | if (ret) |
| 794 | return ret; | 803 | return ret; |
| 795 | 804 | ||
| 796 | rshunt_uohm = val * MICRO + val_fract; | 805 | /* |
| 797 | if (rshunt_uohm == 0 || rshunt_uohm > INT_MAX) | 806 | * This check validates the shunt is not zero and does not surpass |
| 807 | * INT_MAX. The check is done before calculating in order to avoid | ||
| 808 | * val * MICRO overflowing. | ||
| 809 | */ | ||
| 810 | if ((!val && !val_fract) || val > INT_MAX / MICRO || | ||
| 811 | (val == INT_MAX / MICRO && val_fract > INT_MAX % MICRO)) | ||
| 798 | return -EINVAL; | 812 | return -EINVAL; |
| 799 | 813 | ||
| 814 | rshunt_uohm = val * MICRO + val_fract; | ||
| 815 | |||
| 800 | guard(mutex)(&priv->lock); | 816 | guard(mutex)(&priv->lock); |
| 801 | 817 | ||
| 802 | priv->rshunt_uohm = rshunt_uohm; | 818 | priv->rshunt_uohm = rshunt_uohm; |
| @@ -1151,6 +1167,61 @@ static void pac1921_regulator_disable(void *data) · 348 unmodified lines | |||
| 1151 | regulator_disable(regulator); | 1167 | regulator_disable(regulator); |
| 1152 | } | 1168 | } |
| 1153 | 1169 | ||
| 1170 | /* | ||
| 1171 | * Documentation related to the ACPI device definition | ||
| 1172 | * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf | ||
| 1173 | */ | ||
| 1174 | static int pac1921_match_acpi_device(struct iio_dev *indio_dev) | ||
| 1175 | { | ||
| 1176 | acpi_handle handle; | ||
| 1177 | union acpi_object *status; | ||
| 1178 | char *label; | ||
| 1179 | struct pac1921_priv *priv = iio_priv(indio_dev); | ||
| 1180 | struct device *dev = &priv->client->dev; | ||
| 1181 | |||
| 1182 | handle = ACPI_HANDLE(dev); | ||
| 1183 | |||
| 1184 | status = acpi_evaluate_dsm(handle, &pac1921_guid, 1, | ||
| 1185 | PAC1921_ACPI_GET_uOHMS_VALS, NULL); | ||
| 1186 | if (!status) | ||
| 1187 | return dev_err_probe(dev, -EINVAL, | ||
| 1188 | "Could not read shunt from ACPI table\n"); | ||
| 1189 | |||
| 1190 | priv->rshunt_uohm = status->package.elements[0].integer.value; | ||
| 1191 | ACPI_FREE(status); | ||
| 1192 | |||
| 1193 | status = acpi_evaluate_dsm(handle, &pac1921_guid, 1, | ||
| 1194 | PAC1921_ACPI_GET_LABEL, NULL); | ||
| 1195 | if (!status) | ||
| 1196 | return dev_err_probe(dev, -EINVAL, | ||
| 1197 | "Could not read label from ACPI table\n"); | ||
| 1198 | |||
| 1199 | label = devm_kstrdup(dev, status->package.elements[0].string.pointer, | ||
| 1200 | GFP_KERNEL); | ||
| 1201 | if (!label) | ||
| 1202 | return -ENOMEM; | ||
| 1203 | |||
| 1204 | indio_dev->label = label; | ||
| 1205 | ACPI_FREE(status); | ||
| 1206 | |||
| 1207 | return 0; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | static int pac1921_parse_of_fw(struct iio_dev *indio_dev) | ||
| 1211 | { | ||
| 1212 | int ret; | ||
| 1213 | struct pac1921_priv *priv = iio_priv(indio_dev); | ||
| 1214 | struct device *dev = &priv->client->dev; | ||
| 1215 | |||
| 1216 | ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", | ||
| 1217 | &priv->rshunt_uohm); | ||
| 1218 | if (ret) | ||
| 1219 | return dev_err_probe(dev, ret, | ||
| 1220 | "Cannot read shunt resistor property\n"); | ||
| 1221 | |||
| 1222 | return 0; | ||
| 1223 | } | ||
| 1224 | |||
| 1154 | static int pac1921_probe(struct i2c_client *client) | 1225 | static int pac1921_probe(struct i2c_client *client) |
| 1155 | { | 1226 | { |
| 1156 | struct device *dev = &client->dev; | 1227 | struct device *dev = &client->dev; |
| @@ -1179,11 +1250,14 @@ static int pac1921_probe(struct i2c_client *client) · 22 unmodified lines | |||
| 1179 | priv->di_gain = PAC1921_DEFAULT_DI_GAIN; | 1250 | priv->di_gain = PAC1921_DEFAULT_DI_GAIN; |
| 1180 | priv->n_samples = PAC1921_DEFAULT_NUM_SAMPLES; | 1251 | priv->n_samples = PAC1921_DEFAULT_NUM_SAMPLES; |
| 1181 | 1252 | ||
| 1182 | ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", | 1253 | if (is_acpi_device_node(dev->fwnode)) |
| 1183 | &priv->rshunt_uohm); | 1254 | ret = pac1921_match_acpi_device(indio_dev); |
| 1255 | else | ||
| 1256 | ret = pac1921_parse_of_fw(indio_dev); | ||
| 1184 | if (ret) | 1257 | if (ret) |
| 1185 | return dev_err_probe(dev, ret, | 1258 | return dev_err_probe(dev, ret, |
| 1186 | "Cannot read shunt resistor property\n"); | 1259 | "Parameter parsing error\n"); |
| 1260 | |||
| 1187 | if (priv->rshunt_uohm == 0 || priv->rshunt_uohm > INT_MAX) | 1261 | if (priv->rshunt_uohm == 0 || priv->rshunt_uohm > INT_MAX) |
| 1188 | return dev_err_probe(dev, -EINVAL, | 1262 | return dev_err_probe(dev, -EINVAL, |
| 1189 | "Invalid shunt resistor: %u\n", | 1263 | "Invalid shunt resistor: %u\n", |
| @@ -1246,11 +1320,18 @@ static const struct of_device_id pac1921_of_match[] = { · 56 unmodified lines | |||
| 1246 | }; | 1320 | }; |
| 1247 | MODULE_DEVICE_TABLE(of, pac1921_of_match); | 1321 | MODULE_DEVICE_TABLE(of, pac1921_of_match); |
| 1248 | 1322 | ||
| 1323 | static const struct acpi_device_id pac1921_acpi_match[] = { | ||
| 1324 | { "MCHP1921" }, | ||
| 1325 | { } | ||
| 1326 | }; | ||
| 1327 | MODULE_DEVICE_TABLE(acpi, pac1921_acpi_match); | ||
| 1328 | |||
| 1249 | static struct i2c_driver pac1921_driver = { | 1329 | static struct i2c_driver pac1921_driver = { |
| 1250 | .driver = { | 1330 | .driver = { |
| 1251 | .name = "pac1921", | 1331 | .name = "pac1921", |
| 1252 | .pm = pm_sleep_ptr(&pac1921_pm_ops), | 1332 | .pm = pm_sleep_ptr(&pac1921_pm_ops), |
| 1253 | .of_match_table = pac1921_of_match, | 1333 | .of_match_table = pac1921_of_match, |
| 1334 | .acpi_match_table = pac1921_acpi_match, | ||
| 1254 | }, | 1335 | }, |
| 1255 | .probe = pac1921_probe, | 1336 | .probe = pac1921_probe, |
| 1256 | .id_table = pac1921_id, | 1337 | .id_table = pac1921_id, |
| @@ -363,7 +363,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p) · 362 unmodified lines | |||
| 363 | */ | 363 | */ |
| 364 | struct { | 364 | struct { |
| 365 | u16 values[SARADC_MAX_CHANNELS]; | 365 | u16 values[SARADC_MAX_CHANNELS]; |
| 366 | int64_t timestamp; | 366 | aligned_s64 timestamp; |
| 367 | } data; | 367 | } data; |
| 368 | int ret; | 368 | int ret; |
| 369 | int i, j = 0; | 369 | int i, j = 0; |
| @@ -634,7 +634,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p) · 633 unmodified lines | |||
| 634 | struct device *dev = priv->dev; | 634 | struct device *dev = priv->dev; |
| 635 | struct { | 635 | struct { |
| 636 | u16 vals[RTQ6056_MAX_CHANNEL]; | 636 | u16 vals[RTQ6056_MAX_CHANNEL]; |
| 637 | s64 timestamp __aligned(8); | 637 | aligned_s64 timestamp; |
| 638 | } data; | 638 | } data; |
| 639 | unsigned int raw; | 639 | unsigned int raw; |
| 640 | int i = 0, bit, ret; | 640 | int i = 0, bit, ret; |
| @@ -8,12 +8,13 @@ · 7 unmodified lines | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/bitfield.h> | 10 | #include <linux/bitfield.h> |
| 11 | #include <linux/clk.h> | 11 | #include <linux/cleanup.h> |
| 12 | #include <linux/completion.h> | 12 | #include <linux/completion.h> |
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/iio/iio.h> | 14 | #include <linux/iio/iio.h> |
| 15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
| 17 | #include <linux/iopoll.h> | ||
| 17 | #include <linux/mod_devicetable.h> | 18 | #include <linux/mod_devicetable.h> |
| 18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| @@ -32,20 +33,15 @@ · 12 unmodified lines | |||
| 32 | #define RZG2L_ADM1_MS BIT(2) | 33 | #define RZG2L_ADM1_MS BIT(2) |
| 33 | #define RZG2L_ADM1_BS BIT(4) | 34 | #define RZG2L_ADM1_BS BIT(4) |
| 34 | #define RZG2L_ADM1_EGA_MASK GENMASK(13, 12) | 35 | #define RZG2L_ADM1_EGA_MASK GENMASK(13, 12) |
| 35 | #define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0) | ||
| 36 | #define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24) | 36 | #define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24) |
| 37 | #define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16) | 37 | #define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16) |
| 38 | #define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe) | ||
| 39 | #define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0) | ||
| 40 | 38 | ||
| 41 | #define RZG2L_ADINT 0x20 | 39 | #define RZG2L_ADINT 0x20 |
| 42 | #define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0) | ||
| 43 | #define RZG2L_ADINT_CSEEN BIT(16) | 40 | #define RZG2L_ADINT_CSEEN BIT(16) |
| 44 | #define RZG2L_ADINT_INTS BIT(31) | 41 | #define RZG2L_ADINT_INTS BIT(31) |
| 45 | 42 | ||
| 46 | #define RZG2L_ADSTS 0x24 | 43 | #define RZG2L_ADSTS 0x24 |
| 47 | #define RZG2L_ADSTS_CSEST BIT(16) | 44 | #define RZG2L_ADSTS_CSEST BIT(16) |
| 48 | #define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0) | ||
| 49 | 45 | ||
| 50 | #define RZG2L_ADIVC 0x28 | 46 | #define RZG2L_ADIVC 0x28 |
| 51 | #define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0) | 47 | #define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0) |
| @@ -56,12 +52,28 @@ · 4 unmodified lines | |||
| 56 | #define RZG2L_ADCR(n) (0x30 + ((n) * 0x4)) | 52 | #define RZG2L_ADCR(n) (0x30 + ((n) * 0x4)) |
| 57 | #define RZG2L_ADCR_AD_MASK GENMASK(11, 0) | 53 | #define RZG2L_ADCR_AD_MASK GENMASK(11, 0) |
| 58 | 54 | ||
| 59 | #define RZG2L_ADSMP_DEFAULT_SAMPLING 0x578 | 55 | #define RZG2L_ADC_MAX_CHANNELS 9 |
| 60 | |||
| 61 | #define RZG2L_ADC_MAX_CHANNELS 8 | ||
| 62 | #define RZG2L_ADC_CHN_MASK 0x7 | ||
| 63 | #define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4) | 56 | #define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4) |
| 64 | 57 | ||
| 58 | /** | ||
| 59 | * struct rzg2l_adc_hw_params - ADC hardware specific parameters | ||
| 60 | * @default_adsmp: default ADC sampling period (see ADM3 register); index 0 is | ||
| 61 | * used for voltage channels, index 1 is used for temperature channel | ||
| 62 | * @adsmp_mask: ADC sampling period mask (see ADM3 register) | ||
| 63 | * @adint_inten_mask: conversion end interrupt mask (see ADINT register) | ||
| 64 | * @default_adcmp: default ADC cmp (see ADM3 register) | ||
| 65 | * @num_channels: number of supported channels | ||
| 66 | * @adivc: specifies if ADVIC register is available | ||
| 67 | */ | ||
| 68 | struct rzg2l_adc_hw_params { | ||
| 69 | u16 default_adsmp[2]; | ||
| 70 | u16 adsmp_mask; | ||
| 71 | u16 adint_inten_mask; | ||
| 72 | u8 default_adcmp; | ||
| 73 | u8 num_channels; | ||
| 74 | bool adivc; | ||
| 75 | }; | ||
| 76 | |||
| 65 | struct rzg2l_adc_data { | 77 | struct rzg2l_adc_data { |
| 66 | const struct iio_chan_spec *channels; | 78 | const struct iio_chan_spec *channels; |
| 67 | u8 num_channels; | 79 | u8 num_channels; |
| @@ -69,25 +81,36 @@ struct rzg2l_adc_data { · 1 unmodified line | |||
| 69 | 81 | ||
| 70 | struct rzg2l_adc { | 82 | struct rzg2l_adc { |
| 71 | void __iomem *base; | 83 | void __iomem *base; |
| 72 | struct clk *pclk; | ||
| 73 | struct clk *adclk; | ||
| 74 | struct reset_control *presetn; | 84 | struct reset_control *presetn; |
| 75 | struct reset_control *adrstn; | 85 | struct reset_control *adrstn; |
| 76 | struct completion completion; | ||
| 77 | const struct rzg2l_adc_data *data; | 86 | const struct rzg2l_adc_data *data; |
| 87 | const struct rzg2l_adc_hw_params *hw_params; | ||
| 88 | struct completion completion; | ||
| 78 | struct mutex lock; | 89 | struct mutex lock; |
| 79 | u16 last_val[RZG2L_ADC_MAX_CHANNELS]; | 90 | u16 last_val[RZG2L_ADC_MAX_CHANNELS]; |
| 91 | bool was_rpm_active; | ||
| 92 | }; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * struct rzg2l_adc_channel - ADC channel descriptor | ||
| 96 | * @name: ADC channel name | ||
| 97 | * @type: ADC channel type | ||
| 98 | */ | ||
| 99 | struct rzg2l_adc_channel { | ||
| 100 | const char * const name; | ||
| 101 | enum iio_chan_type type; | ||
| 80 | }; | 102 | }; |
| 81 | 103 | ||
| 82 | static const char * const rzg2l_adc_channel_name[] = { | 104 | static const struct rzg2l_adc_channel rzg2l_adc_channels[] = { |
| 83 | "adc0", | 105 | { "adc0", IIO_VOLTAGE }, |
| 84 | "adc1", | 106 | { "adc1", IIO_VOLTAGE }, |
| 85 | "adc2", | 107 | { "adc2", IIO_VOLTAGE }, |
| 86 | "adc3", | 108 | { "adc3", IIO_VOLTAGE }, |
| 87 | "adc4", | 109 | { "adc4", IIO_VOLTAGE }, |
| 88 | "adc5", | 110 | { "adc5", IIO_VOLTAGE }, |
| 89 | "adc6", | 111 | { "adc6", IIO_VOLTAGE }, |
| 90 | "adc7", | 112 | { "adc7", IIO_VOLTAGE }, |
| 113 | { "adc8", IIO_TEMP }, | ||
| 91 | }; | 114 | }; |
| 92 | 115 | ||
| 93 | static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg) | 116 | static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg) |
| @@ -115,7 +138,7 @@ static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on) · 21 unmodified lines | |||
| 115 | 138 | ||
| 116 | static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start) | 139 | static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start) |
| 117 | { | 140 | { |
| 118 | int timeout = 5; | 141 | int ret; |
| 119 | u32 reg; | 142 | u32 reg; |
| 120 | 143 | ||
| 121 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); | 144 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); |
| @@ -128,15 +151,10 @@ static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start) · 6 unmodified lines | |||
| 128 | if (start) | 151 | if (start) |
| 129 | return; | 152 | return; |
| 130 | 153 | ||
| 131 | do { | 154 | ret = read_poll_timeout(rzg2l_adc_readl, reg, !(reg & (RZG2L_ADM0_ADBSY | RZG2L_ADM0_ADCE)), |
| 132 | usleep_range(100, 200); | 155 | 200, 1000, true, adc, RZG2L_ADM(0)); |
| 133 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); | 156 | if (ret) |
| 134 | timeout--; | 157 | pr_err("%s stopping ADC timed out\n", __func__); |
| 135 | if (!timeout) { | ||
| 136 | pr_err("%s stopping ADC timed out\n", __func__); | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | } while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE))); | ||
| 140 | } | 158 | } |
| 141 | 159 | ||
| 142 | static void rzg2l_set_trigger(struct rzg2l_adc *adc) | 160 | static void rzg2l_set_trigger(struct rzg2l_adc *adc) |
| @@ -158,8 +176,18 @@ static void rzg2l_set_trigger(struct rzg2l_adc *adc) · 15 unmodified lines | |||
| 158 | rzg2l_adc_writel(adc, RZG2L_ADM(1), reg); | 176 | rzg2l_adc_writel(adc, RZG2L_ADM(1), reg); |
| 159 | } | 177 | } |
| 160 | 178 | ||
| 179 | static u8 rzg2l_adc_ch_to_adsmp_index(u8 ch) | ||
| 180 | { | ||
| 181 | if (rzg2l_adc_channels[ch].type == IIO_VOLTAGE) | ||
| 182 | return 0; | ||
| 183 | |||
| 184 | return 1; | ||
| 185 | } | ||
| 186 | |||
| 161 | static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) | 187 | static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) |
| 162 | { | 188 | { |
| 189 | const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; | ||
| 190 | u8 index = rzg2l_adc_ch_to_adsmp_index(ch); | ||
| 163 | u32 reg; | 191 | u32 reg; |
| 164 | 192 | ||
| 165 | if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY) | 193 | if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY) |
| @@ -169,10 +197,15 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) · 3 unmodified lines | |||
| 169 | 197 | ||
| 170 | /* Select analog input channel subjected to conversion. */ | 198 | /* Select analog input channel subjected to conversion. */ |
| 171 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(2)); | 199 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(2)); |
| 172 | reg &= ~RZG2L_ADM2_CHSEL_MASK; | 200 | reg &= ~GENMASK(hw_params->num_channels - 1, 0); |
| 173 | reg |= BIT(ch); | 201 | reg |= BIT(ch); |
| 174 | rzg2l_adc_writel(adc, RZG2L_ADM(2), reg); | 202 | rzg2l_adc_writel(adc, RZG2L_ADM(2), reg); |
| 175 | 203 | ||
| 204 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(3)); | ||
| 205 | reg &= ~hw_params->adsmp_mask; | ||
| 206 | reg |= hw_params->default_adsmp[index]; | ||
| 207 | rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); | ||
| 208 | |||
| 176 | /* | 209 | /* |
| 177 | * Setup ADINT | 210 | * Setup ADINT |
| 178 | * INTS[31] - Select pulse signal | 211 | * INTS[31] - Select pulse signal |
| @@ -181,36 +214,26 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) · 2 unmodified lines | |||
| 181 | */ | 214 | */ |
| 182 | reg = rzg2l_adc_readl(adc, RZG2L_ADINT); | 215 | reg = rzg2l_adc_readl(adc, RZG2L_ADINT); |
| 183 | reg &= ~RZG2L_ADINT_INTS; | 216 | reg &= ~RZG2L_ADINT_INTS; |
| 184 | reg &= ~RZG2L_ADINT_INTEN_MASK; | 217 | reg &= ~hw_params->adint_inten_mask; |
| 185 | reg |= (RZG2L_ADINT_CSEEN | BIT(ch)); | 218 | reg |= (RZG2L_ADINT_CSEEN | BIT(ch)); |
| 186 | rzg2l_adc_writel(adc, RZG2L_ADINT, reg); | 219 | rzg2l_adc_writel(adc, RZG2L_ADINT, reg); |
| 187 | 220 | ||
| 188 | return 0; | 221 | return 0; |
| 189 | } | 222 | } |
| 190 | 223 | ||
| 191 | static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on) | ||
| 192 | { | ||
| 193 | struct device *dev = indio_dev->dev.parent; | ||
| 194 | |||
| 195 | if (on) | ||
| 196 | return pm_runtime_resume_and_get(dev); | ||
| 197 | |||
| 198 | return pm_runtime_put_sync(dev); | ||
| 199 | } | ||
| 200 | |||
| 201 | static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch) | 224 | static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch) |
| 202 | { | 225 | { |
| 226 | const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; | ||
| 227 | struct device *dev = indio_dev->dev.parent; | ||
| 203 | int ret; | 228 | int ret; |
| 204 | 229 | ||
| 205 | ret = rzg2l_adc_set_power(indio_dev, true); | 230 | ret = pm_runtime_resume_and_get(dev); |
| 206 | if (ret) | 231 | if (ret) |
| 207 | return ret; | 232 | return ret; |
| 208 | 233 | ||
| 209 | ret = rzg2l_adc_conversion_setup(adc, ch); | 234 | ret = rzg2l_adc_conversion_setup(adc, ch); |
| 210 | if (ret) { | 235 | if (ret) |
| 211 | rzg2l_adc_set_power(indio_dev, false); | 236 | goto rpm_put; |
| 212 | return ret; | ||
| 213 | } | ||
| 214 | 237 | ||
| 215 | reinit_completion(&adc->completion); | 238 | reinit_completion(&adc->completion); |
| 216 | 239 | ||
| @@ -218,13 +241,16 @@ static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc · 1 unmodified line | |||
| 218 | 241 | ||
| 219 | if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) { | 242 | if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) { |
| 220 | rzg2l_adc_writel(adc, RZG2L_ADINT, | 243 | rzg2l_adc_writel(adc, RZG2L_ADINT, |
| 221 | rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK); | 244 | rzg2l_adc_readl(adc, RZG2L_ADINT) & ~hw_params->adint_inten_mask); |
| 222 | rzg2l_adc_start_stop(adc, false); | 245 | ret = -ETIMEDOUT; |
| 223 | rzg2l_adc_set_power(indio_dev, false); | ||
| 224 | return -ETIMEDOUT; | ||
| 225 | } | 246 | } |
| 226 | 247 | ||
| 227 | return rzg2l_adc_set_power(indio_dev, false); | 248 | rzg2l_adc_start_stop(adc, false); |
| 249 | |||
| 250 | rpm_put: | ||
| 251 | pm_runtime_mark_last_busy(dev); | ||
| 252 | pm_runtime_put_autosuspend(dev); | ||
| 253 | return ret; | ||
| 228 | } | 254 | } |
| 229 | 255 | ||
| 230 | static int rzg2l_adc_read_raw(struct iio_dev *indio_dev, | 256 | static int rzg2l_adc_read_raw(struct iio_dev *indio_dev, |
| @@ -233,24 +259,22 @@ static int rzg2l_adc_read_raw(struct iio_dev *indio_dev, · 2 unmodified lines | |||
| 233 | { | 259 | { |
| 234 | struct rzg2l_adc *adc = iio_priv(indio_dev); | 260 | struct rzg2l_adc *adc = iio_priv(indio_dev); |
| 235 | int ret; | 261 | int ret; |
| 236 | u8 ch; | ||
| 237 | 262 | ||
| 238 | switch (mask) { | 263 | switch (mask) { |
| 239 | case IIO_CHAN_INFO_RAW: | 264 | case IIO_CHAN_INFO_RAW: { |
| 240 | if (chan->type != IIO_VOLTAGE) | 265 | if (chan->type != IIO_VOLTAGE && chan->type != IIO_TEMP) |
| 241 | return -EINVAL; | 266 | return -EINVAL; |
| 242 | 267 | ||
| 243 | mutex_lock(&adc->lock); | 268 | guard(mutex)(&adc->lock); |
| 244 | ch = chan->channel & RZG2L_ADC_CHN_MASK; | 269 | |
| 245 | ret = rzg2l_adc_conversion(indio_dev, adc, ch); | 270 | ret = rzg2l_adc_conversion(indio_dev, adc, chan->channel); |
| 246 | if (ret) { | 271 | if (ret) |
| 247 | mutex_unlock(&adc->lock); | ||
| 248 | return ret; | 272 | return ret; |
| 249 | } | 273 | |
| 250 | *val = adc->last_val[ch]; | 274 | *val = adc->last_val[chan->channel]; |
| 251 | mutex_unlock(&adc->lock); | ||
| 252 | 275 | ||
| 253 | return IIO_VAL_INT; | 276 | return IIO_VAL_INT; |
| 277 | } | ||
| 254 | 278 | ||
| 255 | default: | 279 | default: |
| 256 | return -EINVAL; | 280 | return -EINVAL; |
| @@ -261,7 +285,7 @@ static int rzg2l_adc_read_label(struct iio_dev *iio_dev, · 4 unmodified lines | |||
| 261 | const struct iio_chan_spec *chan, | 285 | const struct iio_chan_spec *chan, |
| 262 | char *label) | 286 | char *label) |
| 263 | { | 287 | { |
| 264 | return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]); | 288 | return sysfs_emit(label, "%s\n", rzg2l_adc_channels[chan->channel].name); |
| 265 | } | 289 | } |
| 266 | 290 | ||
| 267 | static const struct iio_info rzg2l_adc_iio_info = { | 291 | static const struct iio_info rzg2l_adc_iio_info = { |
| @@ -272,6 +296,7 @@ static const struct iio_info rzg2l_adc_iio_info = { · 4 unmodified lines | |||
| 272 | static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) | 296 | static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) |
| 273 | { | 297 | { |
| 274 | struct rzg2l_adc *adc = dev_id; | 298 | struct rzg2l_adc *adc = dev_id; |
| 299 | const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; | ||
| 275 | unsigned long intst; | 300 | unsigned long intst; |
| 276 | u32 reg; | 301 | u32 reg; |
| 277 | int ch; | 302 | int ch; |
| @@ -284,11 +309,11 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) · 6 unmodified lines | |||
| 284 | return IRQ_HANDLED; | 309 | return IRQ_HANDLED; |
| 285 | } | 310 | } |
| 286 | 311 | ||
| 287 | intst = reg & RZG2L_ADSTS_INTST_MASK; | 312 | intst = reg & GENMASK(hw_params->num_channels - 1, 0); |
| 288 | if (!intst) | 313 | if (!intst) |
| 289 | return IRQ_NONE; | 314 | return IRQ_NONE; |
| 290 | 315 | ||
| 291 | for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS) | 316 | for_each_set_bit(ch, &intst, hw_params->num_channels) |
| 292 | adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK; | 317 | adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK; |
| 293 | 318 | ||
| 294 | /* clear the channel interrupt */ | 319 | /* clear the channel interrupt */ |
| @@ -301,6 +326,7 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) · 6 unmodified lines | |||
| 301 | 326 | ||
| 302 | static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) | 327 | static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) |
| 303 | { | 328 | { |
| 329 | const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; | ||
| 304 | struct iio_chan_spec *chan_array; | 330 | struct iio_chan_spec *chan_array; |
| 305 | struct rzg2l_adc_data *data; | 331 | struct rzg2l_adc_data *data; |
| 306 | unsigned int channel; | 332 | unsigned int channel; |
| @@ -313,15 +339,12 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l · 6 unmodified lines | |||
| 313 | return -ENOMEM; | 339 | return -ENOMEM; |
| 314 | 340 | ||
| 315 | num_channels = device_get_child_node_count(&pdev->dev); | 341 | num_channels = device_get_child_node_count(&pdev->dev); |
| 316 | if (!num_channels) { | 342 | if (!num_channels) |
| 317 | dev_err(&pdev->dev, "no channel children\n"); | 343 | return dev_err_probe(&pdev->dev, -ENODEV, "no channel children\n"); |
| 318 | return -ENODEV; | ||
| 319 | } | ||
| 320 | 344 | ||
| 321 | if (num_channels > RZG2L_ADC_MAX_CHANNELS) { | 345 | if (num_channels > hw_params->num_channels) |
| 322 | dev_err(&pdev->dev, "num of channel children out of range\n"); | 346 | return dev_err_probe(&pdev->dev, -EINVAL, |
| 323 | return -EINVAL; | 347 | "num of channel children out of range\n"); |
| 324 | } | ||
| 325 | 348 | ||
| 326 | chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array), | 349 | chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array), |
| 327 | GFP_KERNEL); | 350 | GFP_KERNEL); |
| @@ -334,14 +357,14 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l · 6 unmodified lines | |||
| 334 | if (ret) | 357 | if (ret) |
| 335 | return ret; | 358 | return ret; |
| 336 | 359 | ||
| 337 | if (channel >= RZG2L_ADC_MAX_CHANNELS) | 360 | if (channel >= hw_params->num_channels) |
| 338 | return -EINVAL; | 361 | return -EINVAL; |
| 339 | 362 | ||
| 340 | chan_array[i].type = IIO_VOLTAGE; | 363 | chan_array[i].type = rzg2l_adc_channels[channel].type; |
| 341 | chan_array[i].indexed = 1; | 364 | chan_array[i].indexed = 1; |
| 342 | chan_array[i].channel = channel; | 365 | chan_array[i].channel = channel; |
| 343 | chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); | 366 | chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
| 344 | chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel]; | 367 | chan_array[i].datasheet_name = rzg2l_adc_channels[channel].name; |
| 345 | i++; | 368 | i++; |
| 346 | } | 369 | } |
| 347 | 370 | ||
| @@ -352,13 +375,13 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l · 4 unmodified lines | |||
| 352 | return 0; | 375 | return 0; |
| 353 | } | 376 | } |
| 354 | 377 | ||
| 355 | static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) | 378 | static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc) |
| 356 | { | 379 | { |
| 357 | int timeout = 5; | 380 | const struct rzg2l_adc_hw_params *hw_params = adc->hw_params; |
| 358 | u32 reg; | 381 | u32 reg; |
| 359 | int ret; | 382 | int ret; |
| 360 | 383 | ||
| 361 | ret = clk_prepare_enable(adc->pclk); | 384 | ret = pm_runtime_resume_and_get(dev); |
| 362 | if (ret) | 385 | if (ret) |
| 363 | return ret; | 386 | return ret; |
| 364 | 387 | ||
| @@ -367,21 +390,19 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) · 2 unmodified lines | |||
| 367 | reg |= RZG2L_ADM0_SRESB; | 390 | reg |= RZG2L_ADM0_SRESB; |
| 368 | rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); | 391 | rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); |
| 369 | 392 | ||
| 370 | while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) { | 393 | ret = read_poll_timeout(rzg2l_adc_readl, reg, reg & RZG2L_ADM0_SRESB, |
| 371 | if (!timeout) { | 394 | 200, 1000, false, adc, RZG2L_ADM(0)); |
| 372 | ret = -EBUSY; | 395 | if (ret) |
| 373 | goto exit_hw_init; | 396 | goto exit_hw_init; |
| 374 | } | 397 | |
| 375 | timeout--; | 398 | if (hw_params->adivc) { |
| 376 | usleep_range(100, 200); | 399 | /* Only division by 4 can be set */ |
| 400 | reg = rzg2l_adc_readl(adc, RZG2L_ADIVC); | ||
| 401 | reg &= ~RZG2L_ADIVC_DIVADC_MASK; | ||
| 402 | reg |= RZG2L_ADIVC_DIVADC_4; | ||
| 403 | rzg2l_adc_writel(adc, RZG2L_ADIVC, reg); | ||
| 377 | } | 404 | } |
| 378 | 405 | ||
| 379 | /* Only division by 4 can be set */ | ||
| 380 | reg = rzg2l_adc_readl(adc, RZG2L_ADIVC); | ||
| 381 | reg &= ~RZG2L_ADIVC_DIVADC_MASK; | ||
| 382 | reg |= RZG2L_ADIVC_DIVADC_4; | ||
| 383 | rzg2l_adc_writel(adc, RZG2L_ADIVC, reg); | ||
| 384 | |||
| 385 | /* | 406 | /* |
| 386 | * Setup AMD3 | 407 | * Setup AMD3 |
| 387 | * ADIL[31:24] - Should be always set to 0 | 408 | * ADIL[31:24] - Should be always set to 0 |
| @@ -391,35 +412,18 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) · 3 unmodified lines | |||
| 391 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(3)); | 412 | reg = rzg2l_adc_readl(adc, RZG2L_ADM(3)); |
| 392 | reg &= ~RZG2L_ADM3_ADIL_MASK; | 413 | reg &= ~RZG2L_ADM3_ADIL_MASK; |
| 393 | reg &= ~RZG2L_ADM3_ADCMP_MASK; | 414 | reg &= ~RZG2L_ADM3_ADCMP_MASK; |
| 394 | reg &= ~RZG2L_ADM3_ADSMP_MASK; | 415 | reg &= ~hw_params->adsmp_mask; |
| 395 | reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING); | 416 | reg |= FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, hw_params->default_adcmp) | |
| 417 | hw_params->default_adsmp[0]; | ||
| 418 | |||
| 396 | rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); | 419 | rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); |
| 397 | 420 | ||
| 398 | exit_hw_init: | 421 | exit_hw_init: |
| 399 | clk_disable_unprepare(adc->pclk); | 422 | pm_runtime_mark_last_busy(dev); |
| 400 | 423 | pm_runtime_put_autosuspend(dev); | |
| 401 | return ret; | 424 | return ret; |
| 402 | } | 425 | } |
| 403 | 426 | ||
| 404 | static void rzg2l_adc_pm_runtime_disable(void *data) | ||
| 405 | { | ||
| 406 | struct device *dev = data; | ||
| 407 | |||
| 408 | pm_runtime_disable(dev->parent); | ||
| 409 | } | ||
| 410 | |||
| 411 | static void rzg2l_adc_pm_runtime_set_suspended(void *data) | ||
| 412 | { | ||
| 413 | struct device *dev = data; | ||
| 414 | |||
| 415 | pm_runtime_set_suspended(dev->parent); | ||
| 416 | } | ||
| 417 | |||
| 418 | static void rzg2l_adc_reset_assert(void *data) | ||
| 419 | { | ||
| 420 | reset_control_assert(data); | ||
| 421 | } | ||
| 422 | |||
| 423 | static int rzg2l_adc_probe(struct platform_device *pdev) | 427 | static int rzg2l_adc_probe(struct platform_device *pdev) |
| 424 | { | 428 | { |
| 425 | struct device *dev = &pdev->dev; | 429 | struct device *dev = &pdev->dev; |
| @@ -434,6 +438,10 @@ static int rzg2l_adc_probe(struct platform_device *pdev) · 8 unmodified lines | |||
| 434 | 438 | ||
| 435 | adc = iio_priv(indio_dev); | 439 | adc = iio_priv(indio_dev); |
| 436 | 440 | ||
| 441 | adc->hw_params = device_get_match_data(dev); | ||
| 442 | if (!adc->hw_params || adc->hw_params->num_channels > RZG2L_ADC_MAX_CHANNELS) | ||
| 443 | return -EINVAL; | ||
| 444 | |||
| 437 | ret = rzg2l_adc_parse_properties(pdev, adc); | 445 | ret = rzg2l_adc_parse_properties(pdev, adc); |
| 438 | if (ret) | 446 | if (ret) |
| 439 | return ret; | 447 | return ret; |
| @@ -444,63 +452,28 @@ static int rzg2l_adc_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 444 | if (IS_ERR(adc->base)) | 452 | if (IS_ERR(adc->base)) |
| 445 | return PTR_ERR(adc->base); | 453 | return PTR_ERR(adc->base); |
| 446 | 454 | ||
| 447 | adc->pclk = devm_clk_get(dev, "pclk"); | 455 | adc->adrstn = devm_reset_control_get_exclusive_deasserted(dev, "adrst-n"); |
| 448 | if (IS_ERR(adc->pclk)) { | 456 | if (IS_ERR(adc->adrstn)) |
| 449 | dev_err(dev, "Failed to get pclk"); | 457 | return dev_err_probe(dev, PTR_ERR(adc->adrstn), |
| 450 | return PTR_ERR(adc->pclk); | 458 | "failed to get/deassert adrst-n\n"); |
| 451 | } | ||
| 452 | 459 | ||
| 453 | adc->adclk = devm_clk_get(dev, "adclk"); | 460 | adc->presetn = devm_reset_control_get_exclusive_deasserted(dev, "presetn"); |
| 454 | if (IS_ERR(adc->adclk)) { | 461 | if (IS_ERR(adc->presetn)) |
| 455 | dev_err(dev, "Failed to get adclk"); | 462 | return dev_err_probe(dev, PTR_ERR(adc->presetn), |
| 456 | return PTR_ERR(adc->adclk); | 463 | "failed to get/deassert presetn\n"); |
| 457 | } | ||
| 458 | 464 | ||
| 459 | adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n"); | 465 | pm_runtime_set_autosuspend_delay(dev, 300); |
| 460 | if (IS_ERR(adc->adrstn)) { | 466 | pm_runtime_use_autosuspend(dev); |
| 461 | dev_err(dev, "failed to get adrstn\n"); | 467 | ret = devm_pm_runtime_enable(dev); |
| 462 | return PTR_ERR(adc->adrstn); | 468 | if (ret) |
| 463 | } | ||
| 464 | |||
| 465 | adc->presetn = devm_reset_control_get_exclusive(dev, "presetn"); | ||
| 466 | if (IS_ERR(adc->presetn)) { | ||
| 467 | dev_err(dev, "failed to get presetn\n"); | ||
| 468 | return PTR_ERR(adc->presetn); | ||
| 469 | } | ||
| 470 | |||
| 471 | ret = reset_control_deassert(adc->adrstn); | ||
| 472 | if (ret) { | ||
| 473 | dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret); | ||
| 474 | return ret; | ||
| 475 | } | ||
| 476 | |||
| 477 | ret = devm_add_action_or_reset(&pdev->dev, | ||
| 478 | rzg2l_adc_reset_assert, adc->adrstn); | ||
| 479 | if (ret) { | ||
| 480 | dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n", | ||
| 481 | ret); | ||
| 482 | return ret; | 469 | return ret; |
| 483 | } | ||
| 484 | 470 | ||
| 485 | ret = reset_control_deassert(adc->presetn); | 471 | platform_set_drvdata(pdev, indio_dev); |
| 486 | if (ret) { | ||
| 487 | dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret); | ||
| 488 | return ret; | ||
| 489 | } | ||
| 490 | |||
| 491 | ret = devm_add_action_or_reset(&pdev->dev, | ||
| 492 | rzg2l_adc_reset_assert, adc->presetn); | ||
| 493 | if (ret) { | ||
| 494 | dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n", | ||
| 495 | ret); | ||
| 496 | return ret; | ||
| 497 | } | ||
| 498 | 472 | ||
| 499 | ret = rzg2l_adc_hw_init(adc); | 473 | ret = rzg2l_adc_hw_init(dev, adc); |
| 500 | if (ret) { | 474 | if (ret) |
| 501 | dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret); | 475 | return dev_err_probe(&pdev->dev, ret, |
| 502 | return ret; | 476 | "failed to initialize ADC HW\n"); |
| 503 | } | ||
| 504 | 477 | ||
| 505 | irq = platform_get_irq(pdev, 0); | 478 | irq = platform_get_irq(pdev, 0); |
| 506 | if (irq < 0) | 479 | if (irq < 0) |
| @@ -513,72 +486,130 @@ static int rzg2l_adc_probe(struct platform_device *pdev) · 6 unmodified lines | |||
| 513 | 486 | ||
| 514 | init_completion(&adc->completion); | 487 | init_completion(&adc->completion); |
| 515 | 488 | ||
| 516 | platform_set_drvdata(pdev, indio_dev); | ||
| 517 | |||
| 518 | indio_dev->name = DRIVER_NAME; | 489 | indio_dev->name = DRIVER_NAME; |
| 519 | indio_dev->info = &rzg2l_adc_iio_info; | 490 | indio_dev->info = &rzg2l_adc_iio_info; |
| 520 | indio_dev->modes = INDIO_DIRECT_MODE; | 491 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 521 | indio_dev->channels = adc->data->channels; | 492 | indio_dev->channels = adc->data->channels; |
| 522 | indio_dev->num_channels = adc->data->num_channels; | 493 | indio_dev->num_channels = adc->data->num_channels; |
| 523 | 494 | ||
| 524 | pm_runtime_set_suspended(dev); | ||
| 525 | ret = devm_add_action_or_reset(&pdev->dev, | ||
| 526 | rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev); | ||
| 527 | if (ret) | ||
| 528 | return ret; | ||
| 529 | |||
| 530 | pm_runtime_enable(dev); | ||
| 531 | ret = devm_add_action_or_reset(&pdev->dev, | ||
| 532 | rzg2l_adc_pm_runtime_disable, &indio_dev->dev); | ||
| 533 | if (ret) | ||
| 534 | return ret; | ||
| 535 | |||
| 536 | return devm_iio_device_register(dev, indio_dev); | 495 | return devm_iio_device_register(dev, indio_dev); |
| 537 | } | 496 | } |
| 538 | 497 | ||
| 498 | static const struct rzg2l_adc_hw_params rzg2l_hw_params = { | ||
| 499 | .num_channels = 8, | ||
| 500 | .default_adcmp = 0xe, | ||
| 501 | .default_adsmp = { 0x578 }, | ||
| 502 | .adsmp_mask = GENMASK(15, 0), | ||
| 503 | .adint_inten_mask = GENMASK(7, 0), | ||
| 504 | .adivc = true | ||
| 505 | }; | ||
| 506 | |||
| 507 | static const struct rzg2l_adc_hw_params rzg3s_hw_params = { | ||
| 508 | .num_channels = 9, | ||
| 509 | .default_adcmp = 0x1d, | ||
| 510 | .default_adsmp = { 0x7f, 0xff }, | ||
| 511 | .adsmp_mask = GENMASK(7, 0), | ||
| 512 | .adint_inten_mask = GENMASK(11, 0), | ||
| 513 | }; | ||
| 514 | |||
| 539 | static const struct of_device_id rzg2l_adc_match[] = { | 515 | static const struct of_device_id rzg2l_adc_match[] = { |
| 540 | { .compatible = "renesas,rzg2l-adc",}, | 516 | { .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params }, |
| 517 | { .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params }, | ||
| 541 | { /* sentinel */ } | 518 | { /* sentinel */ } |
| 542 | }; | 519 | }; |
| 543 | MODULE_DEVICE_TABLE(of, rzg2l_adc_match); | 520 | MODULE_DEVICE_TABLE(of, rzg2l_adc_match); |
| 544 | 521 | ||
| 545 | static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev) | 522 | static int rzg2l_adc_pm_runtime_suspend(struct device *dev) |
| 546 | { | 523 | { |
| 547 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 524 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
| 548 | struct rzg2l_adc *adc = iio_priv(indio_dev); | 525 | struct rzg2l_adc *adc = iio_priv(indio_dev); |
| 549 | 526 | ||
| 550 | rzg2l_adc_pwr(adc, false); | 527 | rzg2l_adc_pwr(adc, false); |
| 551 | clk_disable_unprepare(adc->adclk); | ||
| 552 | clk_disable_unprepare(adc->pclk); | ||
| 553 | 528 | ||
| 554 | return 0; | 529 | return 0; |
| 555 | } | 530 | } |
| 556 | 531 | ||
| 557 | static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev) | 532 | static int rzg2l_adc_pm_runtime_resume(struct device *dev) |
| 533 | { | ||
| 534 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 535 | struct rzg2l_adc *adc = iio_priv(indio_dev); | ||
| 536 | |||
| 537 | rzg2l_adc_pwr(adc, true); | ||
| 538 | |||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | |||
| 542 | static int rzg2l_adc_suspend(struct device *dev) | ||
| 558 | { | 543 | { |
| 559 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 544 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
| 560 | struct rzg2l_adc *adc = iio_priv(indio_dev); | 545 | struct rzg2l_adc *adc = iio_priv(indio_dev); |
| 546 | struct reset_control_bulk_data resets[] = { | ||
| 547 | { .rstc = adc->presetn }, | ||
| 548 | { .rstc = adc->adrstn }, | ||
| 549 | }; | ||
| 561 | int ret; | 550 | int ret; |
| 562 | 551 | ||
| 563 | ret = clk_prepare_enable(adc->pclk); | 552 | if (pm_runtime_suspended(dev)) { |
| 553 | adc->was_rpm_active = false; | ||
| 554 | } else { | ||
| 555 | ret = pm_runtime_force_suspend(dev); | ||
| 556 | if (ret) | ||
| 557 | return ret; | ||
| 558 | adc->was_rpm_active = true; | ||
| 559 | } | ||
| 560 | |||
| 561 | ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets); | ||
| 564 | if (ret) | 562 | if (ret) |
| 565 | return ret; | 563 | goto rpm_restore; |
| 564 | |||
| 565 | return 0; | ||
| 566 | |||
| 567 | rpm_restore: | ||
| 568 | if (adc->was_rpm_active) | ||
| 569 | pm_runtime_force_resume(dev); | ||
| 570 | |||
| 571 | return ret; | ||
| 572 | } | ||
| 573 | |||
| 574 | static int rzg2l_adc_resume(struct device *dev) | ||
| 575 | { | ||
| 576 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 577 | struct rzg2l_adc *adc = iio_priv(indio_dev); | ||
| 578 | struct reset_control_bulk_data resets[] = { | ||
| 579 | { .rstc = adc->adrstn }, | ||
| 580 | { .rstc = adc->presetn }, | ||
| 581 | }; | ||
| 582 | int ret; | ||
| 566 | 583 | ||
| 567 | ret = clk_prepare_enable(adc->adclk); | 584 | ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets); |
| 568 | if (ret) { | 585 | if (ret) |
| 569 | clk_disable_unprepare(adc->pclk); | ||
| 570 | return ret; | 586 | return ret; |
| 587 | |||
| 588 | if (adc->was_rpm_active) { | ||
| 589 | ret = pm_runtime_force_resume(dev); | ||
| 590 | if (ret) | ||
| 591 | goto resets_restore; | ||
| 571 | } | 592 | } |
| 572 | 593 | ||
| 573 | rzg2l_adc_pwr(adc, true); | 594 | ret = rzg2l_adc_hw_init(dev, adc); |
| 595 | if (ret) | ||
| 596 | goto rpm_restore; | ||
| 574 | 597 | ||
| 575 | return 0; | 598 | return 0; |
| 599 | |||
| 600 | rpm_restore: | ||
| 601 | if (adc->was_rpm_active) { | ||
| 602 | pm_runtime_mark_last_busy(dev); | ||
| 603 | pm_runtime_put_autosuspend(dev); | ||
| 604 | } | ||
| 605 | resets_restore: | ||
| 606 | reset_control_bulk_assert(ARRAY_SIZE(resets), resets); | ||
| 607 | return ret; | ||
| 576 | } | 608 | } |
| 577 | 609 | ||
| 578 | static const struct dev_pm_ops rzg2l_adc_pm_ops = { | 610 | static const struct dev_pm_ops rzg2l_adc_pm_ops = { |
| 579 | SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, | 611 | RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL) |
| 580 | rzg2l_adc_pm_runtime_resume, | 612 | SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume) |
| 581 | NULL) | ||
| 582 | }; | 613 | }; |
| 583 | 614 | ||
| 584 | static struct platform_driver rzg2l_adc_driver = { | 615 | static struct platform_driver rzg2l_adc_driver = { |
| @@ -586,7 +617,7 @@ static struct platform_driver rzg2l_adc_driver = { · 1 unmodified line | |||
| 586 | .driver = { | 617 | .driver = { |
| 587 | .name = DRIVER_NAME, | 618 | .name = DRIVER_NAME, |
| 588 | .of_match_table = rzg2l_adc_match, | 619 | .of_match_table = rzg2l_adc_match, |
| 589 | .pm = &rzg2l_adc_pm_ops, | 620 | .pm = pm_ptr(&rzg2l_adc_pm_ops), |
| 590 | }, | 621 | }, |
| 591 | }; | 622 | }; |
| 592 | 623 | ||
| @@ -37,7 +37,7 @@ struct adc081c { · 36 unmodified lines | |||
| 37 | /* Ensure natural alignment of buffer elements */ | 37 | /* Ensure natural alignment of buffer elements */ |
| 38 | struct { | 38 | struct { |
| 39 | u16 channel; | 39 | u16 channel; |
| 40 | s64 ts __aligned(8); | 40 | aligned_s64 ts; |
| 41 | } scan; | 41 | } scan; |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| @@ -29,7 +29,7 @@ struct adc084s021 { · 28 unmodified lines | |||
| 29 | /* Buffer used to align data */ | 29 | /* Buffer used to align data */ |
| 30 | struct { | 30 | struct { |
| 31 | __be16 channels[4]; | 31 | __be16 channels[4]; |
| 32 | s64 ts __aligned(8); | 32 | aligned_s64 ts; |
| 33 | } scan; | 33 | } scan; |
| 34 | /* | 34 | /* |
| 35 | * DMA (thus cache coherency maintenance) may require the | 35 | * DMA (thus cache coherency maintenance) may require the |
| @@ -448,7 +448,7 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) · 447 unmodified lines | |||
| 448 | /* Ensure natural alignment of timestamp */ | 448 | /* Ensure natural alignment of timestamp */ |
| 449 | struct { | 449 | struct { |
| 450 | s16 chan; | 450 | s16 chan; |
| 451 | s64 timestamp __aligned(8); | 451 | aligned_s64 timestamp; |
| 452 | } scan; | 452 | } scan; |
| 453 | int chan, ret, res; | 453 | int chan, ret, res; |
| 454 | 454 | ||
| @@ -501,7 +501,7 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private) · 500 unmodified lines | |||
| 501 | struct ads1119_state *st = iio_priv(indio_dev); | 501 | struct ads1119_state *st = iio_priv(indio_dev); |
| 502 | struct { | 502 | struct { |
| 503 | s16 sample; | 503 | s16 sample; |
| 504 | s64 timestamp __aligned(8); | 504 | aligned_s64 timestamp; |
| 505 | } scan; | 505 | } scan; |
| 506 | unsigned int index; | 506 | unsigned int index; |
| 507 | int ret; | 507 | int ret; |
| @@ -102,7 +102,7 @@ struct ads131e08_state { · 101 unmodified lines | |||
| 102 | struct completion completion; | 102 | struct completion completion; |
| 103 | struct { | 103 | struct { |
| 104 | u8 data[ADS131E08_NUM_DATA_BYTES_MAX]; | 104 | u8 data[ADS131E08_NUM_DATA_BYTES_MAX]; |
| 105 | s64 ts __aligned(8); | 105 | aligned_s64 ts; |
| 106 | } tmp_buf; | 106 | } tmp_buf; |
| 107 | 107 | ||
| 108 | u8 tx_buf[3] __aligned(IIO_DMA_MINALIGN); | 108 | u8 tx_buf[3] __aligned(IIO_DMA_MINALIGN); |
| @@ -199,7 +199,7 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p) · 198 unmodified lines | |||
| 199 | struct lmp92064_adc_priv *priv = iio_priv(indio_dev); | 199 | struct lmp92064_adc_priv *priv = iio_priv(indio_dev); |
| 200 | struct { | 200 | struct { |
| 201 | u16 values[2]; | 201 | u16 values[2]; |
| 202 | int64_t timestamp __aligned(8); | 202 | aligned_s64 timestamp; |
| 203 | } data; | 203 | } data; |
| 204 | int ret; | 204 | int ret; |
| 205 | 205 | ||
| @@ -157,7 +157,7 @@ struct tsc2046_adc_priv { · 156 unmodified lines | |||
| 157 | /* Scan data for each channel */ | 157 | /* Scan data for each channel */ |
| 158 | u16 data[TI_TSC2046_MAX_CHAN]; | 158 | u16 data[TI_TSC2046_MAX_CHAN]; |
| 159 | /* Timestamp */ | 159 | /* Timestamp */ |
| 160 | s64 ts __aligned(8); | 160 | aligned_s64 ts; |
| 161 | } scan_buf; | 161 | } scan_buf; |
| 162 | 162 | ||
| 163 | /* | 163 | /* |
| @@ -173,10 +173,14 @@ struct vf610_adc { · 172 unmodified lines | |||
| 173 | /* Ensure the timestamp is naturally aligned */ | 173 | /* Ensure the timestamp is naturally aligned */ |
| 174 | struct { | 174 | struct { |
| 175 | u16 chan; | 175 | u16 chan; |
| 176 | s64 timestamp __aligned(8); | 176 | aligned_s64 timestamp; |
| 177 | } scan; | 177 | } scan; |
| 178 | }; | 178 | }; |
| 179 | 179 | ||
| 180 | struct vf610_chip_info { | ||
| 181 | u8 num_channels; | ||
| 182 | }; | ||
| 183 | |||
| 180 | static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; | 184 | static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; |
| 181 | static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; | 185 | static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; |
| 182 | 186 | ||
| @@ -808,14 +812,31 @@ static const struct iio_info vf610_adc_iio_info = { · 625 unmodified lines | |||
| 808 | .attrs = &vf610_attribute_group, | 812 | .attrs = &vf610_attribute_group, |
| 809 | }; | 813 | }; |
| 810 | 814 | ||
| 815 | static const struct vf610_chip_info vf610_chip_info = { | ||
| 816 | .num_channels = ARRAY_SIZE(vf610_adc_iio_channels), | ||
| 817 | }; | ||
| 818 | |||
| 819 | static const struct vf610_chip_info imx6sx_chip_info = { | ||
| 820 | .num_channels = 4, | ||
| 821 | }; | ||
| 822 | |||
| 811 | static const struct of_device_id vf610_adc_match[] = { | 823 | static const struct of_device_id vf610_adc_match[] = { |
| 812 | { .compatible = "fsl,vf610-adc", }, | 824 | { .compatible = "fsl,imx6sx-adc", .data = &imx6sx_chip_info}, |
| 825 | { .compatible = "fsl,vf610-adc", .data = &vf610_chip_info}, | ||
| 813 | { /* sentinel */ } | 826 | { /* sentinel */ } |
| 814 | }; | 827 | }; |
| 815 | MODULE_DEVICE_TABLE(of, vf610_adc_match); | 828 | MODULE_DEVICE_TABLE(of, vf610_adc_match); |
| 816 | 829 | ||
| 830 | static void vf610_adc_action_remove(void *d) | ||
| 831 | { | ||
| 832 | struct vf610_adc *info = d; | ||
| 833 | |||
| 834 | regulator_disable(info->vref); | ||
| 835 | } | ||
| 836 | |||
| 817 | static int vf610_adc_probe(struct platform_device *pdev) | 837 | static int vf610_adc_probe(struct platform_device *pdev) |
| 818 | { | 838 | { |
| 839 | const struct vf610_chip_info *chip_info; | ||
| 819 | struct device *dev = &pdev->dev; | 840 | struct device *dev = &pdev->dev; |
| 820 | struct vf610_adc *info; | 841 | struct vf610_adc *info; |
| 821 | struct iio_dev *indio_dev; | 842 | struct iio_dev *indio_dev; |
| @@ -823,10 +844,8 @@ static int vf610_adc_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 823 | int ret; | 844 | int ret; |
| 824 | 845 | ||
| 825 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); | 846 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); |
| 826 | if (!indio_dev) { | 847 | if (!indio_dev) |
| 827 | dev_err(&pdev->dev, "Failed allocating iio device\n"); | 848 | return dev_err_probe(&pdev->dev, -ENOMEM, "Failed allocating iio device\n"); |
| 828 | return -ENOMEM; | ||
| 829 | } | ||
| 830 | 849 | ||
| 831 | info = iio_priv(indio_dev); | 850 | info = iio_priv(indio_dev); |
| 832 | info->dev = &pdev->dev; | 851 | info->dev = &pdev->dev; |
| @@ -835,6 +854,8 @@ static int vf610_adc_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 835 | if (IS_ERR(info->regs)) | 854 | if (IS_ERR(info->regs)) |
| 836 | return PTR_ERR(info->regs); | 855 | return PTR_ERR(info->regs); |
| 837 | 856 | ||
| 857 | chip_info = device_get_match_data(dev); | ||
| 858 | |||
| 838 | irq = platform_get_irq(pdev, 0); | 859 | irq = platform_get_irq(pdev, 0); |
| 839 | if (irq < 0) | 860 | if (irq < 0) |
| 840 | return irq; | 861 | return irq; |
| @@ -842,17 +863,12 @@ static int vf610_adc_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 842 | ret = devm_request_irq(info->dev, irq, | 863 | ret = devm_request_irq(info->dev, irq, |
| 843 | vf610_adc_isr, 0, | 864 | vf610_adc_isr, 0, |
| 844 | dev_name(&pdev->dev), indio_dev); | 865 | dev_name(&pdev->dev), indio_dev); |
| 845 | if (ret < 0) { | 866 | if (ret < 0) |
| 846 | dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); | 867 | return dev_err_probe(&pdev->dev, ret, "failed requesting irq, irq = %d\n", irq); |
| 847 | return ret; | ||
| 848 | } | ||
| 849 | 868 | ||
| 850 | info->clk = devm_clk_get(&pdev->dev, "adc"); | 869 | info->clk = devm_clk_get_enabled(&pdev->dev, "adc"); |
| 851 | if (IS_ERR(info->clk)) { | 870 | if (IS_ERR(info->clk)) |
| 852 | dev_err(&pdev->dev, "failed getting clock, err = %ld\n", | 871 | return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed getting clock\n"); |
| 853 | PTR_ERR(info->clk)); | ||
| 854 | return PTR_ERR(info->clk); | ||
| 855 | } | ||
| 856 | 872 | ||
| 857 | info->vref = devm_regulator_get(&pdev->dev, "vref"); | 873 | info->vref = devm_regulator_get(&pdev->dev, "vref"); |
| 858 | if (IS_ERR(info->vref)) | 874 | if (IS_ERR(info->vref)) |
| @@ -862,6 +878,10 @@ static int vf610_adc_probe(struct platform_device *pdev) · 3 unmodified lines | |||
| 862 | if (ret) | 878 | if (ret) |
| 863 | return ret; | 879 | return ret; |
| 864 | 880 | ||
| 881 | ret = devm_add_action_or_reset(&pdev->dev, vf610_adc_action_remove, info); | ||
| 882 | if (ret) | ||
| 883 | return ret; | ||
| 884 | |||
| 865 | info->vref_uv = regulator_get_voltage(info->vref); | 885 | info->vref_uv = regulator_get_voltage(info->vref); |
| 866 | 886 | ||
| 867 | device_property_read_u32_array(dev, "fsl,adck-max-frequency", info->max_adck_rate, 3); | 887 | device_property_read_u32_array(dev, "fsl,adck-max-frequency", info->max_adck_rate, 3); |
| @@ -877,54 +897,23 @@ static int vf610_adc_probe(struct platform_device *pdev) · 9 unmodified lines | |||
| 877 | indio_dev->info = &vf610_adc_iio_info; | 897 | indio_dev->info = &vf610_adc_iio_info; |
| 878 | indio_dev->modes = INDIO_DIRECT_MODE; | 898 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 879 | indio_dev->channels = vf610_adc_iio_channels; | 899 | indio_dev->channels = vf610_adc_iio_channels; |
| 880 | indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels); | 900 | indio_dev->num_channels = chip_info->num_channels; |
| 881 | |||
| 882 | ret = clk_prepare_enable(info->clk); | ||
| 883 | if (ret) { | ||
| 884 | dev_err(&pdev->dev, | ||
| 885 | "Could not prepare or enable the clock.\n"); | ||
| 886 | goto error_adc_clk_enable; | ||
| 887 | } | ||
| 888 | 901 | ||
| 889 | vf610_adc_cfg_init(info); | 902 | vf610_adc_cfg_init(info); |
| 890 | vf610_adc_hw_init(info); | 903 | vf610_adc_hw_init(info); |
| 891 | 904 | ||
| 892 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | 905 | ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, &iio_pollfunc_store_time, |
| 893 | NULL, &iio_triggered_buffer_setup_ops); | 906 | NULL, &iio_triggered_buffer_setup_ops); |
| 894 | if (ret < 0) { | 907 | if (ret < 0) |
| 895 | dev_err(&pdev->dev, "Couldn't initialise the buffer\n"); | 908 | return dev_err_probe(&pdev->dev, ret, "Couldn't initialise the buffer\n"); |
| 896 | goto error_iio_device_register; | ||
| 897 | } | ||
| 898 | 909 | ||
| 899 | mutex_init(&info->lock); | 910 | mutex_init(&info->lock); |
| 900 | 911 | ||
| 901 | ret = iio_device_register(indio_dev); | 912 | ret = devm_iio_device_register(&pdev->dev, indio_dev); |
| 902 | if (ret) { | 913 | if (ret) |
| 903 | dev_err(&pdev->dev, "Couldn't register the device.\n"); | 914 | return dev_err_probe(&pdev->dev, ret, "Couldn't register the device.\n"); |
| 904 | goto error_adc_buffer_init; | ||
| 905 | } | ||
| 906 | 915 | ||
| 907 | return 0; | 916 | return 0; |
| 908 | |||
| 909 | error_adc_buffer_init: | ||
| 910 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 911 | error_iio_device_register: | ||
| 912 | clk_disable_unprepare(info->clk); | ||
| 913 | error_adc_clk_enable: | ||
| 914 | regulator_disable(info->vref); | ||
| 915 | |||
| 916 | return ret; | ||
| 917 | } | ||
| 918 | |||
| 919 | static void vf610_adc_remove(struct platform_device *pdev) | ||
| 920 | { | ||
| 921 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
| 922 | struct vf610_adc *info = iio_priv(indio_dev); | ||
| 923 | |||
| 924 | iio_device_unregister(indio_dev); | ||
| 925 | iio_triggered_buffer_cleanup(indio_dev); | ||
| 926 | regulator_disable(info->vref); | ||
| 927 | clk_disable_unprepare(info->clk); | ||
| 928 | } | 917 | } |
| 929 | 918 | ||
| 930 | static int vf610_adc_suspend(struct device *dev) | 919 | static int vf610_adc_suspend(struct device *dev) |
| @@ -972,7 +961,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, · 41 unmodified lines | |||
| 972 | 961 | ||
| 973 | static struct platform_driver vf610_adc_driver = { | 962 | static struct platform_driver vf610_adc_driver = { |
| 974 | .probe = vf610_adc_probe, | 963 | .probe = vf610_adc_probe, |
| 975 | .remove = vf610_adc_remove, | ||
| 976 | .driver = { | 964 | .driver = { |
| 977 | .name = DRIVER_NAME, | 965 | .name = DRIVER_NAME, |
| 978 | .of_match_table = vf610_adc_match, | 966 | .of_match_table = vf610_adc_match, |
| @@ -206,7 +206,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = { · 205 unmodified lines | |||
| 206 | 206 | ||
| 207 | /** | 207 | /** |
| 208 | * iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine | 208 | * iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine |
| 209 | * @dev: Parent device for the buffer | 209 | * @dev: DMA channel consumer device |
| 210 | * @channel: DMA channel name, typically "rx". | 210 | * @channel: DMA channel name, typically "rx". |
| 211 | * | 211 | * |
| 212 | * This allocates a new IIO buffer which internally uses the DMAengine framework | 212 | * This allocates a new IIO buffer which internally uses the DMAengine framework |
| @@ -288,6 +288,21 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) · 75 unmodified lines | |||
| 288 | } | 288 | } |
| 289 | EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, "IIO_DMAENGINE_BUFFER"); | 289 | EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, "IIO_DMAENGINE_BUFFER"); |
| 290 | 290 | ||
| 291 | /** | ||
| 292 | * iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device | ||
| 293 | * @dev: DMA channel consumer device | ||
| 294 | * @indio_dev: IIO device to which to attach this buffer. | ||
| 295 | * @channel: DMA channel name, typically "rx". | ||
| 296 | * @dir: Direction of buffer (in or out) | ||
| 297 | * | ||
| 298 | * This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc() | ||
| 299 | * and attaches it to an IIO device with iio_device_attach_buffer(). | ||
| 300 | * It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the | ||
| 301 | * IIO device. | ||
| 302 | * | ||
| 303 | * Once done using the buffer iio_dmaengine_buffer_free() should be used to | ||
| 304 | * release it. | ||
| 305 | */ | ||
| 291 | struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, | 306 | struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, |
| 292 | struct iio_dev *indio_dev, | 307 | struct iio_dev *indio_dev, |
| 293 | const char *channel, | 308 | const char *channel, |
| @@ -321,7 +336,7 @@ static void __devm_iio_dmaengine_buffer_free(void *buffer) · 27 unmodified lines | |||
| 321 | 336 | ||
| 322 | /** | 337 | /** |
| 323 | * devm_iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device | 338 | * devm_iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device |
| 324 | * @dev: Parent device for the buffer | 339 | * @dev: Device for devm ownership and DMA channel consumer device |
| 325 | * @indio_dev: IIO device to which to attach this buffer. | 340 | * @indio_dev: IIO device to which to attach this buffer. |
| 326 | * @channel: DMA channel name, typically "rx". | 341 | * @channel: DMA channel name, typically "rx". |
| 327 | * @dir: Direction of buffer (in or out) | 342 | * @dir: Direction of buffer (in or out) |
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | #ifndef BME680_H_ | 2 | #ifndef BME680_H_ |
| 3 | #define BME680_H_ | 3 | #define BME680_H_ |
| 4 | 4 | ||
| 5 | #include <linux/pm.h> | ||
| 5 | #include <linux/regmap.h> | 6 | #include <linux/regmap.h> |
| 6 | 7 | ||
| 7 | #define BME680_REG_CHIP_ID 0xD0 | 8 | #define BME680_REG_CHIP_ID 0xD0 |
| @@ -80,6 +81,7 @@ · 72 unmodified lines | |||
| 80 | #define BME680_CALIB_RANGE_3_LEN 5 | 81 | #define BME680_CALIB_RANGE_3_LEN 5 |
| 81 | 82 | ||
| 82 | extern const struct regmap_config bme680_regmap_config; | 83 | extern const struct regmap_config bme680_regmap_config; |
| 84 | extern const struct dev_pm_ops bme680_dev_pm_ops; | ||
| 83 | 85 | ||
| 84 | int bme680_core_probe(struct device *dev, struct regmap *regmap, | 86 | int bme680_core_probe(struct device *dev, struct regmap *regmap, |
| 85 | const char *name); | 87 | const char *name); |
| @@ -14,7 +14,10 @@ · 13 unmodified lines | |||
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/pm.h> | ||
| 18 | #include <linux/pm_runtime.h> | ||
| 17 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
| 20 | #include <linux/regulator/consumer.h> | ||
| 18 | 21 | ||
| 19 | #include <linux/iio/buffer.h> | 22 | #include <linux/iio/buffer.h> |
| 20 | #include <linux/iio/iio.h> | 23 | #include <linux/iio/iio.h> |
| @@ -111,6 +114,8 @@ enum bme680_scan { · 90 unmodified lines | |||
| 111 | BME680_GAS, | 114 | BME680_GAS, |
| 112 | }; | 115 | }; |
| 113 | 116 | ||
| 117 | static const char *const bme680_supply_names[] = { "vdd", "vddio" }; | ||
| 118 | |||
| 114 | struct bme680_data { | 119 | struct bme680_data { |
| 115 | struct regmap *regmap; | 120 | struct regmap *regmap; |
| 116 | struct bme680_calib bme680; | 121 | struct bme680_calib bme680; |
| @@ -817,9 +822,9 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res) · 700 unmodified lines | |||
| 817 | return 0; | 822 | return 0; |
| 818 | } | 823 | } |
| 819 | 824 | ||
| 820 | static int bme680_read_raw(struct iio_dev *indio_dev, | 825 | static int __bme680_read_raw(struct iio_dev *indio_dev, |
| 821 | struct iio_chan_spec const *chan, | 826 | struct iio_chan_spec const *chan, |
| 822 | int *val, int *val2, long mask) | 827 | int *val, int *val2, long mask) |
| 823 | { | 828 | { |
| 824 | struct bme680_data *data = iio_priv(indio_dev); | 829 | struct bme680_data *data = iio_priv(indio_dev); |
| 825 | int chan_val, ret; | 830 | int chan_val, ret; |
| @@ -874,11 +879,11 @@ static int bme680_read_raw(struct iio_dev *indio_dev, · 48 unmodified lines | |||
| 874 | case IIO_CHAN_INFO_RAW: | 879 | case IIO_CHAN_INFO_RAW: |
| 875 | switch (chan->type) { | 880 | switch (chan->type) { |
| 876 | case IIO_TEMP: | 881 | case IIO_TEMP: |
| 877 | ret = bme680_read_temp(data, (s16 *)&chan_val); | 882 | ret = bme680_read_temp(data, &temp_chan_val); |
| 878 | if (ret) | 883 | if (ret) |
| 879 | return ret; | 884 | return ret; |
| 880 | 885 | ||
| 881 | *val = chan_val; | 886 | *val = temp_chan_val; |
| 882 | return IIO_VAL_INT; | 887 | return IIO_VAL_INT; |
| 883 | case IIO_PRESSURE: | 888 | case IIO_PRESSURE: |
| 884 | ret = bme680_read_press(data, &chan_val); | 889 | ret = bme680_read_press(data, &chan_val); |
| @@ -932,14 +937,33 @@ static int bme680_read_raw(struct iio_dev *indio_dev, · 47 unmodified lines | |||
| 932 | } | 937 | } |
| 933 | } | 938 | } |
| 934 | 939 | ||
| 940 | static int bme680_read_raw(struct iio_dev *indio_dev, | ||
| 941 | struct iio_chan_spec const *chan, | ||
| 942 | int *val, int *val2, long mask) | ||
| 943 | { | ||
| 944 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 945 | struct device *dev = regmap_get_device(data->regmap); | ||
| 946 | int ret; | ||
| 947 | |||
| 948 | ret = pm_runtime_resume_and_get(dev); | ||
| 949 | if (ret) | ||
| 950 | return ret; | ||
| 951 | |||
| 952 | ret = __bme680_read_raw(indio_dev, chan, val, val2, mask); | ||
| 953 | pm_runtime_mark_last_busy(dev); | ||
| 954 | pm_runtime_put_autosuspend(dev); | ||
| 955 | |||
| 956 | return ret; | ||
| 957 | } | ||
| 958 | |||
| 935 | static bool bme680_is_valid_oversampling(int rate) | 959 | static bool bme680_is_valid_oversampling(int rate) |
| 936 | { | 960 | { |
| 937 | return (rate > 0 && rate <= 16 && is_power_of_2(rate)); | 961 | return (rate > 0 && rate <= 16 && is_power_of_2(rate)); |
| 938 | } | 962 | } |
| 939 | 963 | ||
| 940 | static int bme680_write_raw(struct iio_dev *indio_dev, | 964 | static int __bme680_write_raw(struct iio_dev *indio_dev, |
| 941 | struct iio_chan_spec const *chan, | 965 | struct iio_chan_spec const *chan, |
| 942 | int val, int val2, long mask) | 966 | int val, int val2, long mask) |
| 943 | { | 967 | { |
| 944 | struct bme680_data *data = iio_priv(indio_dev); | 968 | struct bme680_data *data = iio_priv(indio_dev); |
| 945 | 969 | ||
| @@ -984,6 +1008,25 @@ static int bme680_write_raw(struct iio_dev *indio_dev, · 38 unmodified lines | |||
| 984 | } | 1008 | } |
| 985 | } | 1009 | } |
| 986 | 1010 | ||
| 1011 | static int bme680_write_raw(struct iio_dev *indio_dev, | ||
| 1012 | struct iio_chan_spec const *chan, | ||
| 1013 | int val, int val2, long mask) | ||
| 1014 | { | ||
| 1015 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 1016 | struct device *dev = regmap_get_device(data->regmap); | ||
| 1017 | int ret; | ||
| 1018 | |||
| 1019 | ret = pm_runtime_resume_and_get(dev); | ||
| 1020 | if (ret) | ||
| 1021 | return ret; | ||
| 1022 | |||
| 1023 | ret = __bme680_write_raw(indio_dev, chan, val, val2, mask); | ||
| 1024 | pm_runtime_mark_last_busy(dev); | ||
| 1025 | pm_runtime_put_autosuspend(dev); | ||
| 1026 | |||
| 1027 | return ret; | ||
| 1028 | } | ||
| 1029 | |||
| 987 | static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16"; | 1030 | static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16"; |
| 988 | 1031 | ||
| 989 | static IIO_CONST_ATTR(oversampling_ratio_available, | 1032 | static IIO_CONST_ATTR(oversampling_ratio_available, |
| @@ -1084,6 +1127,29 @@ out: · 94 unmodified lines | |||
| 1084 | return IRQ_HANDLED; | 1127 | return IRQ_HANDLED; |
| 1085 | } | 1128 | } |
| 1086 | 1129 | ||
| 1130 | static int bme680_buffer_preenable(struct iio_dev *indio_dev) | ||
| 1131 | { | ||
| 1132 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 1133 | struct device *dev = regmap_get_device(data->regmap); | ||
| 1134 | |||
| 1135 | return pm_runtime_resume_and_get(dev); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | static int bme680_buffer_postdisable(struct iio_dev *indio_dev) | ||
| 1139 | { | ||
| 1140 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 1141 | struct device *dev = regmap_get_device(data->regmap); | ||
| 1142 | |||
| 1143 | pm_runtime_mark_last_busy(dev); | ||
| 1144 | pm_runtime_put_autosuspend(dev); | ||
| 1145 | return 0; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | static const struct iio_buffer_setup_ops bme680_buffer_setup_ops = { | ||
| 1149 | .preenable = bme680_buffer_preenable, | ||
| 1150 | .postdisable = bme680_buffer_postdisable, | ||
| 1151 | }; | ||
| 1152 | |||
| 1087 | int bme680_core_probe(struct device *dev, struct regmap *regmap, | 1153 | int bme680_core_probe(struct device *dev, struct regmap *regmap, |
| 1088 | const char *name) | 1154 | const char *name) |
| 1089 | { | 1155 | { |
| @@ -1114,6 +1180,14 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, · 24 unmodified lines | |||
| 1114 | data->heater_dur = 150; /* milliseconds */ | 1180 | data->heater_dur = 150; /* milliseconds */ |
| 1115 | data->preheat_curr_mA = 0; | 1181 | data->preheat_curr_mA = 0; |
| 1116 | 1182 | ||
| 1183 | ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(bme680_supply_names), | ||
| 1184 | bme680_supply_names); | ||
| 1185 | if (ret) | ||
| 1186 | return dev_err_probe(dev, ret, | ||
| 1187 | "failed to get and enable supplies.\n"); | ||
| 1188 | |||
| 1189 | fsleep(BME680_STARTUP_TIME_US); | ||
| 1190 | |||
| 1117 | ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET); | 1191 | ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET); |
| 1118 | if (ret < 0) | 1192 | if (ret < 0) |
| 1119 | return dev_err_probe(dev, ret, "Failed to reset chip\n"); | 1193 | return dev_err_probe(dev, ret, "Failed to reset chip\n"); |
| @@ -1149,15 +1223,47 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, · 29 unmodified lines | |||
| 1149 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, | 1223 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, |
| 1150 | iio_pollfunc_store_time, | 1224 | iio_pollfunc_store_time, |
| 1151 | bme680_trigger_handler, | 1225 | bme680_trigger_handler, |
| 1152 | NULL); | 1226 | &bme680_buffer_setup_ops); |
| 1153 | if (ret) | 1227 | if (ret) |
| 1154 | return dev_err_probe(dev, ret, | 1228 | return dev_err_probe(dev, ret, |
| 1155 | "iio triggered buffer setup failed\n"); | 1229 | "iio triggered buffer setup failed\n"); |
| 1156 | 1230 | ||
| 1231 | /* Enable runtime PM */ | ||
| 1232 | pm_runtime_set_autosuspend_delay(dev, BME680_STARTUP_TIME_US); | ||
| 1233 | pm_runtime_use_autosuspend(dev); | ||
| 1234 | pm_runtime_set_active(dev); | ||
| 1235 | ret = devm_pm_runtime_enable(dev); | ||
| 1236 | if (ret) | ||
| 1237 | return ret; | ||
| 1238 | |||
| 1157 | return devm_iio_device_register(dev, indio_dev); | 1239 | return devm_iio_device_register(dev, indio_dev); |
| 1158 | } | 1240 | } |
| 1159 | EXPORT_SYMBOL_NS_GPL(bme680_core_probe, "IIO_BME680"); | 1241 | EXPORT_SYMBOL_NS_GPL(bme680_core_probe, "IIO_BME680"); |
| 1160 | 1242 | ||
| 1243 | static int bme680_runtime_suspend(struct device *dev) | ||
| 1244 | { | ||
| 1245 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 1246 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 1247 | |||
| 1248 | return bme680_set_mode(data, BME680_MODE_SLEEP); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | static int bme680_runtime_resume(struct device *dev) | ||
| 1252 | { | ||
| 1253 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 1254 | struct bme680_data *data = iio_priv(indio_dev); | ||
| 1255 | int ret; | ||
| 1256 | |||
| 1257 | ret = bme680_chip_config(data); | ||
| 1258 | if (ret) | ||
| 1259 | return ret; | ||
| 1260 | |||
| 1261 | return bme680_gas_config(data); | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | EXPORT_RUNTIME_DEV_PM_OPS(bme680_dev_pm_ops, bme680_runtime_suspend, | ||
| 1265 | bme680_runtime_resume, NULL); | ||
| 1266 | |||
| 1161 | MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>"); | 1267 | MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>"); |
| 1162 | MODULE_DESCRIPTION("Bosch BME680 Driver"); | 1268 | MODULE_DESCRIPTION("Bosch BME680 Driver"); |
| 1163 | MODULE_LICENSE("GPL v2"); | 1269 | MODULE_LICENSE("GPL v2"); |
| @@ -51,6 +51,7 @@ static struct i2c_driver bme680_i2c_driver = { · 50 unmodified lines | |||
| 51 | .driver = { | 51 | .driver = { |
| 52 | .name = "bme680_i2c", | 52 | .name = "bme680_i2c", |
| 53 | .of_match_table = bme680_of_i2c_match, | 53 | .of_match_table = bme680_of_i2c_match, |
| 54 | .pm = pm_ptr(&bme680_dev_pm_ops), | ||
| 54 | }, | 55 | }, |
| 55 | .probe = bme680_i2c_probe, | 56 | .probe = bme680_i2c_probe, |
| 56 | .id_table = bme680_i2c_id, | 57 | .id_table = bme680_i2c_id, |
| @@ -154,6 +154,7 @@ static struct spi_driver bme680_spi_driver = { · 153 unmodified lines | |||
| 154 | .driver = { | 154 | .driver = { |
| 155 | .name = "bme680_spi", | 155 | .name = "bme680_spi", |
| 156 | .of_match_table = bme680_of_spi_match, | 156 | .of_match_table = bme680_of_spi_match, |
| 157 | .pm = pm_ptr(&bme680_dev_pm_ops), | ||
| 157 | }, | 158 | }, |
| 158 | .probe = bme680_spi_probe, | 159 | .probe = bme680_spi_probe, |
| 159 | .id_table = bme680_spi_id, | 160 | .id_table = bme680_spi_id, |
| @@ -81,7 +81,7 @@ struct ccs811_data { · 80 unmodified lines | |||
| 81 | /* Ensures correct alignment of timestamp if present */ | 81 | /* Ensures correct alignment of timestamp if present */ |
| 82 | struct { | 82 | struct { |
| 83 | s16 channels[2]; | 83 | s16 channels[2]; |
| 84 | s64 ts __aligned(8); | 84 | aligned_s64 ts; |
| 85 | } scan; | 85 | } scan; |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| @@ -60,7 +60,7 @@ struct ens160_data { · 59 unmodified lines | |||
| 60 | struct mutex mutex; | 60 | struct mutex mutex; |
| 61 | struct { | 61 | struct { |
| 62 | __le16 chans[2]; | 62 | __le16 chans[2]; |
| 63 | s64 timestamp __aligned(8); | 63 | aligned_s64 timestamp; |
| 64 | } scan __aligned(IIO_DMA_MINALIGN); | 64 | } scan __aligned(IIO_DMA_MINALIGN); |
| 65 | u8 fw_version[3]; | 65 | u8 fw_version[3]; |
| 66 | __le16 buf; | 66 | __le16 buf; |
| @@ -594,7 +594,7 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p) · 593 unmodified lines | |||
| 594 | struct scd30_state *state = iio_priv(indio_dev); | 594 | struct scd30_state *state = iio_priv(indio_dev); |
| 595 | struct { | 595 | struct { |
| 596 | int data[SCD30_MEAS_COUNT]; | 596 | int data[SCD30_MEAS_COUNT]; |
| 597 | s64 ts __aligned(8); | 597 | aligned_s64 ts; |
| 598 | } scan; | 598 | } scan; |
| 599 | int ret; | 599 | int ret; |
| 600 | 600 | ||
| @@ -665,7 +665,7 @@ static irqreturn_t scd4x_trigger_handler(int irq, void *p) · 664 unmodified lines | |||
| 665 | struct scd4x_state *state = iio_priv(indio_dev); | 665 | struct scd4x_state *state = iio_priv(indio_dev); |
| 666 | struct { | 666 | struct { |
| 667 | uint16_t data[3]; | 667 | uint16_t data[3]; |
| 668 | int64_t ts __aligned(8); | 668 | aligned_s64 ts; |
| 669 | } scan; | 669 | } scan; |
| 670 | int ret; | 670 | int ret; |
| 671 | 671 | ||
| @@ -109,8 +109,8 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, · 108 unmodified lines | |||
| 109 | 109 | ||
| 110 | static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) | 110 | static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) |
| 111 | { | 111 | { |
| 112 | const int64_t period_min = ts->min_period * ts->mult; | 112 | const int64_t period_min = (int64_t)ts->min_period * ts->mult; |
| 113 | const int64_t period_max = ts->max_period * ts->mult; | 113 | const int64_t period_max = (int64_t)ts->max_period * ts->mult; |
| 114 | int64_t add_max, sub_max; | 114 | int64_t add_max, sub_max; |
| 115 | int64_t delta, jitter; | 115 | int64_t delta, jitter; |
| 116 | int64_t adjust; | 116 | int64_t adjust; |
| @@ -8,6 +8,8 @@ · 7 unmodified lines | |||
| 8 | #include <linux/iio/kfifo_buf.h> | 8 | #include <linux/iio/kfifo_buf.h> |
| 9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <linux/unaligned.h> | ||
| 12 | #include <linux/units.h> | ||
| 11 | #include "ssp_iio_sensor.h" | 13 | #include "ssp_iio_sensor.h" |
| 12 | 14 | ||
| 13 | /** | 15 | /** |
| @@ -70,8 +72,7 @@ EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, "IIO_SSP_SENSORS"); · 56 unmodified lines | |||
| 70 | int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, | 72 | int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, |
| 71 | unsigned int len, int64_t timestamp) | 73 | unsigned int len, int64_t timestamp) |
| 72 | { | 74 | { |
| 73 | __le32 time; | 75 | int64_t calculated_time; |
| 74 | int64_t calculated_time = 0; | ||
| 75 | struct ssp_sensor_data *spd = iio_priv(indio_dev); | 76 | struct ssp_sensor_data *spd = iio_priv(indio_dev); |
| 76 | 77 | ||
| 77 | if (indio_dev->scan_bytes == 0) | 78 | if (indio_dev->scan_bytes == 0) |
| @@ -82,11 +83,8 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, · 4 unmodified lines | |||
| 82 | */ | 83 | */ |
| 83 | memcpy(spd->buffer, buf, len); | 84 | memcpy(spd->buffer, buf, len); |
| 84 | 85 | ||
| 85 | if (indio_dev->scan_timestamp) { | 86 | calculated_time = timestamp + |
| 86 | memcpy(&time, &((char *)buf)[len], SSP_TIME_SIZE); | 87 | (int64_t)get_unaligned_le32(buf + len) * MEGA; |
| 87 | calculated_time = | ||
| 88 | timestamp + (int64_t)le32_to_cpu(time) * 1000000; | ||
| 89 | } | ||
| 90 | 88 | ||
| 91 | return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer, | 89 | return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer, |
| 92 | calculated_time); | 90 | calculated_time); |
| @@ -80,7 +80,7 @@ config AD5421 · 79 unmodified lines | |||
| 80 | depends on SPI | 80 | depends on SPI |
| 81 | help | 81 | help |
| 82 | Say yes here to build support for Analog Devices AD5421 loop-powered | 82 | Say yes here to build support for Analog Devices AD5421 loop-powered |
| 83 | digital-to-analog convertors (DAC). | 83 | digital-to-analog converters (DAC). |
| 84 | 84 | ||
| 85 | To compile this driver as module choose M here: the module will be called | 85 | To compile this driver as module choose M here: the module will be called |
| 86 | ad5421. | 86 | ad5421. |
| @@ -348,6 +348,14 @@ config AD8801 · 261 unmodified lines | |||
| 348 | To compile this driver as a module choose M here: the module will be called | 348 | To compile this driver as a module choose M here: the module will be called |
| 349 | ad8801. | 349 | ad8801. |
| 350 | 350 | ||
| 351 | config BD79703 | ||
| 352 | tristate "ROHM Semiconductor BD79703 DAC driver" | ||
| 353 | depends on SPI | ||
| 354 | select REGMAP_SPI | ||
| 355 | help | ||
| 356 | Say yes here to build support for ROHM Semiconductor BD79703 Digital | ||
| 357 | to Analog Converter (DAC). | ||
| 358 | |||
| 351 | config CIO_DAC | 359 | config CIO_DAC |
| 352 | tristate "Measurement Computing CIO-DAC IIO driver" | 360 | tristate "Measurement Computing CIO-DAC IIO driver" |
| 353 | depends on X86 && (ISA_BUS || PC104) | 361 | depends on X86 && (ISA_BUS || PC104) |
| @@ -34,6 +34,7 @@ obj-$(CONFIG_AD8460) += ad8460.o · 33 unmodified lines | |||
| 34 | obj-$(CONFIG_AD8801) += ad8801.o | 34 | obj-$(CONFIG_AD8801) += ad8801.o |
| 35 | obj-$(CONFIG_AD9739A) += ad9739a.o | 35 | obj-$(CONFIG_AD9739A) += ad9739a.o |
| 36 | obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o | 36 | obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o |
| 37 | obj-$(CONFIG_BD79703) += rohm-bd79703.o | ||
| 37 | obj-$(CONFIG_CIO_DAC) += cio-dac.o | 38 | obj-$(CONFIG_CIO_DAC) += cio-dac.o |
| 38 | obj-$(CONFIG_DPOT_DAC) += dpot-dac.o | 39 | obj-$(CONFIG_DPOT_DAC) += dpot-dac.o |
| 39 | obj-$(CONFIG_DS4424) += ds4424.o | 40 | obj-$(CONFIG_DS4424) += ds4424.o |
| @@ -22,11 +22,10 @@ EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, "IIO_AD3552R"); · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = { | 23 | const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = { |
| 24 | [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, | 24 | [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, |
| 25 | [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 }, | ||
| 26 | [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, | 25 | [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, |
| 27 | [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, | 26 | [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, |
| 28 | [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 }, | 27 | [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }, |
| 29 | [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 } | 28 | [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 } |
| 30 | }; | 29 | }; |
| 31 | EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, "IIO_AD3552R"); | 30 | EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, "IIO_AD3552R"); |
| 32 | 31 | ||
| @@ -329,6 +329,12 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st) · 328 unmodified lines | |||
| 329 | dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n", | 329 | dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n", |
| 330 | AD3552R_ID, id); | 330 | AD3552R_ID, id); |
| 331 | 331 | ||
| 332 | /* Clear reset error flag, see ad3552r manual, rev B table 38. */ | ||
| 333 | ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_ERR_STATUS, | ||
| 334 | AD3552R_MASK_RESET_STATUS, 1); | ||
| 335 | if (ret) | ||
| 336 | return ret; | ||
| 337 | |||
| 332 | ret = st->data->bus_reg_write(st->back, | 338 | ret = st->data->bus_reg_write(st->back, |
| 333 | AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, | 339 | AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, |
| 334 | 0, 1); | 340 | 0, 1); |
| @@ -131,7 +131,7 @@ · 130 unmodified lines | |||
| 131 | #define AD3552R_CH1_ACTIVE BIT(1) | 131 | #define AD3552R_CH1_ACTIVE BIT(1) |
| 132 | 132 | ||
| 133 | #define AD3552R_MAX_RANGES 5 | 133 | #define AD3552R_MAX_RANGES 5 |
| 134 | #define AD3542R_MAX_RANGES 6 | 134 | #define AD3542R_MAX_RANGES 5 |
| 135 | #define AD3552R_QUAD_SPI 2 | 135 | #define AD3552R_QUAD_SPI 2 |
| 136 | 136 | ||
| 137 | extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; | 137 | extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; |
| @@ -189,16 +189,14 @@ enum ad3552r_ch_vref_select { · 51 unmodified lines | |||
| 189 | enum ad3542r_ch_output_range { | 189 | enum ad3542r_ch_output_range { |
| 190 | /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ | 190 | /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ |
| 191 | AD3542R_CH_OUTPUT_RANGE_0__2P5V, | 191 | AD3542R_CH_OUTPUT_RANGE_0__2P5V, |
| 192 | /* Range from 0 V to 3 V. Requires Rfb1x connection */ | ||
| 193 | AD3542R_CH_OUTPUT_RANGE_0__3V, | ||
| 194 | /* Range from 0 V to 5 V. Requires Rfb1x connection */ | 192 | /* Range from 0 V to 5 V. Requires Rfb1x connection */ |
| 195 | AD3542R_CH_OUTPUT_RANGE_0__5V, | 193 | AD3542R_CH_OUTPUT_RANGE_0__5V, |
| 196 | /* Range from 0 V to 10 V. Requires Rfb2x connection */ | 194 | /* Range from 0 V to 10 V. Requires Rfb2x connection */ |
| 197 | AD3542R_CH_OUTPUT_RANGE_0__10V, | 195 | AD3542R_CH_OUTPUT_RANGE_0__10V, |
| 198 | /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ | ||
| 199 | AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, | ||
| 200 | /* Range from -5 V to 5 V. Requires Rfb2x connection */ | 196 | /* Range from -5 V to 5 V. Requires Rfb2x connection */ |
| 201 | AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, | 197 | AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, |
| 198 | /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ | ||
| 199 | AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, | ||
| 202 | }; | 200 | }; |
| 203 | 201 | ||
| 204 | enum ad3552r_ch_output_range { | 202 | enum ad3552r_ch_output_range { |
| @@ -41,11 +41,9 @@ struct ad5624r_chip_info { · 40 unmodified lines | |||
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| 44 | * struct ad5446_state - driver instance specific data | 44 | * struct ad5624r_state - driver instance specific data |
| 45 | * @indio_dev: the industrial I/O device | ||
| 46 | * @us: spi_device | 45 | * @us: spi_device |
| 47 | * @chip_info: chip model specific constants, available modes etc | 46 | * @chip_info: chip model specific constants, available modes etc |
| 48 | * @reg: supply regulator | ||
| 49 | * @vref_mv: actual reference voltage used | 47 | * @vref_mv: actual reference voltage used |
| 50 | * @pwr_down_mask power down mask | 48 | * @pwr_down_mask power down mask |
| 51 | * @pwr_down_mode current power down mode | 49 | * @pwr_down_mode current power down mode |
| @@ -95,11 +95,6 @@ static int ad5686_spi_probe(struct spi_device *spi) · 94 unmodified lines | |||
| 95 | ad5686_spi_write, ad5686_spi_read); | 95 | ad5686_spi_write, ad5686_spi_read); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | static void ad5686_spi_remove(struct spi_device *spi) | ||
| 99 | { | ||
| 100 | ad5686_remove(&spi->dev); | ||
| 101 | } | ||
| 102 | |||
| 103 | static const struct spi_device_id ad5686_spi_id[] = { | 98 | static const struct spi_device_id ad5686_spi_id[] = { |
| 104 | {"ad5310r", ID_AD5310R}, | 99 | {"ad5310r", ID_AD5310R}, |
| 105 | {"ad5672r", ID_AD5672R}, | 100 | {"ad5672r", ID_AD5672R}, |
| @@ -126,7 +121,6 @@ static struct spi_driver ad5686_spi_driver = { · 20 unmodified lines | |||
| 126 | .name = "ad5686", | 121 | .name = "ad5686", |
| 127 | }, | 122 | }, |
| 128 | .probe = ad5686_spi_probe, | 123 | .probe = ad5686_spi_probe, |
| 129 | .remove = ad5686_spi_remove, | ||
| 130 | .id_table = ad5686_spi_id, | 124 | .id_table = ad5686_spi_id, |
| 131 | }; | 125 | }; |
| 132 | 126 | ||
| @@ -455,39 +455,28 @@ int ad5686_probe(struct device *dev, · 454 unmodified lines | |||
| 455 | struct ad5686_state *st; | 455 | struct ad5686_state *st; |
| 456 | struct iio_dev *indio_dev; | 456 | struct iio_dev *indio_dev; |
| 457 | unsigned int val, ref_bit_msk; | 457 | unsigned int val, ref_bit_msk; |
| 458 | bool has_external_vref; | ||
| 458 | u8 cmd; | 459 | u8 cmd; |
| 459 | int ret, i, voltage_uv = 0; | 460 | int ret, i; |
| 460 | 461 | ||
| 461 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); | 462 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
| 462 | if (indio_dev == NULL) | 463 | if (indio_dev == NULL) |
| 463 | return -ENOMEM; | 464 | return -ENOMEM; |
| 464 | 465 | ||
| 465 | st = iio_priv(indio_dev); | 466 | st = iio_priv(indio_dev); |
| 466 | dev_set_drvdata(dev, indio_dev); | ||
| 467 | 467 | ||
| 468 | st->dev = dev; | 468 | st->dev = dev; |
| 469 | st->write = write; | 469 | st->write = write; |
| 470 | st->read = read; | 470 | st->read = read; |
| 471 | 471 | ||
| 472 | st->reg = devm_regulator_get_optional(dev, "vcc"); | ||
| 473 | if (!IS_ERR(st->reg)) { | ||
| 474 | ret = regulator_enable(st->reg); | ||
| 475 | if (ret) | ||
| 476 | return ret; | ||
| 477 | |||
| 478 | ret = regulator_get_voltage(st->reg); | ||
| 479 | if (ret < 0) | ||
| 480 | goto error_disable_reg; | ||
| 481 | |||
| 482 | voltage_uv = ret; | ||
| 483 | } | ||
| 484 | |||
| 485 | st->chip_info = &ad5686_chip_info_tbl[chip_type]; | 472 | st->chip_info = &ad5686_chip_info_tbl[chip_type]; |
| 486 | 473 | ||
| 487 | if (voltage_uv) | 474 | ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); |
| 488 | st->vref_mv = voltage_uv / 1000; | 475 | if (ret < 0 && ret != -ENODEV) |
| 489 | else | 476 | return ret; |
| 490 | st->vref_mv = st->chip_info->int_vref_mv; | 477 | |
| 478 | has_external_vref = ret != -ENODEV; | ||
| 479 | st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv; | ||
| 491 | 480 | ||
| 492 | /* Set all the power down mode for all channels to 1K pulldown */ | 481 | /* Set all the power down mode for all channels to 1K pulldown */ |
| 493 | for (i = 0; i < st->chip_info->num_channels; i++) | 482 | for (i = 0; i < st->chip_info->num_channels; i++) |
| @@ -505,12 +494,12 @@ int ad5686_probe(struct device *dev, · 11 unmodified lines | |||
| 505 | case AD5310_REGMAP: | 494 | case AD5310_REGMAP: |
| 506 | cmd = AD5686_CMD_CONTROL_REG; | 495 | cmd = AD5686_CMD_CONTROL_REG; |
| 507 | ref_bit_msk = AD5310_REF_BIT_MSK; | 496 | ref_bit_msk = AD5310_REF_BIT_MSK; |
| 508 | st->use_internal_vref = !voltage_uv; | 497 | st->use_internal_vref = !has_external_vref; |
| 509 | break; | 498 | break; |
| 510 | case AD5683_REGMAP: | 499 | case AD5683_REGMAP: |
| 511 | cmd = AD5686_CMD_CONTROL_REG; | 500 | cmd = AD5686_CMD_CONTROL_REG; |
| 512 | ref_bit_msk = AD5683_REF_BIT_MSK; | 501 | ref_bit_msk = AD5683_REF_BIT_MSK; |
| 513 | st->use_internal_vref = !voltage_uv; | 502 | st->use_internal_vref = !has_external_vref; |
| 514 | break; | 503 | break; |
| 515 | case AD5686_REGMAP: | 504 | case AD5686_REGMAP: |
| 516 | cmd = AD5686_CMD_INTERNAL_REFER_SETUP; | 505 | cmd = AD5686_CMD_INTERNAL_REFER_SETUP; |
| @@ -519,43 +508,22 @@ int ad5686_probe(struct device *dev, · 2 unmodified lines | |||
| 519 | case AD5693_REGMAP: | 508 | case AD5693_REGMAP: |
| 520 | cmd = AD5686_CMD_CONTROL_REG; | 509 | cmd = AD5686_CMD_CONTROL_REG; |
| 521 | ref_bit_msk = AD5693_REF_BIT_MSK; | 510 | ref_bit_msk = AD5693_REF_BIT_MSK; |
| 522 | st->use_internal_vref = !voltage_uv; | 511 | st->use_internal_vref = !has_external_vref; |
| 523 | break; | 512 | break; |
| 524 | default: | 513 | default: |
| 525 | ret = -EINVAL; | 514 | return -EINVAL; |
| 526 | goto error_disable_reg; | ||
| 527 | } | 515 | } |
| 528 | 516 | ||
| 529 | val = (voltage_uv | ref_bit_msk); | 517 | val = (has_external_vref | ref_bit_msk); |
| 530 | 518 | ||
| 531 | ret = st->write(st, cmd, 0, !!val); | 519 | ret = st->write(st, cmd, 0, !!val); |
| 532 | if (ret) | 520 | if (ret) |
| 533 | goto error_disable_reg; | 521 | return ret; |
| 534 | |||
| 535 | ret = iio_device_register(indio_dev); | ||
| 536 | if (ret) | ||
| 537 | goto error_disable_reg; | ||
| 538 | |||
| 539 | return 0; | ||
| 540 | 522 | ||
| 541 | error_disable_reg: | 523 | return devm_iio_device_register(dev, indio_dev); |
| 542 | if (!IS_ERR(st->reg)) | ||
| 543 | regulator_disable(st->reg); | ||
| 544 | return ret; | ||
| 545 | } | 524 | } |
| 546 | EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686"); | 525 | EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686"); |
| 547 | 526 | ||
| 548 | void ad5686_remove(struct device *dev) | ||
| 549 | { | ||
| 550 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 551 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 552 | |||
| 553 | iio_device_unregister(indio_dev); | ||
| 554 | if (!IS_ERR(st->reg)) | ||
| 555 | regulator_disable(st->reg); | ||
| 556 | } | ||
| 557 | EXPORT_SYMBOL_NS_GPL(ad5686_remove, "IIO_AD5686"); | ||
| 558 | |||
| 559 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); | 527 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
| 560 | MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); | 528 | MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); |
| 561 | MODULE_LICENSE("GPL v2"); | 529 | MODULE_LICENSE("GPL v2"); |
| @@ -115,10 +115,9 @@ struct ad5686_chip_info { · 114 unmodified lines | |||
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | /** | 117 | /** |
| 118 | * struct ad5446_state - driver instance specific data | 118 | * struct ad5686_state - driver instance specific data |
| 119 | * @spi: spi_device | 119 | * @spi: spi_device |
| 120 | * @chip_info: chip model specific constants, available modes etc | 120 | * @chip_info: chip model specific constants, available modes etc |
| 121 | * @reg: supply regulator | ||
| 122 | * @vref_mv: actual reference voltage used | 121 | * @vref_mv: actual reference voltage used |
| 123 | * @pwr_down_mask: power down mask | 122 | * @pwr_down_mask: power down mask |
| 124 | * @pwr_down_mode: current power down mode | 123 | * @pwr_down_mode: current power down mode |
| @@ -130,7 +129,6 @@ struct ad5686_chip_info { · 5 unmodified lines | |||
| 130 | struct ad5686_state { | 129 | struct ad5686_state { |
| 131 | struct device *dev; | 130 | struct device *dev; |
| 132 | const struct ad5686_chip_info *chip_info; | 131 | const struct ad5686_chip_info *chip_info; |
| 133 | struct regulator *reg; | ||
| 134 | unsigned short vref_mv; | 132 | unsigned short vref_mv; |
| 135 | unsigned int pwr_down_mask; | 133 | unsigned int pwr_down_mask; |
| 136 | unsigned int pwr_down_mode; | 134 | unsigned int pwr_down_mode; |
| @@ -157,7 +155,5 @@ int ad5686_probe(struct device *dev, · 20 unmodified lines | |||
| 157 | const char *name, ad5686_write_func write, | 155 | const char *name, ad5686_write_func write, |
| 158 | ad5686_read_func read); | 156 | ad5686_read_func read); |
| 159 | 157 | ||
| 160 | void ad5686_remove(struct device *dev); | ||
| 161 | |||
| 162 | 158 | ||
| 163 | #endif /* __DRIVERS_IIO_DAC_AD5686_H__ */ | 159 | #endif /* __DRIVERS_IIO_DAC_AD5686_H__ */ |
| @@ -65,11 +65,6 @@ static int ad5686_i2c_probe(struct i2c_client *i2c) · 64 unmodified lines | |||
| 65 | ad5686_i2c_write, ad5686_i2c_read); | 65 | ad5686_i2c_write, ad5686_i2c_read); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | static void ad5686_i2c_remove(struct i2c_client *i2c) | ||
| 69 | { | ||
| 70 | ad5686_remove(&i2c->dev); | ||
| 71 | } | ||
| 72 | |||
| 73 | static const struct i2c_device_id ad5686_i2c_id[] = { | 68 | static const struct i2c_device_id ad5686_i2c_id[] = { |
| 74 | {"ad5311r", ID_AD5311R}, | 69 | {"ad5311r", ID_AD5311R}, |
| 75 | {"ad5337r", ID_AD5337R}, | 70 | {"ad5337r", ID_AD5337R}, |
| @@ -116,7 +111,6 @@ static struct i2c_driver ad5686_i2c_driver = { · 40 unmodified lines | |||
| 116 | .of_match_table = ad5686_of_match, | 111 | .of_match_table = ad5686_of_match, |
| 117 | }, | 112 | }, |
| 118 | .probe = ad5686_i2c_probe, | 113 | .probe = ad5686_i2c_probe, |
| 119 | .remove = ad5686_i2c_remove, | ||
| 120 | .id_table = ad5686_i2c_id, | 114 | .id_table = ad5686_i2c_id, |
| 121 | }; | 115 | }; |
| 122 | 116 | ||
| @@ -141,8 +141,6 @@ struct ad7293_state { · 140 unmodified lines | |||
| 141 | /* Protect against concurrent accesses to the device, page selection and data content */ | 141 | /* Protect against concurrent accesses to the device, page selection and data content */ |
| 142 | struct mutex lock; | 142 | struct mutex lock; |
| 143 | struct gpio_desc *gpio_reset; | 143 | struct gpio_desc *gpio_reset; |
| 144 | struct regulator *reg_avdd; | ||
| 145 | struct regulator *reg_vdrive; | ||
| 146 | u8 page_select; | 144 | u8 page_select; |
| 147 | u8 data[3] __aligned(IIO_DMA_MINALIGN); | 145 | u8 data[3] __aligned(IIO_DMA_MINALIGN); |
| 148 | }; | 146 | }; |
| @@ -777,6 +775,15 @@ static int ad7293_reset(struct ad7293_state *st) · 628 unmodified lines | |||
| 777 | static int ad7293_properties_parse(struct ad7293_state *st) | 775 | static int ad7293_properties_parse(struct ad7293_state *st) |
| 778 | { | 776 | { |
| 779 | struct spi_device *spi = st->spi; | 777 | struct spi_device *spi = st->spi; |
| 778 | int ret; | ||
| 779 | |||
| 780 | ret = devm_regulator_get_enable(&spi->dev, "avdd"); | ||
| 781 | if (ret) | ||
| 782 | return dev_err_probe(&spi->dev, ret, "failed to enable AVDD\n"); | ||
| 783 | |||
| 784 | ret = devm_regulator_get_enable(&spi->dev, "vdrive"); | ||
| 785 | if (ret) | ||
| 786 | return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n"); | ||
| 780 | 787 | ||
| 781 | st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", | 788 | st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", |
| 782 | GPIOD_OUT_HIGH); | 789 | GPIOD_OUT_HIGH); |
| @@ -784,24 +791,9 @@ static int ad7293_properties_parse(struct ad7293_state *st) · 1 unmodified line | |||
| 784 | return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset), | 791 | return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset), |
| 785 | "failed to get the reset GPIO\n"); | 792 | "failed to get the reset GPIO\n"); |
| 786 | 793 | ||
| 787 | st->reg_avdd = devm_regulator_get(&spi->dev, "avdd"); | ||
| 788 | if (IS_ERR(st->reg_avdd)) | ||
| 789 | return dev_err_probe(&spi->dev, PTR_ERR(st->reg_avdd), | ||
| 790 | "failed to get the AVDD voltage\n"); | ||
| 791 | |||
| 792 | st->reg_vdrive = devm_regulator_get(&spi->dev, "vdrive"); | ||
| 793 | if (IS_ERR(st->reg_vdrive)) | ||
| 794 | return dev_err_probe(&spi->dev, PTR_ERR(st->reg_vdrive), | ||
| 795 | "failed to get the VDRIVE voltage\n"); | ||
| 796 | |||
| 797 | return 0; | 794 | return 0; |
| 798 | } | 795 | } |
| 799 | 796 | ||
| 800 | static void ad7293_reg_disable(void *data) | ||
| 801 | { | ||
| 802 | regulator_disable(data); | ||
| 803 | } | ||
| 804 | |||
| 805 | static int ad7293_init(struct ad7293_state *st) | 797 | static int ad7293_init(struct ad7293_state *st) |
| 806 | { | 798 | { |
| 807 | int ret; | 799 | int ret; |
| @@ -816,48 +808,6 @@ static int ad7293_init(struct ad7293_state *st) · 8 unmodified lines | |||
| 816 | if (ret) | 808 | if (ret) |
| 817 | return ret; | 809 | return ret; |
| 818 | 810 | ||
| 819 | ret = regulator_enable(st->reg_avdd); | ||
| 820 | if (ret) { | ||
| 821 | dev_err(&spi->dev, | ||
| 822 | "Failed to enable specified AVDD Voltage!\n"); | ||
| 823 | return ret; | ||
| 824 | } | ||
| 825 | |||
| 826 | ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable, | ||
| 827 | st->reg_avdd); | ||
| 828 | if (ret) | ||
| 829 | return ret; | ||
| 830 | |||
| 831 | ret = regulator_enable(st->reg_vdrive); | ||
| 832 | if (ret) { | ||
| 833 | dev_err(&spi->dev, | ||
| 834 | "Failed to enable specified VDRIVE Voltage!\n"); | ||
| 835 | return ret; | ||
| 836 | } | ||
| 837 | |||
| 838 | ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable, | ||
| 839 | st->reg_vdrive); | ||
| 840 | if (ret) | ||
| 841 | return ret; | ||
| 842 | |||
| 843 | ret = regulator_get_voltage(st->reg_avdd); | ||
| 844 | if (ret < 0) { | ||
| 845 | dev_err(&spi->dev, "Failed to read avdd regulator: %d\n", ret); | ||
| 846 | return ret; | ||
| 847 | } | ||
| 848 | |||
| 849 | if (ret > 5500000 || ret < 4500000) | ||
| 850 | return -EINVAL; | ||
| 851 | |||
| 852 | ret = regulator_get_voltage(st->reg_vdrive); | ||
| 853 | if (ret < 0) { | ||
| 854 | dev_err(&spi->dev, | ||
| 855 | "Failed to read vdrive regulator: %d\n", ret); | ||
| 856 | return ret; | ||
| 857 | } | ||
| 858 | if (ret > 5500000 || ret < 1700000) | ||
| 859 | return -EINVAL; | ||
| 860 | |||
| 861 | /* Check Chip ID */ | 811 | /* Check Chip ID */ |
| 862 | ret = __ad7293_spi_read(st, AD7293_REG_DEVICE_ID, &chip_id); | 812 | ret = __ad7293_spi_read(st, AD7293_REG_DEVICE_ID, &chip_id); |
| 863 | if (ret) | 813 | if (ret) |
| @@ -23,8 +23,6 @@ struct ad8801_state { · 22 unmodified lines | |||
| 23 | unsigned char dac_cache[8]; /* Value write on each channel */ | 23 | unsigned char dac_cache[8]; /* Value write on each channel */ |
| 24 | unsigned int vrefh_mv; | 24 | unsigned int vrefh_mv; |
| 25 | unsigned int vrefl_mv; | 25 | unsigned int vrefl_mv; |
| 26 | struct regulator *vrefh_reg; | ||
| 27 | struct regulator *vrefl_reg; | ||
| 28 | 26 | ||
| 29 | __be16 data __aligned(IIO_DMA_MINALIGN); | 27 | __be16 data __aligned(IIO_DMA_MINALIGN); |
| 30 | }; | 28 | }; |
| @@ -122,86 +120,34 @@ static int ad8801_probe(struct spi_device *spi) · 91 unmodified lines | |||
| 122 | state->spi = spi; | 120 | state->spi = spi; |
| 123 | id = spi_get_device_id(spi); | 121 | id = spi_get_device_id(spi); |
| 124 | 122 | ||
| 125 | state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh"); | 123 | ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefh"); |
| 126 | if (IS_ERR(state->vrefh_reg)) | 124 | if (ret < 0) |
| 127 | return dev_err_probe(&spi->dev, PTR_ERR(state->vrefh_reg), | 125 | return dev_err_probe(&spi->dev, ret, |
| 128 | "Vrefh regulator not specified\n"); | 126 | "failed to get Vrefh voltage\n"); |
| 129 | 127 | ||
| 130 | ret = regulator_enable(state->vrefh_reg); | ||
| 131 | if (ret) { | ||
| 132 | dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n", | ||
| 133 | ret); | ||
| 134 | return ret; | ||
| 135 | } | ||
| 136 | |||
| 137 | ret = regulator_get_voltage(state->vrefh_reg); | ||
| 138 | if (ret < 0) { | ||
| 139 | dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n", | ||
| 140 | ret); | ||
| 141 | goto error_disable_vrefh_reg; | ||
| 142 | } | ||
| 143 | state->vrefh_mv = ret / 1000; | 128 | state->vrefh_mv = ret / 1000; |
| 144 | 129 | ||
| 145 | if (id->driver_data == ID_AD8803) { | 130 | if (id->driver_data == ID_AD8803) { |
| 146 | state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl"); | 131 | ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefl"); |
| 147 | if (IS_ERR(state->vrefl_reg)) { | 132 | if (ret < 0) |
| 148 | ret = dev_err_probe(&spi->dev, PTR_ERR(state->vrefl_reg), | 133 | return dev_err_probe(&spi->dev, ret, |
| 149 | "Vrefl regulator not specified\n"); | 134 | "failed to get Vrefl voltage\n"); |
| 150 | goto error_disable_vrefh_reg; | 135 | |
| 151 | } | ||
| 152 | |||
| 153 | ret = regulator_enable(state->vrefl_reg); | ||
| 154 | if (ret) { | ||
| 155 | dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n", | ||
| 156 | ret); | ||
| 157 | goto error_disable_vrefh_reg; | ||
| 158 | } | ||
| 159 | |||
| 160 | ret = regulator_get_voltage(state->vrefl_reg); | ||
| 161 | if (ret < 0) { | ||
| 162 | dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n", | ||
| 163 | ret); | ||
| 164 | goto error_disable_vrefl_reg; | ||
| 165 | } | ||
| 166 | state->vrefl_mv = ret / 1000; | 136 | state->vrefl_mv = ret / 1000; |
| 167 | } else { | ||
| 168 | state->vrefl_mv = 0; | ||
| 169 | state->vrefl_reg = NULL; | ||
| 170 | } | 137 | } |
| 171 | 138 | ||
| 172 | spi_set_drvdata(spi, indio_dev); | ||
| 173 | indio_dev->info = &ad8801_info; | 139 | indio_dev->info = &ad8801_info; |
| 174 | indio_dev->modes = INDIO_DIRECT_MODE; | 140 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 175 | indio_dev->channels = ad8801_channels; | 141 | indio_dev->channels = ad8801_channels; |
| 176 | indio_dev->num_channels = ARRAY_SIZE(ad8801_channels); | 142 | indio_dev->num_channels = ARRAY_SIZE(ad8801_channels); |
| 177 | indio_dev->name = id->name; | 143 | indio_dev->name = id->name; |
| 178 | 144 | ||
| 179 | ret = iio_device_register(indio_dev); | 145 | ret = devm_iio_device_register(&spi->dev, indio_dev); |
| 180 | if (ret) { | 146 | if (ret) |
| 181 | dev_err(&spi->dev, "Failed to register iio device: %d\n", | 147 | return dev_err_probe(&spi->dev, ret, |
| 182 | ret); | 148 | "Failed to register iio device\n"); |
| 183 | goto error_disable_vrefl_reg; | ||
| 184 | } | ||
| 185 | 149 | ||
| 186 | return 0; | 150 | return 0; |
| 187 | |||
| 188 | error_disable_vrefl_reg: | ||
| 189 | if (state->vrefl_reg) | ||
| 190 | regulator_disable(state->vrefl_reg); | ||
| 191 | error_disable_vrefh_reg: | ||
| 192 | regulator_disable(state->vrefh_reg); | ||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | |||
| 196 | static void ad8801_remove(struct spi_device *spi) | ||
| 197 | { | ||
| 198 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 199 | struct ad8801_state *state = iio_priv(indio_dev); | ||
| 200 | |||
| 201 | iio_device_unregister(indio_dev); | ||
| 202 | if (state->vrefl_reg) | ||
| 203 | regulator_disable(state->vrefl_reg); | ||
| 204 | regulator_disable(state->vrefh_reg); | ||
| 205 | } | 151 | } |
| 206 | 152 | ||
| 207 | static const struct spi_device_id ad8801_ids[] = { | 153 | static const struct spi_device_id ad8801_ids[] = { |
| @@ -216,7 +162,6 @@ static struct spi_driver ad8801_driver = { · 8 unmodified lines | |||
| 216 | .name = "ad8801", | 162 | .name = "ad8801", |
| 217 | }, | 163 | }, |
| 218 | .probe = ad8801_probe, | 164 | .probe = ad8801_probe, |
| 219 | .remove = ad8801_remove, | ||
| 220 | .id_table = ad8801_ids, | 165 | .id_table = ad8801_ids, |
| 221 | }; | 166 | }; |
| 222 | module_spi_driver(ad8801_driver); | 167 | module_spi_driver(ad8801_driver); |
| @@ -41,13 +41,11 @@ struct ltc2632_chip_info { · 40 unmodified lines | |||
| 41 | * @spi_dev: pointer to the spi_device struct | 41 | * @spi_dev: pointer to the spi_device struct |
| 42 | * @powerdown_cache_mask: used to show current channel powerdown state | 42 | * @powerdown_cache_mask: used to show current channel powerdown state |
| 43 | * @vref_mv: used reference voltage (internal or external) | 43 | * @vref_mv: used reference voltage (internal or external) |
| 44 | * @vref_reg: regulator for the reference voltage | ||
| 45 | */ | 44 | */ |
| 46 | struct ltc2632_state { | 45 | struct ltc2632_state { |
| 47 | struct spi_device *spi_dev; | 46 | struct spi_device *spi_dev; |
| 48 | unsigned int powerdown_cache_mask; | 47 | unsigned int powerdown_cache_mask; |
| 49 | int vref_mv; | 48 | int vref_mv; |
| 50 | struct regulator *vref_reg; | ||
| 51 | }; | 49 | }; |
| 52 | 50 | ||
| 53 | enum ltc2632_supported_device_ids { | 51 | enum ltc2632_supported_device_ids { |
| @@ -310,6 +308,7 @@ static int ltc2632_probe(struct spi_device *spi) · 256 unmodified lines | |||
| 310 | struct ltc2632_state *st; | 308 | struct ltc2632_state *st; |
| 311 | struct iio_dev *indio_dev; | 309 | struct iio_dev *indio_dev; |
| 312 | struct ltc2632_chip_info *chip_info; | 310 | struct ltc2632_chip_info *chip_info; |
| 311 | bool has_external_vref; | ||
| 313 | int ret; | 312 | int ret; |
| 314 | 313 | ||
| 315 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | 314 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
| @@ -318,49 +317,31 @@ static int ltc2632_probe(struct spi_device *spi) · 2 unmodified lines | |||
| 318 | 317 | ||
| 319 | st = iio_priv(indio_dev); | 318 | st = iio_priv(indio_dev); |
| 320 | 319 | ||
| 321 | spi_set_drvdata(spi, indio_dev); | ||
| 322 | st->spi_dev = spi; | 320 | st->spi_dev = spi; |
| 323 | 321 | ||
| 324 | chip_info = (struct ltc2632_chip_info *) | 322 | chip_info = (struct ltc2632_chip_info *) |
| 325 | spi_get_device_id(spi)->driver_data; | 323 | spi_get_device_id(spi)->driver_data; |
| 326 | 324 | ||
| 327 | st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); | 325 | ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); |
| 328 | if (PTR_ERR(st->vref_reg) == -ENODEV) { | 326 | if (ret < 0 && ret != -ENODEV) |
| 329 | /* use internal reference voltage */ | 327 | return dev_err_probe(&spi->dev, ret, |
| 330 | st->vref_reg = NULL; | 328 | "Failed to get vref regulator voltage\n"); |
| 331 | st->vref_mv = chip_info->vref_mv; | ||
| 332 | 329 | ||
| 333 | ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, | 330 | has_external_vref = ret != -ENODEV; |
| 334 | 0, 0, 0); | 331 | st->vref_mv = has_external_vref ? ret / 1000 : chip_info->vref_mv; |
| 335 | if (ret) { | ||
| 336 | dev_err(&spi->dev, | ||
| 337 | "Set internal reference command failed, %d\n", | ||
| 338 | ret); | ||
| 339 | return ret; | ||
| 340 | } | ||
| 341 | } else if (IS_ERR(st->vref_reg)) { | ||
| 342 | dev_err(&spi->dev, | ||
| 343 | "Error getting voltage reference regulator\n"); | ||
| 344 | return PTR_ERR(st->vref_reg); | ||
| 345 | } else { | ||
| 346 | /* use external reference voltage */ | ||
| 347 | ret = regulator_enable(st->vref_reg); | ||
| 348 | if (ret) { | ||
| 349 | dev_err(&spi->dev, | ||
| 350 | "enable reference regulator failed, %d\n", | ||
| 351 | ret); | ||
| 352 | return ret; | ||
| 353 | } | ||
| 354 | st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000; | ||
| 355 | 332 | ||
| 333 | if (has_external_vref) { | ||
| 356 | ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER, | 334 | ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER, |
| 357 | 0, 0, 0); | 335 | 0, 0, 0); |
| 358 | if (ret) { | 336 | if (ret) |
| 359 | dev_err(&spi->dev, | 337 | return dev_err_probe(&spi->dev, ret, |
| 360 | "Set external reference command failed, %d\n", | 338 | "Set external reference command failed\n"); |
| 361 | ret); | 339 | } else { |
| 362 | return ret; | 340 | ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER, |
| 363 | } | 341 | 0, 0, 0); |
| 342 | if (ret) | ||
| 343 | return dev_err_probe(&spi->dev, ret, | ||
| 344 | "Set internal reference command failed\n"); | ||
| 364 | } | 345 | } |
| 365 | 346 | ||
| 366 | indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name; | 347 | indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name; |
| @@ -369,18 +350,7 @@ static int ltc2632_probe(struct spi_device *spi) · 2 unmodified lines | |||
| 369 | indio_dev->channels = chip_info->channels; | 350 | indio_dev->channels = chip_info->channels; |
| 370 | indio_dev->num_channels = chip_info->num_channels; | 351 | indio_dev->num_channels = chip_info->num_channels; |
| 371 | 352 | ||
| 372 | return iio_device_register(indio_dev); | 353 | return devm_iio_device_register(&spi->dev, indio_dev); |
| 373 | } | ||
| 374 | |||
| 375 | static void ltc2632_remove(struct spi_device *spi) | ||
| 376 | { | ||
| 377 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 378 | struct ltc2632_state *st = iio_priv(indio_dev); | ||
| 379 | |||
| 380 | iio_device_unregister(indio_dev); | ||
| 381 | |||
| 382 | if (st->vref_reg) | ||
| 383 | regulator_disable(st->vref_reg); | ||
| 384 | } | 354 | } |
| 385 | 355 | ||
| 386 | static const struct spi_device_id ltc2632_id[] = { | 356 | static const struct spi_device_id ltc2632_id[] = { |
| @@ -472,7 +442,6 @@ static struct spi_driver ltc2632_driver = { · 85 unmodified lines | |||
| 472 | .of_match_table = ltc2632_of_match, | 442 | .of_match_table = ltc2632_of_match, |
| 473 | }, | 443 | }, |
| 474 | .probe = ltc2632_probe, | 444 | .probe = ltc2632_probe, |
| 475 | .remove = ltc2632_remove, | ||
| 476 | .id_table = ltc2632_id, | 445 | .id_table = ltc2632_id, |
| 477 | }; | 446 | }; |
| 478 | module_spi_driver(ltc2632_driver); | 447 | module_spi_driver(ltc2632_driver); |
| @@ -842,7 +842,7 @@ static int ltc2688_channel_config(struct ltc2688_state *st) · 841 unmodified lines | |||
| 842 | return 0; | 842 | return 0; |
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) | 845 | static int ltc2688_setup(struct ltc2688_state *st, bool has_external_vref) |
| 846 | { | 846 | { |
| 847 | struct device *dev = &st->spi->dev; | 847 | struct device *dev = &st->spi->dev; |
| 848 | struct gpio_desc *gpio; | 848 | struct gpio_desc *gpio; |
| @@ -881,18 +881,13 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref) · 32 unmodified lines | |||
| 881 | if (ret) | 881 | if (ret) |
| 882 | return ret; | 882 | return ret; |
| 883 | 883 | ||
| 884 | if (!vref) | 884 | if (!has_external_vref) |
| 885 | return 0; | 885 | return 0; |
| 886 | 886 | ||
| 887 | return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, | 887 | return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG, |
| 888 | LTC2688_CONFIG_EXT_REF); | 888 | LTC2688_CONFIG_EXT_REF); |
| 889 | } | 889 | } |
| 890 | 890 | ||
| 891 | static void ltc2688_disable_regulator(void *regulator) | ||
| 892 | { | ||
| 893 | regulator_disable(regulator); | ||
| 894 | } | ||
| 895 | |||
| 896 | static bool ltc2688_reg_readable(struct device *dev, unsigned int reg) | 891 | static bool ltc2688_reg_readable(struct device *dev, unsigned int reg) |
| 897 | { | 892 | { |
| 898 | switch (reg) { | 893 | switch (reg) { |
| @@ -947,8 +942,8 @@ static int ltc2688_probe(struct spi_device *spi) · 48 unmodified lines | |||
| 947 | static const char * const regulators[] = { "vcc", "iovcc" }; | 942 | static const char * const regulators[] = { "vcc", "iovcc" }; |
| 948 | struct ltc2688_state *st; | 943 | struct ltc2688_state *st; |
| 949 | struct iio_dev *indio_dev; | 944 | struct iio_dev *indio_dev; |
| 950 | struct regulator *vref_reg; | ||
| 951 | struct device *dev = &spi->dev; | 945 | struct device *dev = &spi->dev; |
| 946 | bool has_external_vref; | ||
| 952 | int ret; | 947 | int ret; |
| 953 | 948 | ||
| 954 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); | 949 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
| @@ -973,34 +968,15 @@ static int ltc2688_probe(struct spi_device *spi) · 18 unmodified lines | |||
| 973 | if (ret) | 968 | if (ret) |
| 974 | return dev_err_probe(dev, ret, "Failed to enable regulators\n"); | 969 | return dev_err_probe(dev, ret, "Failed to enable regulators\n"); |
| 975 | 970 | ||
| 976 | vref_reg = devm_regulator_get_optional(dev, "vref"); | 971 | ret = devm_regulator_get_enable_read_voltage(dev, "vref"); |
| 977 | if (IS_ERR(vref_reg)) { | 972 | if (ret < 0 && ret != -ENODEV) |
| 978 | if (PTR_ERR(vref_reg) != -ENODEV) | 973 | return dev_err_probe(dev, ret, |
| 979 | return dev_err_probe(dev, PTR_ERR(vref_reg), | 974 | "Failed to get vref regulator voltage\n"); |
| 980 | "Failed to get vref regulator"); | ||
| 981 | |||
| 982 | vref_reg = NULL; | ||
| 983 | /* internal reference */ | ||
| 984 | st->vref = 4096; | ||
| 985 | } else { | ||
| 986 | ret = regulator_enable(vref_reg); | ||
| 987 | if (ret) | ||
| 988 | return dev_err_probe(dev, ret, | ||
| 989 | "Failed to enable vref regulators\n"); | ||
| 990 | |||
| 991 | ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator, | ||
| 992 | vref_reg); | ||
| 993 | if (ret) | ||
| 994 | return ret; | ||
| 995 | |||
| 996 | ret = regulator_get_voltage(vref_reg); | ||
| 997 | if (ret < 0) | ||
| 998 | return dev_err_probe(dev, ret, "Failed to get vref\n"); | ||
| 999 | 975 | ||
| 1000 | st->vref = ret / 1000; | 976 | has_external_vref = ret != -ENODEV; |
| 1001 | } | 977 | st->vref = has_external_vref ? ret / 1000 : 0; |
| 1002 | 978 | ||
| 1003 | ret = ltc2688_setup(st, vref_reg); | 979 | ret = ltc2688_setup(st, has_external_vref); |
| 1004 | if (ret) | 980 | if (ret) |
| 1005 | return ret; | 981 | return ret; |
| 1006 | 982 | ||
| @@ -32,7 +32,6 @@ enum max5821_device_ids { · 31 unmodified lines | |||
| 32 | 32 | ||
| 33 | struct max5821_data { | 33 | struct max5821_data { |
| 34 | struct i2c_client *client; | 34 | struct i2c_client *client; |
| 35 | struct regulator *vref_reg; | ||
| 36 | unsigned short vref_mv; | 35 | unsigned short vref_mv; |
| 37 | bool powerdown[MAX5821_MAX_DAC_CHANNELS]; | 36 | bool powerdown[MAX5821_MAX_DAC_CHANNELS]; |
| 38 | u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS]; | 37 | u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS]; |
| @@ -295,11 +294,6 @@ static const struct iio_info max5821_info = { · 256 unmodified lines | |||
| 295 | .write_raw = max5821_write_raw, | 294 | .write_raw = max5821_write_raw, |
| 296 | }; | 295 | }; |
| 297 | 296 | ||
| 298 | static void max5821_regulator_disable(void *reg) | ||
| 299 | { | ||
| 300 | regulator_disable(reg); | ||
| 301 | } | ||
| 302 | |||
| 303 | static int max5821_probe(struct i2c_client *client) | 297 | static int max5821_probe(struct i2c_client *client) |
| 304 | { | 298 | { |
| 305 | const struct i2c_device_id *id = i2c_client_get_device_id(client); | 299 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
| @@ -321,32 +315,10 @@ static int max5821_probe(struct i2c_client *client) · 15 unmodified lines | |||
| 321 | data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND; | 315 | data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND; |
| 322 | } | 316 | } |
| 323 | 317 | ||
| 324 | data->vref_reg = devm_regulator_get(&client->dev, "vref"); | 318 | ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); |
| 325 | if (IS_ERR(data->vref_reg)) | 319 | if (ret) |
| 326 | return dev_err_probe(&client->dev, PTR_ERR(data->vref_reg), | 320 | return dev_err_probe(&client->dev, ret, |
| 327 | "Failed to get vref regulator\n"); | 321 | "Failed to get vref regulator voltage\n"); |
| 328 | |||
| 329 | ret = regulator_enable(data->vref_reg); | ||
| 330 | if (ret) { | ||
| 331 | dev_err(&client->dev, | ||
| 332 | "Failed to enable vref regulator: %d\n", ret); | ||
| 333 | return ret; | ||
| 334 | } | ||
| 335 | |||
| 336 | ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable, | ||
| 337 | data->vref_reg); | ||
| 338 | if (ret) { | ||
| 339 | dev_err(&client->dev, | ||
| 340 | "Failed to add action to managed regulator: %d\n", ret); | ||
| 341 | return ret; | ||
| 342 | } | ||
| 343 | |||
| 344 | ret = regulator_get_voltage(data->vref_reg); | ||
| 345 | if (ret < 0) { | ||
| 346 | dev_err(&client->dev, | ||
| 347 | "Failed to get voltage on regulator: %d\n", ret); | ||
| 348 | return ret; | ||
| 349 | } | ||
| 350 | 322 | ||
| 351 | data->vref_mv = ret / 1000; | 323 | data->vref_mv = ret / 1000; |
| 352 | 324 | ||
| @@ -379,7 +379,7 @@ static int mcp4725_probe_dt(struct device *dev, · 378 unmodified lines | |||
| 379 | struct mcp4725_platform_data *pdata) | 379 | struct mcp4725_platform_data *pdata) |
| 380 | { | 380 | { |
| 381 | /* check if is the vref-supply defined */ | 381 | /* check if is the vref-supply defined */ |
| 382 | pdata->use_vref = device_property_read_bool(dev, "vref-supply"); | 382 | pdata->use_vref = device_property_present(dev, "vref-supply"); |
| 383 | pdata->vref_buffered = | 383 | pdata->vref_buffered = |
| 384 | device_property_read_bool(dev, "microchip,vref-buffered"); | 384 | device_property_read_bool(dev, "microchip,vref-buffered"); |
| 385 | 385 | ||
| @@ -0,0 +1,162 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * BD79703 ROHM Digital to Analog converter | ||
| 4 | * | ||
| 5 | * Copyright (c) 2024, ROHM Semiconductor. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/bits.h> | ||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | #include <linux/regulator/consumer.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <linux/iio/iio.h> | ||
| 15 | |||
| 16 | #define BD79703_MAX_REGISTER 0xf | ||
| 17 | #define BD79703_DAC_BITS 8 | ||
| 18 | #define BD79703_REG_OUT_ALL GENMASK(2, 0) | ||
| 19 | |||
| 20 | /* | ||
| 21 | * The BD79703 uses 12-bit SPI commands. First four bits (high bits) define | ||
| 22 | * channel(s) which are operated on, and also the mode. The mode can be to set | ||
| 23 | * a DAC word only, or set DAC word and output. The data-sheet is not very | ||
| 24 | * specific on how a previously set DAC word can be 'taken in to use'. Thus | ||
| 25 | * this driver only uses the 'set DAC and output it' -mode. | ||
| 26 | * | ||
| 27 | * The BD79703 latches last 12-bits when the chip-select is toggled. Thus we | ||
| 28 | * can use 16-bit transfers which should be widely supported. To simplify this | ||
| 29 | * further, we treat the last 8 bits as a value, and first 8 bits as an | ||
| 30 | * address. This allows us to separate channels/mode by address and treat the | ||
| 31 | * 8-bit register value as DAC word. The highest 4 bits of address will be | ||
| 32 | * discarded when the transfer is latched. | ||
| 33 | */ | ||
| 34 | static const struct regmap_config bd79703_regmap_config = { | ||
| 35 | .reg_bits = 8, | ||
| 36 | .val_bits = 8, | ||
| 37 | .max_register = BD79703_MAX_REGISTER, | ||
| 38 | .cache_type = REGCACHE_RBTREE, | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct bd79703_data { | ||
| 42 | struct regmap *regmap; | ||
| 43 | int vfs; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int bd79703_read_raw(struct iio_dev *idev, | ||
| 47 | struct iio_chan_spec const *chan, int *val, | ||
| 48 | int *val2, long mask) | ||
| 49 | { | ||
| 50 | struct bd79703_data *data = iio_priv(idev); | ||
| 51 | |||
| 52 | if (mask != IIO_CHAN_INFO_SCALE) | ||
| 53 | return -EINVAL; | ||
| 54 | |||
| 55 | *val = data->vfs / 1000; | ||
| 56 | *val2 = BD79703_DAC_BITS; | ||
| 57 | |||
| 58 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int bd79703_write_raw(struct iio_dev *idev, | ||
| 62 | struct iio_chan_spec const *chan, int val, | ||
| 63 | int val2, long mask) | ||
| 64 | { | ||
| 65 | struct bd79703_data *data = iio_priv(idev); | ||
| 66 | |||
| 67 | if (val < 0 || val >= 1 << BD79703_DAC_BITS) | ||
| 68 | return -EINVAL; | ||
| 69 | |||
| 70 | return regmap_write(data->regmap, chan->channel + 1, val); | ||
| 71 | }; | ||
| 72 | |||
| 73 | static const struct iio_info bd79703_info = { | ||
| 74 | .read_raw = bd79703_read_raw, | ||
| 75 | .write_raw = bd79703_write_raw, | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define BD79703_CHAN(_chan) { \ | ||
| 79 | .type = IIO_VOLTAGE, \ | ||
| 80 | .indexed = 1, \ | ||
| 81 | .output = 1, \ | ||
| 82 | .channel = (_chan), \ | ||
| 83 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 84 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 85 | .address = (_chan), \ | ||
| 86 | } | ||
| 87 | |||
| 88 | static const struct iio_chan_spec bd79703_channels[] = { | ||
| 89 | BD79703_CHAN(0), | ||
| 90 | BD79703_CHAN(1), | ||
| 91 | BD79703_CHAN(2), | ||
| 92 | BD79703_CHAN(3), | ||
| 93 | BD79703_CHAN(4), | ||
| 94 | BD79703_CHAN(5), | ||
| 95 | }; | ||
| 96 | |||
| 97 | static int bd79703_probe(struct spi_device *spi) | ||
| 98 | { | ||
| 99 | struct device *dev = &spi->dev; | ||
| 100 | struct bd79703_data *data; | ||
| 101 | struct iio_dev *idev; | ||
| 102 | int ret; | ||
| 103 | |||
| 104 | idev = devm_iio_device_alloc(dev, sizeof(*data)); | ||
| 105 | if (!idev) | ||
| 106 | return -ENOMEM; | ||
| 107 | |||
| 108 | data = iio_priv(idev); | ||
| 109 | |||
| 110 | data->regmap = devm_regmap_init_spi(spi, &bd79703_regmap_config); | ||
| 111 | if (IS_ERR(data->regmap)) | ||
| 112 | return dev_err_probe(dev, PTR_ERR(data->regmap), | ||
| 113 | "Failed to initialize Regmap\n"); | ||
| 114 | |||
| 115 | ret = devm_regulator_get_enable(dev, "vcc"); | ||
| 116 | if (ret) | ||
| 117 | return dev_err_probe(dev, ret, "Failed to enable VCC\n"); | ||
| 118 | |||
| 119 | ret = devm_regulator_get_enable_read_voltage(dev, "vfs"); | ||
| 120 | if (ret < 0) | ||
| 121 | return dev_err_probe(dev, ret, "Failed to get Vfs\n"); | ||
| 122 | |||
| 123 | data->vfs = ret; | ||
| 124 | idev->channels = bd79703_channels; | ||
| 125 | idev->num_channels = ARRAY_SIZE(bd79703_channels); | ||
| 126 | idev->modes = INDIO_DIRECT_MODE; | ||
| 127 | idev->info = &bd79703_info; | ||
| 128 | idev->name = "bd79703"; | ||
| 129 | |||
| 130 | /* Initialize all to output zero */ | ||
| 131 | ret = regmap_write(data->regmap, BD79703_REG_OUT_ALL, 0); | ||
| 132 | if (ret) | ||
| 133 | return ret; | ||
| 134 | |||
| 135 | return devm_iio_device_register(dev, idev); | ||
| 136 | } | ||
| 137 | |||
| 138 | static const struct spi_device_id bd79703_id[] = { | ||
| 139 | { "bd79703", }, | ||
| 140 | { } | ||
| 141 | }; | ||
| 142 | MODULE_DEVICE_TABLE(spi, bd79703_id); | ||
| 143 | |||
| 144 | static const struct of_device_id bd79703_of_match[] = { | ||
| 145 | { .compatible = "rohm,bd79703", }, | ||
| 146 | { } | ||
| 147 | }; | ||
| 148 | MODULE_DEVICE_TABLE(of, bd79703_of_match); | ||
| 149 | |||
| 150 | static struct spi_driver bd79703_driver = { | ||
| 151 | .driver = { | ||
| 152 | .name = "bd79703", | ||
| 153 | .of_match_table = bd79703_of_match, | ||
| 154 | }, | ||
| 155 | .probe = bd79703_probe, | ||
| 156 | .id_table = bd79703_id, | ||
| 157 | }; | ||
| 158 | module_spi_driver(bd79703_driver); | ||
| 159 | |||
| 160 | MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); | ||
| 161 | MODULE_DESCRIPTION("ROHM BD79703 DAC driver"); | ||
| 162 | MODULE_LICENSE("GPL"); | ||
| @@ -75,7 +75,7 @@ struct adxrs290_state { · 74 unmodified lines | |||
| 75 | /* Ensure correct alignment of timestamp when present */ | 75 | /* Ensure correct alignment of timestamp when present */ |
| 76 | struct { | 76 | struct { |
| 77 | s16 channels[3]; | 77 | s16 channels[3]; |
| 78 | s64 ts __aligned(8); | 78 | aligned_s64 ts; |
| 79 | } buffer; | 79 | } buffer; |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| @@ -99,7 +99,7 @@ struct bmg160_data { · 98 unmodified lines | |||
| 99 | /* Ensure naturally aligned timestamp */ | 99 | /* Ensure naturally aligned timestamp */ |
| 100 | struct { | 100 | struct { |
| 101 | s16 chans[3]; | 101 | s16 chans[3]; |
| 102 | s64 timestamp __aligned(8); | 102 | aligned_s64 timestamp; |
| 103 | } scan; | 103 | } scan; |
| 104 | u32 dps_range; | 104 | u32 dps_range; |
| 105 | int ev_enable_state; | 105 | int ev_enable_state; |
| @@ -52,7 +52,7 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p) · 51 unmodified lines | |||
| 52 | */ | 52 | */ |
| 53 | struct { | 53 | struct { |
| 54 | __be16 buf[ITG3200_SCAN_ELEMENTS]; | 54 | __be16 buf[ITG3200_SCAN_ELEMENTS]; |
| 55 | s64 ts __aligned(8); | 55 | aligned_s64 ts; |
| 56 | } scan; | 56 | } scan; |
| 57 | 57 | ||
| 58 | int ret = itg3200_read_all_channels(st->i2c, scan.buf); | 58 | int ret = itg3200_read_all_channels(st->i2c, scan.buf); |
| @@ -474,7 +474,7 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p) · 473 unmodified lines | |||
| 474 | int ret; | 474 | int ret; |
| 475 | struct { | 475 | struct { |
| 476 | __be16 chans[4]; | 476 | __be16 chans[4]; |
| 477 | s64 timestamp __aligned(8); | 477 | aligned_s64 timestamp; |
| 478 | } scan; | 478 | } scan; |
| 479 | s64 timestamp; | 479 | s64 timestamp; |
| 480 | unsigned int datums_from_fifo = 0; | 480 | unsigned int datums_from_fifo = 0; |
| @@ -35,7 +35,7 @@ struct am2315_data { · 34 unmodified lines | |||
| 35 | /* Ensure timestamp is naturally aligned */ | 35 | /* Ensure timestamp is naturally aligned */ |
| 36 | struct { | 36 | struct { |
| 37 | s16 chans[2]; | 37 | s16 chans[2]; |
| 38 | s64 timestamp __aligned(8); | 38 | aligned_s64 timestamp; |
| 39 | } scan; | 39 | } scan; |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| @@ -44,7 +44,7 @@ struct hdc100x_data { · 43 unmodified lines | |||
| 44 | /* Ensure natural alignment of timestamp */ | 44 | /* Ensure natural alignment of timestamp */ |
| 45 | struct { | 45 | struct { |
| 46 | __be16 channels[2]; | 46 | __be16 channels[2]; |
| 47 | s64 ts __aligned(8); | 47 | aligned_s64 ts; |
| 48 | } scan; | 48 | } scan; |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| @@ -40,7 +40,7 @@ struct hts221_hw { · 39 unmodified lines | |||
| 40 | /* Ensure natural alignment of timestamp */ | 40 | /* Ensure natural alignment of timestamp */ |
| 41 | struct { | 41 | struct { |
| 42 | __le16 channels[2]; | 42 | __le16 channels[2]; |
| 43 | s64 ts __aligned(8); | 43 | aligned_s64 ts; |
| 44 | } scan; | 44 | } scan; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| @@ -878,11 +878,32 @@ static const struct iio_chan_spec adis16545_channels[] = { · 877 unmodified lines | |||
| 878 | IIO_CHAN_SOFT_TIMESTAMP(17), | 878 | IIO_CHAN_SOFT_TIMESTAMP(17), |
| 879 | }; | 879 | }; |
| 880 | 880 | ||
| 881 | static const struct iio_chan_spec adis16489_channels[] = { | ||
| 882 | ADIS16480_GYRO_CHANNEL(X), | ||
| 883 | ADIS16480_GYRO_CHANNEL(Y), | ||
| 884 | ADIS16480_GYRO_CHANNEL(Z), | ||
| 885 | ADIS16480_ACCEL_CHANNEL(X), | ||
| 886 | ADIS16480_ACCEL_CHANNEL(Y), | ||
| 887 | ADIS16480_ACCEL_CHANNEL(Z), | ||
| 888 | ADIS16480_PRESSURE_CHANNEL(), | ||
| 889 | ADIS16480_TEMP_CHANNEL(), | ||
| 890 | IIO_CHAN_SOFT_TIMESTAMP(8), | ||
| 891 | ADIS16480_DELTANG_CHANNEL_NO_SCAN(X), | ||
| 892 | ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y), | ||
| 893 | ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z), | ||
| 894 | ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X), | ||
| 895 | ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y), | ||
| 896 | ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z), | ||
| 897 | }; | ||
| 898 | |||
| 881 | enum adis16480_variant { | 899 | enum adis16480_variant { |
| 882 | ADIS16375, | 900 | ADIS16375, |
| 883 | ADIS16480, | 901 | ADIS16480, |
| 884 | ADIS16485, | 902 | ADIS16485, |
| 903 | ADIS16486, | ||
| 904 | ADIS16487, | ||
| 885 | ADIS16488, | 905 | ADIS16488, |
| 906 | ADIS16489, | ||
| 886 | ADIS16490, | 907 | ADIS16490, |
| 887 | ADIS16495_1, | 908 | ADIS16495_1, |
| 888 | ADIS16495_2, | 909 | ADIS16495_2, |
| @@ -1038,6 +1059,38 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 149 unmodified lines | |||
| 1038 | .filter_freqs = adis16480_def_filter_freqs, | 1059 | .filter_freqs = adis16480_def_filter_freqs, |
| 1039 | .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0), | 1060 | .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0), |
| 1040 | }, | 1061 | }, |
| 1062 | [ADIS16486] = { | ||
| 1063 | .channels = adis16485_channels, | ||
| 1064 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 1065 | .gyro_max_val = 22500 << 16, | ||
| 1066 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | ||
| 1067 | .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), | ||
| 1068 | .accel_max_scale = 18, | ||
| 1069 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 1070 | .deltang_max_val = IIO_DEGREE_TO_RAD(720), | ||
| 1071 | .deltvel_max_val = 200, | ||
| 1072 | .int_clk = 2460000, | ||
| 1073 | .max_dec_rate = 2048, | ||
| 1074 | .has_sleep_cnt = true, | ||
| 1075 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 1076 | .adis_data = ADIS16480_DATA(16486, &adis16480_timeouts, 0, 0), | ||
| 1077 | }, | ||
| 1078 | [ADIS16487] = { | ||
| 1079 | .channels = adis16485_channels, | ||
| 1080 | .num_channels = ARRAY_SIZE(adis16485_channels), | ||
| 1081 | .gyro_max_val = 22500 << 16, | ||
| 1082 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | ||
| 1083 | .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), | ||
| 1084 | .accel_max_scale = 5, | ||
| 1085 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 1086 | .deltang_max_val = IIO_DEGREE_TO_RAD(720), | ||
| 1087 | .deltvel_max_val = 50, | ||
| 1088 | .int_clk = 2460000, | ||
| 1089 | .max_dec_rate = 2048, | ||
| 1090 | .has_sleep_cnt = true, | ||
| 1091 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 1092 | .adis_data = ADIS16480_DATA(16487, &adis16485_timeouts, 0, 0), | ||
| 1093 | }, | ||
| 1041 | [ADIS16488] = { | 1094 | [ADIS16488] = { |
| 1042 | .channels = adis16480_channels, | 1095 | .channels = adis16480_channels, |
| 1043 | .num_channels = ARRAY_SIZE(adis16480_channels), | 1096 | .num_channels = ARRAY_SIZE(adis16480_channels), |
| @@ -1054,6 +1107,22 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { · 10 unmodified lines | |||
| 1054 | .filter_freqs = adis16480_def_filter_freqs, | 1107 | .filter_freqs = adis16480_def_filter_freqs, |
| 1055 | .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0), | 1108 | .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0), |
| 1056 | }, | 1109 | }, |
| 1110 | [ADIS16489] = { | ||
| 1111 | .channels = adis16489_channels, | ||
| 1112 | .num_channels = ARRAY_SIZE(adis16489_channels), | ||
| 1113 | .gyro_max_val = 22500 << 16, | ||
| 1114 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | ||
| 1115 | .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), | ||
| 1116 | .accel_max_scale = 18, | ||
| 1117 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ | ||
| 1118 | .deltang_max_val = IIO_DEGREE_TO_RAD(720), | ||
| 1119 | .deltvel_max_val = 200, | ||
| 1120 | .int_clk = 2460000, | ||
| 1121 | .max_dec_rate = 2048, | ||
| 1122 | .has_sleep_cnt = true, | ||
| 1123 | .filter_freqs = adis16480_def_filter_freqs, | ||
| 1124 | .adis_data = ADIS16480_DATA(16489, &adis16480_timeouts, 0, 0), | ||
| 1125 | }, | ||
| 1057 | [ADIS16490] = { | 1126 | [ADIS16490] = { |
| 1058 | .channels = adis16485_channels, | 1127 | .channels = adis16485_channels, |
| 1059 | .num_channels = ARRAY_SIZE(adis16485_channels), | 1128 | .num_channels = ARRAY_SIZE(adis16485_channels), |
| @@ -1741,7 +1810,10 @@ static const struct spi_device_id adis16480_ids[] = { · 681 unmodified lines | |||
| 1741 | { "adis16375", ADIS16375 }, | 1810 | { "adis16375", ADIS16375 }, |
| 1742 | { "adis16480", ADIS16480 }, | 1811 | { "adis16480", ADIS16480 }, |
| 1743 | { "adis16485", ADIS16485 }, | 1812 | { "adis16485", ADIS16485 }, |
| 1813 | { "adis16486", ADIS16486 }, | ||
| 1814 | { "adis16487", ADIS16487 }, | ||
| 1744 | { "adis16488", ADIS16488 }, | 1815 | { "adis16488", ADIS16488 }, |
| 1816 | { "adis16489", ADIS16489 }, | ||
| 1745 | { "adis16490", ADIS16490 }, | 1817 | { "adis16490", ADIS16490 }, |
| 1746 | { "adis16495-1", ADIS16495_1 }, | 1818 | { "adis16495-1", ADIS16495_1 }, |
| 1747 | { "adis16495-2", ADIS16495_2 }, | 1819 | { "adis16495-2", ADIS16495_2 }, |
| @@ -1763,7 +1835,10 @@ static const struct of_device_id adis16480_of_match[] = { · 15 unmodified lines | |||
| 1763 | { .compatible = "adi,adis16375" }, | 1835 | { .compatible = "adi,adis16375" }, |
| 1764 | { .compatible = "adi,adis16480" }, | 1836 | { .compatible = "adi,adis16480" }, |
| 1765 | { .compatible = "adi,adis16485" }, | 1837 | { .compatible = "adi,adis16485" }, |
| 1838 | { .compatible = "adi,adis16486" }, | ||
| 1839 | { .compatible = "adi,adis16487" }, | ||
| 1766 | { .compatible = "adi,adis16488" }, | 1840 | { .compatible = "adi,adis16488" }, |
| 1841 | { .compatible = "adi,adis16489" }, | ||
| 1767 | { .compatible = "adi,adis16490" }, | 1842 | { .compatible = "adi,adis16490" }, |
| 1768 | { .compatible = "adi,adis16495-1" }, | 1843 | { .compatible = "adi,adis16495-1" }, |
| 1769 | { .compatible = "adi,adis16495-2" }, | 1844 | { .compatible = "adi,adis16495-2" }, |
| @@ -174,7 +174,7 @@ struct bmi323_data { · 173 unmodified lines | |||
| 174 | __le16 fifo_buff[BMI323_FIFO_FULL_IN_WORDS] __aligned(IIO_DMA_MINALIGN); | 174 | __le16 fifo_buff[BMI323_FIFO_FULL_IN_WORDS] __aligned(IIO_DMA_MINALIGN); |
| 175 | struct { | 175 | struct { |
| 176 | __le16 channels[BMI323_CHAN_MAX]; | 176 | __le16 channels[BMI323_CHAN_MAX]; |
| 177 | s64 ts __aligned(8); | 177 | aligned_s64 ts; |
| 178 | } buffer; | 178 | } buffer; |
| 179 | __le16 steps_count[BMI323_STEP_LEN]; | 179 | __le16 steps_count[BMI323_STEP_LEN]; |
| 180 | }; | 180 | }; |
| @@ -207,7 +207,7 @@ struct bno055_priv { · 206 unmodified lines | |||
| 207 | bool sw_reset; | 207 | bool sw_reset; |
| 208 | struct { | 208 | struct { |
| 209 | __le16 chans[BNO055_SCAN_CH_COUNT]; | 209 | __le16 chans[BNO055_SCAN_CH_COUNT]; |
| 210 | s64 timestamp __aligned(8); | 210 | aligned_s64 timestamp; |
| 211 | } buf; | 211 | } buf; |
| 212 | struct dentry *debugfs; | 212 | struct dentry *debugfs; |
| 213 | }; | 213 | }; |
| @@ -1193,7 +1193,7 @@ static ssize_t serialnumber_show(struct device *dev, · 979 unmodified lines | |||
| 1193 | } | 1193 | } |
| 1194 | 1194 | ||
| 1195 | static ssize_t calibration_data_read(struct file *filp, struct kobject *kobj, | 1195 | static ssize_t calibration_data_read(struct file *filp, struct kobject *kobj, |
| 1196 | struct bin_attribute *bin_attr, char *buf, | 1196 | const struct bin_attribute *bin_attr, char *buf, |
| 1197 | loff_t pos, size_t count) | 1197 | loff_t pos, size_t count) |
| 1198 | { | 1198 | { |
| 1199 | struct bno055_priv *priv = iio_priv(dev_to_iio_dev(kobj_to_dev(kobj))); | 1199 | struct bno055_priv *priv = iio_priv(dev_to_iio_dev(kobj_to_dev(kobj))); |
| @@ -1348,16 +1348,16 @@ static struct attribute *bno055_attrs[] = { · 148 unmodified lines | |||
| 1348 | NULL | 1348 | NULL |
| 1349 | }; | 1349 | }; |
| 1350 | 1350 | ||
| 1351 | static BIN_ATTR_RO(calibration_data, BNO055_CALDATA_LEN); | 1351 | static const BIN_ATTR_RO(calibration_data, BNO055_CALDATA_LEN); |
| 1352 | 1352 | ||
| 1353 | static struct bin_attribute *bno055_bin_attrs[] = { | 1353 | static const struct bin_attribute *const bno055_bin_attrs[] = { |
| 1354 | &bin_attr_calibration_data, | 1354 | &bin_attr_calibration_data, |
| 1355 | NULL | 1355 | NULL |
| 1356 | }; | 1356 | }; |
| 1357 | 1357 | ||
| 1358 | static const struct attribute_group bno055_attrs_group = { | 1358 | static const struct attribute_group bno055_attrs_group = { |
| 1359 | .attrs = bno055_attrs, | 1359 | .attrs = bno055_attrs, |
| 1360 | .bin_attrs = bno055_bin_attrs, | 1360 | .bin_attrs_new = bno055_bin_attrs, |
| 1361 | }; | 1361 | }; |
| 1362 | 1362 | ||
| 1363 | static const struct iio_info bno055_info = { | 1363 | static const struct iio_info bno055_info = { |
| @@ -178,7 +178,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { · 177 unmodified lines | |||
| 178 | struct inv_icm42600_accel_buffer { | 178 | struct inv_icm42600_accel_buffer { |
| 179 | struct inv_icm42600_fifo_sensor_data accel; | 179 | struct inv_icm42600_fifo_sensor_data accel; |
| 180 | int16_t temp; | 180 | int16_t temp; |
| 181 | int64_t timestamp __aligned(8); | 181 | aligned_s64 timestamp; |
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ | 184 | #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ |
| @@ -78,7 +78,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { · 77 unmodified lines | |||
| 78 | struct inv_icm42600_gyro_buffer { | 78 | struct inv_icm42600_gyro_buffer { |
| 79 | struct inv_icm42600_fifo_sensor_data gyro; | 79 | struct inv_icm42600_fifo_sensor_data gyro; |
| 80 | int16_t temp; | 80 | int16_t temp; |
| 81 | int64_t timestamp __aligned(8); | 81 | aligned_s64 timestamp; |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | #define INV_ICM42600_SCAN_MASK_GYRO_3AXIS \ | 84 | #define INV_ICM42600_SCAN_MASK_GYRO_3AXIS \ |
| @@ -277,6 +277,14 @@ static const struct inv_mpu6050_hw hw_info[] = { · 276 unmodified lines | |||
| 277 | .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, | 277 | .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
| 278 | .startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME}, | 278 | .startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME}, |
| 279 | }, | 279 | }, |
| 280 | { .whoami = INV_IAM20380_WHOAMI_VALUE, | ||
| 281 | .name = "IAM20380", | ||
| 282 | .reg = ®_set_6500, | ||
| 283 | .config = &chip_config_6500, | ||
| 284 | .fifo_size = 512, | ||
| 285 | .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, | ||
| 286 | .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, | ||
| 287 | }, | ||
| 280 | { | 288 | { |
| 281 | .whoami = INV_IAM20680_WHOAMI_VALUE, | 289 | .whoami = INV_IAM20680_WHOAMI_VALUE, |
| 282 | .name = "IAM20680", | 290 | .name = "IAM20680", |
| @@ -1519,6 +1527,14 @@ static const struct iio_chan_spec inv_mpu6050_channels[] = { · 1236 unmodified lines | |||
| 1519 | INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), | 1527 | INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), |
| 1520 | }; | 1528 | }; |
| 1521 | 1529 | ||
| 1530 | static const struct iio_chan_spec inv_iam20380_channels[] = { | ||
| 1531 | IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), | ||
| 1532 | |||
| 1533 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), | ||
| 1534 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), | ||
| 1535 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), | ||
| 1536 | }; | ||
| 1537 | |||
| 1522 | static const struct iio_chan_spec inv_mpu6500_channels[] = { | 1538 | static const struct iio_chan_spec inv_mpu6500_channels[] = { |
| 1523 | IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), | 1539 | IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), |
| 1524 | 1540 | ||
| @@ -1623,6 +1639,10 @@ static const struct iio_chan_spec inv_mpu9250_channels[] = { · 98 unmodified lines | |||
| 1623 | | BIT(INV_MPU9X50_SCAN_MAGN_Y) \ | 1639 | | BIT(INV_MPU9X50_SCAN_MAGN_Y) \ |
| 1624 | | BIT(INV_MPU9X50_SCAN_MAGN_Z)) | 1640 | | BIT(INV_MPU9X50_SCAN_MAGN_Z)) |
| 1625 | 1641 | ||
| 1642 | static const unsigned long inv_iam20380_scan_masks[] = { | ||
| 1643 | INV_MPU6050_SCAN_MASK_3AXIS_GYRO, | ||
| 1644 | }; | ||
| 1645 | |||
| 1626 | static const unsigned long inv_mpu9x50_scan_masks[] = { | 1646 | static const unsigned long inv_mpu9x50_scan_masks[] = { |
| 1627 | /* 3-axis accel */ | 1647 | /* 3-axis accel */ |
| 1628 | INV_MPU6050_SCAN_MASK_3AXIS_ACCEL, | 1648 | INV_MPU6050_SCAN_MASK_3AXIS_ACCEL, |
| @@ -2026,6 +2046,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, · 397 unmodified lines | |||
| 2026 | indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); | 2046 | indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); |
| 2027 | indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; | 2047 | indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; |
| 2028 | break; | 2048 | break; |
| 2049 | case INV_IAM20380: | ||
| 2050 | indio_dev->channels = inv_iam20380_channels; | ||
| 2051 | indio_dev->num_channels = ARRAY_SIZE(inv_iam20380_channels); | ||
| 2052 | indio_dev->available_scan_masks = inv_iam20380_scan_masks; | ||
| 2053 | break; | ||
| 2029 | case INV_ICM20600: | 2054 | case INV_ICM20600: |
| 2030 | case INV_ICM20602: | 2055 | case INV_ICM20602: |
| 2031 | indio_dev->channels = inv_mpu6500_channels; | 2056 | indio_dev->channels = inv_mpu6500_channels; |
| @@ -34,6 +34,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev) · 33 unmodified lines | |||
| 34 | case INV_ICM20689: | 34 | case INV_ICM20689: |
| 35 | case INV_ICM20600: | 35 | case INV_ICM20600: |
| 36 | case INV_ICM20602: | 36 | case INV_ICM20602: |
| 37 | case INV_IAM20380: | ||
| 37 | case INV_IAM20680: | 38 | case INV_IAM20680: |
| 38 | /* no i2c auxiliary bus on the chip */ | 39 | /* no i2c auxiliary bus on the chip */ |
| 39 | return false; | 40 | return false; |
| @@ -187,6 +188,7 @@ static const struct i2c_device_id inv_mpu_id[] = { · 147 unmodified lines | |||
| 187 | {"icm20600", INV_ICM20600}, | 188 | {"icm20600", INV_ICM20600}, |
| 188 | {"icm20602", INV_ICM20602}, | 189 | {"icm20602", INV_ICM20602}, |
| 189 | {"icm20690", INV_ICM20690}, | 190 | {"icm20690", INV_ICM20690}, |
| 191 | {"iam20380", INV_IAM20380}, | ||
| 190 | {"iam20680", INV_IAM20680}, | 192 | {"iam20680", INV_IAM20680}, |
| 191 | {"iam20680hp", INV_IAM20680HP}, | 193 | {"iam20680hp", INV_IAM20680HP}, |
| 192 | {"iam20680ht", INV_IAM20680HT}, | 194 | {"iam20680ht", INV_IAM20680HT}, |
| @@ -252,6 +254,10 @@ static const struct of_device_id inv_of_match[] = { · 59 unmodified lines | |||
| 252 | .compatible = "invensense,icm20690", | 254 | .compatible = "invensense,icm20690", |
| 253 | .data = (void *)INV_ICM20690 | 255 | .data = (void *)INV_ICM20690 |
| 254 | }, | 256 | }, |
| 257 | { | ||
| 258 | .compatible = "invensense,iam20380", | ||
| 259 | .data = (void *)INV_IAM20380 | ||
| 260 | }, | ||
| 255 | { | 261 | { |
| 256 | .compatible = "invensense,iam20680", | 262 | .compatible = "invensense,iam20680", |
| 257 | .data = (void *)INV_IAM20680 | 263 | .data = (void *)INV_IAM20680 |
| @@ -84,6 +84,7 @@ enum inv_devices { · 83 unmodified lines | |||
| 84 | INV_ICM20600, | 84 | INV_ICM20600, |
| 85 | INV_ICM20602, | 85 | INV_ICM20602, |
| 86 | INV_ICM20690, | 86 | INV_ICM20690, |
| 87 | INV_IAM20380, | ||
| 87 | INV_IAM20680, | 88 | INV_IAM20680, |
| 88 | INV_IAM20680HP, | 89 | INV_IAM20680HP, |
| 89 | INV_IAM20680HT, | 90 | INV_IAM20680HT, |
| @@ -425,6 +426,7 @@ struct inv_mpu6050_state { · 335 unmodified lines | |||
| 425 | #define INV_ICM20600_WHOAMI_VALUE 0x11 | 426 | #define INV_ICM20600_WHOAMI_VALUE 0x11 |
| 426 | #define INV_ICM20602_WHOAMI_VALUE 0x12 | 427 | #define INV_ICM20602_WHOAMI_VALUE 0x12 |
| 427 | #define INV_ICM20690_WHOAMI_VALUE 0x20 | 428 | #define INV_ICM20690_WHOAMI_VALUE 0x20 |
| 429 | #define INV_IAM20380_WHOAMI_VALUE 0xB5 | ||
| 428 | #define INV_IAM20680_WHOAMI_VALUE 0xA9 | 430 | #define INV_IAM20680_WHOAMI_VALUE 0xA9 |
| 429 | #define INV_IAM20680HP_WHOAMI_VALUE 0xF8 | 431 | #define INV_IAM20680HP_WHOAMI_VALUE 0xF8 |
| 430 | #define INV_IAM20680HT_WHOAMI_VALUE 0xFA | 432 | #define INV_IAM20680HT_WHOAMI_VALUE 0xFA |
| @@ -79,6 +79,7 @@ static const struct spi_device_id inv_mpu_id[] = { · 78 unmodified lines | |||
| 79 | {"icm20600", INV_ICM20600}, | 79 | {"icm20600", INV_ICM20600}, |
| 80 | {"icm20602", INV_ICM20602}, | 80 | {"icm20602", INV_ICM20602}, |
| 81 | {"icm20690", INV_ICM20690}, | 81 | {"icm20690", INV_ICM20690}, |
| 82 | {"iam20380", INV_IAM20380}, | ||
| 82 | {"iam20680", INV_IAM20680}, | 83 | {"iam20680", INV_IAM20680}, |
| 83 | {"iam20680hp", INV_IAM20680HP}, | 84 | {"iam20680hp", INV_IAM20680HP}, |
| 84 | {"iam20680ht", INV_IAM20680HT}, | 85 | {"iam20680ht", INV_IAM20680HT}, |
| @@ -140,6 +141,10 @@ static const struct of_device_id inv_of_match[] = { · 55 unmodified lines | |||
| 140 | .compatible = "invensense,icm20690", | 141 | .compatible = "invensense,icm20690", |
| 141 | .data = (void *)INV_ICM20690 | 142 | .data = (void *)INV_ICM20690 |
| 142 | }, | 143 | }, |
| 144 | { | ||
| 145 | .compatible = "invensense,iam20380", | ||
| 146 | .data = (void *)INV_IAM20380 | ||
| 147 | }, | ||
| 143 | { | 148 | { |
| 144 | .compatible = "invensense,iam20680", | 149 | .compatible = "invensense,iam20680", |
| 145 | .data = (void *)INV_IAM20680 | 150 | .data = (void *)INV_IAM20680 |
| @@ -6,9 +6,6 @@ config IIO_ST_LSM6DSX · 5 unmodified lines | |||
| 6 | select IIO_BUFFER | 6 | select IIO_BUFFER |
| 7 | select IIO_TRIGGERED_BUFFER | 7 | select IIO_TRIGGERED_BUFFER |
| 8 | select IIO_KFIFO_BUF | 8 | select IIO_KFIFO_BUF |
| 9 | select IIO_ST_LSM6DSX_I2C if (I2C) | ||
| 10 | select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) | ||
| 11 | select IIO_ST_LSM6DSX_I3C if (I3C) | ||
| 12 | help | 9 | help |
| 13 | Say yes here to build support for STMicroelectronics LSM6DSx imu | 10 | Say yes here to build support for STMicroelectronics LSM6DSx imu |
| 14 | sensor. | 11 | sensor. |
| @@ -42,16 +39,19 @@ config IIO_ST_LSM6DSX · 27 unmodified lines | |||
| 42 | will be called st_lsm6dsx. | 39 | will be called st_lsm6dsx. |
| 43 | 40 | ||
| 44 | config IIO_ST_LSM6DSX_I2C | 41 | config IIO_ST_LSM6DSX_I2C |
| 45 | tristate | 42 | tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors I2C Interface" |
| 46 | depends on IIO_ST_LSM6DSX | 43 | depends on I2C && IIO_ST_LSM6DSX |
| 44 | default I2C && IIO_ST_LSM6DSX | ||
| 47 | select REGMAP_I2C | 45 | select REGMAP_I2C |
| 48 | 46 | ||
| 49 | config IIO_ST_LSM6DSX_SPI | 47 | config IIO_ST_LSM6DSX_SPI |
| 50 | tristate | 48 | tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors SPI Interface" |
| 51 | depends on IIO_ST_LSM6DSX | 49 | depends on SPI_MASTER && IIO_ST_LSM6DSX |
| 50 | default SPI_MASTER && IIO_ST_LSM6DSX | ||
| 52 | select REGMAP_SPI | 51 | select REGMAP_SPI |
| 53 | 52 | ||
| 54 | config IIO_ST_LSM6DSX_I3C | 53 | config IIO_ST_LSM6DSX_I3C |
| 55 | tristate | 54 | tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors I3C Interface" |
| 56 | depends on IIO_ST_LSM6DSX | 55 | depends on I3C && IIO_ST_LSM6DSX |
| 56 | default I3C && IIO_ST_LSM6DSX | ||
| 57 | select REGMAP_I3C | 57 | select REGMAP_I3C |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | |||
| 9 | #include <linux/mod_devicetable.h> | 9 | #include <linux/mod_devicetable.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/i3c/device.h> | 11 | #include <linux/i3c/device.h> |
| 12 | #include <linux/i3c/master.h> | ||
| 13 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 14 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
| 15 | 14 | ||
| @@ -30,15 +29,16 @@ static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) · 14 unmodified lines | |||
| 30 | }; | 29 | }; |
| 31 | const struct i3c_device_id *id = i3c_device_match_id(i3cdev, | 30 | const struct i3c_device_id *id = i3c_device_match_id(i3cdev, |
| 32 | st_lsm6dsx_i3c_ids); | 31 | st_lsm6dsx_i3c_ids); |
| 32 | struct device *dev = i3cdev_to_dev(i3cdev); | ||
| 33 | struct regmap *regmap; | 33 | struct regmap *regmap; |
| 34 | 34 | ||
| 35 | regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); | 35 | regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); |
| 36 | if (IS_ERR(regmap)) { | 36 | if (IS_ERR(regmap)) { |
| 37 | dev_err(&i3cdev->dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap)); | 37 | dev_err(dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap)); |
| 38 | return PTR_ERR(regmap); | 38 | return PTR_ERR(regmap); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); | 41 | return st_lsm6dsx_probe(dev, 0, (uintptr_t)id->data, regmap); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static struct i3c_driver st_lsm6dsx_driver = { | 44 | static struct i3c_driver st_lsm6dsx_driver = { |
| @@ -1137,7 +1137,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, · 1136 unmodified lines | |||
| 1137 | int ret; | 1137 | int ret; |
| 1138 | 1138 | ||
| 1139 | indio_dev->active_scan_mask = config->scan_mask; | 1139 | indio_dev->active_scan_mask = config->scan_mask; |
| 1140 | indio_dev->scan_timestamp = config->scan_timestamp; | 1140 | ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp; |
| 1141 | indio_dev->scan_bytes = config->scan_bytes; | 1141 | indio_dev->scan_bytes = config->scan_bytes; |
| 1142 | iio_dev_opaque->currentmode = config->mode; | 1142 | iio_dev_opaque->currentmode = config->mode; |
| 1143 | 1143 | ||
| @@ -915,6 +915,41 @@ int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel · 914 unmodified lines | |||
| 915 | } | 915 | } |
| 916 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_sel_for_scale_using_time, "IIO_GTS_HELPER"); | 916 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_sel_for_scale_using_time, "IIO_GTS_HELPER"); |
| 917 | 917 | ||
| 918 | /** | ||
| 919 | * iio_gts_find_gain_time_sel_for_scale - Fetch gain and time selectors for scale | ||
| 920 | * @gts: Gain time scale descriptor | ||
| 921 | * @scale_int: Integral part of the scale (typically val1) | ||
| 922 | * @scale_nano: Fractional part of the scale (nano or ppb) | ||
| 923 | * @gain_sel: Pointer to value where gain selector is stored. | ||
| 924 | * @time_sel: Pointer to value where time selector is stored. | ||
| 925 | * | ||
| 926 | * Wrapper around iio_gts_find_gain_for_scale_using_time() to fetch the | ||
| 927 | * gain and time selectors for a given scale. | ||
| 928 | * | ||
| 929 | * Return: 0 on success and -EINVAL on error. | ||
| 930 | */ | ||
| 931 | int iio_gts_find_gain_time_sel_for_scale(struct iio_gts *gts, int scale_int, | ||
| 932 | int scale_nano, int *gain_sel, | ||
| 933 | int *time_sel) | ||
| 934 | { | ||
| 935 | int i, ret; | ||
| 936 | |||
| 937 | for (i = 0; i < gts->num_itime; i++) { | ||
| 938 | *time_sel = gts->itime_table[i].sel; | ||
| 939 | ret = iio_gts_find_gain_sel_for_scale_using_time(gts, *time_sel, | ||
| 940 | scale_int, | ||
| 941 | scale_nano, | ||
| 942 | gain_sel); | ||
| 943 | if (ret) | ||
| 944 | continue; | ||
| 945 | |||
| 946 | return 0; | ||
| 947 | } | ||
| 948 | |||
| 949 | return -EINVAL; | ||
| 950 | } | ||
| 951 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_time_sel_for_scale, "IIO_GTS_HELPER"); | ||
| 952 | |||
| 918 | static int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time) | 953 | static int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time) |
| 919 | { | 954 | { |
| 920 | const struct iio_itime_sel_mul *itime; | 955 | const struct iio_itime_sel_mul *itime; |
| @@ -1086,6 +1121,48 @@ int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain, · 165 unmodified lines | |||
| 1086 | } | 1121 | } |
| 1087 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_old_gain_time, "IIO_GTS_HELPER"); | 1122 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_old_gain_time, "IIO_GTS_HELPER"); |
| 1088 | 1123 | ||
| 1124 | /** | ||
| 1125 | * iio_gts_find_new_gain_by_gain_time_min - compensate for time change | ||
| 1126 | * @gts: Gain time scale descriptor | ||
| 1127 | * @old_gain: Previously set gain | ||
| 1128 | * @old_time: Selector corresponding previously set time | ||
| 1129 | * @new_time: Selector corresponding new time to be set | ||
| 1130 | * @new_gain: Pointer to value where new gain is to be written | ||
| 1131 | * @in_range: Indicate if the @new_gain was in the range of | ||
| 1132 | * supported gains. | ||
| 1133 | * | ||
| 1134 | * Wrapper around iio_gts_find_new_gain_by_old_gain_time() that tries to | ||
| 1135 | * set an optimal value if no exact match was found, defaulting to the | ||
| 1136 | * minimum gain to avoid saturations if the optimal value is not in the | ||
| 1137 | * range of supported gains. | ||
| 1138 | * | ||
| 1139 | * Return: 0 on success and a negative value if no gain was found. | ||
| 1140 | */ | ||
| 1141 | int iio_gts_find_new_gain_by_gain_time_min(struct iio_gts *gts, int old_gain, | ||
| 1142 | int old_time, int new_time, | ||
| 1143 | int *new_gain, bool *in_range) | ||
| 1144 | { | ||
| 1145 | int ret; | ||
| 1146 | |||
| 1147 | *in_range = true; | ||
| 1148 | ret = iio_gts_find_new_gain_by_old_gain_time(gts, old_gain, old_time, | ||
| 1149 | new_time, new_gain); | ||
| 1150 | if (*new_gain < 0) | ||
| 1151 | return -EINVAL; | ||
| 1152 | |||
| 1153 | if (ret) { | ||
| 1154 | *new_gain = iio_find_closest_gain_low(gts, *new_gain, in_range); | ||
| 1155 | if (*new_gain < 0) { | ||
| 1156 | *new_gain = iio_gts_get_min_gain(gts); | ||
| 1157 | if (*new_gain < 0) | ||
| 1158 | return -EINVAL; | ||
| 1159 | } | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | return 0; | ||
| 1163 | } | ||
| 1164 | EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_gain_time_min, "IIO_GTS_HELPER"); | ||
| 1165 | |||
| 1089 | MODULE_LICENSE("GPL"); | 1166 | MODULE_LICENSE("GPL"); |
| 1090 | MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); | 1167 | MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); |
| 1091 | MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers"); | 1168 | MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers"); |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/err.h> | 7 | #include <linux/err.h> |
| 8 | #include <linux/export.h> | 8 | #include <linux/export.h> |
| 9 | #include <linux/minmax.h> | 9 | #include <linux/minmax.h> |
| 10 | #include <linux/mm.h> | ||
| 10 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
| 11 | #include <linux/property.h> | 12 | #include <linux/property.h> |
| 12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| @@ -989,6 +990,11 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan, · 976 unmodified lines | |||
| 989 | { | 990 | { |
| 990 | const struct iio_chan_spec_ext_info *ext_info; | 991 | const struct iio_chan_spec_ext_info *ext_info; |
| 991 | 992 | ||
| 993 | if (!buf || offset_in_page(buf)) { | ||
| 994 | pr_err("iio: invalid ext_info read buffer\n"); | ||
| 995 | return -EINVAL; | ||
| 996 | } | ||
| 997 | |||
| 992 | ext_info = iio_lookup_ext_info(chan, attr); | 998 | ext_info = iio_lookup_ext_info(chan, attr); |
| 993 | if (!ext_info) | 999 | if (!ext_info) |
| 994 | return -EINVAL; | 1000 | return -EINVAL; |
| @@ -1014,6 +1020,11 @@ EXPORT_SYMBOL_GPL(iio_write_channel_ext_info); · 19 unmodified lines | |||
| 1014 | 1020 | ||
| 1015 | ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) | 1021 | ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) |
| 1016 | { | 1022 | { |
| 1023 | if (!buf || offset_in_page(buf)) { | ||
| 1024 | pr_err("iio: invalid label read buffer\n"); | ||
| 1025 | return -EINVAL; | ||
| 1026 | } | ||
| 1027 | |||
| 1017 | return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); | 1028 | return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); |
| 1018 | } | 1029 | } |
| 1019 | EXPORT_SYMBOL_GPL(iio_read_channel_label); | 1030 | EXPORT_SYMBOL_GPL(iio_read_channel_label); |
| @@ -329,22 +329,6 @@ config JSA1212 · 328 unmodified lines | |||
| 329 | To compile this driver as a module, choose M here: | 329 | To compile this driver as a module, choose M here: |
| 330 | the module will be called jsa1212. | 330 | the module will be called jsa1212. |
| 331 | 331 | ||
| 332 | config ROHM_BU27008 | ||
| 333 | tristate "ROHM BU27008 color (RGB+C/IR) sensor" | ||
| 334 | depends on I2C | ||
| 335 | select REGMAP_I2C | ||
| 336 | select IIO_GTS_HELPER | ||
| 337 | select IIO_BUFFER | ||
| 338 | select IIO_TRIGGERED_BUFFER | ||
| 339 | help | ||
| 340 | Enable support for the ROHM BU27008 color sensor. | ||
| 341 | The ROHM BU27008 is a sensor with 5 photodiodes (red, green, | ||
| 342 | blue, clear and IR) with four configurable channels. Red and | ||
| 343 | green being always available and two out of the rest three | ||
| 344 | (blue, clear, IR) can be selected to be simultaneously measured. | ||
| 345 | Typical application is adjusting LCD backlight of TVs, | ||
| 346 | mobile phones and tablet PCs. | ||
| 347 | |||
| 348 | config ROHM_BU27034 | 332 | config ROHM_BU27034 |
| 349 | tristate "ROHM BU27034 ambient light sensor" | 333 | tristate "ROHM BU27034 ambient light sensor" |
| 350 | depends on I2C | 334 | depends on I2C |
| @@ -491,6 +475,19 @@ config OPT4001 · 140 unmodified lines | |||
| 491 | If built as a dynamically linked module, it will be called | 475 | If built as a dynamically linked module, it will be called |
| 492 | opt4001. | 476 | opt4001. |
| 493 | 477 | ||
| 478 | config OPT4060 | ||
| 479 | tristate "Texas Instruments OPT4060 RGBW Color Sensor" | ||
| 480 | depends on I2C | ||
| 481 | select REGMAP_I2C | ||
| 482 | select IIO_BUFFER | ||
| 483 | select IIO_TRIGGERED_BUFFER | ||
| 484 | help | ||
| 485 | If you say Y or M here, you get support for Texas Instruments | ||
| 486 | OPT4060 RGBW Color Sensor. | ||
| 487 | |||
| 488 | If built as a dynamically linked module, it will be called | ||
| 489 | opt4060. | ||
| 490 | |||
| 494 | config PA12203001 | 491 | config PA12203001 |
| 495 | tristate "TXC PA12203001 light and proximity sensor" | 492 | tristate "TXC PA12203001 light and proximity sensor" |
| 496 | depends on I2C | 493 | depends on I2C |
| @@ -672,6 +669,7 @@ config VCNL4035 · 175 unmodified lines | |||
| 672 | config VEML3235 | 669 | config VEML3235 |
| 673 | tristate "VEML3235 ambient light sensor" | 670 | tristate "VEML3235 ambient light sensor" |
| 674 | select REGMAP_I2C | 671 | select REGMAP_I2C |
| 672 | select IIO_GTS_HELPER | ||
| 675 | depends on I2C | 673 | depends on I2C |
| 676 | help | 674 | help |
| 677 | Say Y here if you want to build a driver for the Vishay VEML3235 | 675 | Say Y here if you want to build a driver for the Vishay VEML3235 |
| @@ -683,6 +681,8 @@ config VEML3235 · 5 unmodified lines | |||
| 683 | config VEML6030 | 681 | config VEML6030 |
| 684 | tristate "VEML6030 and VEML6035 ambient light sensors" | 682 | tristate "VEML6030 and VEML6035 ambient light sensors" |
| 685 | select REGMAP_I2C | 683 | select REGMAP_I2C |
| 684 | select IIO_BUFFER | ||
| 685 | select IIO_TRIGGERED_BUFFER | ||
| 686 | depends on I2C | 686 | depends on I2C |
| 687 | help | 687 | help |
| 688 | Say Y here if you want to build a driver for the Vishay VEML6030 | 688 | Say Y here if you want to build a driver for the Vishay VEML6030 |
| @@ -42,8 +42,8 @@ obj-$(CONFIG_MAX44009) += max44009.o · 41 unmodified lines | |||
| 42 | obj-$(CONFIG_NOA1305) += noa1305.o | 42 | obj-$(CONFIG_NOA1305) += noa1305.o |
| 43 | obj-$(CONFIG_OPT3001) += opt3001.o | 43 | obj-$(CONFIG_OPT3001) += opt3001.o |
| 44 | obj-$(CONFIG_OPT4001) += opt4001.o | 44 | obj-$(CONFIG_OPT4001) += opt4001.o |
| 45 | obj-$(CONFIG_OPT4060) += opt4060.o | ||
| 45 | obj-$(CONFIG_PA12203001) += pa12203001.o | 46 | obj-$(CONFIG_PA12203001) += pa12203001.o |
| 46 | obj-$(CONFIG_ROHM_BU27008) += rohm-bu27008.o | ||
| 47 | obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o | 47 | obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o |
| 48 | obj-$(CONFIG_RPR0521) += rpr0521.o | 48 | obj-$(CONFIG_RPR0521) += rpr0521.o |
| 49 | obj-$(CONFIG_SI1133) += si1133.o | 49 | obj-$(CONFIG_SI1133) += si1133.o |
| @@ -56,7 +56,7 @@ struct adjd_s311_data { · 55 unmodified lines | |||
| 56 | struct i2c_client *client; | 56 | struct i2c_client *client; |
| 57 | struct { | 57 | struct { |
| 58 | s16 chans[4]; | 58 | s16 chans[4]; |
| 59 | s64 ts __aligned(8); | 59 | aligned_s64 ts; |
| 60 | } scan; | 60 | } scan; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| @@ -177,6 +177,12 @@ struct as73211_data { · 176 unmodified lines | |||
| 177 | BIT(AS73211_SCAN_INDEX_TEMP) | \ | 177 | BIT(AS73211_SCAN_INDEX_TEMP) | \ |
| 178 | AS73211_SCAN_MASK_COLOR) | 178 | AS73211_SCAN_MASK_COLOR) |
| 179 | 179 | ||
| 180 | static const unsigned long as73211_scan_masks[] = { | ||
| 181 | AS73211_SCAN_MASK_COLOR, | ||
| 182 | AS73211_SCAN_MASK_ALL, | ||
| 183 | 0 | ||
| 184 | }; | ||
| 185 | |||
| 180 | static const struct iio_chan_spec as73211_channels[] = { | 186 | static const struct iio_chan_spec as73211_channels[] = { |
| 181 | { | 187 | { |
| 182 | .type = IIO_TEMP, | 188 | .type = IIO_TEMP, |
| @@ -636,7 +642,7 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) · 453 unmodified lines | |||
| 636 | struct as73211_data *data = iio_priv(indio_dev); | 642 | struct as73211_data *data = iio_priv(indio_dev); |
| 637 | struct { | 643 | struct { |
| 638 | __le16 chan[4]; | 644 | __le16 chan[4]; |
| 639 | s64 ts __aligned(8); | 645 | aligned_s64 ts; |
| 640 | } scan; | 646 | } scan; |
| 641 | int data_result, ret; | 647 | int data_result, ret; |
| 642 | 648 | ||
| @@ -672,9 +678,12 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) · 29 unmodified lines | |||
| 672 | 678 | ||
| 673 | /* AS73211 starts reading at address 2 */ | 679 | /* AS73211 starts reading at address 2 */ |
| 674 | ret = i2c_master_recv(data->client, | 680 | ret = i2c_master_recv(data->client, |
| 675 | (char *)&scan.chan[1], 3 * sizeof(scan.chan[1])); | 681 | (char *)&scan.chan[0], 3 * sizeof(scan.chan[0])); |
| 676 | if (ret < 0) | 682 | if (ret < 0) |
| 677 | goto done; | 683 | goto done; |
| 684 | |||
| 685 | /* Avoid pushing uninitialized data */ | ||
| 686 | scan.chan[3] = 0; | ||
| 678 | } | 687 | } |
| 679 | 688 | ||
| 680 | if (data_result) { | 689 | if (data_result) { |
| @@ -682,9 +691,15 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) · 1 unmodified line | |||
| 682 | * Saturate all channels (in case of overflows). Temperature channel | 691 | * Saturate all channels (in case of overflows). Temperature channel |
| 683 | * is not affected by overflows. | 692 | * is not affected by overflows. |
| 684 | */ | 693 | */ |
| 685 | scan.chan[1] = cpu_to_le16(U16_MAX); | 694 | if (*indio_dev->active_scan_mask == AS73211_SCAN_MASK_ALL) { |
| 686 | scan.chan[2] = cpu_to_le16(U16_MAX); | 695 | scan.chan[1] = cpu_to_le16(U16_MAX); |
| 687 | scan.chan[3] = cpu_to_le16(U16_MAX); | 696 | scan.chan[2] = cpu_to_le16(U16_MAX); |
| 697 | scan.chan[3] = cpu_to_le16(U16_MAX); | ||
| 698 | } else { | ||
| 699 | scan.chan[0] = cpu_to_le16(U16_MAX); | ||
| 700 | scan.chan[1] = cpu_to_le16(U16_MAX); | ||
| 701 | scan.chan[2] = cpu_to_le16(U16_MAX); | ||
| 702 | } | ||
| 688 | } | 703 | } |
| 689 | 704 | ||
| 690 | iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); | 705 | iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); |
| @@ -758,6 +773,7 @@ static int as73211_probe(struct i2c_client *client) · 67 unmodified lines | |||
| 758 | indio_dev->channels = data->spec_dev->channels; | 773 | indio_dev->channels = data->spec_dev->channels; |
| 759 | indio_dev->num_channels = data->spec_dev->num_channels; | 774 | indio_dev->num_channels = data->spec_dev->num_channels; |
| 760 | indio_dev->modes = INDIO_DIRECT_MODE; | 775 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 776 | indio_dev->available_scan_masks = as73211_scan_masks; | ||
| 761 | 777 | ||
| 762 | ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR); | 778 | ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR); |
| 763 | if (ret < 0) | 779 | if (ret < 0) |
| @@ -739,7 +739,7 @@ static irqreturn_t bh1745_trigger_handler(int interrupt, void *p) · 738 unmodified lines | |||
| 739 | struct bh1745_data *data = iio_priv(indio_dev); | 739 | struct bh1745_data *data = iio_priv(indio_dev); |
| 740 | struct { | 740 | struct { |
| 741 | u16 chans[4]; | 741 | u16 chans[4]; |
| 742 | s64 timestamp __aligned(8); | 742 | aligned_s64 timestamp; |
| 743 | } scan; | 743 | } scan; |
| 744 | u16 value; | 744 | u16 value; |
| 745 | int ret; | 745 | int ret; |
| @@ -89,6 +89,15 @@ static int cm3232_reg_init(struct cm3232_chip *chip) · 88 unmodified lines | |||
| 89 | 89 | ||
| 90 | chip->als_info = &cm3232_als_info_default; | 90 | chip->als_info = &cm3232_als_info_default; |
| 91 | 91 | ||
| 92 | /* Disable and reset device */ | ||
| 93 | chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET; | ||
| 94 | ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD, | ||
| 95 | chip->regs_cmd); | ||
| 96 | if (ret < 0) { | ||
| 97 | dev_err(&chip->client->dev, "Error writing reg_cmd\n"); | ||
| 98 | return ret; | ||
| 99 | } | ||
| 100 | |||
| 92 | /* Identify device */ | 101 | /* Identify device */ |
| 93 | ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID); | 102 | ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID); |
| 94 | if (ret < 0) { | 103 | if (ret < 0) { |
| @@ -99,15 +108,6 @@ static int cm3232_reg_init(struct cm3232_chip *chip) · 4 unmodified lines | |||
| 99 | if ((ret & 0xFF) != chip->als_info->hw_id) | 108 | if ((ret & 0xFF) != chip->als_info->hw_id) |
| 100 | return -ENODEV; | 109 | return -ENODEV; |
| 101 | 110 | ||
| 102 | /* Disable and reset device */ | ||
| 103 | chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET; | ||
| 104 | ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD, | ||
| 105 | chip->regs_cmd); | ||
| 106 | if (ret < 0) { | ||
| 107 | dev_err(&chip->client->dev, "Error writing reg_cmd\n"); | ||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | |||
| 111 | /* Register default value */ | 111 | /* Register default value */ |
| 112 | chip->regs_cmd = chip->als_info->regs_cmd_default; | 112 | chip->regs_cmd = chip->als_info->regs_cmd_default; |
| 113 | 113 | ||
| @@ -94,6 +94,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, · 93 unmodified lines | |||
| 94 | *val2 = 0; | 94 | *val2 = 0; |
| 95 | switch (mask) { | 95 | switch (mask) { |
| 96 | case IIO_CHAN_INFO_RAW: | 96 | case IIO_CHAN_INFO_RAW: |
| 97 | case IIO_CHAN_INFO_PROCESSED: | ||
| 97 | if (chan->scan_index >= prox_state->num_channels) | 98 | if (chan->scan_index >= prox_state->num_channels) |
| 98 | return -EINVAL; | 99 | return -EINVAL; |
| 99 | address = prox_state->channel2usage[chan->scan_index]; | 100 | address = prox_state->channel2usage[chan->scan_index]; |
| @@ -54,7 +54,7 @@ struct isl29125_data { · 53 unmodified lines | |||
| 54 | /* Ensure timestamp is naturally aligned */ | 54 | /* Ensure timestamp is naturally aligned */ |
| 55 | struct { | 55 | struct { |
| 56 | u16 chans[3]; | 56 | u16 chans[3]; |
| 57 | s64 timestamp __aligned(8); | 57 | aligned_s64 timestamp; |
| 58 | } scan; | 58 | } scan; |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| @@ -1280,7 +1280,7 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p) · 1279 unmodified lines | |||
| 1280 | struct ltr501_data *data = iio_priv(indio_dev); | 1280 | struct ltr501_data *data = iio_priv(indio_dev); |
| 1281 | struct { | 1281 | struct { |
| 1282 | u16 channels[3]; | 1282 | u16 channels[3]; |
| 1283 | s64 ts __aligned(8); | 1283 | aligned_s64 ts; |
| 1284 | } scan; | 1284 | } scan; |
| 1285 | __le16 als_buf[2]; | 1285 | __le16 als_buf[2]; |
| 1286 | u8 mask = 0; | 1286 | u8 mask = 0; |
| @@ -78,7 +78,7 @@ struct max44000_data { · 77 unmodified lines | |||
| 78 | /* Ensure naturally aligned timestamp */ | 78 | /* Ensure naturally aligned timestamp */ |
| 79 | struct { | 79 | struct { |
| 80 | u16 channels[2]; | 80 | u16 channels[2]; |
| 81 | s64 ts __aligned(8); | 81 | aligned_s64 ts; |
| 82 | } scan; | 82 | } scan; |
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| @@ -0,0 +1,1343 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2024 Axis Communications AB | ||
| 4 | * | ||
| 5 | * Datasheet: https://www.ti.com/lit/gpn/opt4060 | ||
| 6 | * | ||
| 7 | * Device driver for the Texas Instruments OPT4060 RGBW Color Sensor. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/bitfield.h> | ||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <linux/iio/iio.h> | ||
| 13 | #include <linux/math64.h> | ||
| 14 | #include <linux/units.h> | ||
| 15 | #include <linux/limits.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/property.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <linux/mutex.h> | ||
| 20 | #include <linux/regulator/consumer.h> | ||
| 21 | #include <linux/iio/events.h> | ||
| 22 | #include <linux/iio/trigger.h> | ||
| 23 | #include <linux/iio/trigger_consumer.h> | ||
| 24 | #include <linux/iio/triggered_buffer.h> | ||
| 25 | |||
| 26 | /* OPT4060 register set */ | ||
| 27 | #define OPT4060_RED_MSB 0x00 | ||
| 28 | #define OPT4060_RED_LSB 0x01 | ||
| 29 | #define OPT4060_GREEN_MSB 0x02 | ||
| 30 | #define OPT4060_GREEN_LSB 0x03 | ||
| 31 | #define OPT4060_BLUE_MSB 0x04 | ||
| 32 | #define OPT4060_BLUE_LSB 0x05 | ||
| 33 | #define OPT4060_CLEAR_MSB 0x06 | ||
| 34 | #define OPT4060_CLEAR_LSB 0x07 | ||
| 35 | #define OPT4060_THRESHOLD_LOW 0x08 | ||
| 36 | #define OPT4060_THRESHOLD_HIGH 0x09 | ||
| 37 | #define OPT4060_CTRL 0x0a | ||
| 38 | #define OPT4060_INT_CTRL 0x0b | ||
| 39 | #define OPT4060_RES_CTRL 0x0c | ||
| 40 | #define OPT4060_DEVICE_ID 0x11 | ||
| 41 | |||
| 42 | /* OPT4060 register mask */ | ||
| 43 | #define OPT4060_EXPONENT_MASK GENMASK(15, 12) | ||
| 44 | #define OPT4060_MSB_MASK GENMASK(11, 0) | ||
| 45 | #define OPT4060_LSB_MASK GENMASK(15, 8) | ||
| 46 | #define OPT4060_COUNTER_MASK GENMASK(7, 4) | ||
| 47 | #define OPT4060_CRC_MASK GENMASK(3, 0) | ||
| 48 | |||
| 49 | /* OPT4060 device id mask */ | ||
| 50 | #define OPT4060_DEVICE_ID_MASK GENMASK(11, 0) | ||
| 51 | |||
| 52 | /* OPT4060 control register masks */ | ||
| 53 | #define OPT4060_CTRL_QWAKE_MASK BIT(15) | ||
| 54 | #define OPT4060_CTRL_RANGE_MASK GENMASK(13, 10) | ||
| 55 | #define OPT4060_CTRL_CONV_TIME_MASK GENMASK(9, 6) | ||
| 56 | #define OPT4060_CTRL_OPER_MODE_MASK GENMASK(5, 4) | ||
| 57 | #define OPT4060_CTRL_LATCH_MASK BIT(3) | ||
| 58 | #define OPT4060_CTRL_INT_POL_MASK BIT(2) | ||
| 59 | #define OPT4060_CTRL_FAULT_COUNT_MASK GENMASK(1, 0) | ||
| 60 | |||
| 61 | /* OPT4060 interrupt control register masks */ | ||
| 62 | #define OPT4060_INT_CTRL_THRESH_SEL GENMASK(6, 5) | ||
| 63 | #define OPT4060_INT_CTRL_OUTPUT BIT(4) | ||
| 64 | #define OPT4060_INT_CTRL_INT_CFG GENMASK(3, 2) | ||
| 65 | #define OPT4060_INT_CTRL_THRESHOLD 0x0 | ||
| 66 | #define OPT4060_INT_CTRL_NEXT_CH 0x1 | ||
| 67 | #define OPT4060_INT_CTRL_ALL_CH 0x3 | ||
| 68 | |||
| 69 | /* OPT4060 result control register masks */ | ||
| 70 | #define OPT4060_RES_CTRL_OVERLOAD BIT(3) | ||
| 71 | #define OPT4060_RES_CTRL_CONV_READY BIT(2) | ||
| 72 | #define OPT4060_RES_CTRL_FLAG_H BIT(1) | ||
| 73 | #define OPT4060_RES_CTRL_FLAG_L BIT(0) | ||
| 74 | |||
| 75 | /* OPT4060 constants */ | ||
| 76 | #define OPT4060_DEVICE_ID_VAL 0x821 | ||
| 77 | |||
| 78 | /* OPT4060 operating modes */ | ||
| 79 | #define OPT4060_CTRL_OPER_MODE_OFF 0x0 | ||
| 80 | #define OPT4060_CTRL_OPER_MODE_FORCED 0x1 | ||
| 81 | #define OPT4060_CTRL_OPER_MODE_ONE_SHOT 0x2 | ||
| 82 | #define OPT4060_CTRL_OPER_MODE_CONTINUOUS 0x3 | ||
| 83 | |||
| 84 | /* OPT4060 conversion control register definitions */ | ||
| 85 | #define OPT4060_CTRL_CONVERSION_0_6MS 0x0 | ||
| 86 | #define OPT4060_CTRL_CONVERSION_1MS 0x1 | ||
| 87 | #define OPT4060_CTRL_CONVERSION_1_8MS 0x2 | ||
| 88 | #define OPT4060_CTRL_CONVERSION_3_4MS 0x3 | ||
| 89 | #define OPT4060_CTRL_CONVERSION_6_5MS 0x4 | ||
| 90 | #define OPT4060_CTRL_CONVERSION_12_7MS 0x5 | ||
| 91 | #define OPT4060_CTRL_CONVERSION_25MS 0x6 | ||
| 92 | #define OPT4060_CTRL_CONVERSION_50MS 0x7 | ||
| 93 | #define OPT4060_CTRL_CONVERSION_100MS 0x8 | ||
| 94 | #define OPT4060_CTRL_CONVERSION_200MS 0x9 | ||
| 95 | #define OPT4060_CTRL_CONVERSION_400MS 0xa | ||
| 96 | #define OPT4060_CTRL_CONVERSION_800MS 0xb | ||
| 97 | |||
| 98 | /* OPT4060 fault count control register definitions */ | ||
| 99 | #define OPT4060_CTRL_FAULT_COUNT_1 0x0 | ||
| 100 | #define OPT4060_CTRL_FAULT_COUNT_2 0x1 | ||
| 101 | #define OPT4060_CTRL_FAULT_COUNT_4 0x2 | ||
| 102 | #define OPT4060_CTRL_FAULT_COUNT_8 0x3 | ||
| 103 | |||
| 104 | /* OPT4060 scale light level range definitions */ | ||
| 105 | #define OPT4060_CTRL_LIGHT_SCALE_AUTO 12 | ||
| 106 | |||
| 107 | /* OPT4060 default values */ | ||
| 108 | #define OPT4060_DEFAULT_CONVERSION_TIME OPT4060_CTRL_CONVERSION_50MS | ||
| 109 | |||
| 110 | /* | ||
| 111 | * enum opt4060_chan_type - OPT4060 channel types | ||
| 112 | * @OPT4060_RED: Red channel. | ||
| 113 | * @OPT4060_GREEN: Green channel. | ||
| 114 | * @OPT4060_BLUE: Blue channel. | ||
| 115 | * @OPT4060_CLEAR: Clear (white) channel. | ||
| 116 | * @OPT4060_ILLUM: Calculated illuminance channel. | ||
| 117 | * @OPT4060_NUM_CHANS: Number of channel types. | ||
| 118 | */ | ||
| 119 | enum opt4060_chan_type { | ||
| 120 | OPT4060_RED, | ||
| 121 | OPT4060_GREEN, | ||
| 122 | OPT4060_BLUE, | ||
| 123 | OPT4060_CLEAR, | ||
| 124 | OPT4060_ILLUM, | ||
| 125 | OPT4060_NUM_CHANS | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct opt4060_chip { | ||
| 129 | struct regmap *regmap; | ||
| 130 | struct device *dev; | ||
| 131 | struct iio_trigger *trig; | ||
| 132 | u8 int_time; | ||
| 133 | int irq; | ||
| 134 | /* | ||
| 135 | * Mutex for protecting sensor irq settings. Switching between interrupt | ||
| 136 | * on each sample and on thresholds needs to be synchronized. | ||
| 137 | */ | ||
| 138 | struct mutex irq_setting_lock; | ||
| 139 | /* | ||
| 140 | * Mutex for protecting event enabling. | ||
| 141 | */ | ||
| 142 | struct mutex event_enabling_lock; | ||
| 143 | struct completion completion; | ||
| 144 | bool thresh_event_lo_active; | ||
| 145 | bool thresh_event_hi_active; | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct opt4060_channel_factor { | ||
| 149 | u32 mul; | ||
| 150 | u32 div; | ||
| 151 | }; | ||
| 152 | |||
| 153 | static const int opt4060_int_time_available[][2] = { | ||
| 154 | { 0, 600 }, | ||
| 155 | { 0, 1000 }, | ||
| 156 | { 0, 1800 }, | ||
| 157 | { 0, 3400 }, | ||
| 158 | { 0, 6500 }, | ||
| 159 | { 0, 12700 }, | ||
| 160 | { 0, 25000 }, | ||
| 161 | { 0, 50000 }, | ||
| 162 | { 0, 100000 }, | ||
| 163 | { 0, 200000 }, | ||
| 164 | { 0, 400000 }, | ||
| 165 | { 0, 800000 }, | ||
| 166 | }; | ||
| 167 | |||
| 168 | /* | ||
| 169 | * Conversion time is integration time + time to set register | ||
| 170 | * this is used as integration time. | ||
| 171 | */ | ||
| 172 | static const int opt4060_int_time_reg[][2] = { | ||
| 173 | { 600, OPT4060_CTRL_CONVERSION_0_6MS }, | ||
| 174 | { 1000, OPT4060_CTRL_CONVERSION_1MS }, | ||
| 175 | { 1800, OPT4060_CTRL_CONVERSION_1_8MS }, | ||
| 176 | { 3400, OPT4060_CTRL_CONVERSION_3_4MS }, | ||
| 177 | { 6500, OPT4060_CTRL_CONVERSION_6_5MS }, | ||
| 178 | { 12700, OPT4060_CTRL_CONVERSION_12_7MS }, | ||
| 179 | { 25000, OPT4060_CTRL_CONVERSION_25MS }, | ||
| 180 | { 50000, OPT4060_CTRL_CONVERSION_50MS }, | ||
| 181 | { 100000, OPT4060_CTRL_CONVERSION_100MS }, | ||
| 182 | { 200000, OPT4060_CTRL_CONVERSION_200MS }, | ||
| 183 | { 400000, OPT4060_CTRL_CONVERSION_400MS }, | ||
| 184 | { 800000, OPT4060_CTRL_CONVERSION_800MS }, | ||
| 185 | }; | ||
| 186 | |||
| 187 | static int opt4060_als_time_to_index(const u32 als_integration_time) | ||
| 188 | { | ||
| 189 | int i; | ||
| 190 | |||
| 191 | for (i = 0; i < ARRAY_SIZE(opt4060_int_time_available); i++) { | ||
| 192 | if (als_integration_time == opt4060_int_time_available[i][1]) | ||
| 193 | return i; | ||
| 194 | } | ||
| 195 | |||
| 196 | return -EINVAL; | ||
| 197 | } | ||
| 198 | |||
| 199 | static u8 opt4060_calculate_crc(u8 exp, u32 mantissa, u8 count) | ||
| 200 | { | ||
| 201 | u8 crc; | ||
| 202 | |||
| 203 | /* | ||
| 204 | * Calculates a 4-bit CRC from a 20-bit mantissa, 4-bit exponent and a 4-bit counter. | ||
| 205 | * crc[0] = XOR(mantissa[19:0], exp[3:0], count[3:0]) | ||
| 206 | * crc[1] = XOR(mantissa[1,3,5,7,9,11,13,15,17,19], exp[1,3], count[1,3]) | ||
| 207 | * crc[2] = XOR(mantissa[3,7,11,15,19], exp[3], count[3]) | ||
| 208 | * crc[3] = XOR(mantissa[3,11,19]) | ||
| 209 | */ | ||
| 210 | crc = (hweight32(mantissa) + hweight32(exp) + hweight32(count)) % 2; | ||
| 211 | crc |= ((hweight32(mantissa & 0xAAAAA) + hweight32(exp & 0xA) | ||
| 212 | + hweight32(count & 0xA)) % 2) << 1; | ||
| 213 | crc |= ((hweight32(mantissa & 0x88888) + hweight32(exp & 0x8) | ||
| 214 | + hweight32(count & 0x8)) % 2) << 2; | ||
| 215 | crc |= (hweight32(mantissa & 0x80808) % 2) << 3; | ||
| 216 | |||
| 217 | return crc; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int opt4060_set_int_state(struct opt4060_chip *chip, u32 state) | ||
| 221 | { | ||
| 222 | int ret; | ||
| 223 | unsigned int regval; | ||
| 224 | |||
| 225 | guard(mutex)(&chip->irq_setting_lock); | ||
| 226 | |||
| 227 | regval = FIELD_PREP(OPT4060_INT_CTRL_INT_CFG, state); | ||
| 228 | ret = regmap_update_bits(chip->regmap, OPT4060_INT_CTRL, | ||
| 229 | OPT4060_INT_CTRL_INT_CFG, regval); | ||
| 230 | if (ret) | ||
| 231 | dev_err(chip->dev, "Failed to set interrupt config\n"); | ||
| 232 | return ret; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int opt4060_set_sampling_mode(struct opt4060_chip *chip, | ||
| 236 | bool continuous) | ||
| 237 | { | ||
| 238 | unsigned int reg; | ||
| 239 | int ret; | ||
| 240 | |||
| 241 | ret = regmap_read(chip->regmap, OPT4060_CTRL, ®); | ||
| 242 | if (ret < 0) { | ||
| 243 | dev_err(chip->dev, "Failed to read ctrl register\n"); | ||
| 244 | return ret; | ||
| 245 | } | ||
| 246 | reg &= ~OPT4060_CTRL_OPER_MODE_MASK; | ||
| 247 | if (continuous) | ||
| 248 | reg |= FIELD_PREP(OPT4060_CTRL_OPER_MODE_MASK, | ||
| 249 | OPT4060_CTRL_OPER_MODE_CONTINUOUS); | ||
| 250 | else | ||
| 251 | reg |= FIELD_PREP(OPT4060_CTRL_OPER_MODE_MASK, | ||
| 252 | OPT4060_CTRL_OPER_MODE_ONE_SHOT); | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Trigger a new conversions by writing to CRTL register. It is not | ||
| 256 | * possible to use regmap_update_bits() since that will only write when | ||
| 257 | * data is modified. | ||
| 258 | */ | ||
| 259 | ret = regmap_write(chip->regmap, OPT4060_CTRL, reg); | ||
| 260 | if (ret) | ||
| 261 | dev_err(chip->dev, "Failed to set ctrl register\n"); | ||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | static bool opt4060_event_active(struct opt4060_chip *chip) | ||
| 266 | { | ||
| 267 | return chip->thresh_event_lo_active || chip->thresh_event_hi_active; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int opt4060_set_state_common(struct opt4060_chip *chip, | ||
| 271 | bool continuous_sampling, | ||
| 272 | bool continuous_irq) | ||
| 273 | { | ||
| 274 | int ret = 0; | ||
| 275 | |||
| 276 | /* It is important to setup irq before sampling to avoid missing samples. */ | ||
| 277 | if (continuous_irq) | ||
| 278 | ret = opt4060_set_int_state(chip, OPT4060_INT_CTRL_ALL_CH); | ||
| 279 | else | ||
| 280 | ret = opt4060_set_int_state(chip, OPT4060_INT_CTRL_THRESHOLD); | ||
| 281 | if (ret) { | ||
| 282 | dev_err(chip->dev, "Failed to set irq state.\n"); | ||
| 283 | return ret; | ||
| 284 | } | ||
| 285 | |||
| 286 | if (continuous_sampling || opt4060_event_active(chip)) | ||
| 287 | ret = opt4060_set_sampling_mode(chip, true); | ||
| 288 | else | ||
| 289 | ret = opt4060_set_sampling_mode(chip, false); | ||
| 290 | if (ret) | ||
| 291 | dev_err(chip->dev, "Failed to set sampling state.\n"); | ||
| 292 | return ret; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Function for setting the driver state for sampling and irq. Either direct | ||
| 297 | * mode of buffer mode will be claimed during the transition to prevent races | ||
| 298 | * between sysfs read, buffer or events. | ||
| 299 | */ | ||
| 300 | static int opt4060_set_driver_state(struct iio_dev *indio_dev, | ||
| 301 | bool continuous_sampling, | ||
| 302 | bool continuous_irq) | ||
| 303 | { | ||
| 304 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 305 | int ret = 0; | ||
| 306 | any_mode_retry: | ||
| 307 | if (iio_device_claim_buffer_mode(indio_dev)) { | ||
| 308 | /* | ||
| 309 | * This one is a *bit* hacky. If we cannot claim buffer mode, | ||
| 310 | * then try direct mode so that we make sure things cannot | ||
| 311 | * concurrently change. And we just keep trying until we get one | ||
| 312 | * of the modes... | ||
| 313 | */ | ||
| 314 | if (iio_device_claim_direct_mode(indio_dev)) | ||
| 315 | goto any_mode_retry; | ||
| 316 | /* | ||
| 317 | * This path means that we managed to claim direct mode. In | ||
| 318 | * this case the buffer isn't enabled and it's okay to leave | ||
| 319 | * continuous mode for sampling and/or irq. | ||
| 320 | */ | ||
| 321 | ret = opt4060_set_state_common(chip, continuous_sampling, | ||
| 322 | continuous_irq); | ||
| 323 | iio_device_release_direct_mode(indio_dev); | ||
| 324 | } else { | ||
| 325 | /* | ||
| 326 | * This path means that we managed to claim buffer mode. In | ||
| 327 | * this case the buffer is enabled and irq and sampling must go | ||
| 328 | * to or remain continuous, but only if the trigger is from this | ||
| 329 | * device. | ||
| 330 | */ | ||
| 331 | if (!iio_trigger_validate_own_device(indio_dev->trig, indio_dev)) | ||
| 332 | ret = opt4060_set_state_common(chip, true, true); | ||
| 333 | else | ||
| 334 | ret = opt4060_set_state_common(chip, continuous_sampling, | ||
| 335 | continuous_irq); | ||
| 336 | iio_device_release_buffer_mode(indio_dev); | ||
| 337 | } | ||
| 338 | return ret; | ||
| 339 | } | ||
| 340 | |||
| 341 | /* | ||
| 342 | * This function is called with framework mutex locked. | ||
| 343 | */ | ||
| 344 | static int opt4060_trigger_set_state(struct iio_trigger *trig, bool state) | ||
| 345 | { | ||
| 346 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | ||
| 347 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 348 | |||
| 349 | return opt4060_set_state_common(chip, state, state); | ||
| 350 | } | ||
| 351 | |||
| 352 | static int opt4060_read_raw_value(struct opt4060_chip *chip, | ||
| 353 | unsigned long address, u32 *raw) | ||
| 354 | { | ||
| 355 | int ret; | ||
| 356 | u16 result[2]; | ||
| 357 | u32 mantissa_raw; | ||
| 358 | u16 msb, lsb; | ||
| 359 | u8 exp, count, crc, calc_crc; | ||
| 360 | |||
| 361 | ret = regmap_bulk_read(chip->regmap, address, result, 2); | ||
| 362 | if (ret) { | ||
| 363 | dev_err(chip->dev, "Reading channel data failed\n"); | ||
| 364 | return ret; | ||
| 365 | } | ||
| 366 | exp = FIELD_GET(OPT4060_EXPONENT_MASK, result[0]); | ||
| 367 | msb = FIELD_GET(OPT4060_MSB_MASK, result[0]); | ||
| 368 | count = FIELD_GET(OPT4060_COUNTER_MASK, result[1]); | ||
| 369 | crc = FIELD_GET(OPT4060_CRC_MASK, result[1]); | ||
| 370 | lsb = FIELD_GET(OPT4060_LSB_MASK, result[1]); | ||
| 371 | mantissa_raw = (msb << 8) + lsb; | ||
| 372 | calc_crc = opt4060_calculate_crc(exp, mantissa_raw, count); | ||
| 373 | if (calc_crc != crc) | ||
| 374 | return -EIO; | ||
| 375 | *raw = mantissa_raw << exp; | ||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int opt4060_trigger_new_samples(struct iio_dev *indio_dev) | ||
| 380 | { | ||
| 381 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 382 | int ret; | ||
| 383 | |||
| 384 | /* | ||
| 385 | * The conversion time should be 500us startup time plus the integration time | ||
| 386 | * times the number of channels. An exact timeout isn't critical, it's better | ||
| 387 | * not to get incorrect errors in the log. Setting the timeout to double the | ||
| 388 | * theoretical time plus and extra 100ms margin. | ||
| 389 | */ | ||
| 390 | unsigned int timeout_us = (500 + OPT4060_NUM_CHANS * | ||
| 391 | opt4060_int_time_reg[chip->int_time][0]) * 2 + 100000; | ||
| 392 | |||
| 393 | /* Setting the state in one shot mode with irq on each sample. */ | ||
| 394 | ret = opt4060_set_driver_state(indio_dev, false, true); | ||
| 395 | if (ret) | ||
| 396 | return ret; | ||
| 397 | |||
| 398 | if (chip->irq) { | ||
| 399 | guard(mutex)(&chip->irq_setting_lock); | ||
| 400 | reinit_completion(&chip->completion); | ||
| 401 | if (wait_for_completion_timeout(&chip->completion, | ||
| 402 | usecs_to_jiffies(timeout_us)) == 0) { | ||
| 403 | dev_err(chip->dev, "Completion timed out.\n"); | ||
| 404 | return -ETIME; | ||
| 405 | } | ||
| 406 | } else { | ||
| 407 | unsigned int ready; | ||
| 408 | |||
| 409 | ret = regmap_read_poll_timeout(chip->regmap, OPT4060_RES_CTRL, | ||
| 410 | ready, (ready & OPT4060_RES_CTRL_CONV_READY), | ||
| 411 | 1000, timeout_us); | ||
| 412 | if (ret) | ||
| 413 | dev_err(chip->dev, "Conversion ready did not finish within timeout.\n"); | ||
| 414 | } | ||
| 415 | /* Setting the state in one shot mode with irq on thresholds. */ | ||
| 416 | return opt4060_set_driver_state(indio_dev, false, false); | ||
| 417 | } | ||
| 418 | |||
| 419 | static int opt4060_read_chan_raw(struct iio_dev *indio_dev, | ||
| 420 | struct iio_chan_spec const *chan, int *val) | ||
| 421 | { | ||
| 422 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 423 | u32 adc_raw; | ||
| 424 | int ret; | ||
| 425 | |||
| 426 | ret = opt4060_trigger_new_samples(indio_dev); | ||
| 427 | if (ret) { | ||
| 428 | dev_err(chip->dev, "Failed to trigger new samples.\n"); | ||
| 429 | return ret; | ||
| 430 | } | ||
| 431 | |||
| 432 | ret = opt4060_read_raw_value(chip, chan->address, &adc_raw); | ||
| 433 | if (ret) { | ||
| 434 | dev_err(chip->dev, "Reading raw channel data failed.\n"); | ||
| 435 | return ret; | ||
| 436 | } | ||
| 437 | *val = adc_raw; | ||
| 438 | return IIO_VAL_INT; | ||
| 439 | } | ||
| 440 | |||
| 441 | /* | ||
| 442 | * Returns the scale values used for red, green and blue. Scales the raw value | ||
| 443 | * so that for a particular test light source, typically white, the measurement | ||
| 444 | * intensity is the same across different color channels. | ||
| 445 | */ | ||
| 446 | static int opt4060_get_chan_scale(struct iio_dev *indio_dev, | ||
| 447 | struct iio_chan_spec const *chan, | ||
| 448 | int *val, int *val2) | ||
| 449 | { | ||
| 450 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 451 | |||
| 452 | switch (chan->scan_index) { | ||
| 453 | case OPT4060_RED: | ||
| 454 | /* 2.4 */ | ||
| 455 | *val = 2; | ||
| 456 | *val2 = 400000; | ||
| 457 | break; | ||
| 458 | case OPT4060_GREEN: | ||
| 459 | /* 1.0 */ | ||
| 460 | *val = 1; | ||
| 461 | *val2 = 0; | ||
| 462 | break; | ||
| 463 | case OPT4060_BLUE: | ||
| 464 | /* 1.3 */ | ||
| 465 | *val = 1; | ||
| 466 | *val2 = 300000; | ||
| 467 | break; | ||
| 468 | default: | ||
| 469 | dev_err(chip->dev, "Unexpected channel index.\n"); | ||
| 470 | return -EINVAL; | ||
| 471 | } | ||
| 472 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 473 | } | ||
| 474 | |||
| 475 | static int opt4060_calc_illuminance(struct opt4060_chip *chip, int *val) | ||
| 476 | { | ||
| 477 | u32 lux_raw; | ||
| 478 | int ret; | ||
| 479 | |||
| 480 | /* The green wide spectral channel is used for illuminance. */ | ||
| 481 | ret = opt4060_read_raw_value(chip, OPT4060_GREEN_MSB, &lux_raw); | ||
| 482 | if (ret) { | ||
| 483 | dev_err(chip->dev, "Reading raw channel data failed\n"); | ||
| 484 | return ret; | ||
| 485 | } | ||
| 486 | |||
| 487 | /* Illuminance is calculated by ADC_RAW * 2.15e-3. */ | ||
| 488 | *val = DIV_U64_ROUND_CLOSEST((u64)(lux_raw * 215), 1000); | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int opt4060_read_illuminance(struct iio_dev *indio_dev, | ||
| 493 | struct iio_chan_spec const *chan, | ||
| 494 | int *val) | ||
| 495 | { | ||
| 496 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 497 | int ret; | ||
| 498 | |||
| 499 | ret = opt4060_trigger_new_samples(indio_dev); | ||
| 500 | if (ret) { | ||
| 501 | dev_err(chip->dev, "Failed to trigger new samples.\n"); | ||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | ret = opt4060_calc_illuminance(chip, val); | ||
| 505 | if (ret) { | ||
| 506 | dev_err(chip->dev, "Failed to calculate illuminance.\n"); | ||
| 507 | return ret; | ||
| 508 | } | ||
| 509 | |||
| 510 | return IIO_VAL_INT; | ||
| 511 | } | ||
| 512 | |||
| 513 | static int opt4060_set_int_time(struct opt4060_chip *chip) | ||
| 514 | { | ||
| 515 | unsigned int regval; | ||
| 516 | int ret; | ||
| 517 | |||
| 518 | regval = FIELD_PREP(OPT4060_CTRL_CONV_TIME_MASK, chip->int_time); | ||
| 519 | ret = regmap_update_bits(chip->regmap, OPT4060_CTRL, | ||
| 520 | OPT4060_CTRL_CONV_TIME_MASK, regval); | ||
| 521 | if (ret) | ||
| 522 | dev_err(chip->dev, "Failed to set integration time.\n"); | ||
| 523 | |||
| 524 | return ret; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int opt4060_power_down(struct opt4060_chip *chip) | ||
| 528 | { | ||
| 529 | int ret; | ||
| 530 | |||
| 531 | ret = regmap_clear_bits(chip->regmap, OPT4060_CTRL, OPT4060_CTRL_OPER_MODE_MASK); | ||
| 532 | if (ret) | ||
| 533 | dev_err(chip->dev, "Failed to power down\n"); | ||
| 534 | |||
| 535 | return ret; | ||
| 536 | } | ||
| 537 | |||
| 538 | static void opt4060_chip_off_action(void *chip) | ||
| 539 | { | ||
| 540 | opt4060_power_down(chip); | ||
| 541 | } | ||
| 542 | |||
| 543 | #define _OPT4060_COLOR_CHANNEL(_color, _mask, _ev_spec, _num_ev_spec) \ | ||
| 544 | { \ | ||
| 545 | .type = IIO_INTENSITY, \ | ||
| 546 | .modified = 1, \ | ||
| 547 | .channel2 = IIO_MOD_LIGHT_##_color, \ | ||
| 548 | .info_mask_separate = _mask, \ | ||
| 549 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 550 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 551 | .address = OPT4060_##_color##_MSB, \ | ||
| 552 | .scan_index = OPT4060_##_color, \ | ||
| 553 | .scan_type = { \ | ||
| 554 | .sign = 'u', \ | ||
| 555 | .realbits = 32, \ | ||
| 556 | .storagebits = 32, \ | ||
| 557 | .endianness = IIO_CPU, \ | ||
| 558 | }, \ | ||
| 559 | .event_spec = _ev_spec, \ | ||
| 560 | .num_event_specs = _num_ev_spec, \ | ||
| 561 | } | ||
| 562 | |||
| 563 | #define OPT4060_COLOR_CHANNEL(_color, _mask) \ | ||
| 564 | _OPT4060_COLOR_CHANNEL(_color, _mask, opt4060_event_spec, \ | ||
| 565 | ARRAY_SIZE(opt4060_event_spec)) \ | ||
| 566 | |||
| 567 | #define OPT4060_COLOR_CHANNEL_NO_EVENTS(_color, _mask) \ | ||
| 568 | _OPT4060_COLOR_CHANNEL(_color, _mask, NULL, 0) \ | ||
| 569 | |||
| 570 | #define OPT4060_LIGHT_CHANNEL(_channel) \ | ||
| 571 | { \ | ||
| 572 | .type = IIO_LIGHT, \ | ||
| 573 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ | ||
| 574 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 575 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 576 | .scan_index = OPT4060_##_channel, \ | ||
| 577 | .scan_type = { \ | ||
| 578 | .sign = 'u', \ | ||
| 579 | .realbits = 32, \ | ||
| 580 | .storagebits = 32, \ | ||
| 581 | .endianness = IIO_CPU, \ | ||
| 582 | }, \ | ||
| 583 | } | ||
| 584 | |||
| 585 | static const struct iio_event_spec opt4060_event_spec[] = { | ||
| 586 | { | ||
| 587 | .type = IIO_EV_TYPE_THRESH, | ||
| 588 | .dir = IIO_EV_DIR_RISING, | ||
| 589 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | ||
| 590 | BIT(IIO_EV_INFO_ENABLE), | ||
| 591 | }, { | ||
| 592 | .type = IIO_EV_TYPE_THRESH, | ||
| 593 | .dir = IIO_EV_DIR_FALLING, | ||
| 594 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | ||
| 595 | BIT(IIO_EV_INFO_ENABLE), | ||
| 596 | }, { | ||
| 597 | .type = IIO_EV_TYPE_THRESH, | ||
| 598 | .dir = IIO_EV_DIR_EITHER, | ||
| 599 | .mask_separate = BIT(IIO_EV_INFO_PERIOD), | ||
| 600 | }, | ||
| 601 | }; | ||
| 602 | |||
| 603 | static const struct iio_chan_spec opt4060_channels[] = { | ||
| 604 | OPT4060_COLOR_CHANNEL(RED, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 605 | OPT4060_COLOR_CHANNEL(GREEN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 606 | OPT4060_COLOR_CHANNEL(BLUE, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 607 | OPT4060_COLOR_CHANNEL(CLEAR, BIT(IIO_CHAN_INFO_RAW)), | ||
| 608 | OPT4060_LIGHT_CHANNEL(ILLUM), | ||
| 609 | IIO_CHAN_SOFT_TIMESTAMP(OPT4060_NUM_CHANS), | ||
| 610 | }; | ||
| 611 | |||
| 612 | static const struct iio_chan_spec opt4060_channels_no_events[] = { | ||
| 613 | OPT4060_COLOR_CHANNEL_NO_EVENTS(RED, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 614 | OPT4060_COLOR_CHANNEL_NO_EVENTS(GREEN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 615 | OPT4060_COLOR_CHANNEL_NO_EVENTS(BLUE, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)), | ||
| 616 | OPT4060_COLOR_CHANNEL_NO_EVENTS(CLEAR, BIT(IIO_CHAN_INFO_RAW)), | ||
| 617 | OPT4060_LIGHT_CHANNEL(ILLUM), | ||
| 618 | IIO_CHAN_SOFT_TIMESTAMP(OPT4060_NUM_CHANS), | ||
| 619 | }; | ||
| 620 | |||
| 621 | static int opt4060_read_raw(struct iio_dev *indio_dev, | ||
| 622 | struct iio_chan_spec const *chan, | ||
| 623 | int *val, int *val2, long mask) | ||
| 624 | { | ||
| 625 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 626 | |||
| 627 | switch (mask) { | ||
| 628 | case IIO_CHAN_INFO_RAW: | ||
| 629 | return opt4060_read_chan_raw(indio_dev, chan, val); | ||
| 630 | case IIO_CHAN_INFO_SCALE: | ||
| 631 | return opt4060_get_chan_scale(indio_dev, chan, val, val2); | ||
| 632 | case IIO_CHAN_INFO_PROCESSED: | ||
| 633 | return opt4060_read_illuminance(indio_dev, chan, val); | ||
| 634 | case IIO_CHAN_INFO_INT_TIME: | ||
| 635 | *val = 0; | ||
| 636 | *val2 = opt4060_int_time_reg[chip->int_time][0]; | ||
| 637 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 638 | default: | ||
| 639 | return -EINVAL; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | |||
| 643 | static int opt4060_write_raw(struct iio_dev *indio_dev, | ||
| 644 | struct iio_chan_spec const *chan, | ||
| 645 | int val, int val2, long mask) | ||
| 646 | { | ||
| 647 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 648 | int int_time; | ||
| 649 | |||
| 650 | switch (mask) { | ||
| 651 | case IIO_CHAN_INFO_INT_TIME: | ||
| 652 | int_time = opt4060_als_time_to_index(val2); | ||
| 653 | if (int_time < 0) | ||
| 654 | return int_time; | ||
| 655 | chip->int_time = int_time; | ||
| 656 | return opt4060_set_int_time(chip); | ||
| 657 | default: | ||
| 658 | return -EINVAL; | ||
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 662 | static int opt4060_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 663 | struct iio_chan_spec const *chan, | ||
| 664 | long mask) | ||
| 665 | { | ||
| 666 | switch (mask) { | ||
| 667 | case IIO_CHAN_INFO_INT_TIME: | ||
| 668 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 669 | default: | ||
| 670 | return -EINVAL; | ||
| 671 | } | ||
| 672 | } | ||
| 673 | |||
| 674 | static u32 opt4060_calc_th_reg(u32 adc_val) | ||
| 675 | { | ||
| 676 | u32 th_val, th_exp, bits; | ||
| 677 | /* | ||
| 678 | * The threshold registers take 4 bits of exponent and 12 bits of data | ||
| 679 | * ADC = TH_VAL << (8 + TH_EXP) | ||
| 680 | */ | ||
| 681 | bits = fls(adc_val); | ||
| 682 | |||
| 683 | if (bits > 31) | ||
| 684 | th_exp = 11; /* Maximum exponent */ | ||
| 685 | else if (bits > 20) | ||
| 686 | th_exp = bits - 20; | ||
| 687 | else | ||
| 688 | th_exp = 0; | ||
| 689 | th_val = (adc_val >> (8 + th_exp)) & 0xfff; | ||
| 690 | |||
| 691 | return (th_exp << 12) + th_val; | ||
| 692 | } | ||
| 693 | |||
| 694 | static u32 opt4060_calc_val_from_th_reg(u32 th_reg) | ||
| 695 | { | ||
| 696 | /* | ||
| 697 | * The threshold registers take 4 bits of exponent and 12 bits of data | ||
| 698 | * ADC = TH_VAL << (8 + TH_EXP) | ||
| 699 | */ | ||
| 700 | u32 th_val, th_exp; | ||
| 701 | |||
| 702 | th_exp = (th_reg >> 12) & 0xf; | ||
| 703 | th_val = th_reg & 0xfff; | ||
| 704 | |||
| 705 | return th_val << (8 + th_exp); | ||
| 706 | } | ||
| 707 | |||
| 708 | static int opt4060_read_available(struct iio_dev *indio_dev, | ||
| 709 | struct iio_chan_spec const *chan, | ||
| 710 | const int **vals, int *type, int *length, | ||
| 711 | long mask) | ||
| 712 | { | ||
| 713 | switch (mask) { | ||
| 714 | case IIO_CHAN_INFO_INT_TIME: | ||
| 715 | *length = ARRAY_SIZE(opt4060_int_time_available) * 2; | ||
| 716 | *vals = (const int *)opt4060_int_time_available; | ||
| 717 | *type = IIO_VAL_INT_PLUS_MICRO; | ||
| 718 | return IIO_AVAIL_LIST; | ||
| 719 | |||
| 720 | default: | ||
| 721 | return -EINVAL; | ||
| 722 | } | ||
| 723 | } | ||
| 724 | |||
| 725 | static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val, | ||
| 726 | int *val2) | ||
| 727 | { | ||
| 728 | int ret, pers, fault_count, int_time; | ||
| 729 | u64 uval; | ||
| 730 | |||
| 731 | int_time = opt4060_int_time_reg[chip->int_time][0]; | ||
| 732 | |||
| 733 | ret = regmap_read(chip->regmap, OPT4060_CTRL, &fault_count); | ||
| 734 | if (ret < 0) | ||
| 735 | return ret; | ||
| 736 | |||
| 737 | fault_count = fault_count & OPT4060_CTRL_FAULT_COUNT_MASK; | ||
| 738 | switch (fault_count) { | ||
| 739 | case OPT4060_CTRL_FAULT_COUNT_2: | ||
| 740 | pers = 2; | ||
| 741 | break; | ||
| 742 | case OPT4060_CTRL_FAULT_COUNT_4: | ||
| 743 | pers = 4; | ||
| 744 | break; | ||
| 745 | case OPT4060_CTRL_FAULT_COUNT_8: | ||
| 746 | pers = 8; | ||
| 747 | break; | ||
| 748 | |||
| 749 | default: | ||
| 750 | pers = 1; | ||
| 751 | break; | ||
| 752 | } | ||
| 753 | |||
| 754 | uval = mul_u32_u32(int_time, pers); | ||
| 755 | *val = div_u64_rem(uval, MICRO, val2); | ||
| 756 | |||
| 757 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 758 | } | ||
| 759 | |||
| 760 | static ssize_t opt4060_write_ev_period(struct opt4060_chip *chip, int val, | ||
| 761 | int val2) | ||
| 762 | { | ||
| 763 | u64 uval, int_time; | ||
| 764 | unsigned int regval, fault_count_val; | ||
| 765 | |||
| 766 | uval = mul_u32_u32(val, MICRO) + val2; | ||
| 767 | int_time = opt4060_int_time_reg[chip->int_time][0]; | ||
| 768 | |||
| 769 | /* Check if the period is closest to 1, 2, 4 or 8 times integration time.*/ | ||
| 770 | if (uval <= int_time) | ||
| 771 | fault_count_val = OPT4060_CTRL_FAULT_COUNT_1; | ||
| 772 | else if (uval <= int_time * 2) | ||
| 773 | fault_count_val = OPT4060_CTRL_FAULT_COUNT_2; | ||
| 774 | else if (uval <= int_time * 4) | ||
| 775 | fault_count_val = OPT4060_CTRL_FAULT_COUNT_4; | ||
| 776 | else | ||
| 777 | fault_count_val = OPT4060_CTRL_FAULT_COUNT_8; | ||
| 778 | |||
| 779 | regval = FIELD_PREP(OPT4060_CTRL_FAULT_COUNT_MASK, fault_count_val); | ||
| 780 | return regmap_update_bits(chip->regmap, OPT4060_CTRL, | ||
| 781 | OPT4060_CTRL_FAULT_COUNT_MASK, regval); | ||
| 782 | } | ||
| 783 | |||
| 784 | static int opt4060_get_channel_sel(struct opt4060_chip *chip, int *ch_sel) | ||
| 785 | { | ||
| 786 | int ret; | ||
| 787 | u32 regval; | ||
| 788 | |||
| 789 | ret = regmap_read(chip->regmap, OPT4060_INT_CTRL, ®val); | ||
| 790 | if (ret) { | ||
| 791 | dev_err(chip->dev, "Failed to get channel selection.\n"); | ||
| 792 | return ret; | ||
| 793 | } | ||
| 794 | *ch_sel = FIELD_GET(OPT4060_INT_CTRL_THRESH_SEL, regval); | ||
| 795 | return ret; | ||
| 796 | } | ||
| 797 | |||
| 798 | static int opt4060_set_channel_sel(struct opt4060_chip *chip, int ch_sel) | ||
| 799 | { | ||
| 800 | int ret; | ||
| 801 | u32 regval; | ||
| 802 | |||
| 803 | regval = FIELD_PREP(OPT4060_INT_CTRL_THRESH_SEL, ch_sel); | ||
| 804 | ret = regmap_update_bits(chip->regmap, OPT4060_INT_CTRL, | ||
| 805 | OPT4060_INT_CTRL_THRESH_SEL, regval); | ||
| 806 | if (ret) | ||
| 807 | dev_err(chip->dev, "Failed to set channel selection.\n"); | ||
| 808 | return ret; | ||
| 809 | } | ||
| 810 | |||
| 811 | static int opt4060_get_thresholds(struct opt4060_chip *chip, u32 *th_lo, u32 *th_hi) | ||
| 812 | { | ||
| 813 | int ret; | ||
| 814 | u32 regval; | ||
| 815 | |||
| 816 | ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_LOW, ®val); | ||
| 817 | if (ret) { | ||
| 818 | dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n"); | ||
| 819 | return ret; | ||
| 820 | } | ||
| 821 | *th_lo = opt4060_calc_val_from_th_reg(regval); | ||
| 822 | |||
| 823 | ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_HIGH, ®val); | ||
| 824 | if (ret) { | ||
| 825 | dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n"); | ||
| 826 | return ret; | ||
| 827 | } | ||
| 828 | *th_hi = opt4060_calc_val_from_th_reg(regval); | ||
| 829 | |||
| 830 | return ret; | ||
| 831 | } | ||
| 832 | |||
| 833 | static int opt4060_set_thresholds(struct opt4060_chip *chip, u32 th_lo, u32 th_hi) | ||
| 834 | { | ||
| 835 | int ret; | ||
| 836 | |||
| 837 | ret = regmap_write(chip->regmap, OPT4060_THRESHOLD_LOW, opt4060_calc_th_reg(th_lo)); | ||
| 838 | if (ret) { | ||
| 839 | dev_err(chip->dev, "Failed to write THRESHOLD_LOW.\n"); | ||
| 840 | return ret; | ||
| 841 | } | ||
| 842 | |||
| 843 | ret = regmap_write(chip->regmap, OPT4060_THRESHOLD_HIGH, opt4060_calc_th_reg(th_hi)); | ||
| 844 | if (ret) | ||
| 845 | dev_err(chip->dev, "Failed to write THRESHOLD_HIGH.\n"); | ||
| 846 | |||
| 847 | return ret; | ||
| 848 | } | ||
| 849 | |||
| 850 | static int opt4060_read_event(struct iio_dev *indio_dev, | ||
| 851 | const struct iio_chan_spec *chan, | ||
| 852 | enum iio_event_type type, | ||
| 853 | enum iio_event_direction dir, | ||
| 854 | enum iio_event_info info, | ||
| 855 | int *val, int *val2) | ||
| 856 | { | ||
| 857 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 858 | u32 th_lo, th_hi; | ||
| 859 | int ret; | ||
| 860 | |||
| 861 | if (chan->type != IIO_INTENSITY) | ||
| 862 | return -EINVAL; | ||
| 863 | if (type != IIO_EV_TYPE_THRESH) | ||
| 864 | return -EINVAL; | ||
| 865 | |||
| 866 | switch (info) { | ||
| 867 | case IIO_EV_INFO_VALUE: | ||
| 868 | ret = opt4060_get_thresholds(chip, &th_lo, &th_hi); | ||
| 869 | if (ret) | ||
| 870 | return ret; | ||
| 871 | if (dir == IIO_EV_DIR_FALLING) { | ||
| 872 | *val = th_lo; | ||
| 873 | ret = IIO_VAL_INT; | ||
| 874 | } else if (dir == IIO_EV_DIR_RISING) { | ||
| 875 | *val = th_hi; | ||
| 876 | ret = IIO_VAL_INT; | ||
| 877 | } | ||
| 878 | return ret; | ||
| 879 | case IIO_EV_INFO_PERIOD: | ||
| 880 | return opt4060_read_ev_period(chip, val, val2); | ||
| 881 | default: | ||
| 882 | return -EINVAL; | ||
| 883 | } | ||
| 884 | } | ||
| 885 | |||
| 886 | static int opt4060_write_event(struct iio_dev *indio_dev, | ||
| 887 | const struct iio_chan_spec *chan, | ||
| 888 | enum iio_event_type type, | ||
| 889 | enum iio_event_direction dir, | ||
| 890 | enum iio_event_info info, | ||
| 891 | int val, int val2) | ||
| 892 | { | ||
| 893 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 894 | u32 th_lo, th_hi; | ||
| 895 | int ret; | ||
| 896 | |||
| 897 | if (chan->type != IIO_INTENSITY) | ||
| 898 | return -EINVAL; | ||
| 899 | if (type != IIO_EV_TYPE_THRESH) | ||
| 900 | return -EINVAL; | ||
| 901 | |||
| 902 | switch (info) { | ||
| 903 | case IIO_EV_INFO_VALUE: | ||
| 904 | ret = opt4060_get_thresholds(chip, &th_lo, &th_hi); | ||
| 905 | if (ret) | ||
| 906 | return ret; | ||
| 907 | if (dir == IIO_EV_DIR_FALLING) | ||
| 908 | th_lo = val; | ||
| 909 | else if (dir == IIO_EV_DIR_RISING) | ||
| 910 | th_hi = val; | ||
| 911 | return opt4060_set_thresholds(chip, th_lo, th_hi); | ||
| 912 | case IIO_EV_INFO_PERIOD: | ||
| 913 | return opt4060_write_ev_period(chip, val, val2); | ||
| 914 | default: | ||
| 915 | return -EINVAL; | ||
| 916 | } | ||
| 917 | } | ||
| 918 | |||
| 919 | static int opt4060_read_event_config(struct iio_dev *indio_dev, | ||
| 920 | const struct iio_chan_spec *chan, | ||
| 921 | enum iio_event_type type, | ||
| 922 | enum iio_event_direction dir) | ||
| 923 | { | ||
| 924 | int ch_sel, ch_idx = chan->scan_index; | ||
| 925 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 926 | int ret; | ||
| 927 | |||
| 928 | if (chan->type != IIO_INTENSITY) | ||
| 929 | return -EINVAL; | ||
| 930 | if (type != IIO_EV_TYPE_THRESH) | ||
| 931 | return -EINVAL; | ||
| 932 | |||
| 933 | ret = opt4060_get_channel_sel(chip, &ch_sel); | ||
| 934 | if (ret) | ||
| 935 | return ret; | ||
| 936 | |||
| 937 | if (((dir == IIO_EV_DIR_FALLING) && chip->thresh_event_lo_active) || | ||
| 938 | ((dir == IIO_EV_DIR_RISING) && chip->thresh_event_hi_active)) | ||
| 939 | return ch_sel == ch_idx; | ||
| 940 | |||
| 941 | return ret; | ||
| 942 | } | ||
| 943 | |||
| 944 | static int opt4060_write_event_config(struct iio_dev *indio_dev, | ||
| 945 | const struct iio_chan_spec *chan, | ||
| 946 | enum iio_event_type type, | ||
| 947 | enum iio_event_direction dir, bool state) | ||
| 948 | { | ||
| 949 | int ch_sel, ch_idx = chan->scan_index; | ||
| 950 | struct opt4060_chip *chip = iio_priv(indio_dev); | ||
| 951 | int ret; | ||
| 952 | |||
| 953 | guard(mutex)(&chip->event_enabling_lock); | ||
| 954 | |||
| 955 | if (chan->type != IIO_INTENSITY) | ||
| 956 | return -EINVAL; | ||
| 957 | if (type != IIO_EV_TYPE_THRESH) | ||
| 958 | return -EINVAL; | ||
| 959 | |||
| 960 | ret = opt4060_get_channel_sel(chip, &ch_sel); | ||
| 961 | if (ret) | ||
| 962 | return ret; | ||
| 963 | |||
| 964 | if (state) { | ||
| 965 | /* Only one channel can be active at the same time */ | ||
| 966 | if ((chip->thresh_event_lo_active || chip->thresh_event_hi_active) && | ||
| 967 | (ch_idx != ch_sel)) | ||
| 968 | return -EBUSY; | ||
| 969 | if (dir == IIO_EV_DIR_FALLING) | ||
| 970 | chip->thresh_event_lo_active = true; | ||
| 971 | else if (dir == IIO_EV_DIR_RISING) | ||
| 972 | chip->thresh_event_hi_active = true; | ||
| 973 | ret = opt4060_set_channel_sel(chip, ch_idx); | ||
| 974 | if (ret) | ||
| 975 | return ret; | ||
| 976 | } else { | ||
| 977 | if (ch_idx == ch_sel) { | ||
| 978 | if (dir == IIO_EV_DIR_FALLING) | ||
| 979 | chip->thresh_event_lo_active = false; | ||
| 980 | else if (dir == IIO_EV_DIR_RISING) | ||
| 981 | chip->thresh_event_hi_active = false; | ||
| 982 | } | ||
| 983 | } | ||
| 984 | |||
| 985 | return opt4060_set_driver_state(indio_dev, | ||
| 986 | chip->thresh_event_hi_active | | ||
| 987 | chip->thresh_event_lo_active, | ||
| 988 | false); | ||
| 989 | } | ||
| 990 | |||
| 991 | static const struct iio_info opt4060_info = { | ||
| 992 | .read_raw = opt4060_read_raw, | ||
| 993 | .write_raw = opt4060_write_raw, | ||
| 994 | .write_raw_get_fmt = opt4060_write_raw_get_fmt, | ||
| 995 | .read_avail = opt4060_read_available, | ||
| 996 | .read_event_value = opt4060_read_event, | ||
| 997 | .write_event_value = opt4060_write_event, | ||
| 998 | .read_event_config = opt4060_read_event_config, | ||
| 999 | .write_event_config = opt4060_write_event_config, | ||
| 1000 | }; | ||
| 1001 | |||
| 1002 | static const struct iio_info opt4060_info_no_irq = { | ||
| 1003 | .read_raw = opt4060_read_raw, | ||
| 1004 | .write_raw = opt4060_write_raw, | ||
| 1005 | .write_raw_get_fmt = opt4060_write_raw_get_fmt, | ||
| 1006 | .read_avail = opt4060_read_available, | ||
| 1007 | }; | ||
| 1008 | |||
| 1009 | static int opt4060_load_defaults(struct opt4060_chip *chip) | ||
| 1010 | { | ||
| 1011 | u16 reg; | ||
| 1012 | int ret; | ||
| 1013 | |||
| 1014 | chip->int_time = OPT4060_DEFAULT_CONVERSION_TIME; | ||
| 1015 | |||
| 1016 | /* Set initial MIN/MAX thresholds */ | ||
| 1017 | ret = opt4060_set_thresholds(chip, 0, UINT_MAX); | ||
| 1018 | if (ret) | ||
| 1019 | return ret; | ||
| 1020 | |||
| 1021 | /* | ||
| 1022 | * Setting auto-range, latched window for thresholds, one-shot conversion | ||
| 1023 | * and quick wake-up mode as default. | ||
| 1024 | */ | ||
| 1025 | reg = FIELD_PREP(OPT4060_CTRL_RANGE_MASK, | ||
| 1026 | OPT4060_CTRL_LIGHT_SCALE_AUTO); | ||
| 1027 | reg |= FIELD_PREP(OPT4060_CTRL_CONV_TIME_MASK, chip->int_time); | ||
| 1028 | reg |= FIELD_PREP(OPT4060_CTRL_OPER_MODE_MASK, | ||
| 1029 | OPT4060_CTRL_OPER_MODE_ONE_SHOT); | ||
| 1030 | reg |= OPT4060_CTRL_QWAKE_MASK | OPT4060_CTRL_LATCH_MASK; | ||
| 1031 | |||
| 1032 | ret = regmap_write(chip->regmap, OPT4060_CTRL, reg); | ||
| 1033 | if (ret) | ||
| 1034 | dev_err(chip->dev, "Failed to set configuration\n"); | ||
| 1035 | |||
| 1036 | return ret; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | static bool opt4060_volatile_reg(struct device *dev, unsigned int reg) | ||
| 1040 | { | ||
| 1041 | return reg <= OPT4060_CLEAR_LSB || reg == OPT4060_RES_CTRL; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static bool opt4060_writable_reg(struct device *dev, unsigned int reg) | ||
| 1045 | { | ||
| 1046 | return reg >= OPT4060_THRESHOLD_LOW || reg >= OPT4060_INT_CTRL; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | static bool opt4060_readonly_reg(struct device *dev, unsigned int reg) | ||
| 1050 | { | ||
| 1051 | return reg == OPT4060_DEVICE_ID; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | static bool opt4060_readable_reg(struct device *dev, unsigned int reg) | ||
| 1055 | { | ||
| 1056 | /* Volatile, writable and read-only registers are readable. */ | ||
| 1057 | return opt4060_volatile_reg(dev, reg) || opt4060_writable_reg(dev, reg) || | ||
| 1058 | opt4060_readonly_reg(dev, reg); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | static const struct regmap_config opt4060_regmap_config = { | ||
| 1062 | .name = "opt4060", | ||
| 1063 | .reg_bits = 8, | ||
| 1064 | .val_bits = 16, | ||
| 1065 | .cache_type = REGCACHE_RBTREE, | ||
| 1066 | .max_register = OPT4060_DEVICE_ID, | ||
| 1067 | .readable_reg = opt4060_readable_reg, | ||
| 1068 | .writeable_reg = opt4060_writable_reg, | ||
| 1069 | .volatile_reg = opt4060_volatile_reg, | ||
| 1070 | .val_format_endian = REGMAP_ENDIAN_BIG, | ||
| 1071 | }; | ||
| 1072 | |||
| 1073 | static const struct iio_trigger_ops opt4060_trigger_ops = { | ||
| 1074 | .set_trigger_state = opt4060_trigger_set_state, | ||
| 1075 | }; | ||
| 1076 | |||
| 1077 | static irqreturn_t opt4060_trigger_handler(int irq, void *p) | ||
| 1078 | { | ||
| 1079 | struct iio_poll_func *pf = p; | ||
| 1080 | struct iio_dev *idev = pf->indio_dev; | ||
| 1081 | struct opt4060_chip *chip = iio_priv(idev); | ||
| 1082 | struct { | ||
| 1083 | u32 chan[OPT4060_NUM_CHANS]; | ||
| 1084 | aligned_s64 ts; | ||
| 1085 | } raw; | ||
| 1086 | int i = 0; | ||
| 1087 | int chan, ret; | ||
| 1088 | |||
| 1089 | /* If the trigger is not from this driver, a new sample is needed.*/ | ||
| 1090 | if (iio_trigger_validate_own_device(idev->trig, idev)) | ||
| 1091 | opt4060_trigger_new_samples(idev); | ||
| 1092 | |||
| 1093 | memset(&raw, 0, sizeof(raw)); | ||
| 1094 | |||
| 1095 | iio_for_each_active_channel(idev, chan) { | ||
| 1096 | if (chan == OPT4060_ILLUM) | ||
| 1097 | ret = opt4060_calc_illuminance(chip, &raw.chan[i++]); | ||
| 1098 | else | ||
| 1099 | ret = opt4060_read_raw_value(chip, | ||
| 1100 | idev->channels[chan].address, | ||
| 1101 | &raw.chan[i++]); | ||
| 1102 | if (ret) { | ||
| 1103 | dev_err(chip->dev, "Reading channel data failed\n"); | ||
| 1104 | goto err_read; | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp); | ||
| 1109 | err_read: | ||
| 1110 | iio_trigger_notify_done(idev->trig); | ||
| 1111 | return IRQ_HANDLED; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | static irqreturn_t opt4060_irq_thread(int irq, void *private) | ||
| 1115 | { | ||
| 1116 | struct iio_dev *idev = private; | ||
| 1117 | struct opt4060_chip *chip = iio_priv(idev); | ||
| 1118 | int ret, dummy; | ||
| 1119 | unsigned int int_res; | ||
| 1120 | |||
| 1121 | ret = regmap_read(chip->regmap, OPT4060_RES_CTRL, &int_res); | ||
| 1122 | if (ret < 0) { | ||
| 1123 | dev_err(chip->dev, "Failed to read interrupt reasons.\n"); | ||
| 1124 | return IRQ_NONE; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | /* Read OPT4060_CTRL to clear interrupt */ | ||
| 1128 | ret = regmap_read(chip->regmap, OPT4060_CTRL, &dummy); | ||
| 1129 | if (ret < 0) { | ||
| 1130 | dev_err(chip->dev, "Failed to clear interrupt\n"); | ||
| 1131 | return IRQ_NONE; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | /* Handle events */ | ||
| 1135 | if (int_res & (OPT4060_RES_CTRL_FLAG_H | OPT4060_RES_CTRL_FLAG_L)) { | ||
| 1136 | u64 code; | ||
| 1137 | int chan = 0; | ||
| 1138 | |||
| 1139 | ret = opt4060_get_channel_sel(chip, &chan); | ||
| 1140 | if (ret) { | ||
| 1141 | dev_err(chip->dev, "Failed to read threshold channel.\n"); | ||
| 1142 | return IRQ_NONE; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | /* Check if the interrupt is from the lower threshold */ | ||
| 1146 | if (int_res & OPT4060_RES_CTRL_FLAG_L) { | ||
| 1147 | code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, | ||
| 1148 | chan, | ||
| 1149 | idev->channels[chan].channel2, | ||
| 1150 | IIO_EV_TYPE_THRESH, | ||
| 1151 | IIO_EV_DIR_FALLING); | ||
| 1152 | iio_push_event(idev, code, iio_get_time_ns(idev)); | ||
| 1153 | } | ||
| 1154 | /* Check if the interrupt is from the upper threshold */ | ||
| 1155 | if (int_res & OPT4060_RES_CTRL_FLAG_H) { | ||
| 1156 | code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, | ||
| 1157 | chan, | ||
| 1158 | idev->channels[chan].channel2, | ||
| 1159 | IIO_EV_TYPE_THRESH, | ||
| 1160 | IIO_EV_DIR_RISING); | ||
| 1161 | iio_push_event(idev, code, iio_get_time_ns(idev)); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | /* Handle conversion ready */ | ||
| 1166 | if (int_res & OPT4060_RES_CTRL_CONV_READY) { | ||
| 1167 | /* Signal completion for potentially waiting reads */ | ||
| 1168 | complete(&chip->completion); | ||
| 1169 | |||
| 1170 | /* Handle data ready triggers */ | ||
| 1171 | if (iio_buffer_enabled(idev)) | ||
| 1172 | iio_trigger_poll_nested(chip->trig); | ||
| 1173 | } | ||
| 1174 | return IRQ_HANDLED; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | static int opt4060_setup_buffer(struct opt4060_chip *chip, struct iio_dev *idev) | ||
| 1178 | { | ||
| 1179 | int ret; | ||
| 1180 | |||
| 1181 | ret = devm_iio_triggered_buffer_setup(chip->dev, idev, | ||
| 1182 | &iio_pollfunc_store_time, | ||
| 1183 | opt4060_trigger_handler, NULL); | ||
| 1184 | if (ret) | ||
| 1185 | return dev_err_probe(chip->dev, ret, | ||
| 1186 | "Buffer setup failed.\n"); | ||
| 1187 | return ret; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | static int opt4060_setup_trigger(struct opt4060_chip *chip, struct iio_dev *idev) | ||
| 1191 | { | ||
| 1192 | struct iio_trigger *data_trigger; | ||
| 1193 | char *name; | ||
| 1194 | int ret; | ||
| 1195 | |||
| 1196 | data_trigger = devm_iio_trigger_alloc(chip->dev, "%s-data-ready-dev%d", | ||
| 1197 | idev->name, iio_device_id(idev)); | ||
| 1198 | if (!data_trigger) | ||
| 1199 | return -ENOMEM; | ||
| 1200 | |||
| 1201 | /* | ||
| 1202 | * The data trigger allows for sample capture on each new conversion | ||
| 1203 | * ready interrupt. | ||
| 1204 | */ | ||
| 1205 | chip->trig = data_trigger; | ||
| 1206 | data_trigger->ops = &opt4060_trigger_ops; | ||
| 1207 | iio_trigger_set_drvdata(data_trigger, idev); | ||
| 1208 | ret = devm_iio_trigger_register(chip->dev, data_trigger); | ||
| 1209 | if (ret) | ||
| 1210 | return dev_err_probe(chip->dev, ret, | ||
| 1211 | "Data ready trigger registration failed\n"); | ||
| 1212 | |||
| 1213 | name = devm_kasprintf(chip->dev, GFP_KERNEL, "%s-opt4060", | ||
| 1214 | dev_name(chip->dev)); | ||
| 1215 | if (!name) | ||
| 1216 | return dev_err_probe(chip->dev, -ENOMEM, "Failed to alloc chip name\n"); | ||
| 1217 | |||
| 1218 | ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL, opt4060_irq_thread, | ||
| 1219 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| 1220 | name, idev); | ||
| 1221 | if (ret) | ||
| 1222 | return dev_err_probe(chip->dev, ret, "Could not request IRQ\n"); | ||
| 1223 | |||
| 1224 | init_completion(&chip->completion); | ||
| 1225 | |||
| 1226 | ret = devm_mutex_init(chip->dev, &chip->irq_setting_lock); | ||
| 1227 | if (ret) | ||
| 1228 | return ret; | ||
| 1229 | |||
| 1230 | ret = devm_mutex_init(chip->dev, &chip->event_enabling_lock); | ||
| 1231 | if (ret) | ||
| 1232 | return ret; | ||
| 1233 | |||
| 1234 | ret = regmap_write_bits(chip->regmap, OPT4060_INT_CTRL, | ||
| 1235 | OPT4060_INT_CTRL_OUTPUT, | ||
| 1236 | OPT4060_INT_CTRL_OUTPUT); | ||
| 1237 | if (ret) | ||
| 1238 | return dev_err_probe(chip->dev, ret, | ||
| 1239 | "Failed to set interrupt as output\n"); | ||
| 1240 | |||
| 1241 | return 0; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | static int opt4060_probe(struct i2c_client *client) | ||
| 1245 | { | ||
| 1246 | struct device *dev = &client->dev; | ||
| 1247 | struct opt4060_chip *chip; | ||
| 1248 | struct iio_dev *indio_dev; | ||
| 1249 | int ret; | ||
| 1250 | unsigned int regval, dev_id; | ||
| 1251 | |||
| 1252 | indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); | ||
| 1253 | if (!indio_dev) | ||
| 1254 | return -ENOMEM; | ||
| 1255 | |||
| 1256 | chip = iio_priv(indio_dev); | ||
| 1257 | |||
| 1258 | ret = devm_regulator_get_enable(dev, "vdd"); | ||
| 1259 | if (ret) | ||
| 1260 | return dev_err_probe(dev, ret, "Failed to enable vdd supply\n"); | ||
| 1261 | |||
| 1262 | chip->regmap = devm_regmap_init_i2c(client, &opt4060_regmap_config); | ||
| 1263 | if (IS_ERR(chip->regmap)) | ||
| 1264 | return dev_err_probe(dev, PTR_ERR(chip->regmap), | ||
| 1265 | "regmap initialization failed\n"); | ||
| 1266 | |||
| 1267 | chip->dev = dev; | ||
| 1268 | chip->irq = client->irq; | ||
| 1269 | |||
| 1270 | ret = regmap_reinit_cache(chip->regmap, &opt4060_regmap_config); | ||
| 1271 | if (ret) | ||
| 1272 | return dev_err_probe(dev, ret, | ||
| 1273 | "failed to reinit regmap cache\n"); | ||
| 1274 | |||
| 1275 | ret = regmap_read(chip->regmap, OPT4060_DEVICE_ID, ®val); | ||
| 1276 | if (ret < 0) | ||
| 1277 | return dev_err_probe(dev, ret, | ||
| 1278 | "Failed to read the device ID register\n"); | ||
| 1279 | |||
| 1280 | dev_id = FIELD_GET(OPT4060_DEVICE_ID_MASK, regval); | ||
| 1281 | if (dev_id != OPT4060_DEVICE_ID_VAL) | ||
| 1282 | dev_info(dev, "Device ID: %#04x unknown\n", dev_id); | ||
| 1283 | |||
| 1284 | if (chip->irq) { | ||
| 1285 | indio_dev->info = &opt4060_info; | ||
| 1286 | indio_dev->channels = opt4060_channels; | ||
| 1287 | indio_dev->num_channels = ARRAY_SIZE(opt4060_channels); | ||
| 1288 | } else { | ||
| 1289 | indio_dev->info = &opt4060_info_no_irq; | ||
| 1290 | indio_dev->channels = opt4060_channels_no_events; | ||
| 1291 | indio_dev->num_channels = ARRAY_SIZE(opt4060_channels_no_events); | ||
| 1292 | } | ||
| 1293 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 1294 | indio_dev->name = "opt4060"; | ||
| 1295 | |||
| 1296 | ret = opt4060_load_defaults(chip); | ||
| 1297 | if (ret < 0) | ||
| 1298 | return dev_err_probe(dev, ret, | ||
| 1299 | "Failed to set sensor defaults\n"); | ||
| 1300 | |||
| 1301 | ret = devm_add_action_or_reset(dev, opt4060_chip_off_action, chip); | ||
| 1302 | if (ret < 0) | ||
| 1303 | return dev_err_probe(dev, ret, | ||
| 1304 | "Failed to setup power off action\n"); | ||
| 1305 | |||
| 1306 | ret = opt4060_setup_buffer(chip, indio_dev); | ||
| 1307 | if (ret) | ||
| 1308 | return ret; | ||
| 1309 | |||
| 1310 | if (chip->irq) { | ||
| 1311 | ret = opt4060_setup_trigger(chip, indio_dev); | ||
| 1312 | if (ret) | ||
| 1313 | return ret; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | return devm_iio_device_register(dev, indio_dev); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | static const struct i2c_device_id opt4060_id[] = { | ||
| 1320 | { "opt4060", }, | ||
| 1321 | { } | ||
| 1322 | }; | ||
| 1323 | MODULE_DEVICE_TABLE(i2c, opt4060_id); | ||
| 1324 | |||
| 1325 | static const struct of_device_id opt4060_of_match[] = { | ||
| 1326 | { .compatible = "ti,opt4060" }, | ||
| 1327 | { } | ||
| 1328 | }; | ||
| 1329 | MODULE_DEVICE_TABLE(of, opt4060_of_match); | ||
| 1330 | |||
| 1331 | static struct i2c_driver opt4060_driver = { | ||
| 1332 | .driver = { | ||
| 1333 | .name = "opt4060", | ||
| 1334 | .of_match_table = opt4060_of_match, | ||
| 1335 | }, | ||
| 1336 | .probe = opt4060_probe, | ||
| 1337 | .id_table = opt4060_id, | ||
| 1338 | }; | ||
| 1339 | module_i2c_driver(opt4060_driver); | ||
| 1340 | |||
| 1341 | MODULE_AUTHOR("Per-Daniel Olsson <perdaniel.olsson@axis.com>"); | ||
| 1342 | MODULE_DESCRIPTION("Texas Instruments OPT4060 RGBW color sensor driver"); | ||
| 1343 | MODULE_LICENSE("GPL"); | ||
| @@ -1,1635 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * ROHM Colour Sensor driver for | ||
| 4 | * - BU27008 RGBC sensor | ||
| 5 | * - BU27010 RGBC + Flickering sensor | ||
| 6 | * | ||
| 7 | * Copyright (c) 2023, ROHM Semiconductor. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/bitfield.h> | ||
| 11 | #include <linux/bitops.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/property.h> | ||
| 17 | #include <linux/regmap.h> | ||
| 18 | #include <linux/regulator/consumer.h> | ||
| 19 | #include <linux/units.h> | ||
| 20 | |||
| 21 | #include <linux/iio/iio.h> | ||
| 22 | #include <linux/iio/iio-gts-helper.h> | ||
| 23 | #include <linux/iio/trigger.h> | ||
| 24 | #include <linux/iio/trigger_consumer.h> | ||
| 25 | #include <linux/iio/triggered_buffer.h> | ||
| 26 | |||
| 27 | /* | ||
| 28 | * A word about register address and mask definitions. | ||
| 29 | * | ||
| 30 | * At a quick glance to the data-sheet register tables, the BU27010 has all the | ||
| 31 | * registers that the BU27008 has. On top of that the BU27010 adds couple of new | ||
| 32 | * ones. | ||
| 33 | * | ||
| 34 | * So, all definitions BU27008_REG_* are there also for BU27010 but none of the | ||
| 35 | * BU27010_REG_* are present on BU27008. This makes sense as BU27010 just adds | ||
| 36 | * some features (Flicker FIFO, more power control) on top of the BU27008. | ||
| 37 | * | ||
| 38 | * Unfortunately, some of the wheel has been re-invented. Even though the names | ||
| 39 | * of the registers have stayed the same, pretty much all of the functionality | ||
| 40 | * provided by the registers has changed place. Contents of all MODE_CONTROL | ||
| 41 | * registers on BU27008 and BU27010 are different. | ||
| 42 | * | ||
| 43 | * Chip-specific mapping from register addresses/bits to functionality is done | ||
| 44 | * in bu27_chip_data structures. | ||
| 45 | */ | ||
| 46 | #define BU27008_REG_SYSTEM_CONTROL 0x40 | ||
| 47 | #define BU27008_MASK_SW_RESET BIT(7) | ||
| 48 | #define BU27008_MASK_PART_ID GENMASK(5, 0) | ||
| 49 | #define BU27008_ID 0x1a | ||
| 50 | #define BU27008_REG_MODE_CONTROL1 0x41 | ||
| 51 | #define BU27008_MASK_MEAS_MODE GENMASK(2, 0) | ||
| 52 | #define BU27008_MASK_CHAN_SEL GENMASK(3, 2) | ||
| 53 | |||
| 54 | #define BU27008_REG_MODE_CONTROL2 0x42 | ||
| 55 | #define BU27008_MASK_RGBC_GAIN GENMASK(7, 3) | ||
| 56 | #define BU27008_MASK_IR_GAIN_LO GENMASK(2, 0) | ||
| 57 | #define BU27008_SHIFT_IR_GAIN 3 | ||
| 58 | |||
| 59 | #define BU27008_REG_MODE_CONTROL3 0x43 | ||
| 60 | #define BU27008_MASK_VALID BIT(7) | ||
| 61 | #define BU27008_MASK_INT_EN BIT(1) | ||
| 62 | #define BU27008_INT_EN BU27008_MASK_INT_EN | ||
| 63 | #define BU27008_INT_DIS 0 | ||
| 64 | #define BU27008_MASK_MEAS_EN BIT(0) | ||
| 65 | #define BU27008_MEAS_EN BIT(0) | ||
| 66 | #define BU27008_MEAS_DIS 0 | ||
| 67 | |||
| 68 | #define BU27008_REG_DATA0_LO 0x50 | ||
| 69 | #define BU27008_REG_DATA1_LO 0x52 | ||
| 70 | #define BU27008_REG_DATA2_LO 0x54 | ||
| 71 | #define BU27008_REG_DATA3_LO 0x56 | ||
| 72 | #define BU27008_REG_DATA3_HI 0x57 | ||
| 73 | #define BU27008_REG_MANUFACTURER_ID 0x92 | ||
| 74 | #define BU27008_REG_MAX BU27008_REG_MANUFACTURER_ID | ||
| 75 | |||
| 76 | /* BU27010 specific definitions */ | ||
| 77 | |||
| 78 | #define BU27010_MASK_SW_RESET BIT(7) | ||
| 79 | #define BU27010_ID 0x1b | ||
| 80 | #define BU27010_REG_POWER 0x3e | ||
| 81 | #define BU27010_MASK_POWER BIT(0) | ||
| 82 | |||
| 83 | #define BU27010_REG_RESET 0x3f | ||
| 84 | #define BU27010_MASK_RESET BIT(0) | ||
| 85 | #define BU27010_RESET_RELEASE BU27010_MASK_RESET | ||
| 86 | |||
| 87 | #define BU27010_MASK_MEAS_EN BIT(1) | ||
| 88 | |||
| 89 | #define BU27010_MASK_CHAN_SEL GENMASK(7, 6) | ||
| 90 | #define BU27010_MASK_MEAS_MODE GENMASK(5, 4) | ||
| 91 | #define BU27010_MASK_RGBC_GAIN GENMASK(3, 0) | ||
| 92 | |||
| 93 | #define BU27010_MASK_DATA3_GAIN GENMASK(7, 6) | ||
| 94 | #define BU27010_MASK_DATA2_GAIN GENMASK(5, 4) | ||
| 95 | #define BU27010_MASK_DATA1_GAIN GENMASK(3, 2) | ||
| 96 | #define BU27010_MASK_DATA0_GAIN GENMASK(1, 0) | ||
| 97 | |||
| 98 | #define BU27010_MASK_FLC_MODE BIT(7) | ||
| 99 | #define BU27010_MASK_FLC_GAIN GENMASK(4, 0) | ||
| 100 | |||
| 101 | #define BU27010_REG_MODE_CONTROL4 0x44 | ||
| 102 | /* If flicker is ever to be supported the IRQ must be handled as a field */ | ||
| 103 | #define BU27010_IRQ_DIS_ALL GENMASK(1, 0) | ||
| 104 | #define BU27010_DRDY_EN BIT(0) | ||
| 105 | #define BU27010_MASK_INT_SEL GENMASK(1, 0) | ||
| 106 | |||
| 107 | #define BU27010_REG_MODE_CONTROL5 0x45 | ||
| 108 | #define BU27010_MASK_RGB_VALID BIT(7) | ||
| 109 | #define BU27010_MASK_FLC_VALID BIT(6) | ||
| 110 | #define BU27010_MASK_WAIT_EN BIT(3) | ||
| 111 | #define BU27010_MASK_FIFO_EN BIT(2) | ||
| 112 | #define BU27010_MASK_RGB_EN BIT(1) | ||
| 113 | #define BU27010_MASK_FLC_EN BIT(0) | ||
| 114 | |||
| 115 | #define BU27010_REG_DATA_FLICKER_LO 0x56 | ||
| 116 | #define BU27010_MASK_DATA_FLICKER_HI GENMASK(2, 0) | ||
| 117 | #define BU27010_REG_FLICKER_COUNT 0x5a | ||
| 118 | #define BU27010_REG_FIFO_LEVEL_LO 0x5b | ||
| 119 | #define BU27010_MASK_FIFO_LEVEL_HI BIT(0) | ||
| 120 | #define BU27010_REG_FIFO_DATA_LO 0x5d | ||
| 121 | #define BU27010_REG_FIFO_DATA_HI 0x5e | ||
| 122 | #define BU27010_MASK_FIFO_DATA_HI GENMASK(2, 0) | ||
| 123 | #define BU27010_REG_MANUFACTURER_ID 0x92 | ||
| 124 | #define BU27010_REG_MAX BU27010_REG_MANUFACTURER_ID | ||
| 125 | |||
| 126 | /** | ||
| 127 | * enum bu27008_chan_type - BU27008 channel types | ||
| 128 | * @BU27008_RED: Red channel. Always via data0. | ||
| 129 | * @BU27008_GREEN: Green channel. Always via data1. | ||
| 130 | * @BU27008_BLUE: Blue channel. Via data2 (when used). | ||
| 131 | * @BU27008_CLEAR: Clear channel. Via data2 or data3 (when used). | ||
| 132 | * @BU27008_IR: IR channel. Via data3 (when used). | ||
| 133 | * @BU27008_LUX: Illuminance channel, computed using RGB and IR. | ||
| 134 | * @BU27008_NUM_CHANS: Number of channel types. | ||
| 135 | */ | ||
| 136 | enum bu27008_chan_type { | ||
| 137 | BU27008_RED, | ||
| 138 | BU27008_GREEN, | ||
| 139 | BU27008_BLUE, | ||
| 140 | BU27008_CLEAR, | ||
| 141 | BU27008_IR, | ||
| 142 | BU27008_LUX, | ||
| 143 | BU27008_NUM_CHANS | ||
| 144 | }; | ||
| 145 | |||
| 146 | /** | ||
| 147 | * enum bu27008_chan - BU27008 physical data channel | ||
| 148 | * @BU27008_DATA0: Always red. | ||
| 149 | * @BU27008_DATA1: Always green. | ||
| 150 | * @BU27008_DATA2: Blue or clear. | ||
| 151 | * @BU27008_DATA3: IR or clear. | ||
| 152 | * @BU27008_NUM_HW_CHANS: Number of physical channels | ||
| 153 | */ | ||
| 154 | enum bu27008_chan { | ||
| 155 | BU27008_DATA0, | ||
| 156 | BU27008_DATA1, | ||
| 157 | BU27008_DATA2, | ||
| 158 | BU27008_DATA3, | ||
| 159 | BU27008_NUM_HW_CHANS | ||
| 160 | }; | ||
| 161 | |||
| 162 | /* We can always measure red and green at same time */ | ||
| 163 | #define ALWAYS_SCANNABLE (BIT(BU27008_RED) | BIT(BU27008_GREEN)) | ||
| 164 | |||
| 165 | /* We use these data channel configs. Ensure scan_masks below follow them too */ | ||
| 166 | #define BU27008_BLUE2_CLEAR3 0x0 /* buffer is R, G, B, C */ | ||
| 167 | #define BU27008_CLEAR2_IR3 0x1 /* buffer is R, G, C, IR */ | ||
| 168 | #define BU27008_BLUE2_IR3 0x2 /* buffer is R, G, B, IR */ | ||
| 169 | |||
| 170 | static const unsigned long bu27008_scan_masks[] = { | ||
| 171 | /* buffer is R, G, B, C */ | ||
| 172 | ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_CLEAR), | ||
| 173 | /* buffer is R, G, C, IR */ | ||
| 174 | ALWAYS_SCANNABLE | BIT(BU27008_CLEAR) | BIT(BU27008_IR), | ||
| 175 | /* buffer is R, G, B, IR */ | ||
| 176 | ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR), | ||
| 177 | /* buffer is R, G, B, IR, LUX */ | ||
| 178 | ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR) | BIT(BU27008_LUX), | ||
| 179 | 0 | ||
| 180 | }; | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Available scales with gain 1x - 1024x, timings 55, 100, 200, 400 mS | ||
| 184 | * Time impacts to gain: 1x, 2x, 4x, 8x. | ||
| 185 | * | ||
| 186 | * => Max total gain is HWGAIN * gain by integration time (8 * 1024) = 8192 | ||
| 187 | * | ||
| 188 | * Max amplification is (HWGAIN * MAX integration-time multiplier) 1024 * 8 | ||
| 189 | * = 8192. With NANO scale we get rid of accuracy loss when we start with the | ||
| 190 | * scale 16.0 for HWGAIN1, INT-TIME 55 mS. This way the nano scale for MAX | ||
| 191 | * total gain 8192 will be 1953125 | ||
| 192 | */ | ||
| 193 | #define BU27008_SCALE_1X 16 | ||
| 194 | |||
| 195 | /* | ||
| 196 | * On BU27010 available scales with gain 1x - 4096x, | ||
| 197 | * timings 55, 100, 200, 400 mS. Time impacts to gain: 1x, 2x, 4x, 8x. | ||
| 198 | * | ||
| 199 | * => Max total gain is HWGAIN * gain by integration time (8 * 4096) | ||
| 200 | * | ||
| 201 | * Using NANO precision for scale we must use scale 64x corresponding gain 1x | ||
| 202 | * to avoid precision loss. | ||
| 203 | */ | ||
| 204 | #define BU27010_SCALE_1X 64 | ||
| 205 | |||
| 206 | /* See the data sheet for the "Gain Setting" table */ | ||
| 207 | #define BU27008_GSEL_1X 0x00 | ||
| 208 | #define BU27008_GSEL_4X 0x08 | ||
| 209 | #define BU27008_GSEL_8X 0x09 | ||
| 210 | #define BU27008_GSEL_16X 0x0a | ||
| 211 | #define BU27008_GSEL_32X 0x0b | ||
| 212 | #define BU27008_GSEL_64X 0x0c | ||
| 213 | #define BU27008_GSEL_256X 0x18 | ||
| 214 | #define BU27008_GSEL_512X 0x19 | ||
| 215 | #define BU27008_GSEL_1024X 0x1a | ||
| 216 | |||
| 217 | static const struct iio_gain_sel_pair bu27008_gains[] = { | ||
| 218 | GAIN_SCALE_GAIN(1, BU27008_GSEL_1X), | ||
| 219 | GAIN_SCALE_GAIN(4, BU27008_GSEL_4X), | ||
| 220 | GAIN_SCALE_GAIN(8, BU27008_GSEL_8X), | ||
| 221 | GAIN_SCALE_GAIN(16, BU27008_GSEL_16X), | ||
| 222 | GAIN_SCALE_GAIN(32, BU27008_GSEL_32X), | ||
| 223 | GAIN_SCALE_GAIN(64, BU27008_GSEL_64X), | ||
| 224 | GAIN_SCALE_GAIN(256, BU27008_GSEL_256X), | ||
| 225 | GAIN_SCALE_GAIN(512, BU27008_GSEL_512X), | ||
| 226 | GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X), | ||
| 227 | }; | ||
| 228 | |||
| 229 | static const struct iio_gain_sel_pair bu27008_gains_ir[] = { | ||
| 230 | GAIN_SCALE_GAIN(2, BU27008_GSEL_1X), | ||
| 231 | GAIN_SCALE_GAIN(4, BU27008_GSEL_4X), | ||
| 232 | GAIN_SCALE_GAIN(8, BU27008_GSEL_8X), | ||
| 233 | GAIN_SCALE_GAIN(16, BU27008_GSEL_16X), | ||
| 234 | GAIN_SCALE_GAIN(32, BU27008_GSEL_32X), | ||
| 235 | GAIN_SCALE_GAIN(64, BU27008_GSEL_64X), | ||
| 236 | GAIN_SCALE_GAIN(256, BU27008_GSEL_256X), | ||
| 237 | GAIN_SCALE_GAIN(512, BU27008_GSEL_512X), | ||
| 238 | GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X), | ||
| 239 | }; | ||
| 240 | |||
| 241 | #define BU27010_GSEL_1X 0x00 /* 000000 */ | ||
| 242 | #define BU27010_GSEL_4X 0x08 /* 001000 */ | ||
| 243 | #define BU27010_GSEL_16X 0x09 /* 001001 */ | ||
| 244 | #define BU27010_GSEL_64X 0x0e /* 001110 */ | ||
| 245 | #define BU27010_GSEL_256X 0x1e /* 011110 */ | ||
| 246 | #define BU27010_GSEL_1024X 0x2e /* 101110 */ | ||
| 247 | #define BU27010_GSEL_4096X 0x3f /* 111111 */ | ||
| 248 | |||
| 249 | static const struct iio_gain_sel_pair bu27010_gains[] = { | ||
| 250 | GAIN_SCALE_GAIN(1, BU27010_GSEL_1X), | ||
| 251 | GAIN_SCALE_GAIN(4, BU27010_GSEL_4X), | ||
| 252 | GAIN_SCALE_GAIN(16, BU27010_GSEL_16X), | ||
| 253 | GAIN_SCALE_GAIN(64, BU27010_GSEL_64X), | ||
| 254 | GAIN_SCALE_GAIN(256, BU27010_GSEL_256X), | ||
| 255 | GAIN_SCALE_GAIN(1024, BU27010_GSEL_1024X), | ||
| 256 | GAIN_SCALE_GAIN(4096, BU27010_GSEL_4096X), | ||
| 257 | }; | ||
| 258 | |||
| 259 | static const struct iio_gain_sel_pair bu27010_gains_ir[] = { | ||
| 260 | GAIN_SCALE_GAIN(2, BU27010_GSEL_1X), | ||
| 261 | GAIN_SCALE_GAIN(4, BU27010_GSEL_4X), | ||
| 262 | GAIN_SCALE_GAIN(16, BU27010_GSEL_16X), | ||
| 263 | GAIN_SCALE_GAIN(64, BU27010_GSEL_64X), | ||
| 264 | GAIN_SCALE_GAIN(256, BU27010_GSEL_256X), | ||
| 265 | GAIN_SCALE_GAIN(1024, BU27010_GSEL_1024X), | ||
| 266 | GAIN_SCALE_GAIN(4096, BU27010_GSEL_4096X), | ||
| 267 | }; | ||
| 268 | |||
| 269 | #define BU27008_MEAS_MODE_100MS 0x00 | ||
| 270 | #define BU27008_MEAS_MODE_55MS 0x01 | ||
| 271 | #define BU27008_MEAS_MODE_200MS 0x02 | ||
| 272 | #define BU27008_MEAS_MODE_400MS 0x04 | ||
| 273 | |||
| 274 | #define BU27010_MEAS_MODE_100MS 0x00 | ||
| 275 | #define BU27010_MEAS_MODE_55MS 0x03 | ||
| 276 | #define BU27010_MEAS_MODE_200MS 0x01 | ||
| 277 | #define BU27010_MEAS_MODE_400MS 0x02 | ||
| 278 | |||
| 279 | #define BU27008_MEAS_TIME_MAX_MS 400 | ||
| 280 | |||
| 281 | static const struct iio_itime_sel_mul bu27008_itimes[] = { | ||
| 282 | GAIN_SCALE_ITIME_US(400000, BU27008_MEAS_MODE_400MS, 8), | ||
| 283 | GAIN_SCALE_ITIME_US(200000, BU27008_MEAS_MODE_200MS, 4), | ||
| 284 | GAIN_SCALE_ITIME_US(100000, BU27008_MEAS_MODE_100MS, 2), | ||
| 285 | GAIN_SCALE_ITIME_US(55000, BU27008_MEAS_MODE_55MS, 1), | ||
| 286 | }; | ||
| 287 | |||
| 288 | static const struct iio_itime_sel_mul bu27010_itimes[] = { | ||
| 289 | GAIN_SCALE_ITIME_US(400000, BU27010_MEAS_MODE_400MS, 8), | ||
| 290 | GAIN_SCALE_ITIME_US(200000, BU27010_MEAS_MODE_200MS, 4), | ||
| 291 | GAIN_SCALE_ITIME_US(100000, BU27010_MEAS_MODE_100MS, 2), | ||
| 292 | GAIN_SCALE_ITIME_US(55000, BU27010_MEAS_MODE_55MS, 1), | ||
| 293 | }; | ||
| 294 | |||
| 295 | /* | ||
| 296 | * All the RGBC channels share the same gain. | ||
| 297 | * IR gain can be fine-tuned from the gain set for the RGBC by 2 bit, but this | ||
| 298 | * would yield quite complex gain setting. Especially since not all bit | ||
| 299 | * compinations are supported. And in any case setting GAIN for RGBC will | ||
| 300 | * always also change the IR-gain. | ||
| 301 | * | ||
| 302 | * On top of this, the selector '0' which corresponds to hw-gain 1X on RGBC, | ||
| 303 | * corresponds to gain 2X on IR. Rest of the selctors correspond to same gains | ||
| 304 | * though. This, however, makes it not possible to use shared gain for all | ||
| 305 | * RGBC and IR settings even though they are all changed at the one go. | ||
| 306 | */ | ||
| 307 | #define BU27008_CHAN(color, data, separate_avail) \ | ||
| 308 | { \ | ||
| 309 | .type = IIO_INTENSITY, \ | ||
| 310 | .modified = 1, \ | ||
| 311 | .channel2 = IIO_MOD_LIGHT_##color, \ | ||
| 312 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 313 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 314 | .info_mask_separate_available = (separate_avail), \ | ||
| 315 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 316 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ | ||
| 317 | .address = BU27008_REG_##data##_LO, \ | ||
| 318 | .scan_index = BU27008_##color, \ | ||
| 319 | .scan_type = { \ | ||
| 320 | .sign = 'u', \ | ||
| 321 | .realbits = 16, \ | ||
| 322 | .storagebits = 16, \ | ||
| 323 | .endianness = IIO_LE, \ | ||
| 324 | }, \ | ||
| 325 | } | ||
| 326 | |||
| 327 | /* For raw reads we always configure DATA3 for CLEAR */ | ||
| 328 | static const struct iio_chan_spec bu27008_channels[] = { | ||
| 329 | BU27008_CHAN(RED, DATA0, BIT(IIO_CHAN_INFO_SCALE)), | ||
| 330 | BU27008_CHAN(GREEN, DATA1, BIT(IIO_CHAN_INFO_SCALE)), | ||
| 331 | BU27008_CHAN(BLUE, DATA2, BIT(IIO_CHAN_INFO_SCALE)), | ||
| 332 | BU27008_CHAN(CLEAR, DATA2, BIT(IIO_CHAN_INFO_SCALE)), | ||
| 333 | /* | ||
| 334 | * We don't allow setting scale for IR (because of shared gain bits). | ||
| 335 | * Hence we don't advertise available ones either. | ||
| 336 | */ | ||
| 337 | BU27008_CHAN(IR, DATA3, 0), | ||
| 338 | { | ||
| 339 | .type = IIO_LIGHT, | ||
| 340 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 341 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 342 | .channel = BU27008_LUX, | ||
| 343 | .scan_index = BU27008_LUX, | ||
| 344 | .scan_type = { | ||
| 345 | .sign = 'u', | ||
| 346 | .realbits = 64, | ||
| 347 | .storagebits = 64, | ||
| 348 | .endianness = IIO_CPU, | ||
| 349 | }, | ||
| 350 | }, | ||
| 351 | IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS), | ||
| 352 | }; | ||
| 353 | |||
| 354 | struct bu27008_data; | ||
| 355 | |||
| 356 | struct bu27_chip_data { | ||
| 357 | const char *name; | ||
| 358 | int (*chip_init)(struct bu27008_data *data); | ||
| 359 | int (*get_gain_sel)(struct bu27008_data *data, int *sel); | ||
| 360 | int (*write_gain_sel)(struct bu27008_data *data, int sel); | ||
| 361 | const struct regmap_config *regmap_cfg; | ||
| 362 | const struct iio_gain_sel_pair *gains; | ||
| 363 | const struct iio_gain_sel_pair *gains_ir; | ||
| 364 | const struct iio_itime_sel_mul *itimes; | ||
| 365 | int num_gains; | ||
| 366 | int num_gains_ir; | ||
| 367 | int num_itimes; | ||
| 368 | int scale1x; | ||
| 369 | |||
| 370 | int drdy_en_reg; | ||
| 371 | int drdy_en_mask; | ||
| 372 | int meas_en_reg; | ||
| 373 | int meas_en_mask; | ||
| 374 | int valid_reg; | ||
| 375 | int chan_sel_reg; | ||
| 376 | int chan_sel_mask; | ||
| 377 | int int_time_mask; | ||
| 378 | u8 part_id; | ||
| 379 | }; | ||
| 380 | |||
| 381 | struct bu27008_data { | ||
| 382 | const struct bu27_chip_data *cd; | ||
| 383 | struct regmap *regmap; | ||
| 384 | struct iio_trigger *trig; | ||
| 385 | struct device *dev; | ||
| 386 | struct iio_gts gts; | ||
| 387 | struct iio_gts gts_ir; | ||
| 388 | int irq; | ||
| 389 | |||
| 390 | /* | ||
| 391 | * Prevent changing gain/time config when scale is read/written. | ||
| 392 | * Similarly, protect the integration_time read/change sequence. | ||
| 393 | * Prevent changing gain/time when data is read. | ||
| 394 | */ | ||
| 395 | struct mutex mutex; | ||
| 396 | }; | ||
| 397 | |||
| 398 | static const struct regmap_range bu27008_volatile_ranges[] = { | ||
| 399 | { | ||
| 400 | .range_min = BU27008_REG_SYSTEM_CONTROL, /* SWRESET */ | ||
| 401 | .range_max = BU27008_REG_SYSTEM_CONTROL, | ||
| 402 | }, { | ||
| 403 | .range_min = BU27008_REG_MODE_CONTROL3, /* VALID */ | ||
| 404 | .range_max = BU27008_REG_MODE_CONTROL3, | ||
| 405 | }, { | ||
| 406 | .range_min = BU27008_REG_DATA0_LO, /* DATA */ | ||
| 407 | .range_max = BU27008_REG_DATA3_HI, | ||
| 408 | }, | ||
| 409 | }; | ||
| 410 | |||
| 411 | static const struct regmap_range bu27010_volatile_ranges[] = { | ||
| 412 | { | ||
| 413 | .range_min = BU27010_REG_RESET, /* RSTB */ | ||
| 414 | .range_max = BU27008_REG_SYSTEM_CONTROL, /* RESET */ | ||
| 415 | }, { | ||
| 416 | .range_min = BU27010_REG_MODE_CONTROL5, /* VALID bits */ | ||
| 417 | .range_max = BU27010_REG_MODE_CONTROL5, | ||
| 418 | }, { | ||
| 419 | .range_min = BU27008_REG_DATA0_LO, | ||
| 420 | .range_max = BU27010_REG_FIFO_DATA_HI, | ||
| 421 | }, | ||
| 422 | }; | ||
| 423 | |||
| 424 | static const struct regmap_access_table bu27008_volatile_regs = { | ||
| 425 | .yes_ranges = &bu27008_volatile_ranges[0], | ||
| 426 | .n_yes_ranges = ARRAY_SIZE(bu27008_volatile_ranges), | ||
| 427 | }; | ||
| 428 | |||
| 429 | static const struct regmap_access_table bu27010_volatile_regs = { | ||
| 430 | .yes_ranges = &bu27010_volatile_ranges[0], | ||
| 431 | .n_yes_ranges = ARRAY_SIZE(bu27010_volatile_ranges), | ||
| 432 | }; | ||
| 433 | |||
| 434 | static const struct regmap_range bu27008_read_only_ranges[] = { | ||
| 435 | { | ||
| 436 | .range_min = BU27008_REG_DATA0_LO, | ||
| 437 | .range_max = BU27008_REG_DATA3_HI, | ||
| 438 | }, { | ||
| 439 | .range_min = BU27008_REG_MANUFACTURER_ID, | ||
| 440 | .range_max = BU27008_REG_MANUFACTURER_ID, | ||
| 441 | }, | ||
| 442 | }; | ||
| 443 | |||
| 444 | static const struct regmap_range bu27010_read_only_ranges[] = { | ||
| 445 | { | ||
| 446 | .range_min = BU27008_REG_DATA0_LO, | ||
| 447 | .range_max = BU27010_REG_FIFO_DATA_HI, | ||
| 448 | }, { | ||
| 449 | .range_min = BU27010_REG_MANUFACTURER_ID, | ||
| 450 | .range_max = BU27010_REG_MANUFACTURER_ID, | ||
| 451 | } | ||
| 452 | }; | ||
| 453 | |||
| 454 | static const struct regmap_access_table bu27008_ro_regs = { | ||
| 455 | .no_ranges = &bu27008_read_only_ranges[0], | ||
| 456 | .n_no_ranges = ARRAY_SIZE(bu27008_read_only_ranges), | ||
| 457 | }; | ||
| 458 | |||
| 459 | static const struct regmap_access_table bu27010_ro_regs = { | ||
| 460 | .no_ranges = &bu27010_read_only_ranges[0], | ||
| 461 | .n_no_ranges = ARRAY_SIZE(bu27010_read_only_ranges), | ||
| 462 | }; | ||
| 463 | |||
| 464 | static const struct regmap_config bu27008_regmap = { | ||
| 465 | .reg_bits = 8, | ||
| 466 | .val_bits = 8, | ||
| 467 | .max_register = BU27008_REG_MAX, | ||
| 468 | .cache_type = REGCACHE_RBTREE, | ||
| 469 | .volatile_table = &bu27008_volatile_regs, | ||
| 470 | .wr_table = &bu27008_ro_regs, | ||
| 471 | /* | ||
| 472 | * All register writes are serialized by the mutex which protects the | ||
| 473 | * scale setting/getting. This is needed because scale is combined by | ||
| 474 | * gain and integration time settings and we need to ensure those are | ||
| 475 | * not read / written when scale is being computed. | ||
| 476 | * | ||
| 477 | * As a result of this serializing, we don't need regmap locking. Note, | ||
| 478 | * this is not true if we add any configurations which are not | ||
| 479 | * serialized by the mutex and which may need for example a protected | ||
| 480 | * read-modify-write cycle (eg. regmap_update_bits()). Please, revise | ||
| 481 | * this when adding features to the driver. | ||
| 482 | */ | ||
| 483 | .disable_locking = true, | ||
| 484 | }; | ||
| 485 | |||
| 486 | static const struct regmap_config bu27010_regmap = { | ||
| 487 | .reg_bits = 8, | ||
| 488 | .val_bits = 8, | ||
| 489 | |||
| 490 | .max_register = BU27010_REG_MAX, | ||
| 491 | .cache_type = REGCACHE_RBTREE, | ||
| 492 | .volatile_table = &bu27010_volatile_regs, | ||
| 493 | .wr_table = &bu27010_ro_regs, | ||
| 494 | .disable_locking = true, | ||
| 495 | }; | ||
| 496 | |||
| 497 | static int bu27008_write_gain_sel(struct bu27008_data *data, int sel) | ||
| 498 | { | ||
| 499 | int regval; | ||
| 500 | |||
| 501 | regval = FIELD_PREP(BU27008_MASK_RGBC_GAIN, sel); | ||
| 502 | |||
| 503 | /* | ||
| 504 | * We do always set also the LOW bits of IR-gain because othervice we | ||
| 505 | * would risk resulting an invalid GAIN register value. | ||
| 506 | * | ||
| 507 | * We could allow setting separate gains for RGBC and IR when the | ||
| 508 | * values were such that HW could support both gain settings. | ||
| 509 | * Eg, when the shared bits were same for both gain values. | ||
| 510 | * | ||
| 511 | * This, however, has a negligible benefit compared to the increased | ||
| 512 | * software complexity when we would need to go through the gains | ||
| 513 | * for both channels separately when the integration time changes. | ||
| 514 | * This would end up with nasty logic for computing gain values for | ||
| 515 | * both channels - and rejecting them if shared bits changed. | ||
| 516 | * | ||
| 517 | * We should then build the logic by guessing what a user prefers. | ||
| 518 | * RGBC or IR gains correctly set while other jumps to odd value? | ||
| 519 | * Maybe look-up a value where both gains are somehow optimized | ||
| 520 | * <what this somehow is, is ATM unknown to us>. Or maybe user would | ||
| 521 | * expect us to reject changes when optimal gains can't be set to both | ||
| 522 | * channels w/given integration time. At best that would result | ||
| 523 | * solution that works well for a very specific subset of | ||
| 524 | * configurations but causes unexpected corner-cases. | ||
| 525 | * | ||
| 526 | * So, we keep it simple. Always set same selector to IR and RGBC. | ||
| 527 | * We disallow setting IR (as I expect that most of the users are | ||
| 528 | * interested in RGBC). This way we can show the user that the scales | ||
| 529 | * for RGBC and IR channels are different (1X Vs 2X with sel 0) while | ||
| 530 | * still keeping the operation deterministic. | ||
| 531 | */ | ||
| 532 | regval |= FIELD_PREP(BU27008_MASK_IR_GAIN_LO, sel); | ||
| 533 | |||
| 534 | return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL2, | ||
| 535 | BU27008_MASK_RGBC_GAIN, regval); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int bu27010_write_gain_sel(struct bu27008_data *data, int sel) | ||
| 539 | { | ||
| 540 | unsigned int regval; | ||
| 541 | int ret, chan_selector; | ||
| 542 | |||
| 543 | /* | ||
| 544 | * Gain 'selector' is composed of two registers. Selector is 6bit value, | ||
| 545 | * 4 high bits being the RGBC gain fieild in MODE_CONTROL1 register and | ||
| 546 | * two low bits being the channel specific gain in MODE_CONTROL2. | ||
| 547 | * | ||
| 548 | * Let's take the 4 high bits of whole 6 bit selector, and prepare | ||
| 549 | * the MODE_CONTROL1 value (RGBC gain part). | ||
| 550 | */ | ||
| 551 | regval = FIELD_PREP(BU27010_MASK_RGBC_GAIN, (sel >> 2)); | ||
| 552 | |||
| 553 | ret = regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1, | ||
| 554 | BU27010_MASK_RGBC_GAIN, regval); | ||
| 555 | if (ret) | ||
| 556 | return ret; | ||
| 557 | |||
| 558 | /* | ||
| 559 | * Two low two bits of the selector must be written for all 4 | ||
| 560 | * channels in the MODE_CONTROL2 register. Copy these two bits for | ||
| 561 | * all channels. | ||
| 562 | */ | ||
| 563 | chan_selector = sel & GENMASK(1, 0); | ||
| 564 | |||
| 565 | regval = FIELD_PREP(BU27010_MASK_DATA0_GAIN, chan_selector); | ||
| 566 | regval |= FIELD_PREP(BU27010_MASK_DATA1_GAIN, chan_selector); | ||
| 567 | regval |= FIELD_PREP(BU27010_MASK_DATA2_GAIN, chan_selector); | ||
| 568 | regval |= FIELD_PREP(BU27010_MASK_DATA3_GAIN, chan_selector); | ||
| 569 | |||
| 570 | return regmap_write(data->regmap, BU27008_REG_MODE_CONTROL2, regval); | ||
| 571 | } | ||
| 572 | |||
| 573 | static int bu27008_get_gain_sel(struct bu27008_data *data, int *sel) | ||
| 574 | { | ||
| 575 | int ret; | ||
| 576 | |||
| 577 | /* | ||
| 578 | * If we always "lock" the gain selectors for all channels to prevent | ||
| 579 | * unsupported configs, then it does not matter which channel is used | ||
| 580 | * we can just return selector from any of them. | ||
| 581 | * | ||
| 582 | * This, however is not true if we decide to support only 4X and 16X | ||
| 583 | * and then individual gains for channels. Currently this is not the | ||
| 584 | * case. | ||
| 585 | * | ||
| 586 | * If we some day decide to support individual gains, then we need to | ||
| 587 | * have channel information here. | ||
| 588 | */ | ||
| 589 | |||
| 590 | ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, sel); | ||
| 591 | if (ret) | ||
| 592 | return ret; | ||
| 593 | |||
| 594 | *sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, *sel); | ||
| 595 | |||
| 596 | return 0; | ||
| 597 | } | ||
| 598 | |||
| 599 | static int bu27010_get_gain_sel(struct bu27008_data *data, int *sel) | ||
| 600 | { | ||
| 601 | int ret, tmp; | ||
| 602 | |||
| 603 | /* | ||
| 604 | * We always "lock" the gain selectors for all channels to prevent | ||
| 605 | * unsupported configs. It does not matter which channel is used | ||
| 606 | * we can just return selector from any of them. | ||
| 607 | * | ||
| 608 | * Read the channel0 gain. | ||
| 609 | */ | ||
| 610 | ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, sel); | ||
| 611 | if (ret) | ||
| 612 | return ret; | ||
| 613 | |||
| 614 | *sel = FIELD_GET(BU27010_MASK_DATA0_GAIN, *sel); | ||
| 615 | |||
| 616 | /* Read the shared gain */ | ||
| 617 | ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &tmp); | ||
| 618 | if (ret) | ||
| 619 | return ret; | ||
| 620 | |||
| 621 | /* | ||
| 622 | * The gain selector is made as a combination of common RGBC gain and | ||
| 623 | * the channel specific gain. The channel specific gain forms the low | ||
| 624 | * bits of selector and RGBC gain is appended right after it. | ||
| 625 | * | ||
| 626 | * Compose the selector from channel0 gain and shared RGBC gain. | ||
| 627 | */ | ||
| 628 | *sel |= FIELD_GET(BU27010_MASK_RGBC_GAIN, tmp) << fls(BU27010_MASK_DATA0_GAIN); | ||
| 629 | |||
| 630 | return ret; | ||
| 631 | } | ||
| 632 | |||
| 633 | static int bu27008_chip_init(struct bu27008_data *data) | ||
| 634 | { | ||
| 635 | int ret; | ||
| 636 | |||
| 637 | ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL, | ||
| 638 | BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET); | ||
| 639 | if (ret) | ||
| 640 | return dev_err_probe(data->dev, ret, "Sensor reset failed\n"); | ||
| 641 | |||
| 642 | /* | ||
| 643 | * The data-sheet does not tell how long performing the IC reset takes. | ||
| 644 | * However, the data-sheet says the minimum time it takes the IC to be | ||
| 645 | * able to take inputs after power is applied, is 100 uS. I'd assume | ||
| 646 | * > 1 mS is enough. | ||
| 647 | */ | ||
| 648 | msleep(1); | ||
| 649 | |||
| 650 | ret = regmap_reinit_cache(data->regmap, data->cd->regmap_cfg); | ||
| 651 | if (ret) | ||
| 652 | dev_err(data->dev, "Failed to reinit reg cache\n"); | ||
| 653 | |||
| 654 | return ret; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int bu27010_chip_init(struct bu27008_data *data) | ||
| 658 | { | ||
| 659 | int ret; | ||
| 660 | |||
| 661 | ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL, | ||
| 662 | BU27010_MASK_SW_RESET, BU27010_MASK_SW_RESET); | ||
| 663 | if (ret) | ||
| 664 | return dev_err_probe(data->dev, ret, "Sensor reset failed\n"); | ||
| 665 | |||
| 666 | msleep(1); | ||
| 667 | |||
| 668 | /* Power ON*/ | ||
| 669 | ret = regmap_write_bits(data->regmap, BU27010_REG_POWER, | ||
| 670 | BU27010_MASK_POWER, BU27010_MASK_POWER); | ||
| 671 | if (ret) | ||
| 672 | return dev_err_probe(data->dev, ret, "Sensor power-on failed\n"); | ||
| 673 | |||
| 674 | msleep(1); | ||
| 675 | |||
| 676 | /* Release blocks from reset */ | ||
| 677 | ret = regmap_write_bits(data->regmap, BU27010_REG_RESET, | ||
| 678 | BU27010_MASK_RESET, BU27010_RESET_RELEASE); | ||
| 679 | if (ret) | ||
| 680 | return dev_err_probe(data->dev, ret, "Sensor powering failed\n"); | ||
| 681 | |||
| 682 | msleep(1); | ||
| 683 | |||
| 684 | /* | ||
| 685 | * The IRQ enabling on BU27010 is done in a peculiar way. The IRQ | ||
| 686 | * enabling is not a bit mask where individual IRQs could be enabled but | ||
| 687 | * a field which values are: | ||
| 688 | * 00 => IRQs disabled | ||
| 689 | * 01 => Data-ready (RGBC/IR) | ||
| 690 | * 10 => Data-ready (flicker) | ||
| 691 | * 11 => Flicker FIFO | ||
| 692 | * | ||
| 693 | * So, only one IRQ can be enabled at a time and enabling for example | ||
| 694 | * flicker FIFO would automagically disable data-ready IRQ. | ||
| 695 | * | ||
| 696 | * Currently the driver does not support the flicker. Hence, we can | ||
| 697 | * just treat the RGBC data-ready as single bit which can be enabled / | ||
| 698 | * disabled. This works for as long as the second bit in the field | ||
| 699 | * stays zero. Here we ensure it gets zeroed. | ||
| 700 | */ | ||
| 701 | return regmap_clear_bits(data->regmap, BU27010_REG_MODE_CONTROL4, | ||
| 702 | BU27010_IRQ_DIS_ALL); | ||
| 703 | } | ||
| 704 | |||
| 705 | static const struct bu27_chip_data bu27010_chip = { | ||
| 706 | .name = "bu27010", | ||
| 707 | .chip_init = bu27010_chip_init, | ||
| 708 | .get_gain_sel = bu27010_get_gain_sel, | ||
| 709 | .write_gain_sel = bu27010_write_gain_sel, | ||
| 710 | .regmap_cfg = &bu27010_regmap, | ||
| 711 | .gains = &bu27010_gains[0], | ||
| 712 | .gains_ir = &bu27010_gains_ir[0], | ||
| 713 | .itimes = &bu27010_itimes[0], | ||
| 714 | .num_gains = ARRAY_SIZE(bu27010_gains), | ||
| 715 | .num_gains_ir = ARRAY_SIZE(bu27010_gains_ir), | ||
| 716 | .num_itimes = ARRAY_SIZE(bu27010_itimes), | ||
| 717 | .scale1x = BU27010_SCALE_1X, | ||
| 718 | .drdy_en_reg = BU27010_REG_MODE_CONTROL4, | ||
| 719 | .drdy_en_mask = BU27010_DRDY_EN, | ||
| 720 | .meas_en_reg = BU27010_REG_MODE_CONTROL5, | ||
| 721 | .meas_en_mask = BU27010_MASK_MEAS_EN, | ||
| 722 | .valid_reg = BU27010_REG_MODE_CONTROL5, | ||
| 723 | .chan_sel_reg = BU27008_REG_MODE_CONTROL1, | ||
| 724 | .chan_sel_mask = BU27010_MASK_CHAN_SEL, | ||
| 725 | .int_time_mask = BU27010_MASK_MEAS_MODE, | ||
| 726 | .part_id = BU27010_ID, | ||
| 727 | }; | ||
| 728 | |||
| 729 | static const struct bu27_chip_data bu27008_chip = { | ||
| 730 | .name = "bu27008", | ||
| 731 | .chip_init = bu27008_chip_init, | ||
| 732 | .get_gain_sel = bu27008_get_gain_sel, | ||
| 733 | .write_gain_sel = bu27008_write_gain_sel, | ||
| 734 | .regmap_cfg = &bu27008_regmap, | ||
| 735 | .gains = &bu27008_gains[0], | ||
| 736 | .gains_ir = &bu27008_gains_ir[0], | ||
| 737 | .itimes = &bu27008_itimes[0], | ||
| 738 | .num_gains = ARRAY_SIZE(bu27008_gains), | ||
| 739 | .num_gains_ir = ARRAY_SIZE(bu27008_gains_ir), | ||
| 740 | .num_itimes = ARRAY_SIZE(bu27008_itimes), | ||
| 741 | .scale1x = BU27008_SCALE_1X, | ||
| 742 | .drdy_en_reg = BU27008_REG_MODE_CONTROL3, | ||
| 743 | .drdy_en_mask = BU27008_MASK_INT_EN, | ||
| 744 | .valid_reg = BU27008_REG_MODE_CONTROL3, | ||
| 745 | .meas_en_reg = BU27008_REG_MODE_CONTROL3, | ||
| 746 | .meas_en_mask = BU27008_MASK_MEAS_EN, | ||
| 747 | .chan_sel_reg = BU27008_REG_MODE_CONTROL3, | ||
| 748 | .chan_sel_mask = BU27008_MASK_CHAN_SEL, | ||
| 749 | .int_time_mask = BU27008_MASK_MEAS_MODE, | ||
| 750 | .part_id = BU27008_ID, | ||
| 751 | }; | ||
| 752 | |||
| 753 | #define BU27008_MAX_VALID_RESULT_WAIT_US 50000 | ||
| 754 | #define BU27008_VALID_RESULT_WAIT_QUANTA_US 1000 | ||
| 755 | |||
| 756 | static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val) | ||
| 757 | { | ||
| 758 | int ret, valid; | ||
| 759 | __le16 tmp; | ||
| 760 | |||
| 761 | ret = regmap_read_poll_timeout(data->regmap, data->cd->valid_reg, | ||
| 762 | valid, (valid & BU27008_MASK_VALID), | ||
| 763 | BU27008_VALID_RESULT_WAIT_QUANTA_US, | ||
| 764 | BU27008_MAX_VALID_RESULT_WAIT_US); | ||
| 765 | if (ret) | ||
| 766 | return ret; | ||
| 767 | |||
| 768 | ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp)); | ||
| 769 | if (ret) | ||
| 770 | dev_err(data->dev, "Reading channel data failed\n"); | ||
| 771 | |||
| 772 | *val = le16_to_cpu(tmp); | ||
| 773 | |||
| 774 | return ret; | ||
| 775 | } | ||
| 776 | |||
| 777 | static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain) | ||
| 778 | { | ||
| 779 | int ret, sel; | ||
| 780 | |||
| 781 | ret = data->cd->get_gain_sel(data, &sel); | ||
| 782 | if (ret) | ||
| 783 | return ret; | ||
| 784 | |||
| 785 | ret = iio_gts_find_gain_by_sel(gts, sel); | ||
| 786 | if (ret < 0) { | ||
| 787 | dev_err(data->dev, "unknown gain value 0x%x\n", sel); | ||
| 788 | return ret; | ||
| 789 | } | ||
| 790 | |||
| 791 | *gain = ret; | ||
| 792 | |||
| 793 | return 0; | ||
| 794 | } | ||
| 795 | |||
| 796 | static int bu27008_set_gain(struct bu27008_data *data, int gain) | ||
| 797 | { | ||
| 798 | int ret; | ||
| 799 | |||
| 800 | ret = iio_gts_find_sel_by_gain(&data->gts, gain); | ||
| 801 | if (ret < 0) | ||
| 802 | return ret; | ||
| 803 | |||
| 804 | return data->cd->write_gain_sel(data, ret); | ||
| 805 | } | ||
| 806 | |||
| 807 | static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel) | ||
| 808 | { | ||
| 809 | int ret, val; | ||
| 810 | |||
| 811 | ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &val); | ||
| 812 | if (ret) | ||
| 813 | return ret; | ||
| 814 | |||
| 815 | val &= data->cd->int_time_mask; | ||
| 816 | val >>= ffs(data->cd->int_time_mask) - 1; | ||
| 817 | |||
| 818 | *sel = val; | ||
| 819 | |||
| 820 | return 0; | ||
| 821 | } | ||
| 822 | |||
| 823 | static int bu27008_set_int_time_sel(struct bu27008_data *data, int sel) | ||
| 824 | { | ||
| 825 | sel <<= ffs(data->cd->int_time_mask) - 1; | ||
| 826 | |||
| 827 | return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1, | ||
| 828 | data->cd->int_time_mask, sel); | ||
| 829 | } | ||
| 830 | |||
| 831 | static int bu27008_get_int_time_us(struct bu27008_data *data) | ||
| 832 | { | ||
| 833 | int ret, sel; | ||
| 834 | |||
| 835 | ret = bu27008_get_int_time_sel(data, &sel); | ||
| 836 | if (ret) | ||
| 837 | return ret; | ||
| 838 | |||
| 839 | return iio_gts_find_int_time_by_sel(&data->gts, sel); | ||
| 840 | } | ||
| 841 | |||
| 842 | static int _bu27008_get_scale(struct bu27008_data *data, bool ir, int *val, | ||
| 843 | int *val2) | ||
| 844 | { | ||
| 845 | struct iio_gts *gts; | ||
| 846 | int gain, ret; | ||
| 847 | |||
| 848 | if (ir) | ||
| 849 | gts = &data->gts_ir; | ||
| 850 | else | ||
| 851 | gts = &data->gts; | ||
| 852 | |||
| 853 | ret = bu27008_get_gain(data, gts, &gain); | ||
| 854 | if (ret) | ||
| 855 | return ret; | ||
| 856 | |||
| 857 | ret = bu27008_get_int_time_us(data); | ||
| 858 | if (ret < 0) | ||
| 859 | return ret; | ||
| 860 | |||
| 861 | return iio_gts_get_scale(gts, gain, ret, val, val2); | ||
| 862 | } | ||
| 863 | |||
| 864 | static int bu27008_get_scale(struct bu27008_data *data, bool ir, int *val, | ||
| 865 | int *val2) | ||
| 866 | { | ||
| 867 | int ret; | ||
| 868 | |||
| 869 | mutex_lock(&data->mutex); | ||
| 870 | ret = _bu27008_get_scale(data, ir, val, val2); | ||
| 871 | mutex_unlock(&data->mutex); | ||
| 872 | |||
| 873 | return ret; | ||
| 874 | } | ||
| 875 | |||
| 876 | static int bu27008_set_int_time(struct bu27008_data *data, int time) | ||
| 877 | { | ||
| 878 | int ret; | ||
| 879 | |||
| 880 | ret = iio_gts_find_sel_by_int_time(&data->gts, time); | ||
| 881 | if (ret < 0) | ||
| 882 | return ret; | ||
| 883 | |||
| 884 | return bu27008_set_int_time_sel(data, ret); | ||
| 885 | } | ||
| 886 | |||
| 887 | /* Try to change the time so that the scale is maintained */ | ||
| 888 | static int bu27008_try_set_int_time(struct bu27008_data *data, int int_time_new) | ||
| 889 | { | ||
| 890 | int ret, old_time_sel, new_time_sel, old_gain, new_gain; | ||
| 891 | |||
| 892 | mutex_lock(&data->mutex); | ||
| 893 | |||
| 894 | ret = bu27008_get_int_time_sel(data, &old_time_sel); | ||
| 895 | if (ret < 0) | ||
| 896 | goto unlock_out; | ||
| 897 | |||
| 898 | if (!iio_gts_valid_time(&data->gts, int_time_new)) { | ||
| 899 | dev_dbg(data->dev, "Unsupported integration time %u\n", | ||
| 900 | int_time_new); | ||
| 901 | |||
| 902 | ret = -EINVAL; | ||
| 903 | goto unlock_out; | ||
| 904 | } | ||
| 905 | |||
| 906 | /* If we already use requested time, then we're done */ | ||
| 907 | new_time_sel = iio_gts_find_sel_by_int_time(&data->gts, int_time_new); | ||
| 908 | if (new_time_sel == old_time_sel) | ||
| 909 | goto unlock_out; | ||
| 910 | |||
| 911 | ret = bu27008_get_gain(data, &data->gts, &old_gain); | ||
| 912 | if (ret) | ||
| 913 | goto unlock_out; | ||
| 914 | |||
| 915 | ret = iio_gts_find_new_gain_sel_by_old_gain_time(&data->gts, old_gain, | ||
| 916 | old_time_sel, new_time_sel, &new_gain); | ||
| 917 | if (ret) { | ||
| 918 | int scale1, scale2; | ||
| 919 | bool ok; | ||
| 920 | |||
| 921 | _bu27008_get_scale(data, false, &scale1, &scale2); | ||
| 922 | dev_dbg(data->dev, | ||
| 923 | "Can't support time %u with current scale %u %u\n", | ||
| 924 | int_time_new, scale1, scale2); | ||
| 925 | |||
| 926 | if (new_gain < 0) | ||
| 927 | goto unlock_out; | ||
| 928 | |||
| 929 | /* | ||
| 930 | * If caller requests for integration time change and we | ||
| 931 | * can't support the scale - then the caller should be | ||
| 932 | * prepared to 'pick up the pieces and deal with the | ||
| 933 | * fact that the scale changed'. | ||
| 934 | */ | ||
| 935 | ret = iio_find_closest_gain_low(&data->gts, new_gain, &ok); | ||
| 936 | if (!ok) | ||
| 937 | dev_dbg(data->dev, "optimal gain out of range\n"); | ||
| 938 | |||
| 939 | if (ret < 0) { | ||
| 940 | dev_dbg(data->dev, | ||
| 941 | "Total gain increase. Risk of saturation"); | ||
| 942 | ret = iio_gts_get_min_gain(&data->gts); | ||
| 943 | if (ret < 0) | ||
| 944 | goto unlock_out; | ||
| 945 | } | ||
| 946 | new_gain = ret; | ||
| 947 | dev_dbg(data->dev, "scale changed, new gain %u\n", new_gain); | ||
| 948 | } | ||
| 949 | |||
| 950 | ret = bu27008_set_gain(data, new_gain); | ||
| 951 | if (ret) | ||
| 952 | goto unlock_out; | ||
| 953 | |||
| 954 | ret = bu27008_set_int_time(data, int_time_new); | ||
| 955 | |||
| 956 | unlock_out: | ||
| 957 | mutex_unlock(&data->mutex); | ||
| 958 | |||
| 959 | return ret; | ||
| 960 | } | ||
| 961 | |||
| 962 | static int bu27008_meas_set(struct bu27008_data *data, bool enable) | ||
| 963 | { | ||
| 964 | if (enable) | ||
| 965 | return regmap_set_bits(data->regmap, data->cd->meas_en_reg, | ||
| 966 | data->cd->meas_en_mask); | ||
| 967 | return regmap_clear_bits(data->regmap, data->cd->meas_en_reg, | ||
| 968 | data->cd->meas_en_mask); | ||
| 969 | } | ||
| 970 | |||
| 971 | static int bu27008_chan_cfg(struct bu27008_data *data, | ||
| 972 | struct iio_chan_spec const *chan) | ||
| 973 | { | ||
| 974 | int chan_sel; | ||
| 975 | |||
| 976 | if (chan->scan_index == BU27008_BLUE) | ||
| 977 | chan_sel = BU27008_BLUE2_CLEAR3; | ||
| 978 | else | ||
| 979 | chan_sel = BU27008_CLEAR2_IR3; | ||
| 980 | |||
| 981 | /* | ||
| 982 | * prepare bitfield for channel sel. The FIELD_PREP works only when | ||
| 983 | * mask is constant. In our case the mask is assigned based on the | ||
| 984 | * chip type. Hence the open-coded FIELD_PREP here. We don't bother | ||
| 985 | * zeroing the irrelevant bits though - update_bits takes care of that. | ||
| 986 | */ | ||
| 987 | chan_sel <<= ffs(data->cd->chan_sel_mask) - 1; | ||
| 988 | |||
| 989 | return regmap_update_bits(data->regmap, data->cd->chan_sel_reg, | ||
| 990 | BU27008_MASK_CHAN_SEL, chan_sel); | ||
| 991 | } | ||
| 992 | |||
| 993 | static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev, | ||
| 994 | struct iio_chan_spec const *chan, int *val, int *val2) | ||
| 995 | { | ||
| 996 | int ret, int_time; | ||
| 997 | |||
| 998 | ret = bu27008_chan_cfg(data, chan); | ||
| 999 | if (ret) | ||
| 1000 | return ret; | ||
| 1001 | |||
| 1002 | ret = bu27008_meas_set(data, true); | ||
| 1003 | if (ret) | ||
| 1004 | return ret; | ||
| 1005 | |||
| 1006 | ret = bu27008_get_int_time_us(data); | ||
| 1007 | if (ret < 0) | ||
| 1008 | int_time = BU27008_MEAS_TIME_MAX_MS; | ||
| 1009 | else | ||
| 1010 | int_time = ret / USEC_PER_MSEC; | ||
| 1011 | |||
| 1012 | msleep(int_time); | ||
| 1013 | |||
| 1014 | ret = bu27008_chan_read_data(data, chan->address, val); | ||
| 1015 | if (!ret) | ||
| 1016 | ret = IIO_VAL_INT; | ||
| 1017 | |||
| 1018 | if (bu27008_meas_set(data, false)) | ||
| 1019 | dev_warn(data->dev, "measurement disabling failed\n"); | ||
| 1020 | |||
| 1021 | return ret; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | #define BU27008_LUX_DATA_RED 0 | ||
| 1025 | #define BU27008_LUX_DATA_GREEN 1 | ||
| 1026 | #define BU27008_LUX_DATA_BLUE 2 | ||
| 1027 | #define BU27008_LUX_DATA_IR 3 | ||
| 1028 | #define LUX_DATA_SIZE (BU27008_NUM_HW_CHANS * sizeof(__le16)) | ||
| 1029 | |||
| 1030 | static int bu27008_read_lux_chans(struct bu27008_data *data, unsigned int time, | ||
| 1031 | __le16 *chan_data) | ||
| 1032 | { | ||
| 1033 | int ret, chan_sel, tmpret, valid; | ||
| 1034 | |||
| 1035 | chan_sel = BU27008_BLUE2_IR3 << (ffs(data->cd->chan_sel_mask) - 1); | ||
| 1036 | |||
| 1037 | ret = regmap_update_bits(data->regmap, data->cd->chan_sel_reg, | ||
| 1038 | data->cd->chan_sel_mask, chan_sel); | ||
| 1039 | if (ret) | ||
| 1040 | return ret; | ||
| 1041 | |||
| 1042 | ret = bu27008_meas_set(data, true); | ||
| 1043 | if (ret) | ||
| 1044 | return ret; | ||
| 1045 | |||
| 1046 | msleep(time / USEC_PER_MSEC); | ||
| 1047 | |||
| 1048 | ret = regmap_read_poll_timeout(data->regmap, data->cd->valid_reg, | ||
| 1049 | valid, (valid & BU27008_MASK_VALID), | ||
| 1050 | BU27008_VALID_RESULT_WAIT_QUANTA_US, | ||
| 1051 | BU27008_MAX_VALID_RESULT_WAIT_US); | ||
| 1052 | if (ret) | ||
| 1053 | goto out; | ||
| 1054 | |||
| 1055 | ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, chan_data, | ||
| 1056 | LUX_DATA_SIZE); | ||
| 1057 | if (ret) | ||
| 1058 | goto out; | ||
| 1059 | out: | ||
| 1060 | tmpret = bu27008_meas_set(data, false); | ||
| 1061 | if (tmpret) | ||
| 1062 | dev_warn(data->dev, "Stopping measurement failed\n"); | ||
| 1063 | |||
| 1064 | return ret; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | /* | ||
| 1068 | * Following equation for computing lux out of register values was given by | ||
| 1069 | * ROHM HW colleagues; | ||
| 1070 | * | ||
| 1071 | * Red = RedData*1024 / Gain * 20 / meas_mode | ||
| 1072 | * Green = GreenData* 1024 / Gain * 20 / meas_mode | ||
| 1073 | * Blue = BlueData* 1024 / Gain * 20 / meas_mode | ||
| 1074 | * IR = IrData* 1024 / Gain * 20 / meas_mode | ||
| 1075 | * | ||
| 1076 | * where meas_mode is the integration time in mS / 10 | ||
| 1077 | * | ||
| 1078 | * IRratio = (IR > 0.18 * Green) ? 0 : 1 | ||
| 1079 | * | ||
| 1080 | * Lx = max(c1*Red + c2*Green + c3*Blue,0) | ||
| 1081 | * | ||
| 1082 | * for | ||
| 1083 | * IRratio 0: c1 = -0.00002237, c2 = 0.0003219, c3 = -0.000120371 | ||
| 1084 | * IRratio 1: c1 = -0.00001074, c2 = 0.000305415, c3 = -0.000129367 | ||
| 1085 | */ | ||
| 1086 | |||
| 1087 | /* | ||
| 1088 | * The max chan data is 0xffff. When we multiply it by 1024 * 20, we'll get | ||
| 1089 | * 0x4FFFB000 which still fits in 32-bit integer. This won't overflow. | ||
| 1090 | */ | ||
| 1091 | #define NORM_CHAN_DATA_FOR_LX_CALC(chan, gain, time) (le16_to_cpu(chan) * \ | ||
| 1092 | 1024 * 20 / (gain) / (time)) | ||
| 1093 | static u64 bu27008_calc_nlux(struct bu27008_data *data, __le16 *lux_data, | ||
| 1094 | unsigned int gain, unsigned int gain_ir, unsigned int time) | ||
| 1095 | { | ||
| 1096 | unsigned int red, green, blue, ir; | ||
| 1097 | s64 c1, c2, c3, nlux; | ||
| 1098 | |||
| 1099 | time /= 10000; | ||
| 1100 | ir = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_IR], gain_ir, time); | ||
| 1101 | red = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_RED], gain, time); | ||
| 1102 | green = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_GREEN], gain, time); | ||
| 1103 | blue = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_BLUE], gain, time); | ||
| 1104 | |||
| 1105 | if ((u64)ir * 100LLU > (u64)green * 18LLU) { | ||
| 1106 | c1 = -22370; | ||
| 1107 | c2 = 321900; | ||
| 1108 | c3 = -120371; | ||
| 1109 | } else { | ||
| 1110 | c1 = -10740; | ||
| 1111 | c2 = 305415; | ||
| 1112 | c3 = -129367; | ||
| 1113 | } | ||
| 1114 | nlux = c1 * red + c2 * green + c3 * blue; | ||
| 1115 | |||
| 1116 | return max_t(s64, 0, nlux); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | static int bu27008_get_time_n_gains(struct bu27008_data *data, | ||
| 1120 | unsigned int *gain, unsigned int *gain_ir, unsigned int *time) | ||
| 1121 | { | ||
| 1122 | int ret; | ||
| 1123 | |||
| 1124 | ret = bu27008_get_gain(data, &data->gts, gain); | ||
| 1125 | if (ret < 0) | ||
| 1126 | return ret; | ||
| 1127 | |||
| 1128 | ret = bu27008_get_gain(data, &data->gts_ir, gain_ir); | ||
| 1129 | if (ret < 0) | ||
| 1130 | return ret; | ||
| 1131 | |||
| 1132 | ret = bu27008_get_int_time_us(data); | ||
| 1133 | if (ret < 0) | ||
| 1134 | return ret; | ||
| 1135 | |||
| 1136 | /* Max integration time is 400000. Fits in signed int. */ | ||
| 1137 | *time = ret; | ||
| 1138 | |||
| 1139 | return 0; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | struct bu27008_buf { | ||
| 1143 | __le16 chan[BU27008_NUM_HW_CHANS]; | ||
| 1144 | u64 lux __aligned(8); | ||
| 1145 | s64 ts __aligned(8); | ||
| 1146 | }; | ||
| 1147 | |||
| 1148 | static int bu27008_buffer_fill_lux(struct bu27008_data *data, | ||
| 1149 | struct bu27008_buf *raw) | ||
| 1150 | { | ||
| 1151 | unsigned int gain, gain_ir, time; | ||
| 1152 | int ret; | ||
| 1153 | |||
| 1154 | ret = bu27008_get_time_n_gains(data, &gain, &gain_ir, &time); | ||
| 1155 | if (ret) | ||
| 1156 | return ret; | ||
| 1157 | |||
| 1158 | raw->lux = bu27008_calc_nlux(data, raw->chan, gain, gain_ir, time); | ||
| 1159 | |||
| 1160 | return 0; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | static int bu27008_read_lux(struct bu27008_data *data, struct iio_dev *idev, | ||
| 1164 | struct iio_chan_spec const *chan, | ||
| 1165 | int *val, int *val2) | ||
| 1166 | { | ||
| 1167 | __le16 lux_data[BU27008_NUM_HW_CHANS]; | ||
| 1168 | unsigned int gain, gain_ir, time; | ||
| 1169 | u64 nlux; | ||
| 1170 | int ret; | ||
| 1171 | |||
| 1172 | ret = bu27008_get_time_n_gains(data, &gain, &gain_ir, &time); | ||
| 1173 | if (ret) | ||
| 1174 | return ret; | ||
| 1175 | |||
| 1176 | ret = bu27008_read_lux_chans(data, time, lux_data); | ||
| 1177 | if (ret) | ||
| 1178 | return ret; | ||
| 1179 | |||
| 1180 | nlux = bu27008_calc_nlux(data, lux_data, gain, gain_ir, time); | ||
| 1181 | *val = (int)nlux; | ||
| 1182 | *val2 = nlux >> 32LLU; | ||
| 1183 | |||
| 1184 | return IIO_VAL_INT_64; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | static int bu27008_read_raw(struct iio_dev *idev, | ||
| 1188 | struct iio_chan_spec const *chan, | ||
| 1189 | int *val, int *val2, long mask) | ||
| 1190 | { | ||
| 1191 | struct bu27008_data *data = iio_priv(idev); | ||
| 1192 | int busy, ret; | ||
| 1193 | |||
| 1194 | switch (mask) { | ||
| 1195 | case IIO_CHAN_INFO_RAW: | ||
| 1196 | busy = iio_device_claim_direct_mode(idev); | ||
| 1197 | if (busy) | ||
| 1198 | return -EBUSY; | ||
| 1199 | |||
| 1200 | mutex_lock(&data->mutex); | ||
| 1201 | if (chan->type == IIO_LIGHT) | ||
| 1202 | ret = bu27008_read_lux(data, idev, chan, val, val2); | ||
| 1203 | else | ||
| 1204 | ret = bu27008_read_one(data, idev, chan, val, val2); | ||
| 1205 | mutex_unlock(&data->mutex); | ||
| 1206 | |||
| 1207 | iio_device_release_direct_mode(idev); | ||
| 1208 | |||
| 1209 | return ret; | ||
| 1210 | |||
| 1211 | case IIO_CHAN_INFO_SCALE: | ||
| 1212 | if (chan->type == IIO_LIGHT) { | ||
| 1213 | *val = 0; | ||
| 1214 | *val2 = 1; | ||
| 1215 | return IIO_VAL_INT_PLUS_NANO; | ||
| 1216 | } | ||
| 1217 | ret = bu27008_get_scale(data, chan->scan_index == BU27008_IR, | ||
| 1218 | val, val2); | ||
| 1219 | if (ret) | ||
| 1220 | return ret; | ||
| 1221 | |||
| 1222 | return IIO_VAL_INT_PLUS_NANO; | ||
| 1223 | |||
| 1224 | case IIO_CHAN_INFO_INT_TIME: | ||
| 1225 | ret = bu27008_get_int_time_us(data); | ||
| 1226 | if (ret < 0) | ||
| 1227 | return ret; | ||
| 1228 | |||
| 1229 | *val = 0; | ||
| 1230 | *val2 = ret; | ||
| 1231 | |||
| 1232 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 1233 | |||
| 1234 | default: | ||
| 1235 | return -EINVAL; | ||
| 1236 | } | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | /* Called if the new scale could not be supported with existing int-time */ | ||
| 1240 | static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val, | ||
| 1241 | int val2, int *gain_sel) | ||
| 1242 | { | ||
| 1243 | int i, ret, new_time_sel; | ||
| 1244 | |||
| 1245 | for (i = 0; i < data->gts.num_itime; i++) { | ||
| 1246 | new_time_sel = data->gts.itime_table[i].sel; | ||
| 1247 | ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, | ||
| 1248 | new_time_sel, val, val2, gain_sel); | ||
| 1249 | if (!ret) | ||
| 1250 | break; | ||
| 1251 | } | ||
| 1252 | if (i == data->gts.num_itime) { | ||
| 1253 | dev_err(data->dev, "Can't support scale %u %u\n", val, val2); | ||
| 1254 | |||
| 1255 | return -EINVAL; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | return bu27008_set_int_time_sel(data, new_time_sel); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | static int bu27008_set_scale(struct bu27008_data *data, | ||
| 1262 | struct iio_chan_spec const *chan, | ||
| 1263 | int val, int val2) | ||
| 1264 | { | ||
| 1265 | int ret, gain_sel, time_sel; | ||
| 1266 | |||
| 1267 | if (chan->scan_index == BU27008_IR) | ||
| 1268 | return -EINVAL; | ||
| 1269 | |||
| 1270 | mutex_lock(&data->mutex); | ||
| 1271 | |||
| 1272 | ret = bu27008_get_int_time_sel(data, &time_sel); | ||
| 1273 | if (ret < 0) | ||
| 1274 | goto unlock_out; | ||
| 1275 | |||
| 1276 | ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, | ||
| 1277 | val, val2, &gain_sel); | ||
| 1278 | if (ret) { | ||
| 1279 | ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel); | ||
| 1280 | if (ret) | ||
| 1281 | goto unlock_out; | ||
| 1282 | |||
| 1283 | } | ||
| 1284 | ret = data->cd->write_gain_sel(data, gain_sel); | ||
| 1285 | |||
| 1286 | unlock_out: | ||
| 1287 | mutex_unlock(&data->mutex); | ||
| 1288 | |||
| 1289 | return ret; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | static int bu27008_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 1293 | struct iio_chan_spec const *chan, | ||
| 1294 | long mask) | ||
| 1295 | { | ||
| 1296 | |||
| 1297 | switch (mask) { | ||
| 1298 | case IIO_CHAN_INFO_SCALE: | ||
| 1299 | return IIO_VAL_INT_PLUS_NANO; | ||
| 1300 | case IIO_CHAN_INFO_INT_TIME: | ||
| 1301 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 1302 | default: | ||
| 1303 | return -EINVAL; | ||
| 1304 | } | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | static int bu27008_write_raw(struct iio_dev *idev, | ||
| 1308 | struct iio_chan_spec const *chan, | ||
| 1309 | int val, int val2, long mask) | ||
| 1310 | { | ||
| 1311 | struct bu27008_data *data = iio_priv(idev); | ||
| 1312 | int ret; | ||
| 1313 | |||
| 1314 | /* | ||
| 1315 | * Do not allow changing scale when measurement is ongoing as doing so | ||
| 1316 | * could make values in the buffer inconsistent. | ||
| 1317 | */ | ||
| 1318 | ret = iio_device_claim_direct_mode(idev); | ||
| 1319 | if (ret) | ||
| 1320 | return ret; | ||
| 1321 | |||
| 1322 | switch (mask) { | ||
| 1323 | case IIO_CHAN_INFO_SCALE: | ||
| 1324 | ret = bu27008_set_scale(data, chan, val, val2); | ||
| 1325 | break; | ||
| 1326 | case IIO_CHAN_INFO_INT_TIME: | ||
| 1327 | if (val) { | ||
| 1328 | ret = -EINVAL; | ||
| 1329 | break; | ||
| 1330 | } | ||
| 1331 | ret = bu27008_try_set_int_time(data, val2); | ||
| 1332 | break; | ||
| 1333 | default: | ||
| 1334 | ret = -EINVAL; | ||
| 1335 | break; | ||
| 1336 | } | ||
| 1337 | iio_device_release_direct_mode(idev); | ||
| 1338 | |||
| 1339 | return ret; | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | static int bu27008_read_avail(struct iio_dev *idev, | ||
| 1343 | struct iio_chan_spec const *chan, const int **vals, | ||
| 1344 | int *type, int *length, long mask) | ||
| 1345 | { | ||
| 1346 | struct bu27008_data *data = iio_priv(idev); | ||
| 1347 | |||
| 1348 | switch (mask) { | ||
| 1349 | case IIO_CHAN_INFO_INT_TIME: | ||
| 1350 | return iio_gts_avail_times(&data->gts, vals, type, length); | ||
| 1351 | case IIO_CHAN_INFO_SCALE: | ||
| 1352 | if (chan->channel2 == IIO_MOD_LIGHT_IR) | ||
| 1353 | return iio_gts_all_avail_scales(&data->gts_ir, vals, | ||
| 1354 | type, length); | ||
| 1355 | return iio_gts_all_avail_scales(&data->gts, vals, type, length); | ||
| 1356 | default: | ||
| 1357 | return -EINVAL; | ||
| 1358 | } | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | static int bu27008_update_scan_mode(struct iio_dev *idev, | ||
| 1362 | const unsigned long *scan_mask) | ||
| 1363 | { | ||
| 1364 | struct bu27008_data *data = iio_priv(idev); | ||
| 1365 | int chan_sel; | ||
| 1366 | |||
| 1367 | /* Configure channel selection */ | ||
| 1368 | if (test_bit(BU27008_BLUE, idev->active_scan_mask)) { | ||
| 1369 | if (test_bit(BU27008_CLEAR, idev->active_scan_mask)) | ||
| 1370 | chan_sel = BU27008_BLUE2_CLEAR3; | ||
| 1371 | else | ||
| 1372 | chan_sel = BU27008_BLUE2_IR3; | ||
| 1373 | } else { | ||
| 1374 | chan_sel = BU27008_CLEAR2_IR3; | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | chan_sel <<= ffs(data->cd->chan_sel_mask) - 1; | ||
| 1378 | |||
| 1379 | return regmap_update_bits(data->regmap, data->cd->chan_sel_reg, | ||
| 1380 | data->cd->chan_sel_mask, chan_sel); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | static const struct iio_info bu27008_info = { | ||
| 1384 | .read_raw = &bu27008_read_raw, | ||
| 1385 | .write_raw = &bu27008_write_raw, | ||
| 1386 | .write_raw_get_fmt = &bu27008_write_raw_get_fmt, | ||
| 1387 | .read_avail = &bu27008_read_avail, | ||
| 1388 | .update_scan_mode = bu27008_update_scan_mode, | ||
| 1389 | .validate_trigger = iio_validate_own_trigger, | ||
| 1390 | }; | ||
| 1391 | |||
| 1392 | static int bu27008_trigger_set_state(struct iio_trigger *trig, bool state) | ||
| 1393 | { | ||
| 1394 | struct bu27008_data *data = iio_trigger_get_drvdata(trig); | ||
| 1395 | int ret; | ||
| 1396 | |||
| 1397 | |||
| 1398 | if (state) | ||
| 1399 | ret = regmap_set_bits(data->regmap, data->cd->drdy_en_reg, | ||
| 1400 | data->cd->drdy_en_mask); | ||
| 1401 | else | ||
| 1402 | ret = regmap_clear_bits(data->regmap, data->cd->drdy_en_reg, | ||
| 1403 | data->cd->drdy_en_mask); | ||
| 1404 | if (ret) | ||
| 1405 | dev_err(data->dev, "Failed to set trigger state\n"); | ||
| 1406 | |||
| 1407 | return ret; | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | static void bu27008_trigger_reenable(struct iio_trigger *trig) | ||
| 1411 | { | ||
| 1412 | struct bu27008_data *data = iio_trigger_get_drvdata(trig); | ||
| 1413 | |||
| 1414 | enable_irq(data->irq); | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | static const struct iio_trigger_ops bu27008_trigger_ops = { | ||
| 1418 | .set_trigger_state = bu27008_trigger_set_state, | ||
| 1419 | .reenable = bu27008_trigger_reenable, | ||
| 1420 | }; | ||
| 1421 | |||
| 1422 | static irqreturn_t bu27008_trigger_handler(int irq, void *p) | ||
| 1423 | { | ||
| 1424 | struct iio_poll_func *pf = p; | ||
| 1425 | struct iio_dev *idev = pf->indio_dev; | ||
| 1426 | struct bu27008_data *data = iio_priv(idev); | ||
| 1427 | struct bu27008_buf raw; | ||
| 1428 | int ret, dummy; | ||
| 1429 | |||
| 1430 | memset(&raw, 0, sizeof(raw)); | ||
| 1431 | |||
| 1432 | /* | ||
| 1433 | * After some measurements, it seems reading the | ||
| 1434 | * BU27008_REG_MODE_CONTROL3 debounces the IRQ line | ||
| 1435 | */ | ||
| 1436 | ret = regmap_read(data->regmap, data->cd->valid_reg, &dummy); | ||
| 1437 | if (ret < 0) | ||
| 1438 | goto err_read; | ||
| 1439 | |||
| 1440 | ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, &raw.chan, | ||
| 1441 | sizeof(raw.chan)); | ||
| 1442 | if (ret < 0) | ||
| 1443 | goto err_read; | ||
| 1444 | |||
| 1445 | if (test_bit(BU27008_LUX, idev->active_scan_mask)) { | ||
| 1446 | ret = bu27008_buffer_fill_lux(data, &raw); | ||
| 1447 | if (ret) | ||
| 1448 | goto err_read; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp); | ||
| 1452 | err_read: | ||
| 1453 | iio_trigger_notify_done(idev->trig); | ||
| 1454 | |||
| 1455 | return IRQ_HANDLED; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | static int bu27008_buffer_preenable(struct iio_dev *idev) | ||
| 1459 | { | ||
| 1460 | struct bu27008_data *data = iio_priv(idev); | ||
| 1461 | |||
| 1462 | return bu27008_meas_set(data, true); | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | static int bu27008_buffer_postdisable(struct iio_dev *idev) | ||
| 1466 | { | ||
| 1467 | struct bu27008_data *data = iio_priv(idev); | ||
| 1468 | |||
| 1469 | return bu27008_meas_set(data, false); | ||
| 1470 | } | ||
| 1471 | |||
| 1472 | static const struct iio_buffer_setup_ops bu27008_buffer_ops = { | ||
| 1473 | .preenable = bu27008_buffer_preenable, | ||
| 1474 | .postdisable = bu27008_buffer_postdisable, | ||
| 1475 | }; | ||
| 1476 | |||
| 1477 | static irqreturn_t bu27008_data_rdy_poll(int irq, void *private) | ||
| 1478 | { | ||
| 1479 | /* | ||
| 1480 | * The BU27008 keeps IRQ asserted until we read the VALID bit from | ||
| 1481 | * a register. We need to keep the IRQ disabled until then. | ||
| 1482 | */ | ||
| 1483 | disable_irq_nosync(irq); | ||
| 1484 | iio_trigger_poll(private); | ||
| 1485 | |||
| 1486 | return IRQ_HANDLED; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | static int bu27008_setup_trigger(struct bu27008_data *data, struct iio_dev *idev) | ||
| 1490 | { | ||
| 1491 | struct iio_trigger *itrig; | ||
| 1492 | char *name; | ||
| 1493 | int ret; | ||
| 1494 | |||
| 1495 | ret = devm_iio_triggered_buffer_setup(data->dev, idev, | ||
| 1496 | &iio_pollfunc_store_time, | ||
| 1497 | bu27008_trigger_handler, | ||
| 1498 | &bu27008_buffer_ops); | ||
| 1499 | if (ret) | ||
| 1500 | return dev_err_probe(data->dev, ret, | ||
| 1501 | "iio_triggered_buffer_setup_ext FAIL\n"); | ||
| 1502 | |||
| 1503 | itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d", | ||
| 1504 | idev->name, iio_device_id(idev)); | ||
| 1505 | if (!itrig) | ||
| 1506 | return -ENOMEM; | ||
| 1507 | |||
| 1508 | data->trig = itrig; | ||
| 1509 | |||
| 1510 | itrig->ops = &bu27008_trigger_ops; | ||
| 1511 | iio_trigger_set_drvdata(itrig, data); | ||
| 1512 | |||
| 1513 | name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bu27008", | ||
| 1514 | dev_name(data->dev)); | ||
| 1515 | |||
| 1516 | ret = devm_request_irq(data->dev, data->irq, | ||
| 1517 | &bu27008_data_rdy_poll, | ||
| 1518 | 0, name, itrig); | ||
| 1519 | if (ret) | ||
| 1520 | return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); | ||
| 1521 | |||
| 1522 | ret = devm_iio_trigger_register(data->dev, itrig); | ||
| 1523 | if (ret) | ||
| 1524 | return dev_err_probe(data->dev, ret, | ||
| 1525 | "Trigger registration failed\n"); | ||
| 1526 | |||
| 1527 | /* set default trigger */ | ||
| 1528 | idev->trig = iio_trigger_get(itrig); | ||
| 1529 | |||
| 1530 | return 0; | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | static int bu27008_probe(struct i2c_client *i2c) | ||
| 1534 | { | ||
| 1535 | struct device *dev = &i2c->dev; | ||
| 1536 | struct bu27008_data *data; | ||
| 1537 | struct regmap *regmap; | ||
| 1538 | unsigned int part_id, reg; | ||
| 1539 | struct iio_dev *idev; | ||
| 1540 | int ret; | ||
| 1541 | |||
| 1542 | idev = devm_iio_device_alloc(dev, sizeof(*data)); | ||
| 1543 | if (!idev) | ||
| 1544 | return -ENOMEM; | ||
| 1545 | |||
| 1546 | ret = devm_regulator_get_enable(dev, "vdd"); | ||
| 1547 | if (ret) | ||
| 1548 | return dev_err_probe(dev, ret, "Failed to get regulator\n"); | ||
| 1549 | |||
| 1550 | data = iio_priv(idev); | ||
| 1551 | |||
| 1552 | data->cd = device_get_match_data(&i2c->dev); | ||
| 1553 | if (!data->cd) | ||
| 1554 | return -ENODEV; | ||
| 1555 | |||
| 1556 | regmap = devm_regmap_init_i2c(i2c, data->cd->regmap_cfg); | ||
| 1557 | if (IS_ERR(regmap)) | ||
| 1558 | return dev_err_probe(dev, PTR_ERR(regmap), | ||
| 1559 | "Failed to initialize Regmap\n"); | ||
| 1560 | |||
| 1561 | |||
| 1562 | ret = regmap_read(regmap, BU27008_REG_SYSTEM_CONTROL, ®); | ||
| 1563 | if (ret) | ||
| 1564 | return dev_err_probe(dev, ret, "Failed to access sensor\n"); | ||
| 1565 | |||
| 1566 | part_id = FIELD_GET(BU27008_MASK_PART_ID, reg); | ||
| 1567 | |||
| 1568 | if (part_id != data->cd->part_id) | ||
| 1569 | dev_warn(dev, "unknown device 0x%x\n", part_id); | ||
| 1570 | |||
| 1571 | ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains, | ||
| 1572 | data->cd->num_gains, data->cd->itimes, | ||
| 1573 | data->cd->num_itimes, &data->gts); | ||
| 1574 | if (ret) | ||
| 1575 | return ret; | ||
| 1576 | |||
| 1577 | ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains_ir, | ||
| 1578 | data->cd->num_gains_ir, data->cd->itimes, | ||
| 1579 | data->cd->num_itimes, &data->gts_ir); | ||
| 1580 | if (ret) | ||
| 1581 | return ret; | ||
| 1582 | |||
| 1583 | mutex_init(&data->mutex); | ||
| 1584 | data->regmap = regmap; | ||
| 1585 | data->dev = dev; | ||
| 1586 | data->irq = i2c->irq; | ||
| 1587 | |||
| 1588 | idev->channels = bu27008_channels; | ||
| 1589 | idev->num_channels = ARRAY_SIZE(bu27008_channels); | ||
| 1590 | idev->name = data->cd->name; | ||
| 1591 | idev->info = &bu27008_info; | ||
| 1592 | idev->modes = INDIO_DIRECT_MODE; | ||
| 1593 | idev->available_scan_masks = bu27008_scan_masks; | ||
| 1594 | |||
| 1595 | ret = data->cd->chip_init(data); | ||
| 1596 | if (ret) | ||
| 1597 | return ret; | ||
| 1598 | |||
| 1599 | if (i2c->irq) { | ||
| 1600 | ret = bu27008_setup_trigger(data, idev); | ||
| 1601 | if (ret) | ||
| 1602 | return ret; | ||
| 1603 | } else { | ||
| 1604 | dev_info(dev, "No IRQ, buffered mode disabled\n"); | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | ret = devm_iio_device_register(dev, idev); | ||
| 1608 | if (ret) | ||
| 1609 | return dev_err_probe(dev, ret, | ||
| 1610 | "Unable to register iio device\n"); | ||
| 1611 | |||
| 1612 | return 0; | ||
| 1613 | } | ||
| 1614 | |||
| 1615 | static const struct of_device_id bu27008_of_match[] = { | ||
| 1616 | { .compatible = "rohm,bu27008", .data = &bu27008_chip }, | ||
| 1617 | { .compatible = "rohm,bu27010", .data = &bu27010_chip }, | ||
| 1618 | { } | ||
| 1619 | }; | ||
| 1620 | MODULE_DEVICE_TABLE(of, bu27008_of_match); | ||
| 1621 | |||
| 1622 | static struct i2c_driver bu27008_i2c_driver = { | ||
| 1623 | .driver = { | ||
| 1624 | .name = "bu27008", | ||
| 1625 | .of_match_table = bu27008_of_match, | ||
| 1626 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
| 1627 | }, | ||
| 1628 | .probe = bu27008_probe, | ||
| 1629 | }; | ||
| 1630 | module_i2c_driver(bu27008_i2c_driver); | ||
| 1631 | |||
| 1632 | MODULE_DESCRIPTION("ROHM BU27008 and BU27010 colour sensor driver"); | ||
| 1633 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | ||
| 1634 | MODULE_LICENSE("GPL"); | ||
| 1635 | MODULE_IMPORT_NS("IIO_GTS_HELPER"); | ||
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | #include <linux/bitfield.h> | 8 | #include <linux/bitfield.h> |
| 9 | #include <linux/bits.h> | 9 | #include <linux/bits.h> |
| 10 | #include <linux/cleanup.h> | ||
| 10 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 11 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| @@ -205,7 +206,7 @@ struct bu27034_data { · 192 unmodified lines | |||
| 205 | struct { | 206 | struct { |
| 206 | u32 mlux; | 207 | u32 mlux; |
| 207 | __le16 channels[BU27034_NUM_HW_DATA_CHANS]; | 208 | __le16 channels[BU27034_NUM_HW_DATA_CHANS]; |
| 208 | s64 ts __aligned(8); | 209 | aligned_s64 ts; |
| 209 | } scan; | 210 | } scan; |
| 210 | }; | 211 | }; |
| 211 | 212 | ||
| @@ -395,30 +396,26 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) · 183 unmodified lines | |||
| 395 | int numg = ARRAY_SIZE(gains); | 396 | int numg = ARRAY_SIZE(gains); |
| 396 | int ret, int_time_old, i; | 397 | int ret, int_time_old, i; |
| 397 | 398 | ||
| 398 | mutex_lock(&data->mutex); | 399 | guard(mutex)(&data->mutex); |
| 399 | ret = bu27034_get_int_time(data); | 400 | ret = bu27034_get_int_time(data); |
| 400 | if (ret < 0) | 401 | if (ret < 0) |
| 401 | goto unlock_out; | 402 | return ret; |
| 402 | 403 | ||
| 403 | int_time_old = ret; | 404 | int_time_old = ret; |
| 404 | 405 | ||
| 405 | if (!iio_gts_valid_time(&data->gts, time_us)) { | 406 | if (!iio_gts_valid_time(&data->gts, time_us)) { |
| 406 | dev_err(data->dev, "Unsupported integration time %u\n", | 407 | dev_err(data->dev, "Unsupported integration time %u\n", |
| 407 | time_us); | 408 | time_us); |
| 408 | ret = -EINVAL; | 409 | return -EINVAL; |
| 409 | |||
| 410 | goto unlock_out; | ||
| 411 | } | 410 | } |
| 412 | 411 | ||
| 413 | if (time_us == int_time_old) { | 412 | if (time_us == int_time_old) |
| 414 | ret = 0; | 413 | return 0; |
| 415 | goto unlock_out; | ||
| 416 | } | ||
| 417 | 414 | ||
| 418 | for (i = 0; i < numg; i++) { | 415 | for (i = 0; i < numg; i++) { |
| 419 | ret = bu27034_get_gain(data, gains[i].chan, &gains[i].old_gain); | 416 | ret = bu27034_get_gain(data, gains[i].chan, &gains[i].old_gain); |
| 420 | if (ret) | 417 | if (ret) |
| 421 | goto unlock_out; | 418 | return 0; |
| 422 | 419 | ||
| 423 | ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, | 420 | ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, |
| 424 | gains[i].old_gain, | 421 | gains[i].old_gain, |
| @@ -434,7 +431,7 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) · 9 unmodified lines | |||
| 434 | gains[i].chan, time_us, scale1, scale2); | 431 | gains[i].chan, time_us, scale1, scale2); |
| 435 | 432 | ||
| 436 | if (gains[i].new_gain < 0) | 433 | if (gains[i].new_gain < 0) |
| 437 | goto unlock_out; | 434 | return ret; |
| 438 | 435 | ||
| 439 | /* | 436 | /* |
| 440 | * If caller requests for integration time change and we | 437 | * If caller requests for integration time change and we |
| @@ -455,7 +452,7 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) · 14 unmodified lines | |||
| 455 | "Total gain increase. Risk of saturation"); | 452 | "Total gain increase. Risk of saturation"); |
| 456 | ret = iio_gts_get_min_gain(&data->gts); | 453 | ret = iio_gts_get_min_gain(&data->gts); |
| 457 | if (ret < 0) | 454 | if (ret < 0) |
| 458 | goto unlock_out; | 455 | return ret; |
| 459 | } | 456 | } |
| 460 | dev_dbg(data->dev, "chan %u scale changed\n", | 457 | dev_dbg(data->dev, "chan %u scale changed\n", |
| 461 | gains[i].chan); | 458 | gains[i].chan); |
| @@ -468,15 +465,10 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) · 6 unmodified lines | |||
| 468 | for (i = 0; i < numg; i++) { | 465 | for (i = 0; i < numg; i++) { |
| 469 | ret = bu27034_set_gain(data, gains[i].chan, gains[i].new_gain); | 466 | ret = bu27034_set_gain(data, gains[i].chan, gains[i].new_gain); |
| 470 | if (ret) | 467 | if (ret) |
| 471 | goto unlock_out; | 468 | return ret; |
| 472 | } | 469 | } |
| 473 | 470 | ||
| 474 | ret = bu27034_set_int_time(data, time_us); | 471 | return bu27034_set_int_time(data, time_us); |
| 475 | |||
| 476 | unlock_out: | ||
| 477 | mutex_unlock(&data->mutex); | ||
| 478 | |||
| 479 | return ret; | ||
| 480 | } | 472 | } |
| 481 | 473 | ||
| 482 | static int bu27034_set_scale(struct bu27034_data *data, int chan, | 474 | static int bu27034_set_scale(struct bu27034_data *data, int chan, |
| @@ -492,10 +484,10 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, · 9 unmodified lines | |||
| 492 | return -EINVAL; | 484 | return -EINVAL; |
| 493 | } | 485 | } |
| 494 | 486 | ||
| 495 | mutex_lock(&data->mutex); | 487 | guard(mutex)(&data->mutex); |
| 496 | ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel); | 488 | ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel); |
| 497 | if (ret) | 489 | if (ret) |
| 498 | goto unlock_out; | 490 | return ret; |
| 499 | 491 | ||
| 500 | ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, | 492 | ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, |
| 501 | val, val2, &gain_sel); | 493 | val, val2, &gain_sel); |
| @@ -518,7 +510,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, · 16 unmodified lines | |||
| 518 | 510 | ||
| 519 | ret = bu27034_get_gain(data, gain.chan, &gain.old_gain); | 511 | ret = bu27034_get_gain(data, gain.chan, &gain.old_gain); |
| 520 | if (ret) | 512 | if (ret) |
| 521 | goto unlock_out; | 513 | return ret; |
| 522 | 514 | ||
| 523 | /* | 515 | /* |
| 524 | * Iterate through all the times to see if we find one which | 516 | * Iterate through all the times to see if we find one which |
| @@ -551,26 +543,20 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan, · 26 unmodified lines | |||
| 551 | if (!found) { | 543 | if (!found) { |
| 552 | dev_dbg(data->dev, | 544 | dev_dbg(data->dev, |
| 553 | "Can't set scale maintaining other channel\n"); | 545 | "Can't set scale maintaining other channel\n"); |
| 554 | ret = -EINVAL; | 546 | return -EINVAL; |
| 555 | |||
| 556 | goto unlock_out; | ||
| 557 | } | 547 | } |
| 558 | 548 | ||
| 559 | ret = bu27034_set_gain(data, gain.chan, gain.new_gain); | 549 | ret = bu27034_set_gain(data, gain.chan, gain.new_gain); |
| 560 | if (ret) | 550 | if (ret) |
| 561 | goto unlock_out; | 551 | return ret; |
| 562 | 552 | ||
| 563 | ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, | 553 | ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, |
| 564 | BU27034_MASK_MEAS_MODE, new_time_sel); | 554 | BU27034_MASK_MEAS_MODE, new_time_sel); |
| 565 | if (ret) | 555 | if (ret) |
| 566 | goto unlock_out; | 556 | return ret; |
| 567 | } | 557 | } |
| 568 | 558 | ||
| 569 | ret = bu27034_write_gain_sel(data, chan, gain_sel); | 559 | return bu27034_write_gain_sel(data, chan, gain_sel); |
| 570 | unlock_out: | ||
| 571 | mutex_unlock(&data->mutex); | ||
| 572 | |||
| 573 | return ret; | ||
| 574 | } | 560 | } |
| 575 | 561 | ||
| 576 | /* | 562 | /* |
| @@ -1221,42 +1207,33 @@ static int bu27034_buffer_enable(struct iio_dev *idev) · 644 unmodified lines | |||
| 1221 | struct task_struct *task; | 1207 | struct task_struct *task; |
| 1222 | int ret; | 1208 | int ret; |
| 1223 | 1209 | ||
| 1224 | mutex_lock(&data->mutex); | 1210 | guard(mutex)(&data->mutex); |
| 1225 | ret = bu27034_meas_set(data, true); | 1211 | ret = bu27034_meas_set(data, true); |
| 1226 | if (ret) | 1212 | if (ret) |
| 1227 | goto unlock_out; | 1213 | return ret; |
| 1228 | 1214 | ||
| 1229 | task = kthread_run(bu27034_buffer_thread, idev, | 1215 | task = kthread_run(bu27034_buffer_thread, idev, |
| 1230 | "bu27034-buffering-%u", | 1216 | "bu27034-buffering-%u", |
| 1231 | iio_device_id(idev)); | 1217 | iio_device_id(idev)); |
| 1232 | if (IS_ERR(task)) { | 1218 | if (IS_ERR(task)) |
| 1233 | ret = PTR_ERR(task); | 1219 | return PTR_ERR(task); |
| 1234 | goto unlock_out; | ||
| 1235 | } | ||
| 1236 | 1220 | ||
| 1237 | data->task = task; | 1221 | data->task = task; |
| 1238 | 1222 | ||
| 1239 | unlock_out: | 1223 | return 0; |
| 1240 | mutex_unlock(&data->mutex); | ||
| 1241 | |||
| 1242 | return ret; | ||
| 1243 | } | 1224 | } |
| 1244 | 1225 | ||
| 1245 | static int bu27034_buffer_disable(struct iio_dev *idev) | 1226 | static int bu27034_buffer_disable(struct iio_dev *idev) |
| 1246 | { | 1227 | { |
| 1247 | struct bu27034_data *data = iio_priv(idev); | 1228 | struct bu27034_data *data = iio_priv(idev); |
| 1248 | int ret; | ||
| 1249 | 1229 | ||
| 1250 | mutex_lock(&data->mutex); | 1230 | guard(mutex)(&data->mutex); |
| 1251 | if (data->task) { | 1231 | if (data->task) { |
| 1252 | kthread_stop(data->task); | 1232 | kthread_stop(data->task); |
| 1253 | data->task = NULL; | 1233 | data->task = NULL; |
| 1254 | } | 1234 | } |
| 1255 | 1235 | ||
| 1256 | ret = bu27034_meas_set(data, false); | 1236 | return bu27034_meas_set(data, false); |
| 1257 | mutex_unlock(&data->mutex); | ||
| 1258 | |||
| 1259 | return ret; | ||
| 1260 | } | 1237 | } |
| 1261 | 1238 | ||
| 1262 | static const struct iio_buffer_setup_ops bu27034_buffer_ops = { | 1239 | static const struct iio_buffer_setup_ops bu27034_buffer_ops = { |
| @@ -203,7 +203,7 @@ struct rpr0521_data { · 202 unmodified lines | |||
| 203 | struct { | 203 | struct { |
| 204 | __le16 channels[3]; | 204 | __le16 channels[3]; |
| 205 | u8 garbage; | 205 | u8 garbage; |
| 206 | s64 ts __aligned(8); | 206 | aligned_s64 ts; |
| 207 | } scan; | 207 | } scan; |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| @@ -30,7 +30,7 @@ struct st_uvis25_hw { · 29 unmodified lines | |||
| 30 | /* Ensure timestamp is naturally aligned */ | 30 | /* Ensure timestamp is naturally aligned */ |
| 31 | struct { | 31 | struct { |
| 32 | u8 chan; | 32 | u8 chan; |
| 33 | s64 ts __aligned(8); | 33 | aligned_s64 ts; |
| 34 | } scan; | 34 | } scan; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| @@ -56,7 +56,7 @@ struct tcs3414_data { · 55 unmodified lines | |||
| 56 | /* Ensure timestamp is naturally aligned */ | 56 | /* Ensure timestamp is naturally aligned */ |
| 57 | struct { | 57 | struct { |
| 58 | u16 chans[4]; | 58 | u16 chans[4]; |
| 59 | s64 timestamp __aligned(8); | 59 | aligned_s64 timestamp; |
| 60 | } scan; | 60 | } scan; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| @@ -67,7 +67,7 @@ struct tcs3472_data { · 66 unmodified lines | |||
| 67 | /* Ensure timestamp is naturally aligned */ | 67 | /* Ensure timestamp is naturally aligned */ |
| 68 | struct { | 68 | struct { |
| 69 | u16 chans[4]; | 69 | u16 chans[4]; |
| 70 | s64 timestamp __aligned(8); | 70 | aligned_s64 timestamp; |
| 71 | } scan; | 71 | } scan; |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| 12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
| 13 | #include <linux/iio/iio.h> | 13 | #include <linux/iio/iio.h> |
| 14 | #include <linux/iio/iio-gts-helper.h> | ||
| 14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 15 | #include <linux/pm_runtime.h> | 16 | #include <linux/pm_runtime.h> |
| 16 | #include <linux/regmap.h> | 17 | #include <linux/regmap.h> |
| @@ -35,17 +36,33 @@ struct veml3235_data { · 18 unmodified lines | |||
| 35 | struct device *dev; | 36 | struct device *dev; |
| 36 | struct regmap *regmap; | 37 | struct regmap *regmap; |
| 37 | struct veml3235_rf rf; | 38 | struct veml3235_rf rf; |
| 39 | struct iio_gts gts; | ||
| 38 | }; | 40 | }; |
| 39 | 41 | ||
| 40 | static const int veml3235_it_times[][2] = { | 42 | static const struct iio_itime_sel_mul veml3235_it_sel[] = { |
| 41 | { 0, 50000 }, | 43 | GAIN_SCALE_ITIME_US(50000, 0, 1), |
| 42 | { 0, 100000 }, | 44 | GAIN_SCALE_ITIME_US(100000, 1, 2), |
| 43 | { 0, 200000 }, | 45 | GAIN_SCALE_ITIME_US(200000, 2, 4), |
| 44 | { 0, 400000 }, | 46 | GAIN_SCALE_ITIME_US(400000, 3, 8), |
| 45 | { 0, 800000 }, | 47 | GAIN_SCALE_ITIME_US(800000, 4, 16), |
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 48 | static const int veml3235_scale_vals[] = { 1, 2, 4, 8 }; | 50 | /* |
| 51 | * The MSB (DG) doubles the value of the rest of the field, which leads to | ||
| 52 | * two possible combinations to obtain gain = 2 and gain = 4. The gain | ||
| 53 | * handling can be simplified by restricting DG = 1 to the only gain that | ||
| 54 | * really requires it, gain = 8. Note that "X10" is a reserved value. | ||
| 55 | */ | ||
| 56 | #define VEML3235_SEL_GAIN_X1 0 | ||
| 57 | #define VEML3235_SEL_GAIN_X2 1 | ||
| 58 | #define VEML3235_SEL_GAIN_X4 3 | ||
| 59 | #define VEML3235_SEL_GAIN_X8 7 | ||
| 60 | static const struct iio_gain_sel_pair veml3235_gain_sel[] = { | ||
| 61 | GAIN_SCALE_GAIN(1, VEML3235_SEL_GAIN_X1), | ||
| 62 | GAIN_SCALE_GAIN(2, VEML3235_SEL_GAIN_X2), | ||
| 63 | GAIN_SCALE_GAIN(4, VEML3235_SEL_GAIN_X4), | ||
| 64 | GAIN_SCALE_GAIN(8, VEML3235_SEL_GAIN_X8), | ||
| 65 | }; | ||
| 49 | 66 | ||
| 50 | static int veml3235_power_on(struct veml3235_data *data) | 67 | static int veml3235_power_on(struct veml3235_data *data) |
| 51 | { | 68 | { |
| @@ -101,42 +118,58 @@ static const struct iio_chan_spec veml3235_channels[] = { · 49 unmodified lines | |||
| 101 | }, | 118 | }, |
| 102 | }; | 119 | }; |
| 103 | 120 | ||
| 121 | static const struct regmap_range veml3235_readable_ranges[] = { | ||
| 122 | regmap_reg_range(VEML3235_REG_CONF, VEML3235_REG_ID), | ||
| 123 | }; | ||
| 124 | |||
| 125 | static const struct regmap_access_table veml3235_readable_table = { | ||
| 126 | .yes_ranges = veml3235_readable_ranges, | ||
| 127 | .n_yes_ranges = ARRAY_SIZE(veml3235_readable_ranges), | ||
| 128 | }; | ||
| 129 | |||
| 130 | static const struct regmap_range veml3235_writable_ranges[] = { | ||
| 131 | regmap_reg_range(VEML3235_REG_CONF, VEML3235_REG_CONF), | ||
| 132 | }; | ||
| 133 | |||
| 134 | static const struct regmap_access_table veml3235_writable_table = { | ||
| 135 | .yes_ranges = veml3235_writable_ranges, | ||
| 136 | .n_yes_ranges = ARRAY_SIZE(veml3235_writable_ranges), | ||
| 137 | }; | ||
| 138 | |||
| 139 | static const struct regmap_range veml3235_volatile_ranges[] = { | ||
| 140 | regmap_reg_range(VEML3235_REG_WH_DATA, VEML3235_REG_ALS_DATA), | ||
| 141 | }; | ||
| 142 | |||
| 143 | static const struct regmap_access_table veml3235_volatile_table = { | ||
| 144 | .yes_ranges = veml3235_volatile_ranges, | ||
| 145 | .n_yes_ranges = ARRAY_SIZE(veml3235_volatile_ranges), | ||
| 146 | }; | ||
| 147 | |||
| 104 | static const struct regmap_config veml3235_regmap_config = { | 148 | static const struct regmap_config veml3235_regmap_config = { |
| 105 | .name = "veml3235_regmap", | 149 | .name = "veml3235_regmap", |
| 106 | .reg_bits = 8, | 150 | .reg_bits = 8, |
| 107 | .val_bits = 16, | 151 | .val_bits = 16, |
| 108 | .max_register = VEML3235_REG_ID, | 152 | .max_register = VEML3235_REG_ID, |
| 109 | .val_format_endian = REGMAP_ENDIAN_LITTLE, | 153 | .val_format_endian = REGMAP_ENDIAN_LITTLE, |
| 154 | .rd_table = &veml3235_readable_table, | ||
| 155 | .wr_table = &veml3235_writable_table, | ||
| 156 | .volatile_table = &veml3235_volatile_table, | ||
| 157 | .cache_type = REGCACHE_RBTREE, | ||
| 110 | }; | 158 | }; |
| 111 | 159 | ||
| 112 | static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) | 160 | static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) |
| 113 | { | 161 | { |
| 114 | int ret, reg; | 162 | int ret, it_idx; |
| 115 | 163 | ||
| 116 | ret = regmap_field_read(data->rf.it, ®); | 164 | ret = regmap_field_read(data->rf.it, &it_idx); |
| 117 | if (ret) | 165 | if (ret) |
| 118 | return ret; | 166 | return ret; |
| 119 | 167 | ||
| 120 | switch (reg) { | 168 | ret = iio_gts_find_int_time_by_sel(&data->gts, it_idx); |
| 121 | case 0: | 169 | if (ret < 0) |
| 122 | *val2 = 50000; | 170 | return ret; |
| 123 | break; | ||
| 124 | case 1: | ||
| 125 | *val2 = 100000; | ||
| 126 | break; | ||
| 127 | case 2: | ||
| 128 | *val2 = 200000; | ||
| 129 | break; | ||
| 130 | case 3: | ||
| 131 | *val2 = 400000; | ||
| 132 | break; | ||
| 133 | case 4: | ||
| 134 | *val2 = 800000; | ||
| 135 | break; | ||
| 136 | default: | ||
| 137 | return -EINVAL; | ||
| 138 | } | ||
| 139 | 171 | ||
| 172 | *val2 = ret; | ||
| 140 | *val = 0; | 173 | *val = 0; |
| 141 | 174 | ||
| 142 | return IIO_VAL_INT_PLUS_MICRO; | 175 | return IIO_VAL_INT_PLUS_MICRO; |
| @@ -145,78 +178,78 @@ static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) · 2 unmodified lines | |||
| 145 | static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2) | 178 | static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2) |
| 146 | { | 179 | { |
| 147 | struct veml3235_data *data = iio_priv(indio_dev); | 180 | struct veml3235_data *data = iio_priv(indio_dev); |
| 148 | int ret, new_it; | 181 | int ret, gain_idx, it_idx, new_gain, prev_gain, prev_it; |
| 182 | bool in_range; | ||
| 149 | 183 | ||
| 150 | if (val) | 184 | if (val || !iio_gts_valid_time(&data->gts, val2)) |
| 151 | return -EINVAL; | 185 | return -EINVAL; |
| 152 | 186 | ||
| 153 | switch (val2) { | 187 | ret = regmap_field_read(data->rf.it, &it_idx); |
| 154 | case 50000: | 188 | if (ret) |
| 155 | new_it = 0x00; | 189 | return ret; |
| 156 | break; | ||
| 157 | case 100000: | ||
| 158 | new_it = 0x01; | ||
| 159 | break; | ||
| 160 | case 200000: | ||
| 161 | new_it = 0x02; | ||
| 162 | break; | ||
| 163 | case 400000: | ||
| 164 | new_it = 0x03; | ||
| 165 | break; | ||
| 166 | case 800000: | ||
| 167 | new_it = 0x04; | ||
| 168 | break; | ||
| 169 | default: | ||
| 170 | return -EINVAL; | ||
| 171 | } | ||
| 172 | 190 | ||
| 173 | ret = regmap_field_write(data->rf.it, new_it); | 191 | ret = regmap_field_read(data->rf.gain, &gain_idx); |
| 174 | if (ret) { | 192 | if (ret) |
| 175 | dev_err(data->dev, | ||
| 176 | "failed to update integration time: %d\n", ret); | ||
| 177 | return ret; | 193 | return ret; |
| 178 | } | ||
| 179 | 194 | ||
| 180 | return 0; | 195 | prev_it = iio_gts_find_int_time_by_sel(&data->gts, it_idx); |
| 196 | if (prev_it < 0) | ||
| 197 | return prev_it; | ||
| 198 | |||
| 199 | if (prev_it == val2) | ||
| 200 | return 0; | ||
| 201 | |||
| 202 | prev_gain = iio_gts_find_gain_by_sel(&data->gts, gain_idx); | ||
| 203 | if (prev_gain < 0) | ||
| 204 | return prev_gain; | ||
| 205 | |||
| 206 | ret = iio_gts_find_new_gain_by_gain_time_min(&data->gts, prev_gain, prev_it, | ||
| 207 | val2, &new_gain, &in_range); | ||
| 208 | if (ret) | ||
| 209 | return ret; | ||
| 210 | |||
| 211 | if (!in_range) | ||
| 212 | dev_dbg(data->dev, "Optimal gain out of range\n"); | ||
| 213 | |||
| 214 | ret = iio_gts_find_sel_by_int_time(&data->gts, val2); | ||
| 215 | if (ret < 0) | ||
| 216 | return ret; | ||
| 217 | |||
| 218 | ret = regmap_field_write(data->rf.it, ret); | ||
| 219 | if (ret) | ||
| 220 | return ret; | ||
| 221 | |||
| 222 | ret = iio_gts_find_sel_by_gain(&data->gts, new_gain); | ||
| 223 | if (ret < 0) | ||
| 224 | return ret; | ||
| 225 | |||
| 226 | return regmap_field_write(data->rf.gain, ret); | ||
| 181 | } | 227 | } |
| 182 | 228 | ||
| 183 | static int veml3235_set_gain(struct iio_dev *indio_dev, int val, int val2) | 229 | static int veml3235_set_scale(struct iio_dev *indio_dev, int val, int val2) |
| 184 | { | 230 | { |
| 185 | struct veml3235_data *data = iio_priv(indio_dev); | 231 | struct veml3235_data *data = iio_priv(indio_dev); |
| 186 | int ret, new_gain; | 232 | int ret, it_idx, gain_sel, time_sel; |
| 187 | 233 | ||
| 188 | if (val2 != 0) | 234 | ret = regmap_field_read(data->rf.it, &it_idx); |
| 189 | return -EINVAL; | 235 | if (ret) |
| 236 | return ret; | ||
| 190 | 237 | ||
| 191 | switch (val) { | 238 | ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2, |
| 192 | case 1: | 239 | &gain_sel, &time_sel); |
| 193 | new_gain = 0x00; | 240 | if (ret) |
| 194 | break; | 241 | return ret; |
| 195 | case 2: | ||
| 196 | new_gain = 0x01; | ||
| 197 | break; | ||
| 198 | case 4: | ||
| 199 | new_gain = 0x03; | ||
| 200 | break; | ||
| 201 | case 8: | ||
| 202 | new_gain = 0x07; | ||
| 203 | break; | ||
| 204 | default: | ||
| 205 | return -EINVAL; | ||
| 206 | } | ||
| 207 | 242 | ||
| 208 | ret = regmap_field_write(data->rf.gain, new_gain); | 243 | ret = regmap_field_write(data->rf.it, time_sel); |
| 209 | if (ret) { | 244 | if (ret) |
| 210 | dev_err(data->dev, "failed to set gain: %d\n", ret); | ||
| 211 | return ret; | 245 | return ret; |
| 212 | } | ||
| 213 | 246 | ||
| 214 | return 0; | 247 | return regmap_field_write(data->rf.gain, gain_sel); |
| 215 | } | 248 | } |
| 216 | 249 | ||
| 217 | static int veml3235_get_gain(struct veml3235_data *data, int *val) | 250 | static int veml3235_get_scale(struct veml3235_data *data, int *val, int *val2) |
| 218 | { | 251 | { |
| 219 | int ret, reg; | 252 | int gain, it, reg, ret; |
| 220 | 253 | ||
| 221 | ret = regmap_field_read(data->rf.gain, ®); | 254 | ret = regmap_field_read(data->rf.gain, ®); |
| 222 | if (ret) { | 255 | if (ret) { |
| @@ -224,25 +257,25 @@ static int veml3235_get_gain(struct veml3235_data *data, int *val) · 1 unmodified line | |||
| 224 | return ret; | 257 | return ret; |
| 225 | } | 258 | } |
| 226 | 259 | ||
| 227 | switch (reg & 0x03) { | 260 | gain = iio_gts_find_gain_by_sel(&data->gts, reg); |
| 228 | case 0: | 261 | if (gain < 0) |
| 229 | *val = 1; | 262 | return gain; |
| 230 | break; | 263 | |
| 231 | case 1: | 264 | ret = regmap_field_read(data->rf.it, ®); |
| 232 | *val = 2; | 265 | if (ret) { |
| 233 | break; | 266 | dev_err(data->dev, "failed to read integration time %d\n", ret); |
| 234 | case 3: | 267 | return ret; |
| 235 | *val = 4; | ||
| 236 | break; | ||
| 237 | default: | ||
| 238 | return -EINVAL; | ||
| 239 | } | 268 | } |
| 240 | 269 | ||
| 241 | /* Double gain */ | 270 | it = iio_gts_find_int_time_by_sel(&data->gts, reg); |
| 242 | if (reg & 0x04) | 271 | if (it < 0) |
| 243 | *val *= 2; | 272 | return it; |
| 273 | |||
| 274 | ret = iio_gts_get_scale(&data->gts, gain, it, val, val2); | ||
| 275 | if (ret) | ||
| 276 | return ret; | ||
| 244 | 277 | ||
| 245 | return IIO_VAL_INT; | 278 | return IIO_VAL_INT_PLUS_NANO; |
| 246 | } | 279 | } |
| 247 | 280 | ||
| 248 | static int veml3235_read_raw(struct iio_dev *indio_dev, | 281 | static int veml3235_read_raw(struct iio_dev *indio_dev, |
| @@ -276,7 +309,7 @@ static int veml3235_read_raw(struct iio_dev *indio_dev, · 27 unmodified lines | |||
| 276 | case IIO_CHAN_INFO_INT_TIME: | 309 | case IIO_CHAN_INFO_INT_TIME: |
| 277 | return veml3235_get_it(data, val, val2); | 310 | return veml3235_get_it(data, val, val2); |
| 278 | case IIO_CHAN_INFO_SCALE: | 311 | case IIO_CHAN_INFO_SCALE: |
| 279 | return veml3235_get_gain(data, val); | 312 | return veml3235_get_scale(data, val, val2); |
| 280 | default: | 313 | default: |
| 281 | return -EINVAL; | 314 | return -EINVAL; |
| 282 | } | 315 | } |
| @@ -287,17 +320,27 @@ static int veml3235_read_avail(struct iio_dev *indio_dev, · 4 unmodified lines | |||
| 287 | const int **vals, int *type, int *length, | 320 | const int **vals, int *type, int *length, |
| 288 | long mask) | 321 | long mask) |
| 289 | { | 322 | { |
| 323 | struct veml3235_data *data = iio_priv(indio_dev); | ||
| 324 | |||
| 290 | switch (mask) { | 325 | switch (mask) { |
| 291 | case IIO_CHAN_INFO_INT_TIME: | 326 | case IIO_CHAN_INFO_INT_TIME: |
| 292 | *vals = (int *)&veml3235_it_times; | 327 | return iio_gts_avail_times(&data->gts, vals, type, length); |
| 293 | *length = 2 * ARRAY_SIZE(veml3235_it_times); | 328 | case IIO_CHAN_INFO_SCALE: |
| 294 | *type = IIO_VAL_INT_PLUS_MICRO; | 329 | return iio_gts_all_avail_scales(&data->gts, vals, type, length); |
| 295 | return IIO_AVAIL_LIST; | 330 | default: |
| 331 | return -EINVAL; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | static int veml3235_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 336 | struct iio_chan_spec const *chan, | ||
| 337 | long mask) | ||
| 338 | { | ||
| 339 | switch (mask) { | ||
| 296 | case IIO_CHAN_INFO_SCALE: | 340 | case IIO_CHAN_INFO_SCALE: |
| 297 | *vals = (int *)&veml3235_scale_vals; | 341 | return IIO_VAL_INT_PLUS_NANO; |
| 298 | *length = ARRAY_SIZE(veml3235_scale_vals); | 342 | case IIO_CHAN_INFO_INT_TIME: |
| 299 | *type = IIO_VAL_INT; | 343 | return IIO_VAL_INT_PLUS_MICRO; |
| 300 | return IIO_AVAIL_LIST; | ||
| 301 | default: | 344 | default: |
| 302 | return -EINVAL; | 345 | return -EINVAL; |
| 303 | } | 346 | } |
| @@ -311,7 +354,7 @@ static int veml3235_write_raw(struct iio_dev *indio_dev, · 7 unmodified lines | |||
| 311 | case IIO_CHAN_INFO_INT_TIME: | 354 | case IIO_CHAN_INFO_INT_TIME: |
| 312 | return veml3235_set_it(indio_dev, val, val2); | 355 | return veml3235_set_it(indio_dev, val, val2); |
| 313 | case IIO_CHAN_INFO_SCALE: | 356 | case IIO_CHAN_INFO_SCALE: |
| 314 | return veml3235_set_gain(indio_dev, val, val2); | 357 | return veml3235_set_scale(indio_dev, val, val2); |
| 315 | } | 358 | } |
| 316 | 359 | ||
| 317 | return -EINVAL; | 360 | return -EINVAL; |
| @@ -321,7 +364,7 @@ static void veml3235_read_id(struct veml3235_data *data) · 3 unmodified lines | |||
| 321 | { | 364 | { |
| 322 | int ret, reg; | 365 | int ret, reg; |
| 323 | 366 | ||
| 324 | ret = regmap_field_read(data->rf.id, ®); | 367 | ret = regmap_field_read(data->rf.id, ®); |
| 325 | if (ret) { | 368 | if (ret) { |
| 326 | dev_info(data->dev, "failed to read ID\n"); | 369 | dev_info(data->dev, "failed to read ID\n"); |
| 327 | return; | 370 | return; |
| @@ -371,6 +414,13 @@ static int veml3235_hw_init(struct iio_dev *indio_dev) · 43 unmodified lines | |||
| 371 | struct device *dev = data->dev; | 414 | struct device *dev = data->dev; |
| 372 | int ret; | 415 | int ret; |
| 373 | 416 | ||
| 417 | ret = devm_iio_init_iio_gts(data->dev, 0, 272640000, | ||
| 418 | veml3235_gain_sel, ARRAY_SIZE(veml3235_gain_sel), | ||
| 419 | veml3235_it_sel, ARRAY_SIZE(veml3235_it_sel), | ||
| 420 | &data->gts); | ||
| 421 | if (ret) | ||
| 422 | return dev_err_probe(data->dev, ret, "failed to init iio gts\n"); | ||
| 423 | |||
| 374 | /* Set gain to 1 and integration time to 100 ms */ | 424 | /* Set gain to 1 and integration time to 100 ms */ |
| 375 | ret = regmap_field_write(data->rf.gain, 0x00); | 425 | ret = regmap_field_write(data->rf.gain, 0x00); |
| 376 | if (ret) | 426 | if (ret) |
| @@ -389,9 +439,10 @@ static int veml3235_hw_init(struct iio_dev *indio_dev) · 12 unmodified lines | |||
| 389 | } | 439 | } |
| 390 | 440 | ||
| 391 | static const struct iio_info veml3235_info = { | 441 | static const struct iio_info veml3235_info = { |
| 392 | .read_raw = veml3235_read_raw, | 442 | .read_raw = veml3235_read_raw, |
| 393 | .read_avail = veml3235_read_avail, | 443 | .read_avail = veml3235_read_avail, |
| 394 | .write_raw = veml3235_write_raw, | 444 | .write_raw = veml3235_write_raw, |
| 445 | .write_raw_get_fmt = veml3235_write_raw_get_fmt, | ||
| 395 | }; | 446 | }; |
| 396 | 447 | ||
| 397 | static int veml3235_probe(struct i2c_client *client) | 448 | static int veml3235_probe(struct i2c_client *client) |
| @@ -493,3 +544,4 @@ module_i2c_driver(veml3235_driver); · 95 unmodified lines | |||
| 493 | MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>"); | 544 | MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>"); |
| 494 | MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor"); | 545 | MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor"); |
| 495 | MODULE_LICENSE("GPL"); | 546 | MODULE_LICENSE("GPL"); |
| 547 | MODULE_IMPORT_NS("IIO_GTS_HELPER"); | ||
| @@ -28,6 +28,8 @@ · 27 unmodified lines | |||
| 28 | #include <linux/iio/iio.h> | 28 | #include <linux/iio/iio.h> |
| 29 | #include <linux/iio/sysfs.h> | 29 | #include <linux/iio/sysfs.h> |
| 30 | #include <linux/iio/events.h> | 30 | #include <linux/iio/events.h> |
| 31 | #include <linux/iio/trigger_consumer.h> | ||
| 32 | #include <linux/iio/triggered_buffer.h> | ||
| 31 | 33 | ||
| 32 | /* Device registers */ | 34 | /* Device registers */ |
| 33 | #define VEML6030_REG_ALS_CONF 0x00 | 35 | #define VEML6030_REG_ALS_CONF 0x00 |
| @@ -37,6 +39,7 @@ · 3 unmodified lines | |||
| 37 | #define VEML6030_REG_ALS_DATA 0x04 | 39 | #define VEML6030_REG_ALS_DATA 0x04 |
| 38 | #define VEML6030_REG_WH_DATA 0x05 | 40 | #define VEML6030_REG_WH_DATA 0x05 |
| 39 | #define VEML6030_REG_ALS_INT 0x06 | 41 | #define VEML6030_REG_ALS_INT 0x06 |
| 42 | #define VEML6030_REG_DATA(ch) (VEML6030_REG_ALS_DATA + (ch)) | ||
| 40 | 43 | ||
| 41 | /* Bit masks for specific functionality */ | 44 | /* Bit masks for specific functionality */ |
| 42 | #define VEML6030_ALS_IT GENMASK(9, 6) | 45 | #define VEML6030_ALS_IT GENMASK(9, 6) |
| @@ -56,6 +59,12 @@ · 13 unmodified lines | |||
| 56 | #define VEML6035_INT_CHAN BIT(3) | 59 | #define VEML6035_INT_CHAN BIT(3) |
| 57 | #define VEML6035_CHAN_EN BIT(2) | 60 | #define VEML6035_CHAN_EN BIT(2) |
| 58 | 61 | ||
| 62 | enum veml6030_scan { | ||
| 63 | VEML6030_SCAN_ALS, | ||
| 64 | VEML6030_SCAN_WH, | ||
| 65 | VEML6030_SCAN_TIMESTAMP, | ||
| 66 | }; | ||
| 67 | |||
| 59 | struct veml603x_chip { | 68 | struct veml603x_chip { |
| 60 | const char *name; | 69 | const char *name; |
| 61 | const int(*scale_vals)[][2]; | 70 | const int(*scale_vals)[][2]; |
| @@ -242,6 +251,13 @@ static const struct iio_chan_spec veml6030_channels[] = { · 180 unmodified lines | |||
| 242 | BIT(IIO_CHAN_INFO_SCALE), | 251 | BIT(IIO_CHAN_INFO_SCALE), |
| 243 | .event_spec = veml6030_event_spec, | 252 | .event_spec = veml6030_event_spec, |
| 244 | .num_event_specs = ARRAY_SIZE(veml6030_event_spec), | 253 | .num_event_specs = ARRAY_SIZE(veml6030_event_spec), |
| 254 | .scan_index = VEML6030_SCAN_ALS, | ||
| 255 | .scan_type = { | ||
| 256 | .sign = 'u', | ||
| 257 | .realbits = 16, | ||
| 258 | .storagebits = 16, | ||
| 259 | .endianness = IIO_CPU, | ||
| 260 | }, | ||
| 245 | }, | 261 | }, |
| 246 | { | 262 | { |
| 247 | .type = IIO_INTENSITY, | 263 | .type = IIO_INTENSITY, |
| @@ -253,7 +269,15 @@ static const struct iio_chan_spec veml6030_channels[] = { · 5 unmodified lines | |||
| 253 | BIT(IIO_CHAN_INFO_SCALE), | 269 | BIT(IIO_CHAN_INFO_SCALE), |
| 254 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | | 270 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | |
| 255 | BIT(IIO_CHAN_INFO_SCALE), | 271 | BIT(IIO_CHAN_INFO_SCALE), |
| 272 | .scan_index = VEML6030_SCAN_WH, | ||
| 273 | .scan_type = { | ||
| 274 | .sign = 'u', | ||
| 275 | .realbits = 16, | ||
| 276 | .storagebits = 16, | ||
| 277 | .endianness = IIO_CPU, | ||
| 278 | }, | ||
| 256 | }, | 279 | }, |
| 280 | IIO_CHAN_SOFT_TIMESTAMP(VEML6030_SCAN_TIMESTAMP), | ||
| 257 | }; | 281 | }; |
| 258 | 282 | ||
| 259 | static const struct iio_chan_spec veml7700_channels[] = { | 283 | static const struct iio_chan_spec veml7700_channels[] = { |
| @@ -266,6 +290,13 @@ static const struct iio_chan_spec veml7700_channels[] = { · 6 unmodified lines | |||
| 266 | BIT(IIO_CHAN_INFO_SCALE), | 290 | BIT(IIO_CHAN_INFO_SCALE), |
| 267 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | | 291 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | |
| 268 | BIT(IIO_CHAN_INFO_SCALE), | 292 | BIT(IIO_CHAN_INFO_SCALE), |
| 293 | .scan_index = VEML6030_SCAN_ALS, | ||
| 294 | .scan_type = { | ||
| 295 | .sign = 'u', | ||
| 296 | .realbits = 16, | ||
| 297 | .storagebits = 16, | ||
| 298 | .endianness = IIO_CPU, | ||
| 299 | }, | ||
| 269 | }, | 300 | }, |
| 270 | { | 301 | { |
| 271 | .type = IIO_INTENSITY, | 302 | .type = IIO_INTENSITY, |
| @@ -277,7 +308,15 @@ static const struct iio_chan_spec veml7700_channels[] = { · 5 unmodified lines | |||
| 277 | BIT(IIO_CHAN_INFO_SCALE), | 308 | BIT(IIO_CHAN_INFO_SCALE), |
| 278 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | | 309 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | |
| 279 | BIT(IIO_CHAN_INFO_SCALE), | 310 | BIT(IIO_CHAN_INFO_SCALE), |
| 311 | .scan_index = VEML6030_SCAN_WH, | ||
| 312 | .scan_type = { | ||
| 313 | .sign = 'u', | ||
| 314 | .realbits = 16, | ||
| 315 | .storagebits = 16, | ||
| 316 | .endianness = IIO_CPU, | ||
| 317 | }, | ||
| 280 | }, | 318 | }, |
| 319 | IIO_CHAN_SOFT_TIMESTAMP(VEML6030_SCAN_TIMESTAMP), | ||
| 281 | }; | 320 | }; |
| 282 | 321 | ||
| 283 | static const struct regmap_config veml6030_regmap_config = { | 322 | static const struct regmap_config veml6030_regmap_config = { |
| @@ -889,6 +928,37 @@ static irqreturn_t veml6030_event_handler(int irq, void *private) · 605 unmodified lines | |||
| 889 | return IRQ_HANDLED; | 928 | return IRQ_HANDLED; |
| 890 | } | 929 | } |
| 891 | 930 | ||
| 931 | static irqreturn_t veml6030_trigger_handler(int irq, void *p) | ||
| 932 | { | ||
| 933 | struct iio_poll_func *pf = p; | ||
| 934 | struct iio_dev *iio = pf->indio_dev; | ||
| 935 | struct veml6030_data *data = iio_priv(iio); | ||
| 936 | unsigned int reg; | ||
| 937 | int ch, ret, i = 0; | ||
| 938 | struct { | ||
| 939 | u16 chans[2]; | ||
| 940 | aligned_s64 timestamp; | ||
| 941 | } scan; | ||
| 942 | |||
| 943 | memset(&scan, 0, sizeof(scan)); | ||
| 944 | |||
| 945 | iio_for_each_active_channel(iio, ch) { | ||
| 946 | ret = regmap_read(data->regmap, VEML6030_REG_DATA(ch), | ||
| 947 | ®); | ||
| 948 | if (ret) | ||
| 949 | goto done; | ||
| 950 | |||
| 951 | scan.chans[i++] = reg; | ||
| 952 | } | ||
| 953 | |||
| 954 | iio_push_to_buffers_with_timestamp(iio, &scan, pf->timestamp); | ||
| 955 | |||
| 956 | done: | ||
| 957 | iio_trigger_notify_done(iio->trig); | ||
| 958 | |||
| 959 | return IRQ_HANDLED; | ||
| 960 | } | ||
| 961 | |||
| 892 | static int veml6030_set_info(struct iio_dev *indio_dev) | 962 | static int veml6030_set_info(struct iio_dev *indio_dev) |
| 893 | { | 963 | { |
| 894 | struct veml6030_data *data = iio_priv(indio_dev); | 964 | struct veml6030_data *data = iio_priv(indio_dev); |
| @@ -1077,6 +1147,12 @@ static int veml6030_probe(struct i2c_client *client) · 182 unmodified lines | |||
| 1077 | if (ret < 0) | 1147 | if (ret < 0) |
| 1078 | return ret; | 1148 | return ret; |
| 1079 | 1149 | ||
| 1150 | ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, | ||
| 1151 | veml6030_trigger_handler, NULL); | ||
| 1152 | if (ret) | ||
| 1153 | return dev_err_probe(&client->dev, ret, | ||
| 1154 | "Failed to register triggered buffer"); | ||
| 1155 | |||
| 1080 | return devm_iio_device_register(&client->dev, indio_dev); | 1156 | return devm_iio_device_register(&client->dev, indio_dev); |
| 1081 | } | 1157 | } |
| 1082 | 1158 | ||
| @@ -360,7 +360,7 @@ static irqreturn_t af8133j_trigger_handler(int irq, void *p) · 359 unmodified lines | |||
| 360 | s64 timestamp = iio_get_time_ns(indio_dev); | 360 | s64 timestamp = iio_get_time_ns(indio_dev); |
| 361 | struct { | 361 | struct { |
| 362 | __le16 values[3]; | 362 | __le16 values[3]; |
| 363 | s64 timestamp __aligned(8); | 363 | aligned_s64 timestamp; |
| 364 | } sample; | 364 | } sample; |
| 365 | int ret; | 365 | int ret; |
| 366 | 366 | ||
| @@ -197,7 +197,7 @@ struct ak8974 { · 196 unmodified lines | |||
| 197 | /* Ensure timestamp is naturally aligned */ | 197 | /* Ensure timestamp is naturally aligned */ |
| 198 | struct { | 198 | struct { |
| 199 | __le16 channels[3]; | 199 | __le16 channels[3]; |
| 200 | s64 ts __aligned(8); | 200 | aligned_s64 ts; |
| 201 | } scan; | 201 | } scan; |
| 202 | }; | 202 | }; |
| 203 | 203 | ||
| @@ -426,7 +426,7 @@ struct ak8975_data { · 425 unmodified lines | |||
| 426 | /* Ensure natural alignment of timestamp */ | 426 | /* Ensure natural alignment of timestamp */ |
| 427 | struct { | 427 | struct { |
| 428 | s16 channels[3]; | 428 | s16 channels[3]; |
| 429 | s64 ts __aligned(8); | 429 | aligned_s64 ts; |
| 430 | } scan; | 430 | } scan; |
| 431 | }; | 431 | }; |
| 432 | 432 | ||
| @@ -140,7 +140,7 @@ struct bmc150_magn_data { · 139 unmodified lines | |||
| 140 | /* Ensure timestamp is naturally aligned */ | 140 | /* Ensure timestamp is naturally aligned */ |
| 141 | struct { | 141 | struct { |
| 142 | s32 chans[3]; | 142 | s32 chans[3]; |
| 143 | s64 timestamp __aligned(8); | 143 | aligned_s64 timestamp; |
| 144 | } scan; | 144 | } scan; |
| 145 | struct iio_trigger *dready_trig; | 145 | struct iio_trigger *dready_trig; |
| 146 | bool dready_trigger_on; | 146 | bool dready_trigger_on; |
| @@ -44,7 +44,7 @@ struct hmc5843_data { · 43 unmodified lines | |||
| 44 | struct iio_mount_matrix orientation; | 44 | struct iio_mount_matrix orientation; |
| 45 | struct { | 45 | struct { |
| 46 | __be16 chans[3]; | 46 | __be16 chans[3]; |
| 47 | s64 timestamp __aligned(8); | 47 | aligned_s64 timestamp; |
| 48 | } scan; | 48 | } scan; |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| @@ -60,7 +60,7 @@ struct mag3110_data { · 59 unmodified lines | |||
| 60 | struct { | 60 | struct { |
| 61 | __be16 channels[3]; | 61 | __be16 channels[3]; |
| 62 | u8 temperature; | 62 | u8 temperature; |
| 63 | s64 ts __aligned(8); | 63 | aligned_s64 ts; |
| 64 | } scan; | 64 | } scan; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| @@ -236,7 +236,7 @@ struct yas5xx { · 235 unmodified lines | |||
| 236 | */ | 236 | */ |
| 237 | struct { | 237 | struct { |
| 238 | s32 channels[4]; | 238 | s32 channels[4]; |
| 239 | s64 ts __aligned(8); | 239 | aligned_s64 ts; |
| 240 | } scan; | 240 | } scan; |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | * Author: Peter Rosin <peda@axentia.se> | 7 | * Author: Peter Rosin <peda@axentia.se> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/cleanup.h> | ||
| 10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| 11 | #include <linux/iio/consumer.h> | 12 | #include <linux/iio/consumer.h> |
| 12 | #include <linux/iio/iio.h> | 13 | #include <linux/iio/iio.h> |
| @@ -237,49 +238,18 @@ static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private, · 224 unmodified lines | |||
| 237 | return ret; | 238 | return ret; |
| 238 | } | 239 | } |
| 239 | 240 | ||
| 240 | static int mux_configure_channel(struct device *dev, struct mux *mux, | 241 | static int mux_configure_chan_ext_info(struct device *dev, struct mux *mux, |
| 241 | u32 state, const char *label, int idx) | 242 | int idx, int num_ext_info) |
| 242 | { | 243 | { |
| 243 | struct mux_child *child = &mux->child[idx]; | 244 | struct mux_child *child = &mux->child[idx]; |
| 244 | struct iio_chan_spec *chan = &mux->chan[idx]; | ||
| 245 | struct iio_chan_spec const *pchan = mux->parent->channel; | 245 | struct iio_chan_spec const *pchan = mux->parent->channel; |
| 246 | char *page = NULL; | ||
| 247 | int num_ext_info; | ||
| 248 | int i; | 246 | int i; |
| 249 | int ret; | 247 | int ret; |
| 250 | 248 | ||
| 251 | chan->indexed = 1; | 249 | char *page __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL); |
| 252 | chan->output = pchan->output; | 250 | if (!page) |
| 253 | chan->datasheet_name = label; | 251 | return -ENOMEM; |
| 254 | chan->ext_info = mux->ext_info; | ||
| 255 | |||
| 256 | ret = iio_get_channel_type(mux->parent, &chan->type); | ||
| 257 | if (ret < 0) { | ||
| 258 | dev_err(dev, "failed to get parent channel type\n"); | ||
| 259 | return ret; | ||
| 260 | } | ||
| 261 | |||
| 262 | if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW)) | ||
| 263 | chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW); | ||
| 264 | if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE)) | ||
| 265 | chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE); | ||
| 266 | |||
| 267 | if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW)) | ||
| 268 | chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); | ||
| 269 | |||
| 270 | if (state >= mux_control_states(mux->control)) { | ||
| 271 | dev_err(dev, "too many channels\n"); | ||
| 272 | return -EINVAL; | ||
| 273 | } | ||
| 274 | |||
| 275 | chan->channel = state; | ||
| 276 | 252 | ||
| 277 | num_ext_info = iio_get_channel_ext_info_count(mux->parent); | ||
| 278 | if (num_ext_info) { | ||
| 279 | page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); | ||
| 280 | if (!page) | ||
| 281 | return -ENOMEM; | ||
| 282 | } | ||
| 283 | child->ext_info_cache = devm_kcalloc(dev, | 253 | child->ext_info_cache = devm_kcalloc(dev, |
| 284 | num_ext_info, | 254 | num_ext_info, |
| 285 | sizeof(*child->ext_info_cache), | 255 | sizeof(*child->ext_info_cache), |
| @@ -318,8 +288,46 @@ static int mux_configure_channel(struct device *dev, struct mux *mux, · 32 unmodified lines | |||
| 318 | child->ext_info_cache[i].size = ret; | 288 | child->ext_info_cache[i].size = ret; |
| 319 | } | 289 | } |
| 320 | 290 | ||
| 321 | if (page) | 291 | return 0; |
| 322 | devm_kfree(dev, page); | 292 | } |
| 293 | |||
| 294 | static int mux_configure_channel(struct device *dev, struct mux *mux, u32 state, | ||
| 295 | const char *label, int idx) | ||
| 296 | { | ||
| 297 | struct iio_chan_spec *chan = &mux->chan[idx]; | ||
| 298 | struct iio_chan_spec const *pchan = mux->parent->channel; | ||
| 299 | int num_ext_info; | ||
| 300 | int ret; | ||
| 301 | |||
| 302 | chan->indexed = 1; | ||
| 303 | chan->output = pchan->output; | ||
| 304 | chan->datasheet_name = label; | ||
| 305 | chan->ext_info = mux->ext_info; | ||
| 306 | |||
| 307 | ret = iio_get_channel_type(mux->parent, &chan->type); | ||
| 308 | if (ret < 0) { | ||
| 309 | dev_err(dev, "failed to get parent channel type\n"); | ||
| 310 | return ret; | ||
| 311 | } | ||
| 312 | |||
| 313 | if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW)) | ||
| 314 | chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW); | ||
| 315 | if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE)) | ||
| 316 | chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE); | ||
| 317 | |||
| 318 | if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW)) | ||
| 319 | chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); | ||
| 320 | |||
| 321 | if (state >= mux_control_states(mux->control)) { | ||
| 322 | dev_err(dev, "too many channels\n"); | ||
| 323 | return -EINVAL; | ||
| 324 | } | ||
| 325 | |||
| 326 | chan->channel = state; | ||
| 327 | |||
| 328 | num_ext_info = iio_get_channel_ext_info_count(mux->parent); | ||
| 329 | if (num_ext_info) | ||
| 330 | return mux_configure_chan_ext_info(dev, mux, idx, num_ext_info); | ||
| 323 | 331 | ||
| 324 | return 0; | 332 | return 0; |
| 325 | } | 333 | } |
| @@ -1002,7 +1002,7 @@ static int bmp280_preinit(struct bmp280_data *data) · 1001 unmodified lines | |||
| 1002 | * after resetting, the device uses the complete power-on sequence so | 1002 | * after resetting, the device uses the complete power-on sequence so |
| 1003 | * it needs to wait for the defined start-up time. | 1003 | * it needs to wait for the defined start-up time. |
| 1004 | */ | 1004 | */ |
| 1005 | fsleep(data->start_up_time); | 1005 | fsleep(data->start_up_time_us); |
| 1006 | 1006 | ||
| 1007 | ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®); | 1007 | ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®); |
| 1008 | if (ret) | 1008 | if (ret) |
| @@ -1161,7 +1161,7 @@ const struct bmp280_chip_info bmp280_chip_info = { · 152 unmodified lines | |||
| 1161 | .chip_id = bmp280_chip_ids, | 1161 | .chip_id = bmp280_chip_ids, |
| 1162 | .num_chip_id = ARRAY_SIZE(bmp280_chip_ids), | 1162 | .num_chip_id = ARRAY_SIZE(bmp280_chip_ids), |
| 1163 | .regmap_config = &bmp280_regmap_config, | 1163 | .regmap_config = &bmp280_regmap_config, |
| 1164 | .start_up_time = 2000, | 1164 | .start_up_time_us = 2000, |
| 1165 | .channels = bmp280_channels, | 1165 | .channels = bmp280_channels, |
| 1166 | .num_channels = ARRAY_SIZE(bmp280_channels), | 1166 | .num_channels = ARRAY_SIZE(bmp280_channels), |
| 1167 | .avail_scan_masks = bmp280_avail_scan_masks, | 1167 | .avail_scan_masks = bmp280_avail_scan_masks, |
| @@ -1347,7 +1347,7 @@ const struct bmp280_chip_info bme280_chip_info = { · 179 unmodified lines | |||
| 1347 | .chip_id = bme280_chip_ids, | 1347 | .chip_id = bme280_chip_ids, |
| 1348 | .num_chip_id = ARRAY_SIZE(bme280_chip_ids), | 1348 | .num_chip_id = ARRAY_SIZE(bme280_chip_ids), |
| 1349 | .regmap_config = &bme280_regmap_config, | 1349 | .regmap_config = &bme280_regmap_config, |
| 1350 | .start_up_time = 2000, | 1350 | .start_up_time_us = 2000, |
| 1351 | .channels = bme280_channels, | 1351 | .channels = bme280_channels, |
| 1352 | .num_channels = ARRAY_SIZE(bme280_channels), | 1352 | .num_channels = ARRAY_SIZE(bme280_channels), |
| 1353 | .avail_scan_masks = bme280_avail_scan_masks, | 1353 | .avail_scan_masks = bme280_avail_scan_masks, |
| @@ -1414,7 +1414,7 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd) · 60 unmodified lines | |||
| 1414 | return ret; | 1414 | return ret; |
| 1415 | } | 1415 | } |
| 1416 | /* Wait for 2ms for command to be processed */ | 1416 | /* Wait for 2ms for command to be processed */ |
| 1417 | usleep_range(data->start_up_time, data->start_up_time + 100); | 1417 | fsleep(data->start_up_time_us); |
| 1418 | /* Check for command processing error */ | 1418 | /* Check for command processing error */ |
| 1419 | ret = regmap_read(data->regmap, BMP380_REG_ERROR, ®); | 1419 | ret = regmap_read(data->regmap, BMP380_REG_ERROR, ®); |
| 1420 | if (ret) { | 1420 | if (ret) { |
| @@ -1806,7 +1806,7 @@ static int bmp380_chip_config(struct bmp280_data *data) · 385 unmodified lines | |||
| 1806 | * formula in datasheet section 3.9.2 with an offset of ~+15% | 1806 | * formula in datasheet section 3.9.2 with an offset of ~+15% |
| 1807 | * as it seen as well in table 3.9.1. | 1807 | * as it seen as well in table 3.9.1. |
| 1808 | */ | 1808 | */ |
| 1809 | msleep(150); | 1809 | fsleep(150 * USEC_PER_MSEC); |
| 1810 | 1810 | ||
| 1811 | /* Check config error flag */ | 1811 | /* Check config error flag */ |
| 1812 | ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp); | 1812 | ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp); |
| @@ -1957,7 +1957,7 @@ const struct bmp280_chip_info bmp380_chip_info = { · 144 unmodified lines | |||
| 1957 | .num_chip_id = ARRAY_SIZE(bmp380_chip_ids), | 1957 | .num_chip_id = ARRAY_SIZE(bmp380_chip_ids), |
| 1958 | .regmap_config = &bmp380_regmap_config, | 1958 | .regmap_config = &bmp380_regmap_config, |
| 1959 | .spi_read_extra_byte = true, | 1959 | .spi_read_extra_byte = true, |
| 1960 | .start_up_time = 2000, | 1960 | .start_up_time_us = 2000, |
| 1961 | .channels = bmp380_channels, | 1961 | .channels = bmp380_channels, |
| 1962 | .num_channels = ARRAY_SIZE(bmp380_channels), | 1962 | .num_channels = ARRAY_SIZE(bmp380_channels), |
| 1963 | .avail_scan_masks = bmp280_avail_scan_masks, | 1963 | .avail_scan_masks = bmp280_avail_scan_masks, |
| @@ -2006,7 +2006,8 @@ static int bmp580_soft_reset(struct bmp280_data *data) · 42 unmodified lines | |||
| 2006 | dev_err(data->dev, "failed to send reset command to device\n"); | 2006 | dev_err(data->dev, "failed to send reset command to device\n"); |
| 2007 | return ret; | 2007 | return ret; |
| 2008 | } | 2008 | } |
| 2009 | usleep_range(2000, 2500); | 2009 | /* From datasheet's table 4: electrical characteristics */ |
| 2010 | fsleep(2000); | ||
| 2010 | 2011 | ||
| 2011 | /* Dummy read of chip_id */ | 2012 | /* Dummy read of chip_id */ |
| 2012 | ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); | 2013 | ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); |
| @@ -2208,7 +2209,7 @@ static int bmp580_nvmem_read_impl(void *priv, unsigned int offset, void *val, · 195 unmodified lines | |||
| 2208 | goto exit; | 2209 | goto exit; |
| 2209 | } | 2210 | } |
| 2210 | /* Wait standby transition time */ | 2211 | /* Wait standby transition time */ |
| 2211 | usleep_range(2500, 3000); | 2212 | fsleep(2500); |
| 2212 | 2213 | ||
| 2213 | while (bytes >= sizeof(*dst)) { | 2214 | while (bytes >= sizeof(*dst)) { |
| 2214 | addr = bmp580_nvmem_addrs[offset / sizeof(*dst)]; | 2215 | addr = bmp580_nvmem_addrs[offset / sizeof(*dst)]; |
| @@ -2274,7 +2275,7 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val, · 59 unmodified lines | |||
| 2274 | goto exit; | 2275 | goto exit; |
| 2275 | } | 2276 | } |
| 2276 | /* Wait standby transition time */ | 2277 | /* Wait standby transition time */ |
| 2277 | usleep_range(2500, 3000); | 2278 | fsleep(2500); |
| 2278 | 2279 | ||
| 2279 | while (bytes >= sizeof(*buf)) { | 2280 | while (bytes >= sizeof(*buf)) { |
| 2280 | addr = bmp580_nvmem_addrs[offset / sizeof(*buf)]; | 2281 | addr = bmp580_nvmem_addrs[offset / sizeof(*buf)]; |
| @@ -2458,7 +2459,7 @@ static int bmp580_chip_config(struct bmp280_data *data) · 177 unmodified lines | |||
| 2458 | return ret; | 2459 | return ret; |
| 2459 | } | 2460 | } |
| 2460 | /* From datasheet's table 4: electrical characteristics */ | 2461 | /* From datasheet's table 4: electrical characteristics */ |
| 2461 | usleep_range(2500, 3000); | 2462 | fsleep(2500); |
| 2462 | 2463 | ||
| 2463 | /* Set default DSP mode settings */ | 2464 | /* Set default DSP mode settings */ |
| 2464 | reg_val = FIELD_PREP(BMP580_DSP_COMP_MASK, BMP580_DSP_PRESS_TEMP_COMP_EN) | | 2465 | reg_val = FIELD_PREP(BMP580_DSP_COMP_MASK, BMP580_DSP_PRESS_TEMP_COMP_EN) | |
| @@ -2649,7 +2650,7 @@ const struct bmp280_chip_info bmp580_chip_info = { · 184 unmodified lines | |||
| 2649 | .chip_id = bmp580_chip_ids, | 2650 | .chip_id = bmp580_chip_ids, |
| 2650 | .num_chip_id = ARRAY_SIZE(bmp580_chip_ids), | 2651 | .num_chip_id = ARRAY_SIZE(bmp580_chip_ids), |
| 2651 | .regmap_config = &bmp580_regmap_config, | 2652 | .regmap_config = &bmp580_regmap_config, |
| 2652 | .start_up_time = 2000, | 2653 | .start_up_time_us = 2000, |
| 2653 | .channels = bmp580_channels, | 2654 | .channels = bmp580_channels, |
| 2654 | .num_channels = ARRAY_SIZE(bmp580_channels), | 2655 | .num_channels = ARRAY_SIZE(bmp580_channels), |
| 2655 | .avail_scan_masks = bmp280_avail_scan_masks, | 2656 | .avail_scan_masks = bmp280_avail_scan_masks, |
| @@ -2720,7 +2721,7 @@ static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) · 64 unmodified lines | |||
| 2720 | delay_us = | 2721 | delay_us = |
| 2721 | conversion_time_max[data->oversampling_press]; | 2722 | conversion_time_max[data->oversampling_press]; |
| 2722 | 2723 | ||
| 2723 | usleep_range(delay_us, delay_us + 1000); | 2724 | fsleep(delay_us); |
| 2724 | } | 2725 | } |
| 2725 | 2726 | ||
| 2726 | ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); | 2727 | ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); |
| @@ -2988,7 +2989,7 @@ const struct bmp280_chip_info bmp180_chip_info = { · 261 unmodified lines | |||
| 2988 | .chip_id = bmp180_chip_ids, | 2989 | .chip_id = bmp180_chip_ids, |
| 2989 | .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), | 2990 | .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), |
| 2990 | .regmap_config = &bmp180_regmap_config, | 2991 | .regmap_config = &bmp180_regmap_config, |
| 2991 | .start_up_time = 2000, | 2992 | .start_up_time_us = 2000, |
| 2992 | .channels = bmp280_channels, | 2993 | .channels = bmp280_channels, |
| 2993 | .num_channels = ARRAY_SIZE(bmp280_channels), | 2994 | .num_channels = ARRAY_SIZE(bmp280_channels), |
| 2994 | .avail_scan_masks = bmp280_avail_scan_masks, | 2995 | .avail_scan_masks = bmp280_avail_scan_masks, |
| @@ -3066,7 +3067,7 @@ const struct bmp280_chip_info bmp085_chip_info = { · 71 unmodified lines | |||
| 3066 | .chip_id = bmp180_chip_ids, | 3067 | .chip_id = bmp180_chip_ids, |
| 3067 | .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), | 3068 | .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), |
| 3068 | .regmap_config = &bmp180_regmap_config, | 3069 | .regmap_config = &bmp180_regmap_config, |
| 3069 | .start_up_time = 2000, | 3070 | .start_up_time_us = 2000, |
| 3070 | .channels = bmp280_channels, | 3071 | .channels = bmp280_channels, |
| 3071 | .num_channels = ARRAY_SIZE(bmp280_channels), | 3072 | .num_channels = ARRAY_SIZE(bmp280_channels), |
| 3072 | .avail_scan_masks = bmp280_avail_scan_masks, | 3073 | .avail_scan_masks = bmp280_avail_scan_masks, |
| @@ -3175,7 +3176,7 @@ int bmp280_common_probe(struct device *dev, · 102 unmodified lines | |||
| 3175 | data->oversampling_temp = chip_info->oversampling_temp_default; | 3176 | data->oversampling_temp = chip_info->oversampling_temp_default; |
| 3176 | data->iir_filter_coeff = chip_info->iir_filter_coeff_default; | 3177 | data->iir_filter_coeff = chip_info->iir_filter_coeff_default; |
| 3177 | data->sampling_freq = chip_info->sampling_freq_default; | 3178 | data->sampling_freq = chip_info->sampling_freq_default; |
| 3178 | data->start_up_time = chip_info->start_up_time; | 3179 | data->start_up_time_us = chip_info->start_up_time_us; |
| 3179 | 3180 | ||
| 3180 | /* Bring up regulators */ | 3181 | /* Bring up regulators */ |
| 3181 | regulator_bulk_set_supply_names(data->supplies, | 3182 | regulator_bulk_set_supply_names(data->supplies, |
| @@ -3201,7 +3202,7 @@ int bmp280_common_probe(struct device *dev, · 19 unmodified lines | |||
| 3201 | return ret; | 3202 | return ret; |
| 3202 | 3203 | ||
| 3203 | /* Wait to make sure we started up properly */ | 3204 | /* Wait to make sure we started up properly */ |
| 3204 | usleep_range(data->start_up_time, data->start_up_time + 100); | 3205 | fsleep(data->start_up_time_us); |
| 3205 | 3206 | ||
| 3206 | /* Bring chip out of reset if there is an assigned GPIO line */ | 3207 | /* Bring chip out of reset if there is an assigned GPIO line */ |
| 3207 | gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); | 3208 | gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); |
| @@ -3287,7 +3288,7 @@ int bmp280_common_probe(struct device *dev, · 79 unmodified lines | |||
| 3287 | * Set autosuspend to two orders of magnitude larger than the | 3288 | * Set autosuspend to two orders of magnitude larger than the |
| 3288 | * start-up time. | 3289 | * start-up time. |
| 3289 | */ | 3290 | */ |
| 3290 | pm_runtime_set_autosuspend_delay(dev, data->start_up_time / 10); | 3291 | pm_runtime_set_autosuspend_delay(dev, data->start_up_time_us / 10); |
| 3291 | pm_runtime_use_autosuspend(dev); | 3292 | pm_runtime_use_autosuspend(dev); |
| 3292 | pm_runtime_put(dev); | 3293 | pm_runtime_put(dev); |
| 3293 | 3294 | ||
| @@ -3306,7 +3307,7 @@ static int bmp280_runtime_suspend(struct device *dev) · 12 unmodified lines | |||
| 3306 | 3307 | ||
| 3307 | data->chip_info->set_mode(data, BMP280_SLEEP); | 3308 | data->chip_info->set_mode(data, BMP280_SLEEP); |
| 3308 | 3309 | ||
| 3309 | fsleep(data->start_up_time); | 3310 | fsleep(data->start_up_time_us); |
| 3310 | return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies); | 3311 | return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies); |
| 3311 | } | 3312 | } |
| 3312 | 3313 | ||
| @@ -3320,7 +3321,7 @@ static int bmp280_runtime_resume(struct device *dev) · 7 unmodified lines | |||
| 3320 | if (ret) | 3321 | if (ret) |
| 3321 | return ret; | 3322 | return ret; |
| 3322 | 3323 | ||
| 3323 | usleep_range(data->start_up_time, data->start_up_time + 100); | 3324 | fsleep(data->start_up_time_us); |
| 3324 | 3325 | ||
| 3325 | ret = data->chip_info->chip_config(data); | 3326 | ret = data->chip_info->chip_config(data); |
| 3326 | if (ret) | 3327 | if (ret) |
| @@ -434,7 +434,7 @@ struct bmp280_data { · 433 unmodified lines | |||
| 434 | struct bmp380_calib bmp380; | 434 | struct bmp380_calib bmp380; |
| 435 | } calib; | 435 | } calib; |
| 436 | struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES]; | 436 | struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES]; |
| 437 | unsigned int start_up_time; /* in microseconds */ | 437 | unsigned int start_up_time_us; |
| 438 | 438 | ||
| 439 | /* log of base 2 of oversampling rate */ | 439 | /* log of base 2 of oversampling rate */ |
| 440 | u8 oversampling_press; | 440 | u8 oversampling_press; |
| @@ -470,8 +470,8 @@ struct bmp280_data { · 29 unmodified lines | |||
| 470 | /* Sensor data buffer */ | 470 | /* Sensor data buffer */ |
| 471 | u8 buf[BME280_BURST_READ_BYTES]; | 471 | u8 buf[BME280_BURST_READ_BYTES]; |
| 472 | /* Calibration data buffers */ | 472 | /* Calibration data buffers */ |
| 473 | __le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2]; | 473 | __le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / sizeof(__le16)]; |
| 474 | __be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2]; | 474 | __be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / sizeof(__be16)]; |
| 475 | u8 bme280_humid_cal_buf[BME280_CONTIGUOUS_CALIB_REGS]; | 475 | u8 bme280_humid_cal_buf[BME280_CONTIGUOUS_CALIB_REGS]; |
| 476 | u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT]; | 476 | u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT]; |
| 477 | /* Miscellaneous, endianness-aware data buffers */ | 477 | /* Miscellaneous, endianness-aware data buffers */ |
| @@ -490,7 +490,7 @@ struct bmp280_chip_info { · 12 unmodified lines | |||
| 490 | 490 | ||
| 491 | const struct iio_chan_spec *channels; | 491 | const struct iio_chan_spec *channels; |
| 492 | int num_channels; | 492 | int num_channels; |
| 493 | unsigned int start_up_time; | 493 | unsigned int start_up_time_us; |
| 494 | const unsigned long *avail_scan_masks; | 494 | const unsigned long *avail_scan_masks; |
| 495 | 495 | ||
| 496 | const int *oversampling_temp_avail; | 496 | const int *oversampling_temp_avail; |
| @@ -58,7 +58,7 @@ struct hsc_data { · 57 unmodified lines | |||
| 58 | s32 p_offset_dec; | 58 | s32 p_offset_dec; |
| 59 | struct { | 59 | struct { |
| 60 | __be16 chan[2]; | 60 | __be16 chan[2]; |
| 61 | s64 timestamp __aligned(8); | 61 | aligned_s64 timestamp; |
| 62 | } scan; | 62 | } scan; |
| 63 | u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); | 63 | u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN); |
| 64 | }; | 64 | }; |
| @@ -213,7 +213,7 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p) · 212 unmodified lines | |||
| 213 | /* Ensure buffer elements are naturally aligned */ | 213 | /* Ensure buffer elements are naturally aligned */ |
| 214 | struct { | 214 | struct { |
| 215 | s32 channels[2]; | 215 | s32 channels[2]; |
| 216 | s64 ts __aligned(8); | 216 | aligned_s64 ts; |
| 217 | } scan; | 217 | } scan; |
| 218 | int ret; | 218 | int ret; |
| 219 | 219 | ||
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/bitfield.h> | 9 | #include <linux/bitfield.h> |
| 10 | #include <linux/bits.h> | 10 | #include <linux/bits.h> |
| 11 | #include <linux/cleanup.h> | ||
| 11 | #include <linux/device.h> | 12 | #include <linux/device.h> |
| 12 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| @@ -138,7 +139,7 @@ enum { · 124 unmodified lines | |||
| 138 | struct bm1390_data_buf { | 139 | struct bm1390_data_buf { |
| 139 | u32 pressure; | 140 | u32 pressure; |
| 140 | __be16 temp; | 141 | __be16 temp; |
| 141 | s64 ts __aligned(8); | 142 | aligned_s64 ts; |
| 142 | }; | 143 | }; |
| 143 | 144 | ||
| 144 | /* BM1390 has FIFO for 4 pressure samples */ | 145 | /* BM1390 has FIFO for 4 pressure samples */ |
| @@ -263,14 +264,14 @@ static int bm1390_read_data(struct bm1390_data *data, · 118 unmodified lines | |||
| 263 | { | 264 | { |
| 264 | int ret, warn; | 265 | int ret, warn; |
| 265 | 266 | ||
| 266 | mutex_lock(&data->mutex); | 267 | guard(mutex)(&data->mutex); |
| 267 | /* | 268 | /* |
| 268 | * We use 'continuous mode' even for raw read because according to the | 269 | * We use 'continuous mode' even for raw read because according to the |
| 269 | * data-sheet an one-shot mode can't be used with IIR filter. | 270 | * data-sheet an one-shot mode can't be used with IIR filter. |
| 270 | */ | 271 | */ |
| 271 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); | 272 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); |
| 272 | if (ret) | 273 | if (ret) |
| 273 | goto unlock_out; | 274 | return ret; |
| 274 | 275 | ||
| 275 | switch (chan->type) { | 276 | switch (chan->type) { |
| 276 | case IIO_PRESSURE: | 277 | case IIO_PRESSURE: |
| @@ -287,10 +288,8 @@ static int bm1390_read_data(struct bm1390_data *data, · 10 unmodified lines | |||
| 287 | warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); | 288 | warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); |
| 288 | if (warn) | 289 | if (warn) |
| 289 | dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn); | 290 | dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn); |
| 290 | unlock_out: | ||
| 291 | mutex_unlock(&data->mutex); | ||
| 292 | 291 | ||
| 293 | return ret; | 292 | return 0; |
| 294 | } | 293 | } |
| 295 | 294 | ||
| 296 | static int bm1390_read_raw(struct iio_dev *idev, | 295 | static int bm1390_read_raw(struct iio_dev *idev, |
| @@ -543,38 +542,33 @@ static int bm1390_fifo_enable(struct iio_dev *idev) · 246 unmodified lines | |||
| 543 | if (data->irq <= 0) | 542 | if (data->irq <= 0) |
| 544 | return -EINVAL; | 543 | return -EINVAL; |
| 545 | 544 | ||
| 546 | mutex_lock(&data->mutex); | 545 | guard(mutex)(&data->mutex); |
| 547 | if (data->trigger_enabled) { | 546 | |
| 548 | ret = -EBUSY; | 547 | if (data->trigger_enabled) |
| 549 | goto unlock_out; | 548 | return -EBUSY; |
| 550 | } | ||
| 551 | 549 | ||
| 552 | /* Update watermark to HW */ | 550 | /* Update watermark to HW */ |
| 553 | ret = bm1390_fifo_set_wmi(data); | 551 | ret = bm1390_fifo_set_wmi(data); |
| 554 | if (ret) | 552 | if (ret) |
| 555 | goto unlock_out; | 553 | return ret; |
| 556 | 554 | ||
| 557 | /* Enable WMI_IRQ */ | 555 | /* Enable WMI_IRQ */ |
| 558 | ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, | 556 | ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, |
| 559 | BM1390_MASK_WMI_EN); | 557 | BM1390_MASK_WMI_EN); |
| 560 | if (ret) | 558 | if (ret) |
| 561 | goto unlock_out; | 559 | return ret; |
| 562 | 560 | ||
| 563 | /* Enable FIFO */ | 561 | /* Enable FIFO */ |
| 564 | ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL, | 562 | ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL, |
| 565 | BM1390_MASK_FIFO_EN); | 563 | BM1390_MASK_FIFO_EN); |
| 566 | if (ret) | 564 | if (ret) |
| 567 | goto unlock_out; | 565 | return ret; |
| 568 | 566 | ||
| 569 | data->state = BM1390_STATE_FIFO; | 567 | data->state = BM1390_STATE_FIFO; |
| 570 | 568 | ||
| 571 | data->old_timestamp = iio_get_time_ns(idev); | 569 | data->old_timestamp = iio_get_time_ns(idev); |
| 572 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); | ||
| 573 | 570 | ||
| 574 | unlock_out: | 571 | return bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); |
| 575 | mutex_unlock(&data->mutex); | ||
| 576 | |||
| 577 | return ret; | ||
| 578 | } | 572 | } |
| 579 | 573 | ||
| 580 | static int bm1390_fifo_disable(struct iio_dev *idev) | 574 | static int bm1390_fifo_disable(struct iio_dev *idev) |
| @@ -584,27 +578,22 @@ static int bm1390_fifo_disable(struct iio_dev *idev) · 3 unmodified lines | |||
| 584 | 578 | ||
| 585 | msleep(1); | 579 | msleep(1); |
| 586 | 580 | ||
| 587 | mutex_lock(&data->mutex); | 581 | guard(mutex)(&data->mutex); |
| 588 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); | 582 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); |
| 589 | if (ret) | 583 | if (ret) |
| 590 | goto unlock_out; | 584 | return ret; |
| 591 | 585 | ||
| 592 | /* Disable FIFO */ | 586 | /* Disable FIFO */ |
| 593 | ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL, | 587 | ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL, |
| 594 | BM1390_MASK_FIFO_EN); | 588 | BM1390_MASK_FIFO_EN); |
| 595 | if (ret) | 589 | if (ret) |
| 596 | goto unlock_out; | 590 | return ret; |
| 597 | 591 | ||
| 598 | data->state = BM1390_STATE_SAMPLE; | 592 | data->state = BM1390_STATE_SAMPLE; |
| 599 | 593 | ||
| 600 | /* Disable WMI_IRQ */ | 594 | /* Disable WMI_IRQ */ |
| 601 | ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, | 595 | return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, |
| 602 | BM1390_MASK_WMI_EN); | 596 | BM1390_MASK_WMI_EN); |
| 603 | |||
| 604 | unlock_out: | ||
| 605 | mutex_unlock(&data->mutex); | ||
| 606 | |||
| 607 | return ret; | ||
| 608 | } | 597 | } |
| 609 | 598 | ||
| 610 | static int bm1390_buffer_postenable(struct iio_dev *idev) | 599 | static int bm1390_buffer_postenable(struct iio_dev *idev) |
| @@ -688,25 +677,24 @@ static irqreturn_t bm1390_irq_thread_handler(int irq, void *private) · 77 unmodified lines | |||
| 688 | { | 677 | { |
| 689 | struct iio_dev *idev = private; | 678 | struct iio_dev *idev = private; |
| 690 | struct bm1390_data *data = iio_priv(idev); | 679 | struct bm1390_data *data = iio_priv(idev); |
| 691 | int ret = IRQ_NONE; | ||
| 692 | 680 | ||
| 693 | mutex_lock(&data->mutex); | 681 | guard(mutex)(&data->mutex); |
| 694 | 682 | ||
| 695 | if (data->trigger_enabled) { | 683 | if (data->trigger_enabled) { |
| 696 | iio_trigger_poll_nested(data->trig); | 684 | iio_trigger_poll_nested(data->trig); |
| 697 | ret = IRQ_HANDLED; | 685 | return IRQ_HANDLED; |
| 698 | } else if (data->state == BM1390_STATE_FIFO) { | 686 | } |
| 687 | |||
| 688 | if (data->state == BM1390_STATE_FIFO) { | ||
| 699 | int ok; | 689 | int ok; |
| 700 | 690 | ||
| 701 | ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH, | 691 | ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH, |
| 702 | data->timestamp); | 692 | data->timestamp); |
| 703 | if (ok > 0) | 693 | if (ok > 0) |
| 704 | ret = IRQ_HANDLED; | 694 | return IRQ_HANDLED; |
| 705 | } | 695 | } |
| 706 | 696 | ||
| 707 | mutex_unlock(&data->mutex); | 697 | return IRQ_NONE; |
| 708 | |||
| 709 | return ret; | ||
| 710 | } | 698 | } |
| 711 | 699 | ||
| 712 | static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en) | 700 | static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en) |
| @@ -722,17 +710,16 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig, · 9 unmodified lines | |||
| 722 | bool state) | 710 | bool state) |
| 723 | { | 711 | { |
| 724 | struct bm1390_data *data = iio_trigger_get_drvdata(trig); | 712 | struct bm1390_data *data = iio_trigger_get_drvdata(trig); |
| 725 | int ret = 0; | 713 | int ret; |
| 726 | 714 | ||
| 727 | mutex_lock(&data->mutex); | 715 | guard(mutex)(&data->mutex); |
| 728 | 716 | ||
| 729 | if (data->trigger_enabled == state) | 717 | if (data->trigger_enabled == state) |
| 730 | goto unlock_out; | 718 | return 0; |
| 731 | 719 | ||
| 732 | if (data->state == BM1390_STATE_FIFO) { | 720 | if (data->state == BM1390_STATE_FIFO) { |
| 733 | dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); | 721 | dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); |
| 734 | ret = -EBUSY; | 722 | return -EBUSY; |
| 735 | goto unlock_out; | ||
| 736 | } | 723 | } |
| 737 | 724 | ||
| 738 | data->trigger_enabled = state; | 725 | data->trigger_enabled = state; |
| @@ -740,13 +727,13 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig, · 1 unmodified line | |||
| 740 | if (state) { | 727 | if (state) { |
| 741 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); | 728 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); |
| 742 | if (ret) | 729 | if (ret) |
| 743 | goto unlock_out; | 730 | return ret; |
| 744 | } else { | 731 | } else { |
| 745 | int dummy; | 732 | int dummy; |
| 746 | 733 | ||
| 747 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); | 734 | ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); |
| 748 | if (ret) | 735 | if (ret) |
| 749 | goto unlock_out; | 736 | return ret; |
| 750 | 737 | ||
| 751 | /* | 738 | /* |
| 752 | * We need to read the status register in order to ACK the | 739 | * We need to read the status register in order to ACK the |
| @@ -758,12 +745,7 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig, · 5 unmodified lines | |||
| 758 | dev_warn(data->dev, "status read failed\n"); | 745 | dev_warn(data->dev, "status read failed\n"); |
| 759 | } | 746 | } |
| 760 | 747 | ||
| 761 | ret = bm1390_set_drdy_irq(data, state); | 748 | return bm1390_set_drdy_irq(data, state); |
| 762 | |||
| 763 | unlock_out: | ||
| 764 | mutex_unlock(&data->mutex); | ||
| 765 | |||
| 766 | return ret; | ||
| 767 | } | 749 | } |
| 768 | 750 | ||
| 769 | static const struct iio_trigger_ops bm1390_trigger_ops = { | 751 | static const struct iio_trigger_ops bm1390_trigger_ops = { |
| @@ -63,7 +63,7 @@ struct as3935_state { · 62 unmodified lines | |||
| 63 | /* Ensure timestamp is naturally aligned */ | 63 | /* Ensure timestamp is naturally aligned */ |
| 64 | struct { | 64 | struct { |
| 65 | u8 chan; | 65 | u8 chan; |
| 66 | s64 timestamp __aligned(8); | 66 | aligned_s64 timestamp; |
| 67 | } scan; | 67 | } scan; |
| 68 | u8 buf[2] __aligned(IIO_DMA_MINALIGN); | 68 | u8 buf[2] __aligned(IIO_DMA_MINALIGN); |
| 69 | }; | 69 | }; |
| @@ -433,7 +433,7 @@ static int aw96103_write_event_config(struct iio_dev *indio_dev, · 432 unmodified lines | |||
| 433 | state ? BIT(chan->channel) : 0); | 433 | state ? BIT(chan->channel) : 0); |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | static struct iio_info iio_info = { | 436 | static const struct iio_info iio_info = { |
| 437 | .read_raw = aw96103_read_raw, | 437 | .read_raw = aw96103_read_raw, |
| 438 | .read_event_value = aw96103_read_event_val, | 438 | .read_event_value = aw96103_read_event_val, |
| 439 | .write_event_value = aw96103_write_event_val, | 439 | .write_event_value = aw96103_write_event_val, |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/cleanup.h> | 14 | #include <linux/cleanup.h> |
| 15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 17 | #include <linux/firmware.h> | ||
| 17 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 19 | #include <linux/irqreturn.h> | 20 | #include <linux/irqreturn.h> |
| @@ -100,6 +101,17 @@ · 80 unmodified lines | |||
| 100 | #define HX9023S_INTERRUPT_MASK GENMASK(9, 0) | 101 | #define HX9023S_INTERRUPT_MASK GENMASK(9, 0) |
| 101 | #define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0) | 102 | #define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0) |
| 102 | 103 | ||
| 104 | #define FW_VER_OFFSET 2 | ||
| 105 | #define FW_REG_CNT_OFFSET 3 | ||
| 106 | #define FW_DATA_OFFSET 16 | ||
| 107 | |||
| 108 | struct hx9023s_bin { | ||
| 109 | u16 reg_count; | ||
| 110 | u16 fw_size; | ||
| 111 | u8 fw_ver; | ||
| 112 | u8 data[] __counted_by(fw_size); | ||
| 113 | }; | ||
| 114 | |||
| 103 | struct hx9023s_ch_data { | 115 | struct hx9023s_ch_data { |
| 104 | s16 raw; /* Raw Data*/ | 116 | s16 raw; /* Raw Data*/ |
| 105 | s16 lp; /* Low Pass Filter Data*/ | 117 | s16 lp; /* Low Pass Filter Data*/ |
| @@ -134,7 +146,7 @@ struct hx9023s_data { · 28 unmodified lines | |||
| 134 | 146 | ||
| 135 | struct { | 147 | struct { |
| 136 | __le16 channels[HX9023S_CH_NUM]; | 148 | __le16 channels[HX9023S_CH_NUM]; |
| 137 | s64 ts __aligned(8); | 149 | aligned_s64 ts; |
| 138 | } buffer; | 150 | } buffer; |
| 139 | 151 | ||
| 140 | /* | 152 | /* |
| @@ -998,6 +1010,77 @@ static int hx9023s_id_check(struct iio_dev *indio_dev) · 857 unmodified lines | |||
| 998 | return 0; | 1010 | return 0; |
| 999 | } | 1011 | } |
| 1000 | 1012 | ||
| 1013 | static int hx9023s_bin_load(struct hx9023s_data *data, struct hx9023s_bin *bin) | ||
| 1014 | { | ||
| 1015 | u8 *cfg_start = bin->data + FW_DATA_OFFSET; | ||
| 1016 | u8 addr, val; | ||
| 1017 | u16 i; | ||
| 1018 | int ret; | ||
| 1019 | |||
| 1020 | for (i = 0; i < bin->reg_count; i++) { | ||
| 1021 | addr = cfg_start[i * 2]; | ||
| 1022 | val = cfg_start[i * 2 + 1]; | ||
| 1023 | ret = regmap_write(data->regmap, addr, val); | ||
| 1024 | if (ret < 0) | ||
| 1025 | return ret; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | return 0; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | static int hx9023s_send_cfg(const struct firmware *fw, struct hx9023s_data *data) | ||
| 1032 | { | ||
| 1033 | struct hx9023s_bin *bin __free(kfree) = | ||
| 1034 | kzalloc(fw->size + sizeof(*bin), GFP_KERNEL); | ||
| 1035 | if (!bin) | ||
| 1036 | return -ENOMEM; | ||
| 1037 | |||
| 1038 | memcpy(bin->data, fw->data, fw->size); | ||
| 1039 | release_firmware(fw); | ||
| 1040 | |||
| 1041 | bin->fw_size = fw->size; | ||
| 1042 | bin->fw_ver = bin->data[FW_VER_OFFSET]; | ||
| 1043 | bin->reg_count = get_unaligned_le16(bin->data + FW_REG_CNT_OFFSET); | ||
| 1044 | |||
| 1045 | return hx9023s_bin_load(data, bin); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static void hx9023s_cfg_update(const struct firmware *fw, void *context) | ||
| 1049 | { | ||
| 1050 | struct hx9023s_data *data = context; | ||
| 1051 | struct device *dev = regmap_get_device(data->regmap); | ||
| 1052 | int ret; | ||
| 1053 | |||
| 1054 | if (!fw || !fw->data) { | ||
| 1055 | dev_warn(dev, "No firmware\n"); | ||
| 1056 | goto no_fw; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | ret = hx9023s_send_cfg(fw, data); | ||
| 1060 | if (ret) { | ||
| 1061 | dev_warn(dev, "Firmware update failed: %d\n", ret); | ||
| 1062 | goto no_fw; | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | ret = regcache_sync(data->regmap); | ||
| 1066 | if (ret) | ||
| 1067 | dev_err(dev, "regcache sync failed\n"); | ||
| 1068 | |||
| 1069 | return; | ||
| 1070 | |||
| 1071 | no_fw: | ||
| 1072 | ret = regmap_multi_reg_write(data->regmap, hx9023s_reg_init_list, | ||
| 1073 | ARRAY_SIZE(hx9023s_reg_init_list)); | ||
| 1074 | if (ret) { | ||
| 1075 | dev_err(dev, "Error loading default configuration\n"); | ||
| 1076 | return; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | ret = regcache_sync(data->regmap); | ||
| 1080 | if (ret) | ||
| 1081 | dev_err(dev, "regcache sync failed\n"); | ||
| 1082 | } | ||
| 1083 | |||
| 1001 | static int hx9023s_probe(struct i2c_client *client) | 1084 | static int hx9023s_probe(struct i2c_client *client) |
| 1002 | { | 1085 | { |
| 1003 | struct device *dev = &client->dev; | 1086 | struct device *dev = &client->dev; |
| @@ -1036,18 +1119,14 @@ static int hx9023s_probe(struct i2c_client *client) · 32 unmodified lines | |||
| 1036 | indio_dev->modes = INDIO_DIRECT_MODE; | 1119 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 1037 | i2c_set_clientdata(client, indio_dev); | 1120 | i2c_set_clientdata(client, indio_dev); |
| 1038 | 1121 | ||
| 1039 | ret = regmap_multi_reg_write(data->regmap, hx9023s_reg_init_list, | ||
| 1040 | ARRAY_SIZE(hx9023s_reg_init_list)); | ||
| 1041 | if (ret) | ||
| 1042 | return dev_err_probe(dev, ret, "device init failed\n"); | ||
| 1043 | |||
| 1044 | ret = hx9023s_ch_cfg(data); | 1122 | ret = hx9023s_ch_cfg(data); |
| 1045 | if (ret) | 1123 | if (ret) |
| 1046 | return dev_err_probe(dev, ret, "channel config failed\n"); | 1124 | return dev_err_probe(dev, ret, "channel config failed\n"); |
| 1047 | 1125 | ||
| 1048 | ret = regcache_sync(data->regmap); | 1126 | ret = request_firmware_nowait(THIS_MODULE, true, "hx9023s.bin", dev, |
| 1127 | GFP_KERNEL, data, hx9023s_cfg_update); | ||
| 1049 | if (ret) | 1128 | if (ret) |
| 1050 | return dev_err_probe(dev, ret, "regcache sync failed\n"); | 1129 | return dev_err_probe(dev, ret, "reg config failed\n"); |
| 1051 | 1130 | ||
| 1052 | if (client->irq) { | 1131 | if (client->irq) { |
| 1053 | ret = devm_request_threaded_irq(dev, client->irq, | 1132 | ret = devm_request_threaded_irq(dev, client->irq, |
| @@ -45,7 +45,7 @@ struct mb1232_data { · 44 unmodified lines | |||
| 45 | /* Ensure correct alignment of data to push to IIO buffer */ | 45 | /* Ensure correct alignment of data to push to IIO buffer */ |
| 46 | struct { | 46 | struct { |
| 47 | s16 distance; | 47 | s16 distance; |
| 48 | s64 ts __aligned(8); | 48 | aligned_s64 ts; |
| 49 | } scan; | 49 | } scan; |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| @@ -47,7 +47,7 @@ struct lidar_data { · 46 unmodified lines | |||
| 47 | /* Ensure timestamp is naturally aligned */ | 47 | /* Ensure timestamp is naturally aligned */ |
| 48 | struct { | 48 | struct { |
| 49 | u16 chan; | 49 | u16 chan; |
| 50 | s64 timestamp __aligned(8); | 50 | aligned_s64 timestamp; |
| 51 | } scan; | 51 | } scan; |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| @@ -66,7 +66,7 @@ struct srf08_data { · 65 unmodified lines | |||
| 66 | /* Ensure timestamp is naturally aligned */ | 66 | /* Ensure timestamp is naturally aligned */ |
| 67 | struct { | 67 | struct { |
| 68 | s16 chan; | 68 | s16 chan; |
| 69 | s64 timestamp __aligned(8); | 69 | aligned_s64 timestamp; |
| 70 | } scan; | 70 | } scan; |
| 71 | 71 | ||
| 72 | /* Sensor-Type */ | 72 | /* Sensor-Type */ |
| @@ -125,7 +125,7 @@ struct sx_common_data { · 124 unmodified lines | |||
| 125 | /* Ensure correct alignment of timestamp when present. */ | 125 | /* Ensure correct alignment of timestamp when present. */ |
| 126 | struct { | 126 | struct { |
| 127 | __be16 channels[SX_COMMON_MAX_NUM_CHANNELS]; | 127 | __be16 channels[SX_COMMON_MAX_NUM_CHANNELS]; |
| 128 | s64 ts __aligned(8); | 128 | aligned_s64 ts; |
| 129 | } buffer; | 129 | } buffer; |
| 130 | 130 | ||
| 131 | unsigned int suspend_ctrl; | 131 | unsigned int suspend_ctrl; |
| @@ -164,7 +164,7 @@ struct ad2s1210_state { · 163 unmodified lines | |||
| 164 | struct { | 164 | struct { |
| 165 | __be16 chan[2]; | 165 | __be16 chan[2]; |
| 166 | /* Ensure timestamp is naturally aligned. */ | 166 | /* Ensure timestamp is naturally aligned. */ |
| 167 | s64 timestamp __aligned(8); | 167 | aligned_s64 timestamp; |
| 168 | } scan; | 168 | } scan; |
| 169 | /** SPI transmit buffer. */ | 169 | /** SPI transmit buffer. */ |
| 170 | u8 rx[2]; | 170 | u8 rx[2]; |
| @@ -248,7 +248,7 @@ static irqreturn_t tmp006_trigger_handler(int irq, void *p) · 247 unmodified lines | |||
| 248 | struct tmp006_data *data = iio_priv(indio_dev); | 248 | struct tmp006_data *data = iio_priv(indio_dev); |
| 249 | struct { | 249 | struct { |
| 250 | s16 channels[2]; | 250 | s16 channels[2]; |
| 251 | s64 ts __aligned(8); | 251 | aligned_s64 ts; |
| 252 | } scan; | 252 | } scan; |
| 253 | s32 ret; | 253 | s32 ret; |
| 254 | 254 | ||
| @@ -38,6 +38,9 @@ static const void *triggers_table[][MAX_TRIGGERS] = { · 37 unmodified lines | |||
| 38 | { TIM15_TRGO,}, | 38 | { TIM15_TRGO,}, |
| 39 | { TIM16_OC1,}, | 39 | { TIM16_OC1,}, |
| 40 | { TIM17_OC1,}, | 40 | { TIM17_OC1,}, |
| 41 | { }, /* timer 18 */ | ||
| 42 | { }, /* timer 19 */ | ||
| 43 | { TIM20_TRGO, TIM20_TRGO2, TIM20_OC1, TIM20_OC2, TIM20_OC3, }, | ||
| 41 | }; | 44 | }; |
| 42 | 45 | ||
| 43 | /* List the triggers accepted by each timer */ | 46 | /* List the triggers accepted by each timer */ |
| @@ -119,7 +122,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, · 75 unmodified lines | |||
| 119 | unsigned int frequency) | 122 | unsigned int frequency) |
| 120 | { | 123 | { |
| 121 | unsigned long long prd, div; | 124 | unsigned long long prd, div; |
| 122 | int prescaler = 0; | 125 | int prescaler = 0, ret; |
| 123 | u32 ccer; | 126 | u32 ccer; |
| 124 | 127 | ||
| 125 | /* Period and prescaler values depends of clock rate */ | 128 | /* Period and prescaler values depends of clock rate */ |
| @@ -150,10 +153,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, · 24 unmodified lines | |||
| 150 | if (ccer & TIM_CCER_CCXE) | 153 | if (ccer & TIM_CCER_CCXE) |
| 151 | return -EBUSY; | 154 | return -EBUSY; |
| 152 | 155 | ||
| 153 | mutex_lock(&priv->lock); | 156 | guard(mutex)(&priv->lock); |
| 154 | if (!priv->enabled) { | 157 | if (!priv->enabled) { |
| 155 | priv->enabled = true; | 158 | priv->enabled = true; |
| 156 | clk_enable(priv->clk); | 159 | ret = clk_enable(priv->clk); |
| 160 | if (ret) | ||
| 161 | return ret; | ||
| 157 | } | 162 | } |
| 158 | 163 | ||
| 159 | regmap_write(priv->regmap, TIM_PSC, prescaler); | 164 | regmap_write(priv->regmap, TIM_PSC, prescaler); |
| @@ -173,7 +178,6 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, · 13 unmodified lines | |||
| 173 | 178 | ||
| 174 | /* Enable controller */ | 179 | /* Enable controller */ |
| 175 | regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); | 180 | regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); |
| 176 | mutex_unlock(&priv->lock); | ||
| 177 | 181 | ||
| 178 | return 0; | 182 | return 0; |
| 179 | } | 183 | } |
| @@ -307,7 +311,7 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, · 127 unmodified lines | |||
| 307 | struct stm32_timer_trigger *priv = dev_get_drvdata(dev); | 311 | struct stm32_timer_trigger *priv = dev_get_drvdata(dev); |
| 308 | struct iio_trigger *trig = to_iio_trigger(dev); | 312 | struct iio_trigger *trig = to_iio_trigger(dev); |
| 309 | u32 mask, shift, master_mode_max; | 313 | u32 mask, shift, master_mode_max; |
| 310 | int i; | 314 | int i, ret; |
| 311 | 315 | ||
| 312 | if (stm32_timer_is_trgo2_name(trig->name)) { | 316 | if (stm32_timer_is_trgo2_name(trig->name)) { |
| 313 | mask = TIM_CR2_MMS2; | 317 | mask = TIM_CR2_MMS2; |
| @@ -322,15 +326,16 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, · 8 unmodified lines | |||
| 322 | for (i = 0; i <= master_mode_max; i++) { | 326 | for (i = 0; i <= master_mode_max; i++) { |
| 323 | if (!strncmp(master_mode_table[i], buf, | 327 | if (!strncmp(master_mode_table[i], buf, |
| 324 | strlen(master_mode_table[i]))) { | 328 | strlen(master_mode_table[i]))) { |
| 325 | mutex_lock(&priv->lock); | 329 | guard(mutex)(&priv->lock); |
| 326 | if (!priv->enabled) { | 330 | if (!priv->enabled) { |
| 327 | /* Clock should be enabled first */ | 331 | /* Clock should be enabled first */ |
| 328 | priv->enabled = true; | 332 | priv->enabled = true; |
| 329 | clk_enable(priv->clk); | 333 | ret = clk_enable(priv->clk); |
| 334 | if (ret) | ||
| 335 | return ret; | ||
| 330 | } | 336 | } |
| 331 | regmap_update_bits(priv->regmap, TIM_CR2, mask, | 337 | regmap_update_bits(priv->regmap, TIM_CR2, mask, |
| 332 | i << shift); | 338 | i << shift); |
| 333 | mutex_unlock(&priv->lock); | ||
| 334 | return len; | 339 | return len; |
| 335 | } | 340 | } |
| 336 | } | 341 | } |
| @@ -482,6 +487,7 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, · 145 unmodified lines | |||
| 482 | int val, int val2, long mask) | 487 | int val, int val2, long mask) |
| 483 | { | 488 | { |
| 484 | struct stm32_timer_trigger *priv = iio_priv(indio_dev); | 489 | struct stm32_timer_trigger *priv = iio_priv(indio_dev); |
| 490 | int ret; | ||
| 485 | 491 | ||
| 486 | switch (mask) { | 492 | switch (mask) { |
| 487 | case IIO_CHAN_INFO_RAW: | 493 | case IIO_CHAN_INFO_RAW: |
| @@ -491,12 +497,14 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 491 | /* fixed scale */ | 497 | /* fixed scale */ |
| 492 | return -EINVAL; | 498 | return -EINVAL; |
| 493 | 499 | ||
| 494 | case IIO_CHAN_INFO_ENABLE: | 500 | case IIO_CHAN_INFO_ENABLE: { |
| 495 | mutex_lock(&priv->lock); | 501 | guard(mutex)(&priv->lock); |
| 496 | if (val) { | 502 | if (val) { |
| 497 | if (!priv->enabled) { | 503 | if (!priv->enabled) { |
| 498 | priv->enabled = true; | 504 | priv->enabled = true; |
| 499 | clk_enable(priv->clk); | 505 | ret = clk_enable(priv->clk); |
| 506 | if (ret) | ||
| 507 | return ret; | ||
| 500 | } | 508 | } |
| 501 | regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); | 509 | regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); |
| 502 | } else { | 510 | } else { |
| @@ -506,11 +514,12 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 506 | clk_disable(priv->clk); | 514 | clk_disable(priv->clk); |
| 507 | } | 515 | } |
| 508 | } | 516 | } |
| 509 | mutex_unlock(&priv->lock); | 517 | |
| 510 | return 0; | 518 | return 0; |
| 511 | } | 519 | } |
| 512 | 520 | default: | |
| 513 | return -EINVAL; | 521 | return -EINVAL; |
| 522 | } | ||
| 514 | } | 523 | } |
| 515 | 524 | ||
| 516 | static int stm32_counter_validate_trigger(struct iio_dev *indio_dev, | 525 | static int stm32_counter_validate_trigger(struct iio_dev *indio_dev, |
| @@ -602,6 +611,7 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, · 85 unmodified lines | |||
| 602 | { | 611 | { |
| 603 | struct stm32_timer_trigger *priv = iio_priv(indio_dev); | 612 | struct stm32_timer_trigger *priv = iio_priv(indio_dev); |
| 604 | int sms = stm32_enable_mode2sms(mode); | 613 | int sms = stm32_enable_mode2sms(mode); |
| 614 | int ret; | ||
| 605 | 615 | ||
| 606 | if (sms < 0) | 616 | if (sms < 0) |
| 607 | return sms; | 617 | return sms; |
| @@ -609,12 +619,15 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 609 | * Triggered mode sets CEN bit automatically by hardware. So, first | 619 | * Triggered mode sets CEN bit automatically by hardware. So, first |
| 610 | * enable counter clock, so it can use it. Keeps it in sync with CEN. | 620 | * enable counter clock, so it can use it. Keeps it in sync with CEN. |
| 611 | */ | 621 | */ |
| 612 | mutex_lock(&priv->lock); | 622 | scoped_guard(mutex, &priv->lock) { |
| 613 | if (sms == 6 && !priv->enabled) { | 623 | if (sms == 6 && !priv->enabled) { |
| 614 | clk_enable(priv->clk); | 624 | ret = clk_enable(priv->clk); |
| 615 | priv->enabled = true; | 625 | if (ret) |
| 626 | return ret; | ||
| 627 | |||
| 628 | priv->enabled = true; | ||
| 629 | } | ||
| 616 | } | 630 | } |
| 617 | mutex_unlock(&priv->lock); | ||
| 618 | 631 | ||
| 619 | regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); | 632 | regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms); |
| 620 | 633 | ||
| @@ -781,7 +794,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) · 160 unmodified lines | |||
| 781 | return -EINVAL; | 794 | return -EINVAL; |
| 782 | 795 | ||
| 783 | /* Create an IIO device only if we have triggers to be validated */ | 796 | /* Create an IIO device only if we have triggers to be validated */ |
| 784 | if (*cfg->valids_table[index]) | 797 | if (cfg->valids_table && *cfg->valids_table[index]) |
| 785 | priv = stm32_setup_counter_device(dev); | 798 | priv = stm32_setup_counter_device(dev); |
| 786 | else | 799 | else |
| 787 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 800 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| @@ -794,7 +807,8 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) · 6 unmodified lines | |||
| 794 | priv->clk = ddata->clk; | 807 | priv->clk = ddata->clk; |
| 795 | priv->max_arr = ddata->max_arr; | 808 | priv->max_arr = ddata->max_arr; |
| 796 | priv->triggers = triggers_table[index]; | 809 | priv->triggers = triggers_table[index]; |
| 797 | priv->valids = cfg->valids_table[index]; | 810 | if (cfg->valids_table && *cfg->valids_table[index]) |
| 811 | priv->valids = cfg->valids_table[index]; | ||
| 798 | stm32_timer_detect_trgo2(priv); | 812 | stm32_timer_detect_trgo2(priv); |
| 799 | mutex_init(&priv->lock); | 813 | mutex_init(&priv->lock); |
| 800 | 814 | ||
| @@ -886,6 +900,16 @@ static const struct stm32_timer_trigger_cfg stm32h7_timer_trg_cfg = { · 85 unmodified lines | |||
| 886 | .num_valids_table = ARRAY_SIZE(stm32h7_valids_table), | 900 | .num_valids_table = ARRAY_SIZE(stm32h7_valids_table), |
| 887 | }; | 901 | }; |
| 888 | 902 | ||
| 903 | static const struct stm32_timer_trigger_cfg stm32mp25_timer_trg_cfg = { | ||
| 904 | /* | ||
| 905 | * valids_table not used: counter framework is now superseding the deprecated IIO | ||
| 906 | * counter interface (IIO_COUNT), so don't support it. num_valids_table is only | ||
| 907 | * kept here to register the IIO HW triggers. valids_table should be moved at some | ||
| 908 | * point to the stm32-timer-cnt driver instead. | ||
| 909 | */ | ||
| 910 | .num_valids_table = ARRAY_SIZE(triggers_table), | ||
| 911 | }; | ||
| 912 | |||
| 889 | static const struct of_device_id stm32_trig_of_match[] = { | 913 | static const struct of_device_id stm32_trig_of_match[] = { |
| 890 | { | 914 | { |
| 891 | .compatible = "st,stm32-timer-trigger", | 915 | .compatible = "st,stm32-timer-trigger", |
| @@ -893,6 +917,9 @@ static const struct of_device_id stm32_trig_of_match[] = { · 1 unmodified line | |||
| 893 | }, { | 917 | }, { |
| 894 | .compatible = "st,stm32h7-timer-trigger", | 918 | .compatible = "st,stm32h7-timer-trigger", |
| 895 | .data = (void *)&stm32h7_timer_trg_cfg, | 919 | .data = (void *)&stm32h7_timer_trg_cfg, |
| 920 | }, { | ||
| 921 | .compatible = "st,stm32mp25-timer-trigger", | ||
| 922 | .data = (void *)&stm32mp25_timer_trg_cfg, | ||
| 896 | }, | 923 | }, |
| 897 | { /* end node */ }, | 924 | { /* end node */ }, |
| 898 | }; | 925 | }; |
| @@ -337,6 +337,15 @@ config INTERCONNECT_QCOM_SM8650 · 336 unmodified lines | |||
| 337 | This is a driver for the Qualcomm Network-on-Chip on SM8650-based | 337 | This is a driver for the Qualcomm Network-on-Chip on SM8650-based |
| 338 | platforms. | 338 | platforms. |
| 339 | 339 | ||
| 340 | config INTERCONNECT_QCOM_SM8750 | ||
| 341 | tristate "Qualcomm SM8750 interconnect driver" | ||
| 342 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE | ||
| 343 | select INTERCONNECT_QCOM_RPMH | ||
| 344 | select INTERCONNECT_QCOM_BCM_VOTER | ||
| 345 | help | ||
| 346 | This is a driver for the Qualcomm Network-on-Chip on SM8750-based | ||
| 347 | platforms. | ||
| 348 | |||
| 340 | config INTERCONNECT_QCOM_X1E80100 | 349 | config INTERCONNECT_QCOM_X1E80100 |
| 341 | tristate "Qualcomm X1E80100 interconnect driver" | 350 | tristate "Qualcomm X1E80100 interconnect driver" |
| 342 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE | 351 | depends on INTERCONNECT_QCOM_RPMH_POSSIBLE |
| @@ -40,6 +40,7 @@ qnoc-sm8350-objs := sm8350.o · 39 unmodified lines | |||
| 40 | qnoc-sm8450-objs := sm8450.o | 40 | qnoc-sm8450-objs := sm8450.o |
| 41 | qnoc-sm8550-objs := sm8550.o | 41 | qnoc-sm8550-objs := sm8550.o |
| 42 | qnoc-sm8650-objs := sm8650.o | 42 | qnoc-sm8650-objs := sm8650.o |
| 43 | qnoc-sm8750-objs := sm8750.o | ||
| 43 | qnoc-x1e80100-objs := x1e80100.o | 44 | qnoc-x1e80100-objs := x1e80100.o |
| 44 | icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o | 45 | icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o |
| 45 | 46 | ||
| @@ -80,5 +81,6 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o · 34 unmodified lines | |||
| 80 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8450) += qnoc-sm8450.o | 81 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8450) += qnoc-sm8450.o |
| 81 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8550) += qnoc-sm8550.o | 82 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8550) += qnoc-sm8550.o |
| 82 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8650) += qnoc-sm8650.o | 83 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8650) += qnoc-sm8650.o |
| 84 | obj-$(CONFIG_INTERCONNECT_QCOM_SM8750) += qnoc-sm8750.o | ||
| 83 | obj-$(CONFIG_INTERCONNECT_QCOM_X1E80100) += qnoc-x1e80100.o | 85 | obj-$(CONFIG_INTERCONNECT_QCOM_X1E80100) += qnoc-x1e80100.o |
| 84 | obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o | 86 | obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o |
| @@ -0,0 +1,1705 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. | ||
| 4 | * | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/device.h> | ||
| 8 | #include <linux/interconnect.h> | ||
| 9 | #include <linux/interconnect-provider.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/of_platform.h> | ||
| 12 | #include <dt-bindings/interconnect/qcom,sm8750-rpmh.h> | ||
| 13 | |||
| 14 | #include "bcm-voter.h" | ||
| 15 | #include "icc-rpmh.h" | ||
| 16 | |||
| 17 | #define SM8750_MASTER_GPU_TCU 0 | ||
| 18 | #define SM8750_MASTER_SYS_TCU 1 | ||
| 19 | #define SM8750_MASTER_APPSS_PROC 2 | ||
| 20 | #define SM8750_MASTER_LLCC 3 | ||
| 21 | #define SM8750_MASTER_QDSS_BAM 4 | ||
| 22 | #define SM8750_MASTER_QSPI_0 5 | ||
| 23 | #define SM8750_MASTER_QUP_1 6 | ||
| 24 | #define SM8750_MASTER_QUP_2 7 | ||
| 25 | #define SM8750_MASTER_A1NOC_SNOC 8 | ||
| 26 | #define SM8750_MASTER_A2NOC_SNOC 9 | ||
| 27 | #define SM8750_MASTER_CAMNOC_HF 10 | ||
| 28 | #define SM8750_MASTER_CAMNOC_NRT_ICP_SF 11 | ||
| 29 | #define SM8750_MASTER_CAMNOC_RT_CDM_SF 12 | ||
| 30 | #define SM8750_MASTER_CAMNOC_SF 13 | ||
| 31 | #define SM8750_MASTER_GEM_NOC_CNOC 14 | ||
| 32 | #define SM8750_MASTER_GEM_NOC_PCIE_SNOC 15 | ||
| 33 | #define SM8750_MASTER_GFX3D 16 | ||
| 34 | #define SM8750_MASTER_LPASS_GEM_NOC 17 | ||
| 35 | #define SM8750_MASTER_LPASS_LPINOC 18 | ||
| 36 | #define SM8750_MASTER_LPIAON_NOC 19 | ||
| 37 | #define SM8750_MASTER_LPASS_PROC 20 | ||
| 38 | #define SM8750_MASTER_MDP 21 | ||
| 39 | #define SM8750_MASTER_MSS_PROC 22 | ||
| 40 | #define SM8750_MASTER_MNOC_HF_MEM_NOC 23 | ||
| 41 | #define SM8750_MASTER_MNOC_SF_MEM_NOC 24 | ||
| 42 | #define SM8750_MASTER_CDSP_PROC 25 | ||
| 43 | #define SM8750_MASTER_COMPUTE_NOC 26 | ||
| 44 | #define SM8750_MASTER_ANOC_PCIE_GEM_NOC 27 | ||
| 45 | #define SM8750_MASTER_SNOC_SF_MEM_NOC 28 | ||
| 46 | #define SM8750_MASTER_UBWC_P 29 | ||
| 47 | #define SM8750_MASTER_CDSP_HCP 30 | ||
| 48 | #define SM8750_MASTER_VIDEO_CV_PROC 31 | ||
| 49 | #define SM8750_MASTER_VIDEO_EVA 32 | ||
| 50 | #define SM8750_MASTER_VIDEO_MVP 33 | ||
| 51 | #define SM8750_MASTER_VIDEO_V_PROC 34 | ||
| 52 | #define SM8750_MASTER_CNOC_CFG 35 | ||
| 53 | #define SM8750_MASTER_CNOC_MNOC_CFG 36 | ||
| 54 | #define SM8750_MASTER_PCIE_ANOC_CFG 37 | ||
| 55 | #define SM8750_MASTER_QUP_CORE_0 38 | ||
| 56 | #define SM8750_MASTER_QUP_CORE_1 39 | ||
| 57 | #define SM8750_MASTER_QUP_CORE_2 40 | ||
| 58 | #define SM8750_MASTER_CRYPTO 41 | ||
| 59 | #define SM8750_MASTER_IPA 42 | ||
| 60 | #define SM8750_MASTER_QUP_3 43 | ||
| 61 | #define SM8750_MASTER_SOCCP_AGGR_NOC 44 | ||
| 62 | #define SM8750_MASTER_SP 45 | ||
| 63 | #define SM8750_MASTER_GIC 46 | ||
| 64 | #define SM8750_MASTER_PCIE_0 47 | ||
| 65 | #define SM8750_MASTER_QDSS_ETR 48 | ||
| 66 | #define SM8750_MASTER_QDSS_ETR_1 49 | ||
| 67 | #define SM8750_MASTER_SDCC_2 50 | ||
| 68 | #define SM8750_MASTER_SDCC_4 51 | ||
| 69 | #define SM8750_MASTER_UFS_MEM 52 | ||
| 70 | #define SM8750_MASTER_USB3_0 53 | ||
| 71 | #define SM8750_SLAVE_UBWC_P 54 | ||
| 72 | #define SM8750_SLAVE_EBI1 55 | ||
| 73 | #define SM8750_SLAVE_AHB2PHY_SOUTH 56 | ||
| 74 | #define SM8750_SLAVE_AHB2PHY_NORTH 57 | ||
| 75 | #define SM8750_SLAVE_AOSS 58 | ||
| 76 | #define SM8750_SLAVE_CAMERA_CFG 59 | ||
| 77 | #define SM8750_SLAVE_CLK_CTL 60 | ||
| 78 | #define SM8750_SLAVE_CRYPTO_0_CFG 61 | ||
| 79 | #define SM8750_SLAVE_DISPLAY_CFG 62 | ||
| 80 | #define SM8750_SLAVE_EVA_CFG 63 | ||
| 81 | #define SM8750_SLAVE_GFX3D_CFG 64 | ||
| 82 | #define SM8750_SLAVE_I2C 65 | ||
| 83 | #define SM8750_SLAVE_I3C_IBI0_CFG 66 | ||
| 84 | #define SM8750_SLAVE_I3C_IBI1_CFG 67 | ||
| 85 | #define SM8750_SLAVE_IMEM_CFG 68 | ||
| 86 | #define SM8750_SLAVE_IPA_CFG 69 | ||
| 87 | #define SM8750_SLAVE_IPC_ROUTER_CFG 70 | ||
| 88 | #define SM8750_SLAVE_CNOC_MSS 71 | ||
| 89 | #define SM8750_SLAVE_PCIE_CFG 72 | ||
| 90 | #define SM8750_SLAVE_PRNG 73 | ||
| 91 | #define SM8750_SLAVE_QDSS_CFG 74 | ||
| 92 | #define SM8750_SLAVE_QSPI_0 75 | ||
| 93 | #define SM8750_SLAVE_QUP_3 76 | ||
| 94 | #define SM8750_SLAVE_QUP_1 77 | ||
| 95 | #define SM8750_SLAVE_QUP_2 78 | ||
| 96 | #define SM8750_SLAVE_SDCC_2 79 | ||
| 97 | #define SM8750_SLAVE_SDCC_4 80 | ||
| 98 | #define SM8750_SLAVE_SOCCP 81 | ||
| 99 | #define SM8750_SLAVE_SPSS_CFG 82 | ||
| 100 | #define SM8750_SLAVE_TCSR 83 | ||
| 101 | #define SM8750_SLAVE_TLMM 84 | ||
| 102 | #define SM8750_SLAVE_TME_CFG 85 | ||
| 103 | #define SM8750_SLAVE_UFS_MEM_CFG 86 | ||
| 104 | #define SM8750_SLAVE_USB3_0 87 | ||
| 105 | #define SM8750_SLAVE_VENUS_CFG 88 | ||
| 106 | #define SM8750_SLAVE_VSENSE_CTRL_CFG 89 | ||
| 107 | #define SM8750_SLAVE_A1NOC_SNOC 90 | ||
| 108 | #define SM8750_SLAVE_A2NOC_SNOC 91 | ||
| 109 | #define SM8750_SLAVE_APPSS 92 | ||
| 110 | #define SM8750_SLAVE_GEM_NOC_CNOC 93 | ||
| 111 | #define SM8750_SLAVE_SNOC_GEM_NOC_SF 94 | ||
| 112 | #define SM8750_SLAVE_LLCC 95 | ||
| 113 | #define SM8750_SLAVE_LPASS_GEM_NOC 96 | ||
| 114 | #define SM8750_SLAVE_LPIAON_NOC_LPASS_AG_NOC 97 | ||
| 115 | #define SM8750_SLAVE_LPICX_NOC_LPIAON_NOC 98 | ||
| 116 | #define SM8750_SLAVE_MNOC_HF_MEM_NOC 99 | ||
| 117 | #define SM8750_SLAVE_MNOC_SF_MEM_NOC 100 | ||
| 118 | #define SM8750_SLAVE_CDSP_MEM_NOC 101 | ||
| 119 | #define SM8750_SLAVE_MEM_NOC_PCIE_SNOC 102 | ||
| 120 | #define SM8750_SLAVE_ANOC_PCIE_GEM_NOC 103 | ||
| 121 | #define SM8750_SLAVE_CNOC_CFG 104 | ||
| 122 | #define SM8750_SLAVE_DDRSS_CFG 105 | ||
| 123 | #define SM8750_SLAVE_CNOC_MNOC_CFG 106 | ||
| 124 | #define SM8750_SLAVE_PCIE_ANOC_CFG 107 | ||
| 125 | #define SM8750_SLAVE_QUP_CORE_0 108 | ||
| 126 | #define SM8750_SLAVE_QUP_CORE_1 109 | ||
| 127 | #define SM8750_SLAVE_QUP_CORE_2 110 | ||
| 128 | #define SM8750_SLAVE_BOOT_IMEM 111 | ||
| 129 | #define SM8750_SLAVE_IMEM 112 | ||
| 130 | #define SM8750_SLAVE_BOOT_IMEM_2 113 | ||
| 131 | #define SM8750_SLAVE_SERVICE_CNOC 114 | ||
| 132 | #define SM8750_SLAVE_SERVICE_MNOC 115 | ||
| 133 | #define SM8750_SLAVE_SERVICE_PCIE_ANOC 116 | ||
| 134 | #define SM8750_SLAVE_PCIE_0 117 | ||
| 135 | #define SM8750_SLAVE_QDSS_STM 118 | ||
| 136 | #define SM8750_SLAVE_TCU 119 | ||
| 137 | |||
| 138 | static struct qcom_icc_node qhm_qspi = { | ||
| 139 | .name = "qhm_qspi", | ||
| 140 | .id = SM8750_MASTER_QSPI_0, | ||
| 141 | .channels = 1, | ||
| 142 | .buswidth = 4, | ||
| 143 | .num_links = 1, | ||
| 144 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static struct qcom_icc_node qhm_qup1 = { | ||
| 148 | .name = "qhm_qup1", | ||
| 149 | .id = SM8750_MASTER_QUP_1, | ||
| 150 | .channels = 1, | ||
| 151 | .buswidth = 4, | ||
| 152 | .num_links = 1, | ||
| 153 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static struct qcom_icc_node qxm_qup02 = { | ||
| 157 | .name = "qxm_qup02", | ||
| 158 | .id = SM8750_MASTER_QUP_3, | ||
| 159 | .channels = 1, | ||
| 160 | .buswidth = 8, | ||
| 161 | .num_links = 1, | ||
| 162 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static struct qcom_icc_node xm_sdc4 = { | ||
| 166 | .name = "xm_sdc4", | ||
| 167 | .id = SM8750_MASTER_SDCC_4, | ||
| 168 | .channels = 1, | ||
| 169 | .buswidth = 8, | ||
| 170 | .num_links = 1, | ||
| 171 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static struct qcom_icc_node xm_ufs_mem = { | ||
| 175 | .name = "xm_ufs_mem", | ||
| 176 | .id = SM8750_MASTER_UFS_MEM, | ||
| 177 | .channels = 1, | ||
| 178 | .buswidth = 16, | ||
| 179 | .num_links = 1, | ||
| 180 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 181 | }; | ||
| 182 | |||
| 183 | static struct qcom_icc_node xm_usb3_0 = { | ||
| 184 | .name = "xm_usb3_0", | ||
| 185 | .id = SM8750_MASTER_USB3_0, | ||
| 186 | .channels = 1, | ||
| 187 | .buswidth = 8, | ||
| 188 | .num_links = 1, | ||
| 189 | .links = { SM8750_SLAVE_A1NOC_SNOC }, | ||
| 190 | }; | ||
| 191 | |||
| 192 | static struct qcom_icc_node qhm_qdss_bam = { | ||
| 193 | .name = "qhm_qdss_bam", | ||
| 194 | .id = SM8750_MASTER_QDSS_BAM, | ||
| 195 | .channels = 1, | ||
| 196 | .buswidth = 4, | ||
| 197 | .num_links = 1, | ||
| 198 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 199 | }; | ||
| 200 | |||
| 201 | static struct qcom_icc_node qhm_qup2 = { | ||
| 202 | .name = "qhm_qup2", | ||
| 203 | .id = SM8750_MASTER_QUP_2, | ||
| 204 | .channels = 1, | ||
| 205 | .buswidth = 4, | ||
| 206 | .num_links = 1, | ||
| 207 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 208 | }; | ||
| 209 | |||
| 210 | static struct qcom_icc_node qxm_crypto = { | ||
| 211 | .name = "qxm_crypto", | ||
| 212 | .id = SM8750_MASTER_CRYPTO, | ||
| 213 | .channels = 1, | ||
| 214 | .buswidth = 8, | ||
| 215 | .num_links = 1, | ||
| 216 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static struct qcom_icc_node qxm_ipa = { | ||
| 220 | .name = "qxm_ipa", | ||
| 221 | .id = SM8750_MASTER_IPA, | ||
| 222 | .channels = 1, | ||
| 223 | .buswidth = 8, | ||
| 224 | .num_links = 1, | ||
| 225 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 226 | }; | ||
| 227 | |||
| 228 | static struct qcom_icc_node qxm_soccp = { | ||
| 229 | .name = "qxm_soccp", | ||
| 230 | .id = SM8750_MASTER_SOCCP_AGGR_NOC, | ||
| 231 | .channels = 1, | ||
| 232 | .buswidth = 8, | ||
| 233 | .num_links = 1, | ||
| 234 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static struct qcom_icc_node qxm_sp = { | ||
| 238 | .name = "qxm_sp", | ||
| 239 | .id = SM8750_MASTER_SP, | ||
| 240 | .channels = 1, | ||
| 241 | .buswidth = 8, | ||
| 242 | .num_links = 1, | ||
| 243 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 244 | }; | ||
| 245 | |||
| 246 | static struct qcom_icc_node xm_qdss_etr_0 = { | ||
| 247 | .name = "xm_qdss_etr_0", | ||
| 248 | .id = SM8750_MASTER_QDSS_ETR, | ||
| 249 | .channels = 1, | ||
| 250 | .buswidth = 8, | ||
| 251 | .num_links = 1, | ||
| 252 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 253 | }; | ||
| 254 | |||
| 255 | static struct qcom_icc_node xm_qdss_etr_1 = { | ||
| 256 | .name = "xm_qdss_etr_1", | ||
| 257 | .id = SM8750_MASTER_QDSS_ETR_1, | ||
| 258 | .channels = 1, | ||
| 259 | .buswidth = 8, | ||
| 260 | .num_links = 1, | ||
| 261 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 262 | }; | ||
| 263 | |||
| 264 | static struct qcom_icc_node xm_sdc2 = { | ||
| 265 | .name = "xm_sdc2", | ||
| 266 | .id = SM8750_MASTER_SDCC_2, | ||
| 267 | .channels = 1, | ||
| 268 | .buswidth = 8, | ||
| 269 | .num_links = 1, | ||
| 270 | .links = { SM8750_SLAVE_A2NOC_SNOC }, | ||
| 271 | }; | ||
| 272 | |||
| 273 | static struct qcom_icc_node qup0_core_master = { | ||
| 274 | .name = "qup0_core_master", | ||
| 275 | .id = SM8750_MASTER_QUP_CORE_0, | ||
| 276 | .channels = 1, | ||
| 277 | .buswidth = 4, | ||
| 278 | .num_links = 1, | ||
| 279 | .links = { SM8750_SLAVE_QUP_CORE_0 }, | ||
| 280 | }; | ||
| 281 | |||
| 282 | static struct qcom_icc_node qup1_core_master = { | ||
| 283 | .name = "qup1_core_master", | ||
| 284 | .id = SM8750_MASTER_QUP_CORE_1, | ||
| 285 | .channels = 1, | ||
| 286 | .buswidth = 4, | ||
| 287 | .num_links = 1, | ||
| 288 | .links = { SM8750_SLAVE_QUP_CORE_1 }, | ||
| 289 | }; | ||
| 290 | |||
| 291 | static struct qcom_icc_node qup2_core_master = { | ||
| 292 | .name = "qup2_core_master", | ||
| 293 | .id = SM8750_MASTER_QUP_CORE_2, | ||
| 294 | .channels = 1, | ||
| 295 | .buswidth = 4, | ||
| 296 | .num_links = 1, | ||
| 297 | .links = { SM8750_SLAVE_QUP_CORE_2 }, | ||
| 298 | }; | ||
| 299 | |||
| 300 | static struct qcom_icc_node qsm_cfg = { | ||
| 301 | .name = "qsm_cfg", | ||
| 302 | .id = SM8750_MASTER_CNOC_CFG, | ||
| 303 | .channels = 1, | ||
| 304 | .buswidth = 4, | ||
| 305 | .num_links = 33, | ||
| 306 | .links = { SM8750_SLAVE_AHB2PHY_SOUTH, SM8750_SLAVE_AHB2PHY_NORTH, | ||
| 307 | SM8750_SLAVE_CAMERA_CFG, SM8750_SLAVE_CLK_CTL, | ||
| 308 | SM8750_SLAVE_CRYPTO_0_CFG, SM8750_SLAVE_DISPLAY_CFG, | ||
| 309 | SM8750_SLAVE_EVA_CFG, SM8750_SLAVE_GFX3D_CFG, | ||
| 310 | SM8750_SLAVE_I2C, SM8750_SLAVE_I3C_IBI0_CFG, | ||
| 311 | SM8750_SLAVE_I3C_IBI1_CFG, SM8750_SLAVE_IMEM_CFG, | ||
| 312 | SM8750_SLAVE_CNOC_MSS, SM8750_SLAVE_PCIE_CFG, | ||
| 313 | SM8750_SLAVE_PRNG, SM8750_SLAVE_QDSS_CFG, | ||
| 314 | SM8750_SLAVE_QSPI_0, SM8750_SLAVE_QUP_3, | ||
| 315 | SM8750_SLAVE_QUP_1, SM8750_SLAVE_QUP_2, | ||
| 316 | SM8750_SLAVE_SDCC_2, SM8750_SLAVE_SDCC_4, | ||
| 317 | SM8750_SLAVE_SPSS_CFG, SM8750_SLAVE_TCSR, | ||
| 318 | SM8750_SLAVE_TLMM, SM8750_SLAVE_UFS_MEM_CFG, | ||
| 319 | SM8750_SLAVE_USB3_0, SM8750_SLAVE_VENUS_CFG, | ||
| 320 | SM8750_SLAVE_VSENSE_CTRL_CFG, SM8750_SLAVE_CNOC_MNOC_CFG, | ||
| 321 | SM8750_SLAVE_PCIE_ANOC_CFG, SM8750_SLAVE_QDSS_STM, | ||
| 322 | SM8750_SLAVE_TCU }, | ||
| 323 | }; | ||
| 324 | |||
| 325 | static struct qcom_icc_node qnm_gemnoc_cnoc = { | ||
| 326 | .name = "qnm_gemnoc_cnoc", | ||
| 327 | .id = SM8750_MASTER_GEM_NOC_CNOC, | ||
| 328 | .channels = 1, | ||
| 329 | .buswidth = 16, | ||
| 330 | .num_links = 12, | ||
| 331 | .links = { SM8750_SLAVE_AOSS, SM8750_SLAVE_IPA_CFG, | ||
| 332 | SM8750_SLAVE_IPC_ROUTER_CFG, SM8750_SLAVE_SOCCP, | ||
| 333 | SM8750_SLAVE_TME_CFG, SM8750_SLAVE_APPSS, | ||
| 334 | SM8750_SLAVE_CNOC_CFG, SM8750_SLAVE_DDRSS_CFG, | ||
| 335 | SM8750_SLAVE_BOOT_IMEM, SM8750_SLAVE_IMEM, | ||
| 336 | SM8750_SLAVE_BOOT_IMEM_2, SM8750_SLAVE_SERVICE_CNOC }, | ||
| 337 | }; | ||
| 338 | |||
| 339 | static struct qcom_icc_node qnm_gemnoc_pcie = { | ||
| 340 | .name = "qnm_gemnoc_pcie", | ||
| 341 | .id = SM8750_MASTER_GEM_NOC_PCIE_SNOC, | ||
| 342 | .channels = 1, | ||
| 343 | .buswidth = 8, | ||
| 344 | .num_links = 1, | ||
| 345 | .links = { SM8750_SLAVE_PCIE_0 }, | ||
| 346 | }; | ||
| 347 | |||
| 348 | static struct qcom_icc_node alm_gpu_tcu = { | ||
| 349 | .name = "alm_gpu_tcu", | ||
| 350 | .id = SM8750_MASTER_GPU_TCU, | ||
| 351 | .channels = 1, | ||
| 352 | .buswidth = 8, | ||
| 353 | .num_links = 2, | ||
| 354 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 355 | }; | ||
| 356 | |||
| 357 | static struct qcom_icc_node alm_sys_tcu = { | ||
| 358 | .name = "alm_sys_tcu", | ||
| 359 | .id = SM8750_MASTER_SYS_TCU, | ||
| 360 | .channels = 1, | ||
| 361 | .buswidth = 8, | ||
| 362 | .num_links = 2, | ||
| 363 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 364 | }; | ||
| 365 | |||
| 366 | static struct qcom_icc_node chm_apps = { | ||
| 367 | .name = "chm_apps", | ||
| 368 | .id = SM8750_MASTER_APPSS_PROC, | ||
| 369 | .channels = 4, | ||
| 370 | .buswidth = 32, | ||
| 371 | .num_links = 4, | ||
| 372 | .links = { SM8750_SLAVE_UBWC_P, SM8750_SLAVE_GEM_NOC_CNOC, | ||
| 373 | SM8750_SLAVE_LLCC, SM8750_SLAVE_MEM_NOC_PCIE_SNOC }, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static struct qcom_icc_node qnm_gpu = { | ||
| 377 | .name = "qnm_gpu", | ||
| 378 | .id = SM8750_MASTER_GFX3D, | ||
| 379 | .channels = 2, | ||
| 380 | .buswidth = 32, | ||
| 381 | .num_links = 2, | ||
| 382 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 383 | }; | ||
| 384 | |||
| 385 | static struct qcom_icc_node qnm_lpass_gemnoc = { | ||
| 386 | .name = "qnm_lpass_gemnoc", | ||
| 387 | .id = SM8750_MASTER_LPASS_GEM_NOC, | ||
| 388 | .channels = 1, | ||
| 389 | .buswidth = 16, | ||
| 390 | .num_links = 3, | ||
| 391 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC, | ||
| 392 | SM8750_SLAVE_MEM_NOC_PCIE_SNOC }, | ||
| 393 | }; | ||
| 394 | |||
| 395 | static struct qcom_icc_node qnm_mdsp = { | ||
| 396 | .name = "qnm_mdsp", | ||
| 397 | .id = SM8750_MASTER_MSS_PROC, | ||
| 398 | .channels = 1, | ||
| 399 | .buswidth = 16, | ||
| 400 | .num_links = 3, | ||
| 401 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC, | ||
| 402 | SM8750_SLAVE_MEM_NOC_PCIE_SNOC }, | ||
| 403 | }; | ||
| 404 | |||
| 405 | static struct qcom_icc_node qnm_mnoc_hf = { | ||
| 406 | .name = "qnm_mnoc_hf", | ||
| 407 | .id = SM8750_MASTER_MNOC_HF_MEM_NOC, | ||
| 408 | .channels = 2, | ||
| 409 | .buswidth = 32, | ||
| 410 | .num_links = 2, | ||
| 411 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 412 | }; | ||
| 413 | |||
| 414 | static struct qcom_icc_node qnm_mnoc_sf = { | ||
| 415 | .name = "qnm_mnoc_sf", | ||
| 416 | .id = SM8750_MASTER_MNOC_SF_MEM_NOC, | ||
| 417 | .channels = 2, | ||
| 418 | .buswidth = 32, | ||
| 419 | .num_links = 2, | ||
| 420 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 421 | }; | ||
| 422 | |||
| 423 | static struct qcom_icc_node qnm_nsp_gemnoc = { | ||
| 424 | .name = "qnm_nsp_gemnoc", | ||
| 425 | .id = SM8750_MASTER_COMPUTE_NOC, | ||
| 426 | .channels = 2, | ||
| 427 | .buswidth = 32, | ||
| 428 | .num_links = 3, | ||
| 429 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC, | ||
| 430 | SM8750_SLAVE_MEM_NOC_PCIE_SNOC }, | ||
| 431 | }; | ||
| 432 | |||
| 433 | static struct qcom_icc_node qnm_pcie = { | ||
| 434 | .name = "qnm_pcie", | ||
| 435 | .id = SM8750_MASTER_ANOC_PCIE_GEM_NOC, | ||
| 436 | .channels = 1, | ||
| 437 | .buswidth = 8, | ||
| 438 | .num_links = 2, | ||
| 439 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC }, | ||
| 440 | }; | ||
| 441 | |||
| 442 | static struct qcom_icc_node qnm_snoc_sf = { | ||
| 443 | .name = "qnm_snoc_sf", | ||
| 444 | .id = SM8750_MASTER_SNOC_SF_MEM_NOC, | ||
| 445 | .channels = 1, | ||
| 446 | .buswidth = 16, | ||
| 447 | .num_links = 3, | ||
| 448 | .links = { SM8750_SLAVE_GEM_NOC_CNOC, SM8750_SLAVE_LLCC, | ||
| 449 | SM8750_SLAVE_MEM_NOC_PCIE_SNOC }, | ||
| 450 | }; | ||
| 451 | |||
| 452 | static struct qcom_icc_node qnm_ubwc_p = { | ||
| 453 | .name = "qnm_ubwc_p", | ||
| 454 | .id = SM8750_MASTER_UBWC_P, | ||
| 455 | .channels = 1, | ||
| 456 | .buswidth = 32, | ||
| 457 | .num_links = 1, | ||
| 458 | .links = { SM8750_SLAVE_LLCC }, | ||
| 459 | }; | ||
| 460 | |||
| 461 | static struct qcom_icc_node xm_gic = { | ||
| 462 | .name = "xm_gic", | ||
| 463 | .id = SM8750_MASTER_GIC, | ||
| 464 | .channels = 1, | ||
| 465 | .buswidth = 8, | ||
| 466 | .num_links = 1, | ||
| 467 | .links = { SM8750_SLAVE_LLCC }, | ||
| 468 | }; | ||
| 469 | |||
| 470 | static struct qcom_icc_node qnm_lpiaon_noc = { | ||
| 471 | .name = "qnm_lpiaon_noc", | ||
| 472 | .id = SM8750_MASTER_LPIAON_NOC, | ||
| 473 | .channels = 1, | ||
| 474 | .buswidth = 16, | ||
| 475 | .num_links = 1, | ||
| 476 | .links = { SM8750_SLAVE_LPASS_GEM_NOC }, | ||
| 477 | }; | ||
| 478 | |||
| 479 | static struct qcom_icc_node qnm_lpass_lpinoc = { | ||
| 480 | .name = "qnm_lpass_lpinoc", | ||
| 481 | .id = SM8750_MASTER_LPASS_LPINOC, | ||
| 482 | .channels = 1, | ||
| 483 | .buswidth = 16, | ||
| 484 | .num_links = 1, | ||
| 485 | .links = { SM8750_SLAVE_LPIAON_NOC_LPASS_AG_NOC }, | ||
| 486 | }; | ||
| 487 | |||
| 488 | static struct qcom_icc_node qnm_lpinoc_dsp_qns4m = { | ||
| 489 | .name = "qnm_lpinoc_dsp_qns4m", | ||
| 490 | .id = SM8750_MASTER_LPASS_PROC, | ||
| 491 | .channels = 1, | ||
| 492 | .buswidth = 16, | ||
| 493 | .num_links = 1, | ||
| 494 | .links = { SM8750_SLAVE_LPICX_NOC_LPIAON_NOC }, | ||
| 495 | }; | ||
| 496 | |||
| 497 | static struct qcom_icc_node llcc_mc = { | ||
| 498 | .name = "llcc_mc", | ||
| 499 | .id = SM8750_MASTER_LLCC, | ||
| 500 | .channels = 4, | ||
| 501 | .buswidth = 4, | ||
| 502 | .num_links = 1, | ||
| 503 | .links = { SM8750_SLAVE_EBI1 }, | ||
| 504 | }; | ||
| 505 | |||
| 506 | static struct qcom_icc_node qnm_camnoc_hf = { | ||
| 507 | .name = "qnm_camnoc_hf", | ||
| 508 | .id = SM8750_MASTER_CAMNOC_HF, | ||
| 509 | .channels = 2, | ||
| 510 | .buswidth = 32, | ||
| 511 | .num_links = 1, | ||
| 512 | .links = { SM8750_SLAVE_MNOC_HF_MEM_NOC }, | ||
| 513 | }; | ||
| 514 | |||
| 515 | static struct qcom_icc_node qnm_camnoc_nrt_icp_sf = { | ||
| 516 | .name = "qnm_camnoc_nrt_icp_sf", | ||
| 517 | .id = SM8750_MASTER_CAMNOC_NRT_ICP_SF, | ||
| 518 | .channels = 1, | ||
| 519 | .buswidth = 8, | ||
| 520 | .num_links = 1, | ||
| 521 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 522 | }; | ||
| 523 | |||
| 524 | static struct qcom_icc_node qnm_camnoc_rt_cdm_sf = { | ||
| 525 | .name = "qnm_camnoc_rt_cdm_sf", | ||
| 526 | .id = SM8750_MASTER_CAMNOC_RT_CDM_SF, | ||
| 527 | .channels = 1, | ||
| 528 | .buswidth = 8, | ||
| 529 | .num_links = 1, | ||
| 530 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 531 | }; | ||
| 532 | |||
| 533 | static struct qcom_icc_node qnm_camnoc_sf = { | ||
| 534 | .name = "qnm_camnoc_sf", | ||
| 535 | .id = SM8750_MASTER_CAMNOC_SF, | ||
| 536 | .channels = 2, | ||
| 537 | .buswidth = 32, | ||
| 538 | .num_links = 1, | ||
| 539 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 540 | }; | ||
| 541 | |||
| 542 | static struct qcom_icc_node qnm_mdp = { | ||
| 543 | .name = "qnm_mdp", | ||
| 544 | .id = SM8750_MASTER_MDP, | ||
| 545 | .channels = 2, | ||
| 546 | .buswidth = 32, | ||
| 547 | .num_links = 1, | ||
| 548 | .links = { SM8750_SLAVE_MNOC_HF_MEM_NOC }, | ||
| 549 | }; | ||
| 550 | |||
| 551 | static struct qcom_icc_node qnm_vapss_hcp = { | ||
| 552 | .name = "qnm_vapss_hcp", | ||
| 553 | .id = SM8750_MASTER_CDSP_HCP, | ||
| 554 | .channels = 1, | ||
| 555 | .buswidth = 32, | ||
| 556 | .num_links = 1, | ||
| 557 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 558 | }; | ||
| 559 | |||
| 560 | static struct qcom_icc_node qnm_video_cv_cpu = { | ||
| 561 | .name = "qnm_video_cv_cpu", | ||
| 562 | .id = SM8750_MASTER_VIDEO_CV_PROC, | ||
| 563 | .channels = 1, | ||
| 564 | .buswidth = 8, | ||
| 565 | .num_links = 1, | ||
| 566 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 567 | }; | ||
| 568 | |||
| 569 | static struct qcom_icc_node qnm_video_eva = { | ||
| 570 | .name = "qnm_video_eva", | ||
| 571 | .id = SM8750_MASTER_VIDEO_EVA, | ||
| 572 | .channels = 2, | ||
| 573 | .buswidth = 32, | ||
| 574 | .num_links = 1, | ||
| 575 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 576 | }; | ||
| 577 | |||
| 578 | static struct qcom_icc_node qnm_video_mvp = { | ||
| 579 | .name = "qnm_video_mvp", | ||
| 580 | .id = SM8750_MASTER_VIDEO_MVP, | ||
| 581 | .channels = 2, | ||
| 582 | .buswidth = 32, | ||
| 583 | .num_links = 1, | ||
| 584 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 585 | }; | ||
| 586 | |||
| 587 | static struct qcom_icc_node qnm_video_v_cpu = { | ||
| 588 | .name = "qnm_video_v_cpu", | ||
| 589 | .id = SM8750_MASTER_VIDEO_V_PROC, | ||
| 590 | .channels = 1, | ||
| 591 | .buswidth = 8, | ||
| 592 | .num_links = 1, | ||
| 593 | .links = { SM8750_SLAVE_MNOC_SF_MEM_NOC }, | ||
| 594 | }; | ||
| 595 | |||
| 596 | static struct qcom_icc_node qsm_mnoc_cfg = { | ||
| 597 | .name = "qsm_mnoc_cfg", | ||
| 598 | .id = SM8750_MASTER_CNOC_MNOC_CFG, | ||
| 599 | .channels = 1, | ||
| 600 | .buswidth = 4, | ||
| 601 | .num_links = 1, | ||
| 602 | .links = { SM8750_SLAVE_SERVICE_MNOC }, | ||
| 603 | }; | ||
| 604 | |||
| 605 | static struct qcom_icc_node qnm_nsp = { | ||
| 606 | .name = "qnm_nsp", | ||
| 607 | .id = SM8750_MASTER_CDSP_PROC, | ||
| 608 | .channels = 2, | ||
| 609 | .buswidth = 32, | ||
| 610 | .num_links = 1, | ||
| 611 | .links = { SM8750_SLAVE_CDSP_MEM_NOC }, | ||
| 612 | }; | ||
| 613 | |||
| 614 | static struct qcom_icc_node qsm_pcie_anoc_cfg = { | ||
| 615 | .name = "qsm_pcie_anoc_cfg", | ||
| 616 | .id = SM8750_MASTER_PCIE_ANOC_CFG, | ||
| 617 | .channels = 1, | ||
| 618 | .buswidth = 4, | ||
| 619 | .num_links = 1, | ||
| 620 | .links = { SM8750_SLAVE_SERVICE_PCIE_ANOC }, | ||
| 621 | }; | ||
| 622 | |||
| 623 | static struct qcom_icc_node xm_pcie3 = { | ||
| 624 | .name = "xm_pcie3", | ||
| 625 | .id = SM8750_MASTER_PCIE_0, | ||
| 626 | .channels = 1, | ||
| 627 | .buswidth = 8, | ||
| 628 | .num_links = 1, | ||
| 629 | .links = { SM8750_SLAVE_ANOC_PCIE_GEM_NOC }, | ||
| 630 | }; | ||
| 631 | |||
| 632 | static struct qcom_icc_node qnm_aggre1_noc = { | ||
| 633 | .name = "qnm_aggre1_noc", | ||
| 634 | .id = SM8750_MASTER_A1NOC_SNOC, | ||
| 635 | .channels = 1, | ||
| 636 | .buswidth = 16, | ||
| 637 | .num_links = 1, | ||
| 638 | .links = { SM8750_SLAVE_SNOC_GEM_NOC_SF }, | ||
| 639 | }; | ||
| 640 | |||
| 641 | static struct qcom_icc_node qnm_aggre2_noc = { | ||
| 642 | .name = "qnm_aggre2_noc", | ||
| 643 | .id = SM8750_MASTER_A2NOC_SNOC, | ||
| 644 | .channels = 1, | ||
| 645 | .buswidth = 16, | ||
| 646 | .num_links = 1, | ||
| 647 | .links = { SM8750_SLAVE_SNOC_GEM_NOC_SF }, | ||
| 648 | }; | ||
| 649 | |||
| 650 | static struct qcom_icc_node qns_a1noc_snoc = { | ||
| 651 | .name = "qns_a1noc_snoc", | ||
| 652 | .id = SM8750_SLAVE_A1NOC_SNOC, | ||
| 653 | .channels = 1, | ||
| 654 | .buswidth = 16, | ||
| 655 | .num_links = 1, | ||
| 656 | .links = { SM8750_MASTER_A1NOC_SNOC }, | ||
| 657 | }; | ||
| 658 | |||
| 659 | static struct qcom_icc_node qns_a2noc_snoc = { | ||
| 660 | .name = "qns_a2noc_snoc", | ||
| 661 | .id = SM8750_SLAVE_A2NOC_SNOC, | ||
| 662 | .channels = 1, | ||
| 663 | .buswidth = 16, | ||
| 664 | .num_links = 1, | ||
| 665 | .links = { SM8750_MASTER_A2NOC_SNOC }, | ||
| 666 | }; | ||
| 667 | |||
| 668 | static struct qcom_icc_node qup0_core_slave = { | ||
| 669 | .name = "qup0_core_slave", | ||
| 670 | .id = SM8750_SLAVE_QUP_CORE_0, | ||
| 671 | .channels = 1, | ||
| 672 | .buswidth = 4, | ||
| 673 | .num_links = 0, | ||
| 674 | }; | ||
| 675 | |||
| 676 | static struct qcom_icc_node qup1_core_slave = { | ||
| 677 | .name = "qup1_core_slave", | ||
| 678 | .id = SM8750_SLAVE_QUP_CORE_1, | ||
| 679 | .channels = 1, | ||
| 680 | .buswidth = 4, | ||
| 681 | .num_links = 0, | ||
| 682 | }; | ||
| 683 | |||
| 684 | static struct qcom_icc_node qup2_core_slave = { | ||
| 685 | .name = "qup2_core_slave", | ||
| 686 | .id = SM8750_SLAVE_QUP_CORE_2, | ||
| 687 | .channels = 1, | ||
| 688 | .buswidth = 4, | ||
| 689 | .num_links = 0, | ||
| 690 | }; | ||
| 691 | |||
| 692 | static struct qcom_icc_node qhs_ahb2phy0 = { | ||
| 693 | .name = "qhs_ahb2phy0", | ||
| 694 | .id = SM8750_SLAVE_AHB2PHY_SOUTH, | ||
| 695 | .channels = 1, | ||
| 696 | .buswidth = 4, | ||
| 697 | .num_links = 0, | ||
| 698 | }; | ||
| 699 | |||
| 700 | static struct qcom_icc_node qhs_ahb2phy1 = { | ||
| 701 | .name = "qhs_ahb2phy1", | ||
| 702 | .id = SM8750_SLAVE_AHB2PHY_NORTH, | ||
| 703 | .channels = 1, | ||
| 704 | .buswidth = 4, | ||
| 705 | .num_links = 0, | ||
| 706 | }; | ||
| 707 | |||
| 708 | static struct qcom_icc_node qhs_camera_cfg = { | ||
| 709 | .name = "qhs_camera_cfg", | ||
| 710 | .id = SM8750_SLAVE_CAMERA_CFG, | ||
| 711 | .channels = 1, | ||
| 712 | .buswidth = 4, | ||
| 713 | .num_links = 0, | ||
| 714 | }; | ||
| 715 | |||
| 716 | static struct qcom_icc_node qhs_clk_ctl = { | ||
| 717 | .name = "qhs_clk_ctl", | ||
| 718 | .id = SM8750_SLAVE_CLK_CTL, | ||
| 719 | .channels = 1, | ||
| 720 | .buswidth = 4, | ||
| 721 | .num_links = 0, | ||
| 722 | }; | ||
| 723 | |||
| 724 | static struct qcom_icc_node qhs_crypto0_cfg = { | ||
| 725 | .name = "qhs_crypto0_cfg", | ||
| 726 | .id = SM8750_SLAVE_CRYPTO_0_CFG, | ||
| 727 | .channels = 1, | ||
| 728 | .buswidth = 4, | ||
| 729 | .num_links = 0, | ||
| 730 | }; | ||
| 731 | |||
| 732 | static struct qcom_icc_node qhs_display_cfg = { | ||
| 733 | .name = "qhs_display_cfg", | ||
| 734 | .id = SM8750_SLAVE_DISPLAY_CFG, | ||
| 735 | .channels = 1, | ||
| 736 | .buswidth = 4, | ||
| 737 | .num_links = 0, | ||
| 738 | }; | ||
| 739 | |||
| 740 | static struct qcom_icc_node qhs_eva_cfg = { | ||
| 741 | .name = "qhs_eva_cfg", | ||
| 742 | .id = SM8750_SLAVE_EVA_CFG, | ||
| 743 | .channels = 1, | ||
| 744 | .buswidth = 4, | ||
| 745 | .num_links = 0, | ||
| 746 | }; | ||
| 747 | |||
| 748 | static struct qcom_icc_node qhs_gpuss_cfg = { | ||
| 749 | .name = "qhs_gpuss_cfg", | ||
| 750 | .id = SM8750_SLAVE_GFX3D_CFG, | ||
| 751 | .channels = 1, | ||
| 752 | .buswidth = 8, | ||
| 753 | .num_links = 0, | ||
| 754 | }; | ||
| 755 | |||
| 756 | static struct qcom_icc_node qhs_i2c = { | ||
| 757 | .name = "qhs_i2c", | ||
| 758 | .id = SM8750_SLAVE_I2C, | ||
| 759 | .channels = 1, | ||
| 760 | .buswidth = 4, | ||
| 761 | .num_links = 0, | ||
| 762 | }; | ||
| 763 | |||
| 764 | static struct qcom_icc_node qhs_i3c_ibi0_cfg = { | ||
| 765 | .name = "qhs_i3c_ibi0_cfg", | ||
| 766 | .id = SM8750_SLAVE_I3C_IBI0_CFG, | ||
| 767 | .channels = 1, | ||
| 768 | .buswidth = 4, | ||
| 769 | .num_links = 0, | ||
| 770 | }; | ||
| 771 | |||
| 772 | static struct qcom_icc_node qhs_i3c_ibi1_cfg = { | ||
| 773 | .name = "qhs_i3c_ibi1_cfg", | ||
| 774 | .id = SM8750_SLAVE_I3C_IBI1_CFG, | ||
| 775 | .channels = 1, | ||
| 776 | .buswidth = 4, | ||
| 777 | .num_links = 0, | ||
| 778 | }; | ||
| 779 | |||
| 780 | static struct qcom_icc_node qhs_imem_cfg = { | ||
| 781 | .name = "qhs_imem_cfg", | ||
| 782 | .id = SM8750_SLAVE_IMEM_CFG, | ||
| 783 | .channels = 1, | ||
| 784 | .buswidth = 4, | ||
| 785 | .num_links = 0, | ||
| 786 | }; | ||
| 787 | |||
| 788 | static struct qcom_icc_node qhs_mss_cfg = { | ||
| 789 | .name = "qhs_mss_cfg", | ||
| 790 | .id = SM8750_SLAVE_CNOC_MSS, | ||
| 791 | .channels = 1, | ||
| 792 | .buswidth = 4, | ||
| 793 | .num_links = 0, | ||
| 794 | }; | ||
| 795 | |||
| 796 | static struct qcom_icc_node qhs_pcie_cfg = { | ||
| 797 | .name = "qhs_pcie_cfg", | ||
| 798 | .id = SM8750_SLAVE_PCIE_CFG, | ||
| 799 | .channels = 1, | ||
| 800 | .buswidth = 4, | ||
| 801 | .num_links = 0, | ||
| 802 | }; | ||
| 803 | |||
| 804 | static struct qcom_icc_node qhs_prng = { | ||
| 805 | .name = "qhs_prng", | ||
| 806 | .id = SM8750_SLAVE_PRNG, | ||
| 807 | .channels = 1, | ||
| 808 | .buswidth = 4, | ||
| 809 | .num_links = 0, | ||
| 810 | }; | ||
| 811 | |||
| 812 | static struct qcom_icc_node qhs_qdss_cfg = { | ||
| 813 | .name = "qhs_qdss_cfg", | ||
| 814 | .id = SM8750_SLAVE_QDSS_CFG, | ||
| 815 | .channels = 1, | ||
| 816 | .buswidth = 4, | ||
| 817 | .num_links = 0, | ||
| 818 | }; | ||
| 819 | |||
| 820 | static struct qcom_icc_node qhs_qspi = { | ||
| 821 | .name = "qhs_qspi", | ||
| 822 | .id = SM8750_SLAVE_QSPI_0, | ||
| 823 | .channels = 1, | ||
| 824 | .buswidth = 4, | ||
| 825 | .num_links = 0, | ||
| 826 | }; | ||
| 827 | |||
| 828 | static struct qcom_icc_node qhs_qup02 = { | ||
| 829 | .name = "qhs_qup02", | ||
| 830 | .id = SM8750_SLAVE_QUP_3, | ||
| 831 | .channels = 1, | ||
| 832 | .buswidth = 4, | ||
| 833 | .num_links = 0, | ||
| 834 | }; | ||
| 835 | |||
| 836 | static struct qcom_icc_node qhs_qup1 = { | ||
| 837 | .name = "qhs_qup1", | ||
| 838 | .id = SM8750_SLAVE_QUP_1, | ||
| 839 | .channels = 1, | ||
| 840 | .buswidth = 4, | ||
| 841 | .num_links = 0, | ||
| 842 | }; | ||
| 843 | |||
| 844 | static struct qcom_icc_node qhs_qup2 = { | ||
| 845 | .name = "qhs_qup2", | ||
| 846 | .id = SM8750_SLAVE_QUP_2, | ||
| 847 | .channels = 1, | ||
| 848 | .buswidth = 4, | ||
| 849 | .num_links = 0, | ||
| 850 | }; | ||
| 851 | |||
| 852 | static struct qcom_icc_node qhs_sdc2 = { | ||
| 853 | .name = "qhs_sdc2", | ||
| 854 | .id = SM8750_SLAVE_SDCC_2, | ||
| 855 | .channels = 1, | ||
| 856 | .buswidth = 4, | ||
| 857 | .num_links = 0, | ||
| 858 | }; | ||
| 859 | |||
| 860 | static struct qcom_icc_node qhs_sdc4 = { | ||
| 861 | .name = "qhs_sdc4", | ||
| 862 | .id = SM8750_SLAVE_SDCC_4, | ||
| 863 | .channels = 1, | ||
| 864 | .buswidth = 4, | ||
| 865 | .num_links = 0, | ||
| 866 | }; | ||
| 867 | |||
| 868 | static struct qcom_icc_node qhs_spss_cfg = { | ||
| 869 | .name = "qhs_spss_cfg", | ||
| 870 | .id = SM8750_SLAVE_SPSS_CFG, | ||
| 871 | .channels = 1, | ||
| 872 | .buswidth = 4, | ||
| 873 | .num_links = 0, | ||
| 874 | }; | ||
| 875 | |||
| 876 | static struct qcom_icc_node qhs_tcsr = { | ||
| 877 | .name = "qhs_tcsr", | ||
| 878 | .id = SM8750_SLAVE_TCSR, | ||
| 879 | .channels = 1, | ||
| 880 | .buswidth = 4, | ||
| 881 | .num_links = 0, | ||
| 882 | }; | ||
| 883 | |||
| 884 | static struct qcom_icc_node qhs_tlmm = { | ||
| 885 | .name = "qhs_tlmm", | ||
| 886 | .id = SM8750_SLAVE_TLMM, | ||
| 887 | .channels = 1, | ||
| 888 | .buswidth = 4, | ||
| 889 | .num_links = 0, | ||
| 890 | }; | ||
| 891 | |||
| 892 | static struct qcom_icc_node qhs_ufs_mem_cfg = { | ||
| 893 | .name = "qhs_ufs_mem_cfg", | ||
| 894 | .id = SM8750_SLAVE_UFS_MEM_CFG, | ||
| 895 | .channels = 1, | ||
| 896 | .buswidth = 4, | ||
| 897 | .num_links = 0, | ||
| 898 | }; | ||
| 899 | |||
| 900 | static struct qcom_icc_node qhs_usb3_0 = { | ||
| 901 | .name = "qhs_usb3_0", | ||
| 902 | .id = SM8750_SLAVE_USB3_0, | ||
| 903 | .channels = 1, | ||
| 904 | .buswidth = 4, | ||
| 905 | .num_links = 0, | ||
| 906 | }; | ||
| 907 | |||
| 908 | static struct qcom_icc_node qhs_venus_cfg = { | ||
| 909 | .name = "qhs_venus_cfg", | ||
| 910 | .id = SM8750_SLAVE_VENUS_CFG, | ||
| 911 | .channels = 1, | ||
| 912 | .buswidth = 4, | ||
| 913 | .num_links = 0, | ||
| 914 | }; | ||
| 915 | |||
| 916 | static struct qcom_icc_node qhs_vsense_ctrl_cfg = { | ||
| 917 | .name = "qhs_vsense_ctrl_cfg", | ||
| 918 | .id = SM8750_SLAVE_VSENSE_CTRL_CFG, | ||
| 919 | .channels = 1, | ||
| 920 | .buswidth = 4, | ||
| 921 | .num_links = 0, | ||
| 922 | }; | ||
| 923 | |||
| 924 | static struct qcom_icc_node qss_mnoc_cfg = { | ||
| 925 | .name = "qss_mnoc_cfg", | ||
| 926 | .id = SM8750_SLAVE_CNOC_MNOC_CFG, | ||
| 927 | .channels = 1, | ||
| 928 | .buswidth = 4, | ||
| 929 | .num_links = 1, | ||
| 930 | .links = { SM8750_MASTER_CNOC_MNOC_CFG }, | ||
| 931 | }; | ||
| 932 | |||
| 933 | static struct qcom_icc_node qss_pcie_anoc_cfg = { | ||
| 934 | .name = "qss_pcie_anoc_cfg", | ||
| 935 | .id = SM8750_SLAVE_PCIE_ANOC_CFG, | ||
| 936 | .channels = 1, | ||
| 937 | .buswidth = 4, | ||
| 938 | .num_links = 1, | ||
| 939 | .links = { SM8750_MASTER_PCIE_ANOC_CFG }, | ||
| 940 | }; | ||
| 941 | |||
| 942 | static struct qcom_icc_node xs_qdss_stm = { | ||
| 943 | .name = "xs_qdss_stm", | ||
| 944 | .id = SM8750_SLAVE_QDSS_STM, | ||
| 945 | .channels = 1, | ||
| 946 | .buswidth = 4, | ||
| 947 | .num_links = 0, | ||
| 948 | }; | ||
| 949 | |||
| 950 | static struct qcom_icc_node xs_sys_tcu_cfg = { | ||
| 951 | .name = "xs_sys_tcu_cfg", | ||
| 952 | .id = SM8750_SLAVE_TCU, | ||
| 953 | .channels = 1, | ||
| 954 | .buswidth = 8, | ||
| 955 | .num_links = 0, | ||
| 956 | }; | ||
| 957 | |||
| 958 | static struct qcom_icc_node qhs_aoss = { | ||
| 959 | .name = "qhs_aoss", | ||
| 960 | .id = SM8750_SLAVE_AOSS, | ||
| 961 | .channels = 1, | ||
| 962 | .buswidth = 4, | ||
| 963 | .num_links = 0, | ||
| 964 | }; | ||
| 965 | |||
| 966 | static struct qcom_icc_node qhs_ipa = { | ||
| 967 | .name = "qhs_ipa", | ||
| 968 | .id = SM8750_SLAVE_IPA_CFG, | ||
| 969 | .channels = 1, | ||
| 970 | .buswidth = 4, | ||
| 971 | .num_links = 0, | ||
| 972 | }; | ||
| 973 | |||
| 974 | static struct qcom_icc_node qhs_ipc_router = { | ||
| 975 | .name = "qhs_ipc_router", | ||
| 976 | .id = SM8750_SLAVE_IPC_ROUTER_CFG, | ||
| 977 | .channels = 1, | ||
| 978 | .buswidth = 4, | ||
| 979 | .num_links = 0, | ||
| 980 | }; | ||
| 981 | |||
| 982 | static struct qcom_icc_node qhs_soccp = { | ||
| 983 | .name = "qhs_soccp", | ||
| 984 | .id = SM8750_SLAVE_SOCCP, | ||
| 985 | .channels = 1, | ||
| 986 | .buswidth = 4, | ||
| 987 | .num_links = 0, | ||
| 988 | }; | ||
| 989 | |||
| 990 | static struct qcom_icc_node qhs_tme_cfg = { | ||
| 991 | .name = "qhs_tme_cfg", | ||
| 992 | .id = SM8750_SLAVE_TME_CFG, | ||
| 993 | .channels = 1, | ||
| 994 | .buswidth = 4, | ||
| 995 | .num_links = 0, | ||
| 996 | }; | ||
| 997 | |||
| 998 | static struct qcom_icc_node qns_apss = { | ||
| 999 | .name = "qns_apss", | ||
| 1000 | .id = SM8750_SLAVE_APPSS, | ||
| 1001 | .channels = 1, | ||
| 1002 | .buswidth = 8, | ||
| 1003 | .num_links = 0, | ||
| 1004 | }; | ||
| 1005 | |||
| 1006 | static struct qcom_icc_node qss_cfg = { | ||
| 1007 | .name = "qss_cfg", | ||
| 1008 | .id = SM8750_SLAVE_CNOC_CFG, | ||
| 1009 | .channels = 1, | ||
| 1010 | .buswidth = 4, | ||
| 1011 | .num_links = 1, | ||
| 1012 | .links = { SM8750_MASTER_CNOC_CFG }, | ||
| 1013 | }; | ||
| 1014 | |||
| 1015 | static struct qcom_icc_node qss_ddrss_cfg = { | ||
| 1016 | .name = "qss_ddrss_cfg", | ||
| 1017 | .id = SM8750_SLAVE_DDRSS_CFG, | ||
| 1018 | .channels = 1, | ||
| 1019 | .buswidth = 4, | ||
| 1020 | .num_links = 0, | ||
| 1021 | }; | ||
| 1022 | |||
| 1023 | static struct qcom_icc_node qxs_boot_imem = { | ||
| 1024 | .name = "qxs_boot_imem", | ||
| 1025 | .id = SM8750_SLAVE_BOOT_IMEM, | ||
| 1026 | .channels = 1, | ||
| 1027 | .buswidth = 16, | ||
| 1028 | .num_links = 0, | ||
| 1029 | }; | ||
| 1030 | |||
| 1031 | static struct qcom_icc_node qxs_imem = { | ||
| 1032 | .name = "qxs_imem", | ||
| 1033 | .id = SM8750_SLAVE_IMEM, | ||
| 1034 | .channels = 1, | ||
| 1035 | .buswidth = 8, | ||
| 1036 | .num_links = 0, | ||
| 1037 | }; | ||
| 1038 | |||
| 1039 | static struct qcom_icc_node qxs_modem_boot_imem = { | ||
| 1040 | .name = "qxs_modem_boot_imem", | ||
| 1041 | .id = SM8750_SLAVE_BOOT_IMEM_2, | ||
| 1042 | .channels = 1, | ||
| 1043 | .buswidth = 8, | ||
| 1044 | .num_links = 0, | ||
| 1045 | }; | ||
| 1046 | |||
| 1047 | static struct qcom_icc_node srvc_cnoc_main = { | ||
| 1048 | .name = "srvc_cnoc_main", | ||
| 1049 | .id = SM8750_SLAVE_SERVICE_CNOC, | ||
| 1050 | .channels = 1, | ||
| 1051 | .buswidth = 4, | ||
| 1052 | .num_links = 0, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | static struct qcom_icc_node xs_pcie = { | ||
| 1056 | .name = "xs_pcie", | ||
| 1057 | .id = SM8750_SLAVE_PCIE_0, | ||
| 1058 | .channels = 1, | ||
| 1059 | .buswidth = 8, | ||
| 1060 | .num_links = 0, | ||
| 1061 | }; | ||
| 1062 | |||
| 1063 | static struct qcom_icc_node chs_ubwc_p = { | ||
| 1064 | .name = "chs_ubwc_p", | ||
| 1065 | .id = SM8750_SLAVE_UBWC_P, | ||
| 1066 | .channels = 1, | ||
| 1067 | .buswidth = 32, | ||
| 1068 | .num_links = 0, | ||
| 1069 | }; | ||
| 1070 | |||
| 1071 | static struct qcom_icc_node qns_gem_noc_cnoc = { | ||
| 1072 | .name = "qns_gem_noc_cnoc", | ||
| 1073 | .id = SM8750_SLAVE_GEM_NOC_CNOC, | ||
| 1074 | .channels = 1, | ||
| 1075 | .buswidth = 16, | ||
| 1076 | .num_links = 1, | ||
| 1077 | .links = { SM8750_MASTER_GEM_NOC_CNOC }, | ||
| 1078 | }; | ||
| 1079 | |||
| 1080 | static struct qcom_icc_node qns_llcc = { | ||
| 1081 | .name = "qns_llcc", | ||
| 1082 | .id = SM8750_SLAVE_LLCC, | ||
| 1083 | .channels = 4, | ||
| 1084 | .buswidth = 16, | ||
| 1085 | .num_links = 1, | ||
| 1086 | .links = { SM8750_MASTER_LLCC }, | ||
| 1087 | }; | ||
| 1088 | |||
| 1089 | static struct qcom_icc_node qns_pcie = { | ||
| 1090 | .name = "qns_pcie", | ||
| 1091 | .id = SM8750_SLAVE_MEM_NOC_PCIE_SNOC, | ||
| 1092 | .channels = 1, | ||
| 1093 | .buswidth = 8, | ||
| 1094 | .num_links = 1, | ||
| 1095 | .links = { SM8750_MASTER_GEM_NOC_PCIE_SNOC }, | ||
| 1096 | }; | ||
| 1097 | |||
| 1098 | static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = { | ||
| 1099 | .name = "qns_lpass_ag_noc_gemnoc", | ||
| 1100 | .id = SM8750_SLAVE_LPASS_GEM_NOC, | ||
| 1101 | .channels = 1, | ||
| 1102 | .buswidth = 16, | ||
| 1103 | .num_links = 1, | ||
| 1104 | .links = { SM8750_MASTER_LPASS_GEM_NOC }, | ||
| 1105 | }; | ||
| 1106 | |||
| 1107 | static struct qcom_icc_node qns_lpass_aggnoc = { | ||
| 1108 | .name = "qns_lpass_aggnoc", | ||
| 1109 | .id = SM8750_SLAVE_LPIAON_NOC_LPASS_AG_NOC, | ||
| 1110 | .channels = 1, | ||
| 1111 | .buswidth = 16, | ||
| 1112 | .num_links = 1, | ||
| 1113 | .links = { SM8750_MASTER_LPIAON_NOC }, | ||
| 1114 | }; | ||
| 1115 | |||
| 1116 | static struct qcom_icc_node qns_lpi_aon_noc = { | ||
| 1117 | .name = "qns_lpi_aon_noc", | ||
| 1118 | .id = SM8750_SLAVE_LPICX_NOC_LPIAON_NOC, | ||
| 1119 | .channels = 1, | ||
| 1120 | .buswidth = 16, | ||
| 1121 | .num_links = 1, | ||
| 1122 | .links = { SM8750_MASTER_LPASS_LPINOC }, | ||
| 1123 | }; | ||
| 1124 | |||
| 1125 | static struct qcom_icc_node ebi = { | ||
| 1126 | .name = "ebi", | ||
| 1127 | .id = SM8750_SLAVE_EBI1, | ||
| 1128 | .channels = 4, | ||
| 1129 | .buswidth = 4, | ||
| 1130 | .num_links = 0, | ||
| 1131 | }; | ||
| 1132 | |||
| 1133 | static struct qcom_icc_node qns_mem_noc_hf = { | ||
| 1134 | .name = "qns_mem_noc_hf", | ||
| 1135 | .id = SM8750_SLAVE_MNOC_HF_MEM_NOC, | ||
| 1136 | .channels = 2, | ||
| 1137 | .buswidth = 32, | ||
| 1138 | .num_links = 1, | ||
| 1139 | .links = { SM8750_MASTER_MNOC_HF_MEM_NOC }, | ||
| 1140 | }; | ||
| 1141 | |||
| 1142 | static struct qcom_icc_node qns_mem_noc_sf = { | ||
| 1143 | .name = "qns_mem_noc_sf", | ||
| 1144 | .id = SM8750_SLAVE_MNOC_SF_MEM_NOC, | ||
| 1145 | .channels = 2, | ||
| 1146 | .buswidth = 32, | ||
| 1147 | .num_links = 1, | ||
| 1148 | .links = { SM8750_MASTER_MNOC_SF_MEM_NOC }, | ||
| 1149 | }; | ||
| 1150 | |||
| 1151 | static struct qcom_icc_node srvc_mnoc = { | ||
| 1152 | .name = "srvc_mnoc", | ||
| 1153 | .id = SM8750_SLAVE_SERVICE_MNOC, | ||
| 1154 | .channels = 1, | ||
| 1155 | .buswidth = 4, | ||
| 1156 | .num_links = 0, | ||
| 1157 | }; | ||
| 1158 | |||
| 1159 | static struct qcom_icc_node qns_nsp_gemnoc = { | ||
| 1160 | .name = "qns_nsp_gemnoc", | ||
| 1161 | .id = SM8750_SLAVE_CDSP_MEM_NOC, | ||
| 1162 | .channels = 2, | ||
| 1163 | .buswidth = 32, | ||
| 1164 | .num_links = 1, | ||
| 1165 | .links = { SM8750_MASTER_COMPUTE_NOC }, | ||
| 1166 | }; | ||
| 1167 | |||
| 1168 | static struct qcom_icc_node qns_pcie_mem_noc = { | ||
| 1169 | .name = "qns_pcie_mem_noc", | ||
| 1170 | .id = SM8750_SLAVE_ANOC_PCIE_GEM_NOC, | ||
| 1171 | .channels = 1, | ||
| 1172 | .buswidth = 8, | ||
| 1173 | .num_links = 1, | ||
| 1174 | .links = { SM8750_MASTER_ANOC_PCIE_GEM_NOC }, | ||
| 1175 | }; | ||
| 1176 | |||
| 1177 | static struct qcom_icc_node srvc_pcie_aggre_noc = { | ||
| 1178 | .name = "srvc_pcie_aggre_noc", | ||
| 1179 | .id = SM8750_SLAVE_SERVICE_PCIE_ANOC, | ||
| 1180 | .channels = 1, | ||
| 1181 | .buswidth = 4, | ||
| 1182 | .num_links = 0, | ||
| 1183 | }; | ||
| 1184 | |||
| 1185 | static struct qcom_icc_node qns_gemnoc_sf = { | ||
| 1186 | .name = "qns_gemnoc_sf", | ||
| 1187 | .id = SM8750_SLAVE_SNOC_GEM_NOC_SF, | ||
| 1188 | .channels = 1, | ||
| 1189 | .buswidth = 16, | ||
| 1190 | .num_links = 1, | ||
| 1191 | .links = { SM8750_MASTER_SNOC_SF_MEM_NOC }, | ||
| 1192 | }; | ||
| 1193 | |||
| 1194 | static struct qcom_icc_bcm bcm_acv = { | ||
| 1195 | .name = "ACV", | ||
| 1196 | .enable_mask = BIT(0), | ||
| 1197 | .num_nodes = 1, | ||
| 1198 | .nodes = { &ebi }, | ||
| 1199 | }; | ||
| 1200 | |||
| 1201 | static struct qcom_icc_bcm bcm_ce0 = { | ||
| 1202 | .name = "CE0", | ||
| 1203 | .num_nodes = 1, | ||
| 1204 | .nodes = { &qxm_crypto }, | ||
| 1205 | }; | ||
| 1206 | |||
| 1207 | static struct qcom_icc_bcm bcm_cn0 = { | ||
| 1208 | .name = "CN0", | ||
| 1209 | .enable_mask = BIT(0), | ||
| 1210 | .keepalive = true, | ||
| 1211 | .num_nodes = 44, | ||
| 1212 | .nodes = { &qsm_cfg, &qhs_ahb2phy0, | ||
| 1213 | &qhs_ahb2phy1, &qhs_camera_cfg, | ||
| 1214 | &qhs_clk_ctl, &qhs_crypto0_cfg, | ||
| 1215 | &qhs_eva_cfg, &qhs_gpuss_cfg, | ||
| 1216 | &qhs_i3c_ibi0_cfg, &qhs_i3c_ibi1_cfg, | ||
| 1217 | &qhs_imem_cfg, &qhs_mss_cfg, | ||
| 1218 | &qhs_pcie_cfg, &qhs_prng, | ||
| 1219 | &qhs_qdss_cfg, &qhs_qspi, | ||
| 1220 | &qhs_sdc2, &qhs_sdc4, | ||
| 1221 | &qhs_spss_cfg, &qhs_tcsr, | ||
| 1222 | &qhs_tlmm, &qhs_ufs_mem_cfg, | ||
| 1223 | &qhs_usb3_0, &qhs_venus_cfg, | ||
| 1224 | &qhs_vsense_ctrl_cfg, &qss_mnoc_cfg, | ||
| 1225 | &qss_pcie_anoc_cfg, &xs_qdss_stm, | ||
| 1226 | &xs_sys_tcu_cfg, &qnm_gemnoc_cnoc, | ||
| 1227 | &qnm_gemnoc_pcie, &qhs_aoss, | ||
| 1228 | &qhs_ipa, &qhs_ipc_router, | ||
| 1229 | &qhs_soccp, &qhs_tme_cfg, | ||
| 1230 | &qns_apss, &qss_cfg, | ||
| 1231 | &qss_ddrss_cfg, &qxs_boot_imem, | ||
| 1232 | &qxs_imem, &qxs_modem_boot_imem, | ||
| 1233 | &srvc_cnoc_main, &xs_pcie }, | ||
| 1234 | }; | ||
| 1235 | |||
| 1236 | static struct qcom_icc_bcm bcm_cn1 = { | ||
| 1237 | .name = "CN1", | ||
| 1238 | .num_nodes = 5, | ||
| 1239 | .nodes = { &qhs_display_cfg, &qhs_i2c, | ||
| 1240 | &qhs_qup02, &qhs_qup1, | ||
| 1241 | &qhs_qup2 }, | ||
| 1242 | }; | ||
| 1243 | |||
| 1244 | static struct qcom_icc_bcm bcm_co0 = { | ||
| 1245 | .name = "CO0", | ||
| 1246 | .enable_mask = BIT(0), | ||
| 1247 | .num_nodes = 2, | ||
| 1248 | .nodes = { &qnm_nsp, &qns_nsp_gemnoc }, | ||
| 1249 | }; | ||
| 1250 | |||
| 1251 | static struct qcom_icc_bcm bcm_lp0 = { | ||
| 1252 | .name = "LP0", | ||
| 1253 | .num_nodes = 2, | ||
| 1254 | .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc }, | ||
| 1255 | }; | ||
| 1256 | |||
| 1257 | static struct qcom_icc_bcm bcm_mc0 = { | ||
| 1258 | .name = "MC0", | ||
| 1259 | .keepalive = true, | ||
| 1260 | .num_nodes = 1, | ||
| 1261 | .nodes = { &ebi }, | ||
| 1262 | }; | ||
| 1263 | |||
| 1264 | static struct qcom_icc_bcm bcm_mm0 = { | ||
| 1265 | .name = "MM0", | ||
| 1266 | .num_nodes = 1, | ||
| 1267 | .nodes = { &qns_mem_noc_hf }, | ||
| 1268 | }; | ||
| 1269 | |||
| 1270 | static struct qcom_icc_bcm bcm_mm1 = { | ||
| 1271 | .name = "MM1", | ||
| 1272 | .enable_mask = BIT(0), | ||
| 1273 | .num_nodes = 9, | ||
| 1274 | .nodes = { &qnm_camnoc_hf, &qnm_camnoc_nrt_icp_sf, | ||
| 1275 | &qnm_camnoc_rt_cdm_sf, &qnm_camnoc_sf, | ||
| 1276 | &qnm_vapss_hcp, &qnm_video_cv_cpu, | ||
| 1277 | &qnm_video_mvp, &qnm_video_v_cpu, | ||
| 1278 | &qns_mem_noc_sf }, | ||
| 1279 | }; | ||
| 1280 | |||
| 1281 | static struct qcom_icc_bcm bcm_qup0 = { | ||
| 1282 | .name = "QUP0", | ||
| 1283 | .keepalive = true, | ||
| 1284 | .vote_scale = 1, | ||
| 1285 | .num_nodes = 1, | ||
| 1286 | .nodes = { &qup0_core_slave }, | ||
| 1287 | }; | ||
| 1288 | |||
| 1289 | static struct qcom_icc_bcm bcm_qup1 = { | ||
| 1290 | .name = "QUP1", | ||
| 1291 | .keepalive = true, | ||
| 1292 | .vote_scale = 1, | ||
| 1293 | .num_nodes = 1, | ||
| 1294 | .nodes = { &qup1_core_slave }, | ||
| 1295 | }; | ||
| 1296 | |||
| 1297 | static struct qcom_icc_bcm bcm_qup2 = { | ||
| 1298 | .name = "QUP2", | ||
| 1299 | .keepalive = true, | ||
| 1300 | .vote_scale = 1, | ||
| 1301 | .num_nodes = 1, | ||
404 more lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 248 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 1130 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 309 lines aren’t shown here.
This diff is large: its 9 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 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 105 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 36 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
File renamed without changes.
This diff is large: its 47 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 18 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 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 1344 lines aren’t shown here.