Jonathan writes: Second set of IIO new device support, features and cleanups. There are also a couple of fixes that can wait for the coming merge window. Core new features * Support for phase channels (used in time of flight sensors amongst other things) * Support for deep UV light channel modifier. New Device Support * AD4758 DAC - New driver and dt bindings. * adxl345 - Support the adxl375 +-200g part which is register compatible. * isl29501 Time of flight sensor. - New driver * meson-saradc - Support the Meson8m2 Socs - right now this is just an ID, but there will be additional difference in future. * mpu6050 - New ID for 6515 variant. * si1133 UV sensor. - New driver * Spreadtrum SC27xx PMIC ADC - New driver and dt bindings. Features * adxl345 - Add calibration offset readback and writing. - Add sampling frequency control. Fixes and Cleanups * ad5933 - Use a macro for the channel definition to reduce duplication. * ad9523 - Replace use of core mlock with a local lock. Part of ongoing efforts to avoid confusing the purpose of mlock which is only about iio core state changes. - Fix displayed phase which was out by a factor of 10. * adxl345 - Add a link to the datasheet. - Rework the use of the address field in the chan_spec structures to allow addition of more per channel information. * adis imu - Mark switch fall throughs. * at91-sama5d2 - Fix some casting on big endian systems. * bmp280 - Drop some DT elements that aren't used and should mostly be done from userspace rather than in DT. * hx711 - add clock-frequency dt binding and resulting delay to deal with capacitance issue on some boards. - fix a spurious unit-address in the example. * ina2xx - Avoid a possible kthread_stop with a stale task_struct. * ltc2632 - Remove some unused local variables (assigned but value never used). * max1363 - Use device_get_match_data to remove some boilerplate. * mma8452 - Mark switch fall throughs. * sca3000 - Fix a missing return in a switch statement (a bad fallthrough previously!) * sigma-delta-modulator - Drop incorrect unit address from the DT example. * st_accel - Use device_get_match_data to drop some boiler plate. - Move to probe_new for i2c driver as second parameter not used. * st_sensors library - Use a strlcpy (safe in this case). * st_lsm6dsx - Add some error logging. * ti-ads7950 - SPDX - Allow simultaneous buffered and polled reads. Needed on a Lego Mindstorms EV3 where some channels are used for power supply monitoring at a very low rate. * ti-dac5571 - Remove an unused variable. * xadc - Drop some dead code.
Unified · Split
| @@ -1307,13 +1307,16 @@ What: /sys/.../iio:deviceX/in_intensityY_raw · 1306 unmodified lines | |||
| 1307 | What: /sys/.../iio:deviceX/in_intensityY_ir_raw | 1307 | What: /sys/.../iio:deviceX/in_intensityY_ir_raw |
| 1308 | What: /sys/.../iio:deviceX/in_intensityY_both_raw | 1308 | What: /sys/.../iio:deviceX/in_intensityY_both_raw |
| 1309 | What: /sys/.../iio:deviceX/in_intensityY_uv_raw | 1309 | What: /sys/.../iio:deviceX/in_intensityY_uv_raw |
| 1310 | What: /sys/.../iio:deviceX/in_intensityY_duv_raw | ||
| 1310 | KernelVersion: 3.4 | 1311 | KernelVersion: 3.4 |
| 1311 | Contact: linux-iio@vger.kernel.org | 1312 | Contact: linux-iio@vger.kernel.org |
| 1312 | Description: | 1313 | Description: |
| 1313 | Unit-less light intensity. Modifiers both and ir indicate | 1314 | Unit-less light intensity. Modifiers both and ir indicate |
| 1314 | that measurements contain visible and infrared light | 1315 | that measurements contain visible and infrared light |
| 1315 | components or just infrared light, respectively. Modifier uv indicates | 1316 | components or just infrared light, respectively. Modifier |
| 1316 | that measurements contain ultraviolet light components. | 1317 | uv indicates that measurements contain ultraviolet light |
| 1318 | components. Modifier duv indicates that measurements | ||
| 1319 | contain deep ultraviolet light components. | ||
| 1317 | 1320 | ||
| 1318 | What: /sys/.../iio:deviceX/in_uvindex_input | 1321 | What: /sys/.../iio:deviceX/in_uvindex_input |
| 1319 | KernelVersion: 4.6 | 1322 | KernelVersion: 4.6 |
| @@ -1675,3 +1678,10 @@ KernelVersion: 4.12 · 355 unmodified lines | |||
| 1675 | Contact: linux-iio@vger.kernel.org | 1678 | Contact: linux-iio@vger.kernel.org |
| 1676 | Description: | 1679 | Description: |
| 1677 | Raw counter device counters direction for channel Y. | 1680 | Raw counter device counters direction for channel Y. |
| 1681 | |||
| 1682 | What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw | ||
| 1683 | KernelVersion: 4.18 | ||
| 1684 | Contact: linux-iio@vger.kernel.org | ||
| 1685 | Description: | ||
| 1686 | Raw (unscaled) phase difference reading from channel Y | ||
| 1687 | that can be processed to radians. | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain | ||
| 2 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain_bias | ||
| 3 | KernelVersion: 4.18 | ||
| 4 | Contact: linux-iio@vger.kernel.org | ||
| 5 | Description: | ||
| 6 | This sensor has an automatic gain control (agc) loop | ||
| 7 | which sets the analog signal levels at an optimum | ||
| 8 | level by controlling programmable gain amplifiers. The | ||
| 9 | criteria for optimal gain is determined by the sensor. | ||
| 10 | |||
| 11 | Return the actual gain value as an integer in [0; 65536] | ||
| 12 | range when read from. | ||
| 13 | |||
| 14 | The agc gain read when measuring crosstalk shall be | ||
| 15 | written into in_proximity0_agc_gain_bias. | ||
| 16 | |||
| 17 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_a | ||
| 18 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_b | ||
| 19 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_a | ||
| 20 | What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_b | ||
| 21 | KernelVersion: 4.18 | ||
| 22 | Contact: linux-iio@vger.kernel.org | ||
| 23 | Description: | ||
| 24 | The sensor is able to perform correction of distance | ||
| 25 | measurements due to changing temperature and ambient | ||
| 26 | light conditions. It can be programmed to correct for | ||
| 27 | a second order error polynomial. | ||
| 28 | |||
| 29 | Phase data has to be collected when temperature and | ||
| 30 | ambient light are modulated independently. | ||
| 31 | |||
| 32 | Then a least squares curve fit to a second order | ||
| 33 | polynomial has to be generated from the data. The | ||
| 34 | resultant curves have the form ax^2 + bx + c. | ||
| 35 | |||
| 36 | From those two curves, a and b coefficients shall be | ||
| 37 | stored in in_proximity0_calib_phase_temp_a and | ||
| 38 | in_proximity0_calib_phase_temp_b for temperature and | ||
| 39 | in in_proximity0_calib_phase_light_a and | ||
| 40 | in_proximity0_calib_phase_light_b for ambient light. | ||
| 41 | |||
| 42 | Those values must be integer in [0; 8355840] range. | ||
| 43 | |||
| 44 | Finally, the c constant is set by the sensor | ||
| 45 | internally. | ||
| 46 | |||
| 47 | The value stored in sensor is displayed when read from. | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_small_raw | ||
| 2 | KernelVersion: 4.18 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Unit-less infrared intensity. The intensity is measured from 1 | ||
| 6 | dark photodiode. "small" indicate the surface area capturing | ||
| 7 | infrared. | ||
| 8 | |||
| 9 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_large_raw | ||
| 10 | KernelVersion: 4.18 | ||
| 11 | Contact: linux-iio@vger.kernel.org | ||
| 12 | Description: | ||
| 13 | Unit-less infrared intensity. The intensity is measured from 4 | ||
| 14 | dark photodiodes. "large" indicate the surface area capturing | ||
| 15 | infrared. | ||
| 16 | |||
| 17 | What: /sys/bus/iio/devices/iio:deviceX/in_intensity_large_raw | ||
| 18 | KernelVersion: 4.18 | ||
| 19 | Contact: linux-iio@vger.kernel.org | ||
| 20 | Description: | ||
| 21 | Unit-less light intensity with more diodes. | ||
| 22 | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | Analog Devices ADXL345 3-Axis, +/-(2g/4g/8g/16g) Digital Accelerometer | 1 | Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers |
| 2 | 2 | ||
| 3 | http://www.analog.com/en/products/mems/accelerometers/adxl345.html | 3 | http://www.analog.com/en/products/mems/accelerometers/adxl345.html |
| 4 | http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html | ||
| 4 | 5 | ||
| 5 | Required properties: | 6 | Required properties: |
| 6 | - compatible : should be "adi,adxl345" | 7 | - compatible : should be one of |
| 8 | "adi,adxl345" | ||
| 9 | "adi,adxl375" | ||
| 7 | - reg : the I2C address or SPI chip select number of the sensor | 10 | - reg : the I2C address or SPI chip select number of the sensor |
| 8 | 11 | ||
| 9 | Required properties for SPI bus usage: | 12 | Required properties for SPI bus usage: |
| @@ -4,6 +4,7 @@ Required properties: · 3 unmodified lines | |||
| 4 | - compatible: depending on the SoC this should be one of: | 4 | - compatible: depending on the SoC this should be one of: |
| 5 | - "amlogic,meson8-saradc" for Meson8 | 5 | - "amlogic,meson8-saradc" for Meson8 |
| 6 | - "amlogic,meson8b-saradc" for Meson8b | 6 | - "amlogic,meson8b-saradc" for Meson8b |
| 7 | - "amlogic,meson8m2-saradc" for Meson8m2 | ||
| 7 | - "amlogic,meson-gxbb-saradc" for GXBB | 8 | - "amlogic,meson-gxbb-saradc" for GXBB |
| 8 | - "amlogic,meson-gxl-saradc" for GXL | 9 | - "amlogic,meson-gxl-saradc" for GXL |
| 9 | - "amlogic,meson-gxm-saradc" for GXM | 10 | - "amlogic,meson-gxm-saradc" for GXM |
| @@ -8,11 +8,17 @@ Required properties: · 7 unmodified lines | |||
| 8 | See Documentation/devicetree/bindings/gpio/gpio.txt | 8 | See Documentation/devicetree/bindings/gpio/gpio.txt |
| 9 | - avdd-supply: Definition of the regulator used as analog supply | 9 | - avdd-supply: Definition of the regulator used as analog supply |
| 10 | 10 | ||
| 11 | Optional properties: | ||
| 12 | - clock-frequency: Frequency of PD_SCK in Hz | ||
| 13 | Minimum value allowed is 10 kHz because of maximum | ||
| 14 | high time of 50 microseconds. | ||
| 15 | |||
| 11 | Example: | 16 | Example: |
| 12 | weight@0 { | 17 | weight { |
| 13 | compatible = "avia,hx711"; | 18 | compatible = "avia,hx711"; |
| 14 | sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; | 19 | sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; |
| 15 | dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; | 20 | dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; |
| 16 | avdd-suppy = <&avdd>; | 21 | avdd-suppy = <&avdd>; |
| 22 | clock-frequency = <100000>; | ||
| 17 | }; | 23 | }; |
| 18 | 24 | ||
| @@ -7,7 +7,7 @@ Required properties: · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | Example node: | 8 | Example node: |
| 9 | 9 | ||
| 10 | ads1202: adc@0 { | 10 | ads1202: adc { |
| 11 | compatible = "sd-modulator"; | 11 | compatible = "sd-modulator"; |
| 12 | #io-channel-cells = <0>; | 12 | #io-channel-cells = <0>; |
| 13 | }; | 13 | }; |
| @@ -0,0 +1,36 @@ | |||
| 1 | Spreadtrum SC27XX series PMICs ADC binding | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be one of the following. | ||
| 5 | "sprd,sc2720-adc" | ||
| 6 | "sprd,sc2721-adc" | ||
| 7 | "sprd,sc2723-adc" | ||
| 8 | "sprd,sc2730-adc" | ||
| 9 | "sprd,sc2731-adc" | ||
| 10 | - reg: The address offset of ADC controller. | ||
| 11 | - interrupt-parent: The interrupt controller. | ||
| 12 | - interrupts: The interrupt number for the ADC device. | ||
| 13 | - #io-channel-cells: Number of cells in an IIO specifier. | ||
| 14 | - hwlocks: Reference to a phandle of a hwlock provider node. | ||
| 15 | |||
| 16 | Example: | ||
| 17 | |||
| 18 | sc2731_pmic: pmic@0 { | ||
| 19 | compatible = "sprd,sc2731"; | ||
| 20 | reg = <0>; | ||
| 21 | spi-max-frequency = <26000000>; | ||
| 22 | interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; | ||
| 23 | interrupt-controller; | ||
| 24 | #interrupt-cells = <2>; | ||
| 25 | #address-cells = <1>; | ||
| 26 | #size-cells = <0>; | ||
| 27 | |||
| 28 | pmic_adc: adc@480 { | ||
| 29 | compatible = "sprd,sc2731-adc"; | ||
| 30 | reg = <0x480>; | ||
| 31 | interrupt-parent = <&sc2731_pmic>; | ||
| 32 | interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; | ||
| 33 | #io-channel-cells = <1>; | ||
| 34 | hwlocks = <&hwlock 4>; | ||
| 35 | }; | ||
| 36 | }; | ||
| @@ -0,0 +1,78 @@ | |||
| 1 | Analog Devices AD5758 DAC device driver | ||
| 2 | |||
| 3 | Required properties for the AD5758: | ||
| 4 | - compatible: Must be "adi,ad5758" | ||
| 5 | - reg: SPI chip select number for the device | ||
| 6 | - spi-max-frequency: Max SPI frequency to use (< 50000000) | ||
| 7 | - spi-cpha: is the only mode that is supported | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | |||
| 11 | - adi,dc-dc-mode: Mode of operation of the dc-to-dc converter | ||
| 12 | Dynamic Power Control (DPC) | ||
| 13 | In this mode, the AD5758 circuitry senses the output | ||
| 14 | voltage and dynamically regulates the supply voltage, | ||
| 15 | VDPC+, to meet compliance requirements plus an optimized | ||
| 16 | headroom voltage for the output buffer. | ||
| 17 | |||
| 18 | Programmable Power Control (PPC) | ||
| 19 | In this mode, the VDPC+ voltage is user-programmable to | ||
| 20 | a fixed level that needs to accommodate the maximum output | ||
| 21 | load required. | ||
| 22 | |||
| 23 | The output of the DAC core is either converted to a | ||
| 24 | current or voltage output at the VIOUT pin. Only one mode | ||
| 25 | can be enabled at any one time. | ||
| 26 | |||
| 27 | The following values are currently supported: | ||
| 28 | * 1: DPC current mode | ||
| 29 | * 2: DPC voltage mode | ||
| 30 | * 3: PPC current mode | ||
| 31 | |||
| 32 | Depending on the selected output mode (voltage or current) one of the | ||
| 33 | two properties must | ||
| 34 | be present: | ||
| 35 | |||
| 36 | - adi,range-microvolt: Voltage output range | ||
| 37 | The array of voltage output ranges must contain two fields: | ||
| 38 | * <0 5000000>: 0 V to 5 V voltage range | ||
| 39 | * <0 10000000>: 0 V to 10 V voltage range | ||
| 40 | * <(-5000000) 5000000>: ±5 V voltage range | ||
| 41 | * <(-10000000) 10000000>: ±10 V voltage range | ||
| 42 | - adi,range-microamp: Current output range | ||
| 43 | The array of current output ranges must contain two fields: | ||
| 44 | * <0 20000>: 0 mA to 20 mA current range | ||
| 45 | * <0 24000>: 0 mA to 24 mA current range | ||
| 46 | * <4 24000>: 4 mA to 20 mA current range | ||
| 47 | * <(-20000) 20000>: ±20 mA current range | ||
| 48 | * <(-24000) 24000>: ±24 mA current range | ||
| 49 | * <(-1000) 22000>: −1 mA to +22 mA current range | ||
| 50 | |||
| 51 | Optional properties: | ||
| 52 | |||
| 53 | - adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit | ||
| 54 | The following values are currently supported [uA]: | ||
| 55 | * 150000 | ||
| 56 | * 200000 | ||
| 57 | * 250000 | ||
| 58 | * 300000 | ||
| 59 | * 350000 | ||
| 60 | * 400000 | ||
| 61 | |||
| 62 | - adi,slew-time-us: The time it takes for the output to reach the | ||
| 63 | full scale [uS] | ||
| 64 | The supported range is between 133us up to 1023984375us | ||
| 65 | |||
| 66 | AD5758 Example: | ||
| 67 | |||
| 68 | dac@0 { | ||
| 69 | compatible = "adi,ad5758"; | ||
| 70 | reg = <0>; | ||
| 71 | spi-max-frequency = <1000000>; | ||
| 72 | spi-cpha; | ||
| 73 | |||
| 74 | adi,dc-dc-mode = <2>; | ||
| 75 | adi,range-microvolt = <0 10000000>; | ||
| 76 | adi,dc-dc-ilim-microamp = <200000>; | ||
| 77 | adi,slew-time-us = <125000>; | ||
| 78 | }; | ||
| @@ -6,6 +6,7 @@ Required properties: · 5 unmodified lines | |||
| 6 | - compatible : should be one of | 6 | - compatible : should be one of |
| 7 | "invensense,mpu6050" | 7 | "invensense,mpu6050" |
| 8 | "invensense,mpu6500" | 8 | "invensense,mpu6500" |
| 9 | "invensense,mpu6515" | ||
| 9 | "invensense,mpu9150" | 10 | "invensense,mpu9150" |
| 10 | "invensense,mpu9250" | 11 | "invensense,mpu9250" |
| 11 | "invensense,mpu9255" | 12 | "invensense,mpu9255" |
| @@ -0,0 +1,13 @@ | |||
| 1 | * ISL29501 Time-of-flight sensor. | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : should be "renesas,isl29501" | ||
| 6 | - reg : the I2C address of the sensor | ||
| 7 | |||
| 8 | Example: | ||
| 9 | |||
| 10 | isl29501@57 { | ||
| 11 | compatible = "renesas,isl29501"; | ||
| 12 | reg = <0x57>; | ||
| 13 | }; | ||
| @@ -8,10 +8,6 @@ Required properties: · 7 unmodified lines | |||
| 8 | "bosch,bme280" | 8 | "bosch,bme280" |
| 9 | 9 | ||
| 10 | Optional properties: | 10 | Optional properties: |
| 11 | - chip-id: configurable chip id for non-default chip revisions | ||
| 12 | - temp-measurement-period: temperature measurement period (milliseconds) | ||
| 13 | - default-oversampling: default oversampling value to be used at startup, | ||
| 14 | value range is 0-3 with rising sensitivity. | ||
| 15 | - interrupt-parent: should be the phandle for the interrupt controller | 11 | - interrupt-parent: should be the phandle for the interrupt controller |
| 16 | - interrupts: interrupt mapping for IRQ | 12 | - interrupts: interrupt mapping for IRQ |
| 17 | - reset-gpios: a GPIO line handling reset of the sensor: as the line is | 13 | - reset-gpios: a GPIO line handling reset of the sensor: as the line is |
| @@ -24,9 +20,6 @@ Example: · 6 unmodified lines | |||
| 24 | pressure@77 { | 20 | pressure@77 { |
| 25 | compatible = "bosch,bmp085"; | 21 | compatible = "bosch,bmp085"; |
| 26 | reg = <0x77>; | 22 | reg = <0x77>; |
| 27 | chip-id = <10>; | ||
| 28 | temp-measurement-period = <100>; | ||
| 29 | default-oversampling = <2>; | ||
| 30 | interrupt-parent = <&gpio0>; | 23 | interrupt-parent = <&gpio0>; |
| 31 | interrupts = <25 IRQ_TYPE_EDGE_RISING>; | 24 | interrupts = <25 IRQ_TYPE_EDGE_RISING>; |
| 32 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; | 25 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; |
| @@ -796,6 +796,14 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch> · 795 unmodified lines | |||
| 796 | S: Supported | 796 | S: Supported |
| 797 | F: drivers/macintosh/ams/ | 797 | F: drivers/macintosh/ams/ |
| 798 | 798 | ||
| 799 | ANALOG DEVICES INC AD5758 DRIVER | ||
| 800 | M: Stefan Popa <stefan.popa@analog.com> | ||
| 801 | L: linux-iio@vger.kernel.org | ||
| 802 | W: http://ez.analog.com/community/linux-device-drivers | ||
| 803 | S: Supported | ||
| 804 | F: drivers/iio/dac/ad5758.c | ||
| 805 | F: Documentation/devicetree/bindings/iio/dac/ad5758.txt | ||
| 806 | |||
| 799 | ANALOG DEVICES INC AD5686 DRIVER | 807 | ANALOG DEVICES INC AD5686 DRIVER |
| 800 | M: Stefan Popa <stefan.popa@analog.com> | 808 | M: Stefan Popa <stefan.popa@analog.com> |
| 801 | L: linux-pm@vger.kernel.org | 809 | L: linux-pm@vger.kernel.org |
| @@ -40,7 +40,7 @@ config ADXL345_I2C · 39 unmodified lines | |||
| 40 | select REGMAP_I2C | 40 | select REGMAP_I2C |
| 41 | help | 41 | help |
| 42 | Say Y here if you want to build support for the Analog Devices | 42 | Say Y here if you want to build support for the Analog Devices |
| 43 | ADXL345 3-axis digital accelerometer. | 43 | ADXL345 or ADXL375 3-axis digital accelerometer. |
| 44 | 44 | ||
| 45 | To compile this driver as a module, choose M here: the module | 45 | To compile this driver as a module, choose M here: the module |
| 46 | will be called adxl345_i2c and you will also get adxl345_core | 46 | will be called adxl345_i2c and you will also get adxl345_core |
| @@ -54,7 +54,7 @@ config ADXL345_SPI · 7 unmodified lines | |||
| 54 | select REGMAP_SPI | 54 | select REGMAP_SPI |
| 55 | help | 55 | help |
| 56 | Say Y here if you want to build support for the Analog Devices | 56 | Say Y here if you want to build support for the Analog Devices |
| 57 | ADXL345 3-axis digital accelerometer. | 57 | ADXL345 or ADXL375 3-axis digital accelerometer. |
| 58 | 58 | ||
| 59 | To compile this driver as a module, choose M here: the module | 59 | To compile this driver as a module, choose M here: the module |
| 60 | will be called adxl345_spi and you will also get adxl345_core | 60 | will be called adxl345_spi and you will also get adxl345_core |
| @@ -11,8 +11,13 @@ · 10 unmodified lines | |||
| 11 | #ifndef _ADXL345_H_ | 11 | #ifndef _ADXL345_H_ |
| 12 | #define _ADXL345_H_ | 12 | #define _ADXL345_H_ |
| 13 | 13 | ||
| 14 | enum adxl345_device_type { | ||
| 15 | ADXL345, | ||
| 16 | ADXL375, | ||
| 17 | }; | ||
| 18 | |||
| 14 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, | 19 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, |
| 15 | const char *name); | 20 | enum adxl345_device_type type, const char *name); |
| 16 | int adxl345_core_remove(struct device *dev); | 21 | int adxl345_core_remove(struct device *dev); |
| 17 | 22 | ||
| 18 | #endif /* _ADXL345_H_ */ | 23 | #endif /* _ADXL345_H_ */ |
| @@ -6,21 +6,35 @@ · 5 unmodified lines | |||
| 6 | * This file is subject to the terms and conditions of version 2 of | 6 | * This file is subject to the terms and conditions of version 2 of |
| 7 | * the GNU General Public License. See the file COPYING in the main | 7 | * the GNU General Public License. See the file COPYING in the main |
| 8 | * directory of this archive for more details. | 8 | * directory of this archive for more details. |
| 9 | * | ||
| 10 | * Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf | ||
| 9 | */ | 11 | */ |
| 10 | 12 | ||
| 11 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 12 | #include <linux/regmap.h> | 14 | #include <linux/regmap.h> |
| 13 | 15 | ||
| 14 | #include <linux/iio/iio.h> | 16 | #include <linux/iio/iio.h> |
| 17 | #include <linux/iio/sysfs.h> | ||
| 15 | 18 | ||
| 16 | #include "adxl345.h" | 19 | #include "adxl345.h" |
| 17 | 20 | ||
| 18 | #define ADXL345_REG_DEVID 0x00 | 21 | #define ADXL345_REG_DEVID 0x00 |
| 22 | #define ADXL345_REG_OFSX 0x1e | ||
| 23 | #define ADXL345_REG_OFSY 0x1f | ||
| 24 | #define ADXL345_REG_OFSZ 0x20 | ||
| 25 | #define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) | ||
| 26 | #define ADXL345_REG_BW_RATE 0x2C | ||
| 19 | #define ADXL345_REG_POWER_CTL 0x2D | 27 | #define ADXL345_REG_POWER_CTL 0x2D |
| 20 | #define ADXL345_REG_DATA_FORMAT 0x31 | 28 | #define ADXL345_REG_DATA_FORMAT 0x31 |
| 21 | #define ADXL345_REG_DATAX0 0x32 | 29 | #define ADXL345_REG_DATAX0 0x32 |
| 22 | #define ADXL345_REG_DATAY0 0x34 | 30 | #define ADXL345_REG_DATAY0 0x34 |
| 23 | #define ADXL345_REG_DATAZ0 0x36 | 31 | #define ADXL345_REG_DATAZ0 0x36 |
| 32 | #define ADXL345_REG_DATA_AXIS(index) \ | ||
| 33 | (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) | ||
| 34 | |||
| 35 | #define ADXL345_BW_RATE GENMASK(3, 0) | ||
| 36 | #define ADXL345_BASE_RATE_NANO_HZ 97656250LL | ||
| 37 | #define NHZ_PER_HZ 1000000000LL | ||
| 24 | 38 | ||
| 25 | #define ADXL345_POWER_CTL_MEASURE BIT(3) | 39 | #define ADXL345_POWER_CTL_MEASURE BIT(3) |
| 26 | #define ADXL345_POWER_CTL_STANDBY 0x00 | 40 | #define ADXL345_POWER_CTL_STANDBY 0x00 |
| @@ -42,24 +56,33 @@ · 15 unmodified lines | |||
| 42 | */ | 56 | */ |
| 43 | static const int adxl345_uscale = 38300; | 57 | static const int adxl345_uscale = 38300; |
| 44 | 58 | ||
| 59 | /* | ||
| 60 | * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's | ||
| 61 | * ~480mm/s**2 per LSB. | ||
| 62 | */ | ||
| 63 | static const int adxl375_uscale = 480000; | ||
| 64 | |||
| 45 | struct adxl345_data { | 65 | struct adxl345_data { |
| 46 | struct regmap *regmap; | 66 | struct regmap *regmap; |
| 47 | u8 data_range; | 67 | u8 data_range; |
| 68 | enum adxl345_device_type type; | ||
| 48 | }; | 69 | }; |
| 49 | 70 | ||
| 50 | #define ADXL345_CHANNEL(reg, axis) { \ | 71 | #define ADXL345_CHANNEL(index, axis) { \ |
| 51 | .type = IIO_ACCEL, \ | 72 | .type = IIO_ACCEL, \ |
| 52 | .modified = 1, \ | 73 | .modified = 1, \ |
| 53 | .channel2 = IIO_MOD_##axis, \ | 74 | .channel2 = IIO_MOD_##axis, \ |
| 54 | .address = reg, \ | 75 | .address = index, \ |
| 55 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | 76 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
| 56 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | 77 | BIT(IIO_CHAN_INFO_CALIBBIAS), \ |
| 78 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | ||
| 79 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
| 57 | } | 80 | } |
| 58 | 81 | ||
| 59 | static const struct iio_chan_spec adxl345_channels[] = { | 82 | static const struct iio_chan_spec adxl345_channels[] = { |
| 60 | ADXL345_CHANNEL(ADXL345_REG_DATAX0, X), | 83 | ADXL345_CHANNEL(0, X), |
| 61 | ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y), | 84 | ADXL345_CHANNEL(1, Y), |
| 62 | ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z), | 85 | ADXL345_CHANNEL(2, Z), |
| 63 | }; | 86 | }; |
| 64 | 87 | ||
| 65 | static int adxl345_read_raw(struct iio_dev *indio_dev, | 88 | static int adxl345_read_raw(struct iio_dev *indio_dev, |
| @@ -67,7 +90,9 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 67 | int *val, int *val2, long mask) | 90 | int *val, int *val2, long mask) |
| 68 | { | 91 | { |
| 69 | struct adxl345_data *data = iio_priv(indio_dev); | 92 | struct adxl345_data *data = iio_priv(indio_dev); |
| 70 | __le16 regval; | 93 | __le16 accel; |
| 94 | long long samp_freq_nhz; | ||
| 95 | unsigned int regval; | ||
| 71 | int ret; | 96 | int ret; |
| 72 | 97 | ||
| 73 | switch (mask) { | 98 | switch (mask) { |
| @@ -77,29 +102,117 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, · 3 unmodified lines | |||
| 77 | * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte | 102 | * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte |
| 78 | * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte | 103 | * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte |
| 79 | */ | 104 | */ |
| 80 | ret = regmap_bulk_read(data->regmap, chan->address, ®val, | 105 | ret = regmap_bulk_read(data->regmap, |
| 81 | sizeof(regval)); | 106 | ADXL345_REG_DATA_AXIS(chan->address), |
| 107 | &accel, sizeof(accel)); | ||
| 82 | if (ret < 0) | 108 | if (ret < 0) |
| 83 | return ret; | 109 | return ret; |
| 84 | 110 | ||
| 85 | *val = sign_extend32(le16_to_cpu(regval), 12); | 111 | *val = sign_extend32(le16_to_cpu(accel), 12); |
| 86 | return IIO_VAL_INT; | 112 | return IIO_VAL_INT; |
| 87 | case IIO_CHAN_INFO_SCALE: | 113 | case IIO_CHAN_INFO_SCALE: |
| 88 | *val = 0; | 114 | *val = 0; |
| 89 | *val2 = adxl345_uscale; | 115 | switch (data->type) { |
| 116 | case ADXL345: | ||
| 117 | *val2 = adxl345_uscale; | ||
| 118 | break; | ||
| 119 | case ADXL375: | ||
| 120 | *val2 = adxl375_uscale; | ||
| 121 | break; | ||
| 122 | } | ||
| 90 | 123 | ||
| 91 | return IIO_VAL_INT_PLUS_MICRO; | 124 | return IIO_VAL_INT_PLUS_MICRO; |
| 125 | case IIO_CHAN_INFO_CALIBBIAS: | ||
| 126 | ret = regmap_read(data->regmap, | ||
| 127 | ADXL345_REG_OFS_AXIS(chan->address), ®val); | ||
| 128 | if (ret < 0) | ||
| 129 | return ret; | ||
| 130 | /* | ||
| 131 | * 8-bit resolution at +/- 2g, that is 4x accel data scale | ||
| 132 | * factor | ||
| 133 | */ | ||
| 134 | *val = sign_extend32(regval, 7) * 4; | ||
| 135 | |||
| 136 | return IIO_VAL_INT; | ||
| 137 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 138 | ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val); | ||
| 139 | if (ret < 0) | ||
| 140 | return ret; | ||
| 141 | |||
| 142 | samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ << | ||
| 143 | (regval & ADXL345_BW_RATE); | ||
| 144 | *val = div_s64_rem(samp_freq_nhz, NHZ_PER_HZ, val2); | ||
| 145 | |||
| 146 | return IIO_VAL_INT_PLUS_NANO; | ||
| 92 | } | 147 | } |
| 93 | 148 | ||
| 94 | return -EINVAL; | 149 | return -EINVAL; |
| 95 | } | 150 | } |
| 96 | 151 | ||
| 152 | static int adxl345_write_raw(struct iio_dev *indio_dev, | ||
| 153 | struct iio_chan_spec const *chan, | ||
| 154 | int val, int val2, long mask) | ||
| 155 | { | ||
| 156 | struct adxl345_data *data = iio_priv(indio_dev); | ||
| 157 | s64 n; | ||
| 158 | |||
| 159 | switch (mask) { | ||
| 160 | case IIO_CHAN_INFO_CALIBBIAS: | ||
| 161 | /* | ||
| 162 | * 8-bit resolution at +/- 2g, that is 4x accel data scale | ||
| 163 | * factor | ||
| 164 | */ | ||
| 165 | return regmap_write(data->regmap, | ||
| 166 | ADXL345_REG_OFS_AXIS(chan->address), | ||
| 167 | val / 4); | ||
| 168 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 169 | n = div_s64(val * NHZ_PER_HZ + val2, ADXL345_BASE_RATE_NANO_HZ); | ||
| 170 | |||
| 171 | return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE, | ||
| 172 | ADXL345_BW_RATE, | ||
| 173 | clamp_val(ilog2(n), 0, | ||
| 174 | ADXL345_BW_RATE)); | ||
| 175 | } | ||
| 176 | |||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 181 | struct iio_chan_spec const *chan, | ||
| 182 | long mask) | ||
| 183 | { | ||
| 184 | switch (mask) { | ||
| 185 | case IIO_CHAN_INFO_CALIBBIAS: | ||
| 186 | return IIO_VAL_INT; | ||
| 187 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 188 | return IIO_VAL_INT_PLUS_NANO; | ||
| 189 | default: | ||
| 190 | return -EINVAL; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( | ||
| 195 | "0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200" | ||
| 196 | ); | ||
| 197 | |||
| 198 | static struct attribute *adxl345_attrs[] = { | ||
| 199 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
| 200 | NULL, | ||
| 201 | }; | ||
| 202 | |||
| 203 | static const struct attribute_group adxl345_attrs_group = { | ||
| 204 | .attrs = adxl345_attrs, | ||
| 205 | }; | ||
| 206 | |||
| 97 | static const struct iio_info adxl345_info = { | 207 | static const struct iio_info adxl345_info = { |
| 208 | .attrs = &adxl345_attrs_group, | ||
| 98 | .read_raw = adxl345_read_raw, | 209 | .read_raw = adxl345_read_raw, |
| 210 | .write_raw = adxl345_write_raw, | ||
| 211 | .write_raw_get_fmt = adxl345_write_raw_get_fmt, | ||
| 99 | }; | 212 | }; |
| 100 | 213 | ||
| 101 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, | 214 | int adxl345_core_probe(struct device *dev, struct regmap *regmap, |
| 102 | const char *name) | 215 | enum adxl345_device_type type, const char *name) |
| 103 | { | 216 | { |
| 104 | struct adxl345_data *data; | 217 | struct adxl345_data *data; |
| 105 | struct iio_dev *indio_dev; | 218 | struct iio_dev *indio_dev; |
| @@ -125,6 +238,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, · 19 unmodified lines | |||
| 125 | data = iio_priv(indio_dev); | 238 | data = iio_priv(indio_dev); |
| 126 | dev_set_drvdata(dev, indio_dev); | 239 | dev_set_drvdata(dev, indio_dev); |
| 127 | data->regmap = regmap; | 240 | data->regmap = regmap; |
| 241 | data->type = type; | ||
| 128 | /* Enable full-resolution mode */ | 242 | /* Enable full-resolution mode */ |
| 129 | data->data_range = ADXL345_DATA_FORMAT_FULL_RES; | 243 | data->data_range = ADXL345_DATA_FORMAT_FULL_RES; |
| 130 | 244 | ||
| @@ -34,7 +34,8 @@ static int adxl345_i2c_probe(struct i2c_client *client, · 33 unmodified lines | |||
| 34 | return PTR_ERR(regmap); | 34 | return PTR_ERR(regmap); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | return adxl345_core_probe(&client->dev, regmap, id ? id->name : NULL); | 37 | return adxl345_core_probe(&client->dev, regmap, id->driver_data, |
| 38 | id ? id->name : NULL); | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | static int adxl345_i2c_remove(struct i2c_client *client) | 41 | static int adxl345_i2c_remove(struct i2c_client *client) |
| @@ -43,7 +44,8 @@ static int adxl345_i2c_remove(struct i2c_client *client) · 2 unmodified lines | |||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | static const struct i2c_device_id adxl345_i2c_id[] = { | 46 | static const struct i2c_device_id adxl345_i2c_id[] = { |
| 46 | { "adxl345", 0 }, | 47 | { "adxl345", ADXL345 }, |
| 48 | { "adxl375", ADXL375 }, | ||
| 47 | { } | 49 | { } |
| 48 | }; | 50 | }; |
| 49 | 51 | ||
| @@ -51,6 +53,7 @@ MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); · 1 unmodified line | |||
| 51 | 53 | ||
| 52 | static const struct of_device_id adxl345_of_match[] = { | 54 | static const struct of_device_id adxl345_of_match[] = { |
| 53 | { .compatible = "adi,adxl345" }, | 55 | { .compatible = "adi,adxl345" }, |
| 56 | { .compatible = "adi,adxl375" }, | ||
| 54 | { }, | 57 | { }, |
| 55 | }; | 58 | }; |
| 56 | 59 | ||
| @@ -42,7 +42,7 @@ static int adxl345_spi_probe(struct spi_device *spi) · 41 unmodified lines | |||
| 42 | return PTR_ERR(regmap); | 42 | return PTR_ERR(regmap); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | return adxl345_core_probe(&spi->dev, regmap, id->name); | 45 | return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | static int adxl345_spi_remove(struct spi_device *spi) | 48 | static int adxl345_spi_remove(struct spi_device *spi) |
| @@ -51,7 +51,8 @@ static int adxl345_spi_remove(struct spi_device *spi) · 2 unmodified lines | |||
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static const struct spi_device_id adxl345_spi_id[] = { | 53 | static const struct spi_device_id adxl345_spi_id[] = { |
| 54 | { "adxl345", 0 }, | 54 | { "adxl345", ADXL345 }, |
| 55 | { "adxl375", ADXL375 }, | ||
| 55 | { } | 56 | { } |
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| @@ -59,6 +60,7 @@ MODULE_DEVICE_TABLE(spi, adxl345_spi_id); · 1 unmodified line | |||
| 59 | 60 | ||
| 60 | static const struct of_device_id adxl345_of_match[] = { | 61 | static const struct of_device_id adxl345_of_match[] = { |
| 61 | { .compatible = "adi,adxl345" }, | 62 | { .compatible = "adi,adxl345" }, |
| 63 | { .compatible = "adi,adxl375" }, | ||
| 62 | { }, | 64 | { }, |
| 63 | }; | 65 | }; |
| 64 | 66 | ||
| @@ -1547,6 +1547,7 @@ static int mma8452_probe(struct i2c_client *client, · 1546 unmodified lines | |||
| 1547 | case FXLS8471_DEVICE_ID: | 1547 | case FXLS8471_DEVICE_ID: |
| 1548 | if (ret == data->chip_info->chip_id) | 1548 | if (ret == data->chip_info->chip_id) |
| 1549 | break; | 1549 | break; |
| 1550 | /* else: fall through */ | ||
| 1550 | default: | 1551 | default: |
| 1551 | return -ENODEV; | 1552 | return -ENODEV; |
| 1552 | } | 1553 | } |
| @@ -797,6 +797,7 @@ static int sca3000_write_raw(struct iio_dev *indio_dev, · 796 unmodified lines | |||
| 797 | mutex_lock(&st->lock); | 797 | mutex_lock(&st->lock); |
| 798 | ret = sca3000_write_3db_freq(st, val); | 798 | ret = sca3000_write_3db_freq(st, val); |
| 799 | mutex_unlock(&st->lock); | 799 | mutex_unlock(&st->lock); |
| 800 | return ret; | ||
| 800 | default: | 801 | default: |
| 801 | return -EINVAL; | 802 | return -EINVAL; |
| 802 | } | 803 | } |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | |||
| 14 | #include <linux/acpi.h> | 14 | #include <linux/acpi.h> |
| 15 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 16 | #include <linux/iio/iio.h> | 16 | #include <linux/iio/iio.h> |
| 17 | #include <linux/property.h> | ||
| 17 | 18 | ||
| 18 | #include <linux/iio/common/st_sensors.h> | ||
| 19 | #include <linux/iio/common/st_sensors_i2c.h> | 19 | #include <linux/iio/common/st_sensors_i2c.h> |
| 20 | #include "st_accel.h" | 20 | #include "st_accel.h" |
| 21 | 21 | ||
| @@ -107,8 +107,8 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match); · 85 unmodified lines | |||
| 107 | 107 | ||
| 108 | #ifdef CONFIG_ACPI | 108 | #ifdef CONFIG_ACPI |
| 109 | static const struct acpi_device_id st_accel_acpi_match[] = { | 109 | static const struct acpi_device_id st_accel_acpi_match[] = { |
| 110 | {"SMO8840", LNG2DM}, | 110 | {"SMO8840", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, |
| 111 | {"SMO8A90", LNG2DM}, | 111 | {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME}, |
| 112 | { }, | 112 | { }, |
| 113 | }; | 113 | }; |
| 114 | MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); | 114 | MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); |
| @@ -117,33 +117,33 @@ MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); · 2 unmodified lines | |||
| 117 | #endif | 117 | #endif |
| 118 | 118 | ||
| 119 | static const struct i2c_device_id st_accel_id_table[] = { | 119 | static const struct i2c_device_id st_accel_id_table[] = { |
| 120 | { LSM303DLH_ACCEL_DEV_NAME, LSM303DLH }, | 120 | { LSM303DLH_ACCEL_DEV_NAME }, |
| 121 | { LSM303DLHC_ACCEL_DEV_NAME, LSM303DLHC }, | 121 | { LSM303DLHC_ACCEL_DEV_NAME }, |
| 122 | { LIS3DH_ACCEL_DEV_NAME, LIS3DH }, | 122 | { LIS3DH_ACCEL_DEV_NAME }, |
| 123 | { LSM330D_ACCEL_DEV_NAME, LSM330D }, | 123 | { LSM330D_ACCEL_DEV_NAME }, |
| 124 | { LSM330DL_ACCEL_DEV_NAME, LSM330DL }, | 124 | { LSM330DL_ACCEL_DEV_NAME }, |
| 125 | { LSM330DLC_ACCEL_DEV_NAME, LSM330DLC }, | 125 | { LSM330DLC_ACCEL_DEV_NAME }, |
| 126 | { LIS331DLH_ACCEL_DEV_NAME, LIS331DLH }, | 126 | { LIS331DLH_ACCEL_DEV_NAME }, |
| 127 | { LSM303DL_ACCEL_DEV_NAME, LSM303DL }, | 127 | { LSM303DL_ACCEL_DEV_NAME }, |
| 128 | { LSM303DLM_ACCEL_DEV_NAME, LSM303DLM }, | 128 | { LSM303DLM_ACCEL_DEV_NAME }, |
| 129 | { LSM330_ACCEL_DEV_NAME, LSM330 }, | 129 | { LSM330_ACCEL_DEV_NAME }, |
| 130 | { LSM303AGR_ACCEL_DEV_NAME, LSM303AGR }, | 130 | { LSM303AGR_ACCEL_DEV_NAME }, |
| 131 | { LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 }, | 131 | { LIS2DH12_ACCEL_DEV_NAME }, |
| 132 | { LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ }, | 132 | { LIS3L02DQ_ACCEL_DEV_NAME }, |
| 133 | { LNG2DM_ACCEL_DEV_NAME, LNG2DM }, | 133 | { LNG2DM_ACCEL_DEV_NAME }, |
| 134 | { H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL }, | 134 | { H3LIS331DL_ACCEL_DEV_NAME }, |
| 135 | { LIS331DL_ACCEL_DEV_NAME, LIS331DL }, | 135 | { LIS331DL_ACCEL_DEV_NAME }, |
| 136 | { LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL }, | 136 | { LIS3LV02DL_ACCEL_DEV_NAME }, |
| 137 | { LIS2DW12_ACCEL_DEV_NAME, LIS2DW12 }, | 137 | { LIS2DW12_ACCEL_DEV_NAME }, |
| 138 | {}, | 138 | {}, |
| 139 | }; | 139 | }; |
| 140 | MODULE_DEVICE_TABLE(i2c, st_accel_id_table); | 140 | MODULE_DEVICE_TABLE(i2c, st_accel_id_table); |
| 141 | 141 | ||
| 142 | static int st_accel_i2c_probe(struct i2c_client *client, | 142 | static int st_accel_i2c_probe(struct i2c_client *client) |
| 143 | const struct i2c_device_id *id) | ||
| 144 | { | 143 | { |
| 145 | struct iio_dev *indio_dev; | 144 | struct iio_dev *indio_dev; |
| 146 | struct st_sensor_data *adata; | 145 | struct st_sensor_data *adata; |
| 146 | const char *match; | ||
| 147 | int ret; | 147 | int ret; |
| 148 | 148 | ||
| 149 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata)); | 149 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata)); |
| @@ -152,19 +152,9 @@ static int st_accel_i2c_probe(struct i2c_client *client, · 2 unmodified lines | |||
| 152 | 152 | ||
| 153 | adata = iio_priv(indio_dev); | 153 | adata = iio_priv(indio_dev); |
| 154 | 154 | ||
| 155 | if (client->dev.of_node) { | 155 | match = device_get_match_data(&client->dev); |
| 156 | st_sensors_of_name_probe(&client->dev, st_accel_of_match, | 156 | if (match) |
| 157 | client->name, sizeof(client->name)); | 157 | strlcpy(client->name, match, sizeof(client->name)); |
| 158 | } else if (ACPI_HANDLE(&client->dev)) { | ||
| 159 | ret = st_sensors_match_acpi_device(&client->dev); | ||
| 160 | if ((ret < 0) || (ret >= ST_ACCEL_MAX)) | ||
| 161 | return -ENODEV; | ||
| 162 | |||
| 163 | strlcpy(client->name, st_accel_id_table[ret].name, | ||
| 164 | sizeof(client->name)); | ||
| 165 | } else if (!id) | ||
| 166 | return -ENODEV; | ||
| 167 | |||
| 168 | 158 | ||
| 169 | st_sensors_i2c_configure(indio_dev, client, adata); | 159 | st_sensors_i2c_configure(indio_dev, client, adata); |
| 170 | 160 | ||
| @@ -188,7 +178,7 @@ static struct i2c_driver st_accel_driver = { · 17 unmodified lines | |||
| 188 | .of_match_table = of_match_ptr(st_accel_of_match), | 178 | .of_match_table = of_match_ptr(st_accel_of_match), |
| 189 | .acpi_match_table = ACPI_PTR(st_accel_acpi_match), | 179 | .acpi_match_table = ACPI_PTR(st_accel_acpi_match), |
| 190 | }, | 180 | }, |
| 191 | .probe = st_accel_i2c_probe, | 181 | .probe_new = st_accel_i2c_probe, |
| 192 | .remove = st_accel_i2c_remove, | 182 | .remove = st_accel_i2c_remove, |
| 193 | .id_table = st_accel_id_table, | 183 | .id_table = st_accel_id_table, |
| 194 | }; | 184 | }; |
| @@ -620,6 +620,16 @@ config ROCKCHIP_SARADC · 619 unmodified lines | |||
| 620 | To compile this driver as a module, choose M here: the | 620 | To compile this driver as a module, choose M here: the |
| 621 | module will be called rockchip_saradc. | 621 | module will be called rockchip_saradc. |
| 622 | 622 | ||
| 623 | config SC27XX_ADC | ||
| 624 | tristate "Spreadtrum SC27xx series PMICs ADC" | ||
| 625 | depends on MFD_SC27XX_PMIC || COMPILE_TEST | ||
| 626 | help | ||
| 627 | Say yes here to build support for the integrated ADC inside the | ||
| 628 | Spreadtrum SC27xx series PMICs. | ||
| 629 | |||
| 630 | This driver can also be built as a module. If so, the module | ||
| 631 | will be called sc27xx_adc. | ||
| 632 | |||
| 623 | config SPEAR_ADC | 633 | config SPEAR_ADC |
| 624 | tristate "ST SPEAr ADC" | 634 | tristate "ST SPEAr ADC" |
| 625 | depends on PLAT_SPEAR || COMPILE_TEST | 635 | depends on PLAT_SPEAR || COMPILE_TEST |
| @@ -59,6 +59,7 @@ obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o · 58 unmodified lines | |||
| 59 | obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o | 59 | obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o |
| 60 | obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o | 60 | obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o |
| 61 | obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o | 61 | obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o |
| 62 | obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o | ||
| 62 | obj-$(CONFIG_SPEAR_ADC) += spear_adc.o | 63 | obj-$(CONFIG_SPEAR_ADC) += spear_adc.o |
| 63 | obj-$(CONFIG_STX104) += stx104.o | 64 | obj-$(CONFIG_STX104) += stx104.o |
| 64 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o | 65 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o |
| @@ -1296,6 +1296,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev, · 1295 unmodified lines | |||
| 1296 | { | 1296 | { |
| 1297 | struct at91_adc_state *st = iio_priv(indio_dev); | 1297 | struct at91_adc_state *st = iio_priv(indio_dev); |
| 1298 | u32 cor = 0; | 1298 | u32 cor = 0; |
| 1299 | u16 tmp_val; | ||
| 1299 | int ret; | 1300 | int ret; |
| 1300 | 1301 | ||
| 1301 | /* | 1302 | /* |
| @@ -1309,7 +1310,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev, · 7 unmodified lines | |||
| 1309 | mutex_lock(&st->lock); | 1310 | mutex_lock(&st->lock); |
| 1310 | 1311 | ||
| 1311 | ret = at91_adc_read_position(st, chan->channel, | 1312 | ret = at91_adc_read_position(st, chan->channel, |
| 1312 | (u16 *)val); | 1313 | &tmp_val); |
| 1314 | *val = tmp_val; | ||
| 1313 | mutex_unlock(&st->lock); | 1315 | mutex_unlock(&st->lock); |
| 1314 | iio_device_release_direct_mode(indio_dev); | 1316 | iio_device_release_direct_mode(indio_dev); |
| 1315 | 1317 | ||
| @@ -1322,7 +1324,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 1322 | mutex_lock(&st->lock); | 1324 | mutex_lock(&st->lock); |
| 1323 | 1325 | ||
| 1324 | ret = at91_adc_read_pressure(st, chan->channel, | 1326 | ret = at91_adc_read_pressure(st, chan->channel, |
| 1325 | (u16 *)val); | 1327 | &tmp_val); |
| 1328 | *val = tmp_val; | ||
| 1326 | mutex_unlock(&st->lock); | 1329 | mutex_unlock(&st->lock); |
| 1327 | iio_device_release_direct_mode(indio_dev); | 1330 | iio_device_release_direct_mode(indio_dev); |
| 1328 | 1331 | ||
| @@ -97,6 +97,14 @@ struct hx711_data { · 96 unmodified lines | |||
| 97 | * 2x32-bit channel + 64-bit timestamp | 97 | * 2x32-bit channel + 64-bit timestamp |
| 98 | */ | 98 | */ |
| 99 | u32 buffer[4]; | 99 | u32 buffer[4]; |
| 100 | /* | ||
| 101 | * delay after a rising edge on SCK until the data is ready DOUT | ||
| 102 | * this is dependent on the hx711 where the datasheet tells a | ||
| 103 | * maximum value of 100 ns | ||
| 104 | * but also on potential parasitic capacities on the wiring | ||
| 105 | */ | ||
| 106 | u32 data_ready_delay_ns; | ||
| 107 | u32 clock_frequency; | ||
| 100 | }; | 108 | }; |
| 101 | 109 | ||
| 102 | static int hx711_cycle(struct hx711_data *hx711_data) | 110 | static int hx711_cycle(struct hx711_data *hx711_data) |
| @@ -110,6 +118,14 @@ static int hx711_cycle(struct hx711_data *hx711_data) · 7 unmodified lines | |||
| 110 | */ | 118 | */ |
| 111 | preempt_disable(); | 119 | preempt_disable(); |
| 112 | gpiod_set_value(hx711_data->gpiod_pd_sck, 1); | 120 | gpiod_set_value(hx711_data->gpiod_pd_sck, 1); |
| 121 | |||
| 122 | /* | ||
| 123 | * wait until DOUT is ready | ||
| 124 | * it turned out that parasitic capacities are extending the time | ||
| 125 | * until DOUT has reached it's value | ||
| 126 | */ | ||
| 127 | ndelay(hx711_data->data_ready_delay_ns); | ||
| 128 | |||
| 113 | val = gpiod_get_value(hx711_data->gpiod_dout); | 129 | val = gpiod_get_value(hx711_data->gpiod_dout); |
| 114 | /* | 130 | /* |
| 115 | * here we are not waiting for 0.2 us as suggested by the datasheet, | 131 | * here we are not waiting for 0.2 us as suggested by the datasheet, |
| @@ -120,6 +136,12 @@ static int hx711_cycle(struct hx711_data *hx711_data) · 4 unmodified lines | |||
| 120 | gpiod_set_value(hx711_data->gpiod_pd_sck, 0); | 136 | gpiod_set_value(hx711_data->gpiod_pd_sck, 0); |
| 121 | preempt_enable(); | 137 | preempt_enable(); |
| 122 | 138 | ||
| 139 | /* | ||
| 140 | * make it a square wave for addressing cases with capacitance on | ||
| 141 | * PC_SCK | ||
| 142 | */ | ||
| 143 | ndelay(hx711_data->data_ready_delay_ns); | ||
| 144 | |||
| 123 | return val; | 145 | return val; |
| 124 | } | 146 | } |
| 125 | 147 | ||
| @@ -458,6 +480,7 @@ static const struct iio_chan_spec hx711_chan_spec[] = { · 332 unmodified lines | |||
| 458 | static int hx711_probe(struct platform_device *pdev) | 480 | static int hx711_probe(struct platform_device *pdev) |
| 459 | { | 481 | { |
| 460 | struct device *dev = &pdev->dev; | 482 | struct device *dev = &pdev->dev; |
| 483 | struct device_node *np = dev->of_node; | ||
| 461 | struct hx711_data *hx711_data; | 484 | struct hx711_data *hx711_data; |
| 462 | struct iio_dev *indio_dev; | 485 | struct iio_dev *indio_dev; |
| 463 | int ret; | 486 | int ret; |
| @@ -530,6 +553,22 @@ static int hx711_probe(struct platform_device *pdev) · 66 unmodified lines | |||
| 530 | hx711_data->gain_set = 128; | 553 | hx711_data->gain_set = 128; |
| 531 | hx711_data->gain_chan_a = 128; | 554 | hx711_data->gain_chan_a = 128; |
| 532 | 555 | ||
| 556 | hx711_data->clock_frequency = 400000; | ||
| 557 | ret = of_property_read_u32(np, "clock-frequency", | ||
| 558 | &hx711_data->clock_frequency); | ||
| 559 | |||
| 560 | /* | ||
| 561 | * datasheet says the high level of PD_SCK has a maximum duration | ||
| 562 | * of 50 microseconds | ||
| 563 | */ | ||
| 564 | if (hx711_data->clock_frequency < 20000) { | ||
| 565 | dev_warn(dev, "clock-frequency too low - assuming 400 kHz\n"); | ||
| 566 | hx711_data->clock_frequency = 400000; | ||
| 567 | } | ||
| 568 | |||
| 569 | hx711_data->data_ready_delay_ns = | ||
| 570 | 1000000000 / hx711_data->clock_frequency; | ||
| 571 | |||
| 533 | platform_set_drvdata(pdev, indio_dev); | 572 | platform_set_drvdata(pdev, indio_dev); |
| 534 | 573 | ||
| 535 | indio_dev->name = "hx711"; | 574 | indio_dev->name = "hx711"; |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/of_device.h> | 31 | #include <linux/of_device.h> |
| 32 | #include <linux/regmap.h> | 32 | #include <linux/regmap.h> |
| 33 | #include <linux/sched/task.h> | ||
| 33 | #include <linux/util_macros.h> | 34 | #include <linux/util_macros.h> |
| 34 | 35 | ||
| 35 | #include <linux/platform_data/ina2xx.h> | 36 | #include <linux/platform_data/ina2xx.h> |
| @@ -826,6 +827,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) · 790 unmodified lines | |||
| 826 | { | 827 | { |
| 827 | struct ina2xx_chip_info *chip = iio_priv(indio_dev); | 828 | struct ina2xx_chip_info *chip = iio_priv(indio_dev); |
| 828 | unsigned int sampling_us = SAMPLING_PERIOD(chip); | 829 | unsigned int sampling_us = SAMPLING_PERIOD(chip); |
| 830 | struct task_struct *task; | ||
| 829 | 831 | ||
| 830 | dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n", | 832 | dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n", |
| 831 | (unsigned int)(*indio_dev->active_scan_mask), | 833 | (unsigned int)(*indio_dev->active_scan_mask), |
| @@ -835,11 +837,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) · 3 unmodified lines | |||
| 835 | dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", | 837 | dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", |
| 836 | chip->allow_async_readout); | 838 | chip->allow_async_readout); |
| 837 | 839 | ||
| 838 | chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, | 840 | task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, |
| 839 | "%s:%d-%uus", indio_dev->name, indio_dev->id, | 841 | "%s:%d-%uus", indio_dev->name, indio_dev->id, |
| 840 | sampling_us); | 842 | sampling_us); |
| 843 | if (IS_ERR(task)) | ||
| 844 | return PTR_ERR(task); | ||
| 845 | |||
| 846 | get_task_struct(task); | ||
| 847 | wake_up_process(task); | ||
| 848 | chip->task = task; | ||
| 841 | 849 | ||
| 842 | return PTR_ERR_OR_ZERO(chip->task); | 850 | return 0; |
| 843 | } | 851 | } |
| 844 | 852 | ||
| 845 | static int ina2xx_buffer_disable(struct iio_dev *indio_dev) | 853 | static int ina2xx_buffer_disable(struct iio_dev *indio_dev) |
| @@ -848,6 +856,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev) · 2 unmodified lines | |||
| 848 | 856 | ||
| 849 | if (chip->task) { | 857 | if (chip->task) { |
| 850 | kthread_stop(chip->task); | 858 | kthread_stop(chip->task); |
| 859 | put_task_struct(chip->task); | ||
| 851 | chip->task = NULL; | 860 | chip->task = NULL; |
| 852 | } | 861 | } |
| 853 | 862 | ||
| @@ -1577,7 +1577,6 @@ static int max1363_probe(struct i2c_client *client, · 1576 unmodified lines | |||
| 1577 | struct max1363_state *st; | 1577 | struct max1363_state *st; |
| 1578 | struct iio_dev *indio_dev; | 1578 | struct iio_dev *indio_dev; |
| 1579 | struct regulator *vref; | 1579 | struct regulator *vref; |
| 1580 | const struct of_device_id *match; | ||
| 1581 | 1580 | ||
| 1582 | indio_dev = devm_iio_device_alloc(&client->dev, | 1581 | indio_dev = devm_iio_device_alloc(&client->dev, |
| 1583 | sizeof(struct max1363_state)); | 1582 | sizeof(struct max1363_state)); |
| @@ -1604,11 +1603,8 @@ static int max1363_probe(struct i2c_client *client, · 20 unmodified lines | |||
| 1604 | /* this is only used for device removal purposes */ | 1603 | /* this is only used for device removal purposes */ |
| 1605 | i2c_set_clientdata(client, indio_dev); | 1604 | i2c_set_clientdata(client, indio_dev); |
| 1606 | 1605 | ||
| 1607 | match = of_match_device(of_match_ptr(max1363_of_match), | 1606 | st->chip_info = of_device_get_match_data(&client->dev); |
| 1608 | &client->dev); | 1607 | if (!st->chip_info) |
| 1609 | if (match) | ||
| 1610 | st->chip_info = of_device_get_match_data(&client->dev); | ||
| 1611 | else | ||
| 1612 | st->chip_info = &max1363_chip_info_tbl[id->driver_data]; | 1608 | st->chip_info = &max1363_chip_info_tbl[id->driver_data]; |
| 1613 | st->client = client; | 1609 | st->client = client; |
| 1614 | 1610 | ||
| @@ -922,6 +922,11 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { · 921 unmodified lines | |||
| 922 | .name = "meson-meson8b-saradc", | 922 | .name = "meson-meson8b-saradc", |
| 923 | }; | 923 | }; |
| 924 | 924 | ||
| 925 | static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = { | ||
| 926 | .param = &meson_sar_adc_meson8_param, | ||
| 927 | .name = "meson-meson8m2-saradc", | ||
| 928 | }; | ||
| 929 | |||
| 925 | static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { | 930 | static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { |
| 926 | .param = &meson_sar_adc_gxbb_param, | 931 | .param = &meson_sar_adc_gxbb_param, |
| 927 | .name = "meson-gxbb-saradc", | 932 | .name = "meson-gxbb-saradc", |
| @@ -951,6 +956,10 @@ static const struct of_device_id meson_sar_adc_of_match[] = { · 23 unmodified lines | |||
| 951 | .compatible = "amlogic,meson8b-saradc", | 956 | .compatible = "amlogic,meson8b-saradc", |
| 952 | .data = &meson_sar_adc_meson8b_data, | 957 | .data = &meson_sar_adc_meson8b_data, |
| 953 | }, | 958 | }, |
| 959 | { | ||
| 960 | .compatible = "amlogic,meson8m2-saradc", | ||
| 961 | .data = &meson_sar_adc_meson8m2_data, | ||
| 962 | }, | ||
| 954 | { | 963 | { |
| 955 | .compatible = "amlogic,meson-gxbb-saradc", | 964 | .compatible = "amlogic,meson-gxbb-saradc", |
| 956 | .data = &meson_sar_adc_gxbb_data, | 965 | .data = &meson_sar_adc_gxbb_data, |
| @@ -0,0 +1,522 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (C) 2018 Spreadtrum Communications Inc. | ||
| 3 | |||
| 4 | #include <linux/hwspinlock.h> | ||
| 5 | #include <linux/iio/iio.h> | ||
| 6 | #include <linux/interrupt.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/of.h> | ||
| 9 | #include <linux/of_device.h> | ||
| 10 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | /* PMIC global registers definition */ | ||
| 14 | #define SC27XX_MODULE_EN 0xc08 | ||
| 15 | #define SC27XX_MODULE_ADC_EN BIT(5) | ||
| 16 | #define SC27XX_ARM_CLK_EN 0xc10 | ||
| 17 | #define SC27XX_CLK_ADC_EN BIT(5) | ||
| 18 | #define SC27XX_CLK_ADC_CLK_EN BIT(6) | ||
| 19 | |||
| 20 | /* ADC controller registers definition */ | ||
| 21 | #define SC27XX_ADC_CTL 0x0 | ||
| 22 | #define SC27XX_ADC_CH_CFG 0x4 | ||
| 23 | #define SC27XX_ADC_DATA 0x4c | ||
| 24 | #define SC27XX_ADC_INT_EN 0x50 | ||
| 25 | #define SC27XX_ADC_INT_CLR 0x54 | ||
| 26 | #define SC27XX_ADC_INT_STS 0x58 | ||
| 27 | #define SC27XX_ADC_INT_RAW 0x5c | ||
| 28 | |||
| 29 | /* Bits and mask definition for SC27XX_ADC_CTL register */ | ||
| 30 | #define SC27XX_ADC_EN BIT(0) | ||
| 31 | #define SC27XX_ADC_CHN_RUN BIT(1) | ||
| 32 | #define SC27XX_ADC_12BIT_MODE BIT(2) | ||
| 33 | #define SC27XX_ADC_RUN_NUM_MASK GENMASK(7, 4) | ||
| 34 | #define SC27XX_ADC_RUN_NUM_SHIFT 4 | ||
| 35 | |||
| 36 | /* Bits and mask definition for SC27XX_ADC_CH_CFG register */ | ||
| 37 | #define SC27XX_ADC_CHN_ID_MASK GENMASK(4, 0) | ||
| 38 | #define SC27XX_ADC_SCALE_MASK GENMASK(10, 8) | ||
| 39 | #define SC27XX_ADC_SCALE_SHIFT 8 | ||
| 40 | |||
| 41 | /* Bits definitions for SC27XX_ADC_INT_EN registers */ | ||
| 42 | #define SC27XX_ADC_IRQ_EN BIT(0) | ||
| 43 | |||
| 44 | /* Bits definitions for SC27XX_ADC_INT_CLR registers */ | ||
| 45 | #define SC27XX_ADC_IRQ_CLR BIT(0) | ||
| 46 | |||
| 47 | /* Mask definition for SC27XX_ADC_DATA register */ | ||
| 48 | #define SC27XX_ADC_DATA_MASK GENMASK(11, 0) | ||
| 49 | |||
| 50 | /* Timeout (ms) for the trylock of hardware spinlocks */ | ||
| 51 | #define SC27XX_ADC_HWLOCK_TIMEOUT 5000 | ||
| 52 | |||
| 53 | /* Maximum ADC channel number */ | ||
| 54 | #define SC27XX_ADC_CHANNEL_MAX 32 | ||
| 55 | |||
| 56 | /* ADC voltage ratio definition */ | ||
| 57 | #define SC27XX_VOLT_RATIO(n, d) \ | ||
| 58 | (((n) << SC27XX_RATIO_NUMERATOR_OFFSET) | (d)) | ||
| 59 | #define SC27XX_RATIO_NUMERATOR_OFFSET 16 | ||
| 60 | #define SC27XX_RATIO_DENOMINATOR_MASK GENMASK(15, 0) | ||
| 61 | |||
| 62 | struct sc27xx_adc_data { | ||
| 63 | struct device *dev; | ||
| 64 | struct regmap *regmap; | ||
| 65 | /* | ||
| 66 | * One hardware spinlock to synchronize between the multiple | ||
| 67 | * subsystems which will access the unique ADC controller. | ||
| 68 | */ | ||
| 69 | struct hwspinlock *hwlock; | ||
| 70 | struct completion completion; | ||
| 71 | int channel_scale[SC27XX_ADC_CHANNEL_MAX]; | ||
| 72 | u32 base; | ||
| 73 | int value; | ||
| 74 | int irq; | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct sc27xx_adc_linear_graph { | ||
| 78 | int volt0; | ||
| 79 | int adc0; | ||
| 80 | int volt1; | ||
| 81 | int adc1; | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * According to the datasheet, we can convert one ADC value to one voltage value | ||
| 86 | * through 2 points in the linear graph. If the voltage is less than 1.2v, we | ||
| 87 | * should use the small-scale graph, and if more than 1.2v, we should use the | ||
| 88 | * big-scale graph. | ||
| 89 | */ | ||
| 90 | static const struct sc27xx_adc_linear_graph big_scale_graph = { | ||
| 91 | 4200, 3310, | ||
| 92 | 3600, 2832, | ||
| 93 | }; | ||
| 94 | |||
| 95 | static const struct sc27xx_adc_linear_graph small_scale_graph = { | ||
| 96 | 1000, 3413, | ||
| 97 | 100, 341, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int sc27xx_adc_get_ratio(int channel, int scale) | ||
| 101 | { | ||
| 102 | switch (channel) { | ||
| 103 | case 1: | ||
| 104 | case 2: | ||
| 105 | case 3: | ||
| 106 | case 4: | ||
| 107 | return scale ? SC27XX_VOLT_RATIO(400, 1025) : | ||
| 108 | SC27XX_VOLT_RATIO(1, 1); | ||
| 109 | case 5: | ||
| 110 | return SC27XX_VOLT_RATIO(7, 29); | ||
| 111 | case 6: | ||
| 112 | return SC27XX_VOLT_RATIO(375, 9000); | ||
| 113 | case 7: | ||
| 114 | case 8: | ||
| 115 | return scale ? SC27XX_VOLT_RATIO(100, 125) : | ||
| 116 | SC27XX_VOLT_RATIO(1, 1); | ||
| 117 | case 19: | ||
| 118 | return SC27XX_VOLT_RATIO(1, 3); | ||
| 119 | default: | ||
| 120 | return SC27XX_VOLT_RATIO(1, 1); | ||
| 121 | } | ||
| 122 | return SC27XX_VOLT_RATIO(1, 1); | ||
| 123 | } | ||
| 124 | |||
| 125 | static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel, | ||
| 126 | int scale, int *val) | ||
| 127 | { | ||
| 128 | int ret; | ||
| 129 | u32 tmp; | ||
| 130 | |||
| 131 | reinit_completion(&data->completion); | ||
| 132 | |||
| 133 | ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT); | ||
| 134 | if (ret) { | ||
| 135 | dev_err(data->dev, "timeout to get the hwspinlock\n"); | ||
| 136 | return ret; | ||
| 137 | } | ||
| 138 | |||
| 139 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, | ||
| 140 | SC27XX_ADC_EN, SC27XX_ADC_EN); | ||
| 141 | if (ret) | ||
| 142 | goto unlock_adc; | ||
| 143 | |||
| 144 | /* Configure the channel id and scale */ | ||
| 145 | tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK; | ||
| 146 | tmp |= channel & SC27XX_ADC_CHN_ID_MASK; | ||
| 147 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CH_CFG, | ||
| 148 | SC27XX_ADC_CHN_ID_MASK | SC27XX_ADC_SCALE_MASK, | ||
| 149 | tmp); | ||
| 150 | if (ret) | ||
| 151 | goto disable_adc; | ||
| 152 | |||
| 153 | /* Select 12bit conversion mode, and only sample 1 time */ | ||
| 154 | tmp = SC27XX_ADC_12BIT_MODE; | ||
| 155 | tmp |= (0 << SC27XX_ADC_RUN_NUM_SHIFT) & SC27XX_ADC_RUN_NUM_MASK; | ||
| 156 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, | ||
| 157 | SC27XX_ADC_RUN_NUM_MASK | SC27XX_ADC_12BIT_MODE, | ||
| 158 | tmp); | ||
| 159 | if (ret) | ||
| 160 | goto disable_adc; | ||
| 161 | |||
| 162 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, | ||
| 163 | SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN); | ||
| 164 | if (ret) | ||
| 165 | goto disable_adc; | ||
| 166 | |||
| 167 | wait_for_completion(&data->completion); | ||
| 168 | |||
| 169 | disable_adc: | ||
| 170 | regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL, | ||
| 171 | SC27XX_ADC_EN, 0); | ||
| 172 | unlock_adc: | ||
| 173 | hwspin_unlock_raw(data->hwlock); | ||
| 174 | |||
| 175 | if (!ret) | ||
| 176 | *val = data->value; | ||
| 177 | |||
| 178 | return ret; | ||
| 179 | } | ||
| 180 | |||
| 181 | static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id) | ||
| 182 | { | ||
| 183 | struct sc27xx_adc_data *data = dev_id; | ||
| 184 | int ret; | ||
| 185 | |||
| 186 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR, | ||
| 187 | SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR); | ||
| 188 | if (ret) | ||
| 189 | return IRQ_RETVAL(ret); | ||
| 190 | |||
| 191 | ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA, | ||
| 192 | &data->value); | ||
| 193 | if (ret) | ||
| 194 | return IRQ_RETVAL(ret); | ||
| 195 | |||
| 196 | data->value &= SC27XX_ADC_DATA_MASK; | ||
| 197 | complete(&data->completion); | ||
| 198 | |||
| 199 | return IRQ_HANDLED; | ||
| 200 | } | ||
| 201 | |||
| 202 | static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data, | ||
| 203 | int channel, int scale, | ||
| 204 | u32 *div_numerator, u32 *div_denominator) | ||
| 205 | { | ||
| 206 | u32 ratio = sc27xx_adc_get_ratio(channel, scale); | ||
| 207 | |||
| 208 | *div_numerator = ratio >> SC27XX_RATIO_NUMERATOR_OFFSET; | ||
| 209 | *div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph, | ||
| 213 | int raw_adc) | ||
| 214 | { | ||
| 215 | int tmp; | ||
| 216 | |||
| 217 | tmp = (graph->volt0 - graph->volt1) * (raw_adc - graph->adc1); | ||
| 218 | tmp /= (graph->adc0 - graph->adc1); | ||
| 219 | tmp += graph->volt1; | ||
| 220 | |||
| 221 | return tmp < 0 ? 0 : tmp; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel, | ||
| 225 | int scale, int raw_adc) | ||
| 226 | { | ||
| 227 | u32 numerator, denominator; | ||
| 228 | u32 volt; | ||
| 229 | |||
| 230 | /* | ||
| 231 | * Convert ADC values to voltage values according to the linear graph, | ||
| 232 | * and channel 5 and channel 1 has been calibrated, so we can just | ||
| 233 | * return the voltage values calculated by the linear graph. But other | ||
| 234 | * channels need be calculated to the real voltage values with the | ||
| 235 | * voltage ratio. | ||
| 236 | */ | ||
| 237 | switch (channel) { | ||
| 238 | case 5: | ||
| 239 | return sc27xx_adc_to_volt(&big_scale_graph, raw_adc); | ||
| 240 | |||
| 241 | case 1: | ||
| 242 | return sc27xx_adc_to_volt(&small_scale_graph, raw_adc); | ||
| 243 | |||
| 244 | default: | ||
| 245 | volt = sc27xx_adc_to_volt(&small_scale_graph, raw_adc); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | |||
| 249 | sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator); | ||
| 250 | |||
| 251 | return (volt * denominator + numerator / 2) / numerator; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data, | ||
| 255 | int channel, int scale, int *val) | ||
| 256 | { | ||
| 257 | int ret, raw_adc; | ||
| 258 | |||
| 259 | ret = sc27xx_adc_read(data, channel, scale, &raw_adc); | ||
| 260 | if (ret) | ||
| 261 | return ret; | ||
| 262 | |||
| 263 | *val = sc27xx_adc_convert_volt(data, channel, scale, raw_adc); | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int sc27xx_adc_read_raw(struct iio_dev *indio_dev, | ||
| 268 | struct iio_chan_spec const *chan, | ||
| 269 | int *val, int *val2, long mask) | ||
| 270 | { | ||
| 271 | struct sc27xx_adc_data *data = iio_priv(indio_dev); | ||
| 272 | int scale = data->channel_scale[chan->channel]; | ||
| 273 | int ret, tmp; | ||
| 274 | |||
| 275 | switch (mask) { | ||
| 276 | case IIO_CHAN_INFO_PROCESSED: | ||
| 277 | mutex_lock(&indio_dev->mlock); | ||
| 278 | ret = sc27xx_adc_read_processed(data, chan->channel, scale, | ||
| 279 | &tmp); | ||
| 280 | mutex_unlock(&indio_dev->mlock); | ||
| 281 | |||
| 282 | if (ret) | ||
| 283 | return ret; | ||
| 284 | |||
| 285 | *val = tmp; | ||
| 286 | return IIO_VAL_INT; | ||
| 287 | |||
| 288 | case IIO_CHAN_INFO_SCALE: | ||
| 289 | *val = scale; | ||
| 290 | return IIO_VAL_INT; | ||
| 291 | |||
| 292 | default: | ||
| 293 | return -EINVAL; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | static int sc27xx_adc_write_raw(struct iio_dev *indio_dev, | ||
| 298 | struct iio_chan_spec const *chan, | ||
| 299 | int val, int val2, long mask) | ||
| 300 | { | ||
| 301 | struct sc27xx_adc_data *data = iio_priv(indio_dev); | ||
| 302 | |||
| 303 | switch (mask) { | ||
| 304 | case IIO_CHAN_INFO_SCALE: | ||
| 305 | data->channel_scale[chan->channel] = val; | ||
| 306 | return IIO_VAL_INT; | ||
| 307 | |||
| 308 | default: | ||
| 309 | return -EINVAL; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | static const struct iio_info sc27xx_info = { | ||
| 314 | .read_raw = &sc27xx_adc_read_raw, | ||
| 315 | .write_raw = &sc27xx_adc_write_raw, | ||
| 316 | }; | ||
| 317 | |||
| 318 | #define SC27XX_ADC_CHANNEL(index) { \ | ||
| 319 | .type = IIO_VOLTAGE, \ | ||
| 320 | .channel = index, \ | ||
| 321 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ | ||
| 322 | BIT(IIO_CHAN_INFO_SCALE), \ | ||
| 323 | .datasheet_name = "CH##index", \ | ||
| 324 | .indexed = 1, \ | ||
| 325 | } | ||
| 326 | |||
| 327 | static const struct iio_chan_spec sc27xx_channels[] = { | ||
| 328 | SC27XX_ADC_CHANNEL(0), | ||
| 329 | SC27XX_ADC_CHANNEL(1), | ||
| 330 | SC27XX_ADC_CHANNEL(2), | ||
| 331 | SC27XX_ADC_CHANNEL(3), | ||
| 332 | SC27XX_ADC_CHANNEL(4), | ||
| 333 | SC27XX_ADC_CHANNEL(5), | ||
| 334 | SC27XX_ADC_CHANNEL(6), | ||
| 335 | SC27XX_ADC_CHANNEL(7), | ||
| 336 | SC27XX_ADC_CHANNEL(8), | ||
| 337 | SC27XX_ADC_CHANNEL(9), | ||
| 338 | SC27XX_ADC_CHANNEL(10), | ||
| 339 | SC27XX_ADC_CHANNEL(11), | ||
| 340 | SC27XX_ADC_CHANNEL(12), | ||
| 341 | SC27XX_ADC_CHANNEL(13), | ||
| 342 | SC27XX_ADC_CHANNEL(14), | ||
| 343 | SC27XX_ADC_CHANNEL(15), | ||
| 344 | SC27XX_ADC_CHANNEL(16), | ||
| 345 | SC27XX_ADC_CHANNEL(17), | ||
| 346 | SC27XX_ADC_CHANNEL(18), | ||
| 347 | SC27XX_ADC_CHANNEL(19), | ||
| 348 | SC27XX_ADC_CHANNEL(20), | ||
| 349 | SC27XX_ADC_CHANNEL(21), | ||
| 350 | SC27XX_ADC_CHANNEL(22), | ||
| 351 | SC27XX_ADC_CHANNEL(23), | ||
| 352 | SC27XX_ADC_CHANNEL(24), | ||
| 353 | SC27XX_ADC_CHANNEL(25), | ||
| 354 | SC27XX_ADC_CHANNEL(26), | ||
| 355 | SC27XX_ADC_CHANNEL(27), | ||
| 356 | SC27XX_ADC_CHANNEL(28), | ||
| 357 | SC27XX_ADC_CHANNEL(29), | ||
| 358 | SC27XX_ADC_CHANNEL(30), | ||
| 359 | SC27XX_ADC_CHANNEL(31), | ||
| 360 | }; | ||
| 361 | |||
| 362 | static int sc27xx_adc_enable(struct sc27xx_adc_data *data) | ||
| 363 | { | ||
| 364 | int ret; | ||
| 365 | |||
| 366 | ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN, | ||
| 367 | SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN); | ||
| 368 | if (ret) | ||
| 369 | return ret; | ||
| 370 | |||
| 371 | /* Enable ADC work clock and controller clock */ | ||
| 372 | ret = regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, | ||
| 373 | SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, | ||
| 374 | SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN); | ||
| 375 | if (ret) | ||
| 376 | goto disable_adc; | ||
| 377 | |||
| 378 | ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, | ||
| 379 | SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN); | ||
| 380 | if (ret) | ||
| 381 | goto disable_clk; | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | |||
| 385 | disable_clk: | ||
| 386 | regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, | ||
| 387 | SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); | ||
| 388 | disable_adc: | ||
| 389 | regmap_update_bits(data->regmap, SC27XX_MODULE_EN, | ||
| 390 | SC27XX_MODULE_ADC_EN, 0); | ||
| 391 | |||
| 392 | return ret; | ||
| 393 | } | ||
| 394 | |||
| 395 | static void sc27xx_adc_disable(void *_data) | ||
| 396 | { | ||
| 397 | struct sc27xx_adc_data *data = _data; | ||
| 398 | |||
| 399 | regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN, | ||
| 400 | SC27XX_ADC_IRQ_EN, 0); | ||
| 401 | |||
| 402 | /* Disable ADC work clock and controller clock */ | ||
| 403 | regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN, | ||
| 404 | SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0); | ||
| 405 | |||
| 406 | regmap_update_bits(data->regmap, SC27XX_MODULE_EN, | ||
| 407 | SC27XX_MODULE_ADC_EN, 0); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void sc27xx_adc_free_hwlock(void *_data) | ||
| 411 | { | ||
| 412 | struct hwspinlock *hwlock = _data; | ||
| 413 | |||
| 414 | hwspin_lock_free(hwlock); | ||
| 415 | } | ||
| 416 | |||
| 417 | static int sc27xx_adc_probe(struct platform_device *pdev) | ||
| 418 | { | ||
| 419 | struct device_node *np = pdev->dev.of_node; | ||
| 420 | struct sc27xx_adc_data *sc27xx_data; | ||
| 421 | struct iio_dev *indio_dev; | ||
| 422 | int ret; | ||
| 423 | |||
| 424 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data)); | ||
| 425 | if (!indio_dev) | ||
| 426 | return -ENOMEM; | ||
| 427 | |||
| 428 | sc27xx_data = iio_priv(indio_dev); | ||
| 429 | |||
| 430 | sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL); | ||
| 431 | if (!sc27xx_data->regmap) { | ||
| 432 | dev_err(&pdev->dev, "failed to get ADC regmap\n"); | ||
| 433 | return -ENODEV; | ||
| 434 | } | ||
| 435 | |||
| 436 | ret = of_property_read_u32(np, "reg", &sc27xx_data->base); | ||
| 437 | if (ret) { | ||
| 438 | dev_err(&pdev->dev, "failed to get ADC base address\n"); | ||
| 439 | return ret; | ||
| 440 | } | ||
| 441 | |||
| 442 | sc27xx_data->irq = platform_get_irq(pdev, 0); | ||
| 443 | if (sc27xx_data->irq < 0) { | ||
| 444 | dev_err(&pdev->dev, "failed to get ADC irq number\n"); | ||
| 445 | return sc27xx_data->irq; | ||
| 446 | } | ||
| 447 | |||
| 448 | ret = of_hwspin_lock_get_id(np, 0); | ||
| 449 | if (ret < 0) { | ||
| 450 | dev_err(&pdev->dev, "failed to get hwspinlock id\n"); | ||
| 451 | return ret; | ||
| 452 | } | ||
| 453 | |||
| 454 | sc27xx_data->hwlock = hwspin_lock_request_specific(ret); | ||
| 455 | if (!sc27xx_data->hwlock) { | ||
| 456 | dev_err(&pdev->dev, "failed to request hwspinlock\n"); | ||
| 457 | return -ENXIO; | ||
| 458 | } | ||
| 459 | |||
| 460 | ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock, | ||
| 461 | sc27xx_data->hwlock); | ||
| 462 | if (ret) { | ||
| 463 | sc27xx_adc_free_hwlock(sc27xx_data->hwlock); | ||
| 464 | dev_err(&pdev->dev, "failed to add hwspinlock action\n"); | ||
| 465 | return ret; | ||
| 466 | } | ||
| 467 | |||
| 468 | init_completion(&sc27xx_data->completion); | ||
| 469 | sc27xx_data->dev = &pdev->dev; | ||
| 470 | |||
| 471 | ret = sc27xx_adc_enable(sc27xx_data); | ||
| 472 | if (ret) { | ||
| 473 | dev_err(&pdev->dev, "failed to enable ADC module\n"); | ||
| 474 | return ret; | ||
| 475 | } | ||
| 476 | |||
| 477 | ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data); | ||
| 478 | if (ret) { | ||
| 479 | sc27xx_adc_disable(sc27xx_data); | ||
| 480 | dev_err(&pdev->dev, "failed to add ADC disable action\n"); | ||
| 481 | return ret; | ||
| 482 | } | ||
| 483 | |||
| 484 | ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL, | ||
| 485 | sc27xx_adc_isr, IRQF_ONESHOT, | ||
| 486 | pdev->name, sc27xx_data); | ||
| 487 | if (ret) { | ||
| 488 | dev_err(&pdev->dev, "failed to request ADC irq\n"); | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 492 | indio_dev->dev.parent = &pdev->dev; | ||
| 493 | indio_dev->name = dev_name(&pdev->dev); | ||
| 494 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 495 | indio_dev->info = &sc27xx_info; | ||
| 496 | indio_dev->channels = sc27xx_channels; | ||
| 497 | indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels); | ||
| 498 | ret = devm_iio_device_register(&pdev->dev, indio_dev); | ||
| 499 | if (ret) | ||
| 500 | dev_err(&pdev->dev, "could not register iio (ADC)"); | ||
| 501 | |||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | |||
| 505 | static const struct of_device_id sc27xx_adc_of_match[] = { | ||
| 506 | { .compatible = "sprd,sc2731-adc", }, | ||
| 507 | { } | ||
| 508 | }; | ||
| 509 | |||
| 510 | static struct platform_driver sc27xx_adc_driver = { | ||
| 511 | .probe = sc27xx_adc_probe, | ||
| 512 | .driver = { | ||
| 513 | .name = "sc27xx-adc", | ||
| 514 | .of_match_table = sc27xx_adc_of_match, | ||
| 515 | }, | ||
| 516 | }; | ||
| 517 | |||
| 518 | module_platform_driver(sc27xx_adc_driver); | ||
| 519 | |||
| 520 | MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>"); | ||
| 521 | MODULE_DESCRIPTION("Spreadtrum SC27XX ADC Driver"); | ||
| 522 | MODULE_LICENSE("GPL v2"); | ||
| @@ -1,3 +1,4 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * Texas Instruments ADS7950 SPI ADC driver | 3 | * Texas Instruments ADS7950 SPI ADC driver |
| 3 | * | 4 | * |
| @@ -10,15 +11,6 @@ · 6 unmodified lines | |||
| 10 | * And also on hwmon/ads79xx.c | 11 | * And also on hwmon/ads79xx.c |
| 11 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ | 12 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ |
| 12 | * Nishanth Menon | 13 | * Nishanth Menon |
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or | ||
| 15 | * modify it under the terms of the GNU General Public License as | ||
| 16 | * published by the Free Software Foundation version 2. | ||
| 17 | * | ||
| 18 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 19 | * kind, whether express or implied; without even the implied warranty | ||
| 20 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | */ | 14 | */ |
| 23 | 15 | ||
| 24 | #include <linux/acpi.h> | 16 | #include <linux/acpi.h> |
| @@ -76,6 +68,9 @@ struct ti_ads7950_state { · 51 unmodified lines | |||
| 76 | __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE] | 68 | __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE] |
| 77 | ____cacheline_aligned; | 69 | ____cacheline_aligned; |
| 78 | __be16 tx_buf[TI_ADS7950_MAX_CHAN]; | 70 | __be16 tx_buf[TI_ADS7950_MAX_CHAN]; |
| 71 | __be16 single_tx; | ||
| 72 | __be16 single_rx; | ||
| 73 | |||
| 79 | }; | 74 | }; |
| 80 | 75 | ||
| 81 | struct ti_ads7950_chip_info { | 76 | struct ti_ads7950_chip_info { |
| @@ -295,18 +290,26 @@ out: · 213 unmodified lines | |||
| 295 | return IRQ_HANDLED; | 290 | return IRQ_HANDLED; |
| 296 | } | 291 | } |
| 297 | 292 | ||
| 298 | static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch) | 293 | static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) |
| 299 | { | 294 | { |
| 295 | struct ti_ads7950_state *st = iio_priv(indio_dev); | ||
| 300 | int ret, cmd; | 296 | int ret, cmd; |
| 301 | 297 | ||
| 298 | mutex_lock(&indio_dev->mlock); | ||
| 299 | |||
| 302 | cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; | 300 | cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; |
| 303 | st->tx_buf[0] = cpu_to_be16(cmd); | 301 | st->single_tx = cpu_to_be16(cmd); |
| 304 | 302 | ||
| 305 | ret = spi_sync(st->spi, &st->scan_single_msg); | 303 | ret = spi_sync(st->spi, &st->scan_single_msg); |
| 306 | if (ret) | 304 | if (ret) |
| 307 | return ret; | 305 | goto out; |
| 306 | |||
| 307 | ret = be16_to_cpu(st->single_rx); | ||
| 308 | 308 | ||
| 309 | return be16_to_cpu(st->rx_buf[0]); | 309 | out: |
| 310 | mutex_unlock(&indio_dev->mlock); | ||
| 311 | |||
| 312 | return ret; | ||
| 310 | } | 313 | } |
| 311 | 314 | ||
| 312 | static int ti_ads7950_get_range(struct ti_ads7950_state *st) | 315 | static int ti_ads7950_get_range(struct ti_ads7950_state *st) |
| @@ -338,13 +341,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, · 25 unmodified lines | |||
| 338 | 341 | ||
| 339 | switch (m) { | 342 | switch (m) { |
| 340 | case IIO_CHAN_INFO_RAW: | 343 | case IIO_CHAN_INFO_RAW: |
| 341 | 344 | ret = ti_ads7950_scan_direct(indio_dev, chan->address); | |
| 342 | ret = iio_device_claim_direct_mode(indio_dev); | ||
| 343 | if (ret < 0) | ||
| 344 | return ret; | ||
| 345 | |||
| 346 | ret = ti_ads7950_scan_direct(st, chan->address); | ||
| 347 | iio_device_release_direct_mode(indio_dev); | ||
| 348 | if (ret < 0) | 345 | if (ret < 0) |
| 349 | return ret; | 346 | return ret; |
| 350 | 347 | ||
| @@ -410,13 +407,13 @@ static int ti_ads7950_probe(struct spi_device *spi) · 59 unmodified lines | |||
| 410 | * was read at the end of the first transfer. | 407 | * was read at the end of the first transfer. |
| 411 | */ | 408 | */ |
| 412 | 409 | ||
| 413 | st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; | 410 | st->scan_single_xfer[0].tx_buf = &st->single_tx; |
| 414 | st->scan_single_xfer[0].len = 2; | 411 | st->scan_single_xfer[0].len = 2; |
| 415 | st->scan_single_xfer[0].cs_change = 1; | 412 | st->scan_single_xfer[0].cs_change = 1; |
| 416 | st->scan_single_xfer[1].tx_buf = &st->tx_buf[0]; | 413 | st->scan_single_xfer[1].tx_buf = &st->single_tx; |
| 417 | st->scan_single_xfer[1].len = 2; | 414 | st->scan_single_xfer[1].len = 2; |
| 418 | st->scan_single_xfer[1].cs_change = 1; | 415 | st->scan_single_xfer[1].cs_change = 1; |
| 419 | st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; | 416 | st->scan_single_xfer[2].rx_buf = &st->single_rx; |
| 420 | st->scan_single_xfer[2].len = 2; | 417 | st->scan_single_xfer[2].len = 2; |
| 421 | 418 | ||
| 422 | spi_message_init_with_transfers(&st->scan_single_msg, | 419 | spi_message_init_with_transfers(&st->scan_single_msg, |
| @@ -341,8 +341,6 @@ static int xadc_zynq_setup(struct platform_device *pdev, · 340 unmodified lines | |||
| 341 | 341 | ||
| 342 | pcap_rate = clk_get_rate(xadc->clk); | 342 | pcap_rate = clk_get_rate(xadc->clk); |
| 343 | 343 | ||
| 344 | if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) | ||
| 345 | tck_rate = XADC_ZYNQ_TCK_RATE_MAX; | ||
| 346 | if (tck_rate > pcap_rate / 2) { | 344 | if (tck_rate > pcap_rate / 2) { |
| 347 | div = 2; | 345 | div = 2; |
| 348 | } else { | 346 | } else { |
| @@ -1045,7 +1043,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, · 696 unmodified lines | |||
| 1045 | unsigned int num_channels; | 1043 | unsigned int num_channels; |
| 1046 | const char *external_mux; | 1044 | const char *external_mux; |
| 1047 | u32 ext_mux_chan; | 1045 | u32 ext_mux_chan; |
| 1048 | int reg; | 1046 | u32 reg; |
| 1049 | int ret; | 1047 | int ret; |
| 1050 | 1048 | ||
| 1051 | *conf = 0; | 1049 | *conf = 0; |
| @@ -380,8 +380,7 @@ void st_sensors_of_name_probe(struct device *dev, · 379 unmodified lines | |||
| 380 | return; | 380 | return; |
| 381 | 381 | ||
| 382 | /* The name from the OF match takes precedence if present */ | 382 | /* The name from the OF match takes precedence if present */ |
| 383 | strncpy(name, of_id->data, len); | 383 | strlcpy(name, of_id->data, len); |
| 384 | name[len - 1] = '\0'; | ||
| 385 | } | 384 | } |
| 386 | EXPORT_SYMBOL(st_sensors_of_name_probe); | 385 | EXPORT_SYMBOL(st_sensors_of_name_probe); |
| 387 | #else | 386 | #else |
| @@ -167,6 +167,16 @@ config AD5755 · 166 unmodified lines | |||
| 167 | To compile this driver as a module, choose M here: the | 167 | To compile this driver as a module, choose M here: the |
| 168 | module will be called ad5755. | 168 | module will be called ad5755. |
| 169 | 169 | ||
| 170 | config AD5758 | ||
| 171 | tristate "Analog Devices AD5758 DAC driver" | ||
| 172 | depends on SPI_MASTER | ||
| 173 | help | ||
| 174 | Say yes here to build support for Analog Devices AD5758 single channel | ||
| 175 | Digital to Analog Converter. | ||
| 176 | |||
| 177 | To compile this driver as a module, choose M here: the | ||
| 178 | module will be called ad5758. | ||
| 179 | |||
| 170 | config AD5761 | 180 | config AD5761 |
| 171 | tristate "Analog Devices AD5761/61R/21/21R DAC driver" | 181 | tristate "Analog Devices AD5761/61R/21/21R DAC driver" |
| 172 | depends on SPI_MASTER | 182 | depends on SPI_MASTER |
| @@ -16,6 +16,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o · 15 unmodified lines | |||
| 16 | obj-$(CONFIG_AD5592R) += ad5592r.o | 16 | obj-$(CONFIG_AD5592R) += ad5592r.o |
| 17 | obj-$(CONFIG_AD5593R) += ad5593r.o | 17 | obj-$(CONFIG_AD5593R) += ad5593r.o |
| 18 | obj-$(CONFIG_AD5755) += ad5755.o | 18 | obj-$(CONFIG_AD5755) += ad5755.o |
| 19 | obj-$(CONFIG_AD5755) += ad5758.o | ||
| 19 | obj-$(CONFIG_AD5761) += ad5761.o | 20 | obj-$(CONFIG_AD5761) += ad5761.o |
| 20 | obj-$(CONFIG_AD5764) += ad5764.o | 21 | obj-$(CONFIG_AD5764) += ad5764.o |
| 21 | obj-$(CONFIG_AD5791) += ad5791.o | 22 | obj-$(CONFIG_AD5791) += ad5791.o |
| @@ -0,0 +1,897 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * AD5758 Digital to analog converters driver | ||
| 4 | * | ||
| 5 | * Copyright 2018 Analog Devices Inc. | ||
| 6 | * | ||
| 7 | * TODO: Currently CRC is not supported in this driver | ||
| 8 | */ | ||
| 9 | #include <linux/bsearch.h> | ||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/property.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | |||
| 16 | #include <linux/iio/iio.h> | ||
| 17 | #include <linux/iio/sysfs.h> | ||
| 18 | |||
| 19 | /* AD5758 registers definition */ | ||
| 20 | #define AD5758_NOP 0x00 | ||
| 21 | #define AD5758_DAC_INPUT 0x01 | ||
| 22 | #define AD5758_DAC_OUTPUT 0x02 | ||
| 23 | #define AD5758_CLEAR_CODE 0x03 | ||
| 24 | #define AD5758_USER_GAIN 0x04 | ||
| 25 | #define AD5758_USER_OFFSET 0x05 | ||
| 26 | #define AD5758_DAC_CONFIG 0x06 | ||
| 27 | #define AD5758_SW_LDAC 0x07 | ||
| 28 | #define AD5758_KEY 0x08 | ||
| 29 | #define AD5758_GP_CONFIG1 0x09 | ||
| 30 | #define AD5758_GP_CONFIG2 0x0A | ||
| 31 | #define AD5758_DCDC_CONFIG1 0x0B | ||
| 32 | #define AD5758_DCDC_CONFIG2 0x0C | ||
| 33 | #define AD5758_WDT_CONFIG 0x0F | ||
| 34 | #define AD5758_DIGITAL_DIAG_CONFIG 0x10 | ||
| 35 | #define AD5758_ADC_CONFIG 0x11 | ||
| 36 | #define AD5758_FAULT_PIN_CONFIG 0x12 | ||
| 37 | #define AD5758_TWO_STAGE_READBACK_SELECT 0x13 | ||
| 38 | #define AD5758_DIGITAL_DIAG_RESULTS 0x14 | ||
| 39 | #define AD5758_ANALOG_DIAG_RESULTS 0x15 | ||
| 40 | #define AD5758_STATUS 0x16 | ||
| 41 | #define AD5758_CHIP_ID 0x17 | ||
| 42 | #define AD5758_FREQ_MONITOR 0x18 | ||
| 43 | #define AD5758_DEVICE_ID_0 0x19 | ||
| 44 | #define AD5758_DEVICE_ID_1 0x1A | ||
| 45 | #define AD5758_DEVICE_ID_2 0x1B | ||
| 46 | #define AD5758_DEVICE_ID_3 0x1C | ||
| 47 | |||
| 48 | /* AD5758_DAC_CONFIG */ | ||
| 49 | #define AD5758_DAC_CONFIG_RANGE_MSK GENMASK(3, 0) | ||
| 50 | #define AD5758_DAC_CONFIG_RANGE_MODE(x) (((x) & 0xF) << 0) | ||
| 51 | #define AD5758_DAC_CONFIG_INT_EN_MSK BIT(5) | ||
| 52 | #define AD5758_DAC_CONFIG_INT_EN_MODE(x) (((x) & 0x1) << 5) | ||
| 53 | #define AD5758_DAC_CONFIG_OUT_EN_MSK BIT(6) | ||
| 54 | #define AD5758_DAC_CONFIG_OUT_EN_MODE(x) (((x) & 0x1) << 6) | ||
| 55 | #define AD5758_DAC_CONFIG_SR_EN_MSK BIT(8) | ||
| 56 | #define AD5758_DAC_CONFIG_SR_EN_MODE(x) (((x) & 0x1) << 8) | ||
| 57 | #define AD5758_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9) | ||
| 58 | #define AD5758_DAC_CONFIG_SR_CLOCK_MODE(x) (((x) & 0xF) << 9) | ||
| 59 | #define AD5758_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13) | ||
| 60 | #define AD5758_DAC_CONFIG_SR_STEP_MODE(x) (((x) & 0x7) << 13) | ||
| 61 | |||
| 62 | /* AD5758_KEY */ | ||
| 63 | #define AD5758_KEY_CODE_RESET_1 0x15FA | ||
| 64 | #define AD5758_KEY_CODE_RESET_2 0xAF51 | ||
| 65 | #define AD5758_KEY_CODE_SINGLE_ADC_CONV 0x1ADC | ||
| 66 | #define AD5758_KEY_CODE_RESET_WDT 0x0D06 | ||
| 67 | #define AD5758_KEY_CODE_CALIB_MEM_REFRESH 0xFCBA | ||
| 68 | |||
| 69 | /* AD5758_DCDC_CONFIG1 */ | ||
| 70 | #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MSK GENMASK(4, 0) | ||
| 71 | #define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0) | ||
| 72 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5) | ||
| 73 | #define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5) | ||
| 74 | #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7) | ||
| 75 | #define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7) | ||
| 76 | |||
| 77 | /* AD5758_DCDC_CONFIG2 */ | ||
| 78 | #define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1) | ||
| 79 | #define AD5758_DCDC_CONFIG2_ILIMIT_MODE(x) (((x) & 0x7) << 1) | ||
| 80 | #define AD5758_DCDC_CONFIG2_INTR_SAT_3WI_MSK BIT(11) | ||
| 81 | #define AD5758_DCDC_CONFIG2_BUSY_3WI_MSK BIT(12) | ||
| 82 | |||
| 83 | /* AD5758_DIGITAL_DIAG_RESULTS */ | ||
| 84 | #define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15) | ||
| 85 | |||
| 86 | #define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F)) | ||
| 87 | |||
| 88 | #define AD5758_FULL_SCALE_MICRO 65535000000ULL | ||
| 89 | |||
| 90 | /** | ||
| 91 | * struct ad5758_state - driver instance specific data | ||
| 92 | * @spi: spi_device | ||
| 93 | * @lock: mutex lock | ||
| 94 | * @out_range: struct which stores the output range | ||
| 95 | * @dc_dc_mode: variable which stores the mode of operation | ||
| 96 | * @dc_dc_ilim: variable which stores the dc-to-dc converter current limit | ||
| 97 | * @slew_time: variable which stores the target slew time | ||
| 98 | * @pwr_down: variable which contains whether a channel is powered down or not | ||
| 99 | * @data: spi transfer buffers | ||
| 100 | */ | ||
| 101 | |||
| 102 | struct ad5758_range { | ||
| 103 | int reg; | ||
| 104 | int min; | ||
| 105 | int max; | ||
| 106 | }; | ||
| 107 | |||
| 108 | struct ad5758_state { | ||
| 109 | struct spi_device *spi; | ||
| 110 | struct mutex lock; | ||
| 111 | struct ad5758_range out_range; | ||
| 112 | unsigned int dc_dc_mode; | ||
| 113 | unsigned int dc_dc_ilim; | ||
| 114 | unsigned int slew_time; | ||
| 115 | bool pwr_down; | ||
| 116 | __be32 d32[3]; | ||
| 117 | }; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Output ranges corresponding to bits [3:0] from DAC_CONFIG register | ||
| 121 | * 0000: 0 V to 5 V voltage range | ||
| 122 | * 0001: 0 V to 10 V voltage range | ||
| 123 | * 0010: ±5 V voltage range | ||
| 124 | * 0011: ±10 V voltage range | ||
| 125 | * 1000: 0 mA to 20 mA current range | ||
| 126 | * 1001: 0 mA to 24 mA current range | ||
| 127 | * 1010: 4 mA to 20 mA current range | ||
| 128 | * 1011: ±20 mA current range | ||
| 129 | * 1100: ±24 mA current range | ||
| 130 | * 1101: -1 mA to +22 mA current range | ||
| 131 | */ | ||
| 132 | enum ad5758_output_range { | ||
| 133 | AD5758_RANGE_0V_5V, | ||
| 134 | AD5758_RANGE_0V_10V, | ||
| 135 | AD5758_RANGE_PLUSMINUS_5V, | ||
| 136 | AD5758_RANGE_PLUSMINUS_10V, | ||
| 137 | AD5758_RANGE_0mA_20mA = 8, | ||
| 138 | AD5758_RANGE_0mA_24mA, | ||
| 139 | AD5758_RANGE_4mA_24mA, | ||
| 140 | AD5758_RANGE_PLUSMINUS_20mA, | ||
| 141 | AD5758_RANGE_PLUSMINUS_24mA, | ||
| 142 | AD5758_RANGE_MINUS_1mA_PLUS_22mA, | ||
| 143 | }; | ||
| 144 | |||
| 145 | enum ad5758_dc_dc_mode { | ||
| 146 | AD5758_DCDC_MODE_POWER_OFF, | ||
| 147 | AD5758_DCDC_MODE_DPC_CURRENT, | ||
| 148 | AD5758_DCDC_MODE_DPC_VOLTAGE, | ||
| 149 | AD5758_DCDC_MODE_PPC_CURRENT, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static const struct ad5758_range ad5758_voltage_range[] = { | ||
| 153 | { AD5758_RANGE_0V_5V, 0, 5000000 }, | ||
| 154 | { AD5758_RANGE_0V_10V, 0, 10000000 }, | ||
| 155 | { AD5758_RANGE_PLUSMINUS_5V, -5000000, 5000000 }, | ||
| 156 | { AD5758_RANGE_PLUSMINUS_10V, -10000000, 10000000 } | ||
| 157 | }; | ||
| 158 | |||
| 159 | static const struct ad5758_range ad5758_current_range[] = { | ||
| 160 | { AD5758_RANGE_0mA_20mA, 0, 20000}, | ||
| 161 | { AD5758_RANGE_0mA_24mA, 0, 24000 }, | ||
| 162 | { AD5758_RANGE_4mA_24mA, 4, 24000 }, | ||
| 163 | { AD5758_RANGE_PLUSMINUS_20mA, -20000, 20000 }, | ||
| 164 | { AD5758_RANGE_PLUSMINUS_24mA, -24000, 24000 }, | ||
| 165 | { AD5758_RANGE_MINUS_1mA_PLUS_22mA, -1000, 22000 }, | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const int ad5758_sr_clk[16] = { | ||
| 169 | 240000, 200000, 150000, 128000, 64000, 32000, 16000, 8000, 4000, 2000, | ||
| 170 | 1000, 512, 256, 128, 64, 16 | ||
| 171 | }; | ||
| 172 | |||
| 173 | static const int ad5758_sr_step[8] = { | ||
| 174 | 4, 12, 64, 120, 256, 500, 1820, 2048 | ||
| 175 | }; | ||
| 176 | |||
| 177 | static const int ad5758_dc_dc_ilim[6] = { | ||
| 178 | 150000, 200000, 250000, 300000, 350000, 400000 | ||
| 179 | }; | ||
| 180 | |||
| 181 | static int ad5758_spi_reg_read(struct ad5758_state *st, unsigned int addr) | ||
| 182 | { | ||
| 183 | struct spi_transfer t[] = { | ||
| 184 | { | ||
| 185 | .tx_buf = &st->d32[0], | ||
| 186 | .len = 4, | ||
| 187 | .cs_change = 1, | ||
| 188 | }, { | ||
| 189 | .tx_buf = &st->d32[1], | ||
| 190 | .rx_buf = &st->d32[2], | ||
| 191 | .len = 4, | ||
| 192 | }, | ||
| 193 | }; | ||
| 194 | int ret; | ||
| 195 | |||
| 196 | st->d32[0] = cpu_to_be32( | ||
| 197 | (AD5758_WR_FLAG_MSK(AD5758_TWO_STAGE_READBACK_SELECT) << 24) | | ||
| 198 | (addr << 8)); | ||
| 199 | st->d32[1] = cpu_to_be32(AD5758_WR_FLAG_MSK(AD5758_NOP) << 24); | ||
| 200 | |||
| 201 | ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); | ||
| 202 | if (ret < 0) | ||
| 203 | return ret; | ||
| 204 | |||
| 205 | return (be32_to_cpu(st->d32[2]) >> 8) & 0xFFFF; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int ad5758_spi_reg_write(struct ad5758_state *st, | ||
| 209 | unsigned int addr, | ||
| 210 | unsigned int val) | ||
| 211 | { | ||
| 212 | st->d32[0] = cpu_to_be32((AD5758_WR_FLAG_MSK(addr) << 24) | | ||
| 213 | ((val & 0xFFFF) << 8)); | ||
| 214 | |||
| 215 | return spi_write(st->spi, &st->d32[0], sizeof(st->d32[0])); | ||
| 216 | } | ||
| 217 | |||
| 218 | static int ad5758_spi_write_mask(struct ad5758_state *st, | ||
| 219 | unsigned int addr, | ||
| 220 | unsigned long int mask, | ||
| 221 | unsigned int val) | ||
| 222 | { | ||
| 223 | int regval; | ||
| 224 | |||
| 225 | regval = ad5758_spi_reg_read(st, addr); | ||
| 226 | if (regval < 0) | ||
| 227 | return regval; | ||
| 228 | |||
| 229 | regval &= ~mask; | ||
| 230 | regval |= val; | ||
| 231 | |||
| 232 | return ad5758_spi_reg_write(st, addr, regval); | ||
| 233 | } | ||
| 234 | |||
| 235 | static int cmpfunc(const void *a, const void *b) | ||
| 236 | { | ||
| 237 | return *(int *)a - *(int *)b; | ||
| 238 | } | ||
| 239 | |||
| 240 | static int ad5758_find_closest_match(const int *array, | ||
| 241 | unsigned int size, int val) | ||
| 242 | { | ||
| 243 | int i; | ||
| 244 | |||
| 245 | for (i = 0; i < size; i++) { | ||
| 246 | if (val <= array[i]) | ||
| 247 | return i; | ||
| 248 | } | ||
| 249 | |||
| 250 | return size - 1; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int ad5758_wait_for_task_complete(struct ad5758_state *st, | ||
| 254 | unsigned int reg, | ||
| 255 | unsigned int mask) | ||
| 256 | { | ||
| 257 | unsigned int timeout; | ||
| 258 | int ret; | ||
| 259 | |||
| 260 | timeout = 10; | ||
| 261 | do { | ||
| 262 | ret = ad5758_spi_reg_read(st, reg); | ||
| 263 | if (ret < 0) | ||
| 264 | return ret; | ||
| 265 | |||
| 266 | if (!(ret & mask)) | ||
| 267 | return 0; | ||
| 268 | |||
| 269 | usleep_range(100, 1000); | ||
| 270 | } while (--timeout); | ||
| 271 | |||
| 272 | dev_err(&st->spi->dev, | ||
| 273 | "Error reading bit 0x%x in 0x%x register\n", mask, reg); | ||
| 274 | |||
| 275 | return -EIO; | ||
| 276 | } | ||
| 277 | |||
| 278 | static int ad5758_calib_mem_refresh(struct ad5758_state *st) | ||
| 279 | { | ||
| 280 | int ret; | ||
| 281 | |||
| 282 | ret = ad5758_spi_reg_write(st, AD5758_KEY, | ||
| 283 | AD5758_KEY_CODE_CALIB_MEM_REFRESH); | ||
| 284 | if (ret < 0) { | ||
| 285 | dev_err(&st->spi->dev, | ||
| 286 | "Failed to initiate a calibration memory refresh\n"); | ||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Wait to allow time for the internal calibrations to complete */ | ||
| 291 | return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, | ||
| 292 | AD5758_CAL_MEM_UNREFRESHED_MSK); | ||
| 293 | } | ||
| 294 | |||
| 295 | static int ad5758_soft_reset(struct ad5758_state *st) | ||
| 296 | { | ||
| 297 | int ret; | ||
| 298 | |||
| 299 | ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_1); | ||
| 300 | if (ret < 0) | ||
| 301 | return ret; | ||
| 302 | |||
| 303 | ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_2); | ||
| 304 | |||
| 305 | /* Perform a software reset and wait at least 100us */ | ||
| 306 | usleep_range(100, 1000); | ||
| 307 | |||
| 308 | return ret; | ||
| 309 | } | ||
| 310 | |||
| 311 | static int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st, | ||
| 312 | enum ad5758_dc_dc_mode mode) | ||
| 313 | { | ||
| 314 | int ret; | ||
| 315 | |||
| 316 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | ||
| 317 | AD5758_DCDC_CONFIG1_DCDC_MODE_MSK, | ||
| 318 | AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode)); | ||
| 319 | if (ret < 0) | ||
| 320 | return ret; | ||
| 321 | |||
| 322 | /* | ||
| 323 | * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. | ||
| 324 | * This allows the 3-wire interface communication to complete. | ||
| 325 | */ | ||
| 326 | ret = ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, | ||
| 327 | AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); | ||
| 328 | if (ret < 0) | ||
| 329 | return ret; | ||
| 330 | |||
| 331 | st->dc_dc_mode = mode; | ||
| 332 | |||
| 333 | return ret; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int ad5758_set_dc_dc_ilim(struct ad5758_state *st, unsigned int ilim) | ||
| 337 | { | ||
| 338 | int ret; | ||
| 339 | |||
| 340 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG2, | ||
| 341 | AD5758_DCDC_CONFIG2_ILIMIT_MSK, | ||
| 342 | AD5758_DCDC_CONFIG2_ILIMIT_MODE(ilim)); | ||
| 343 | if (ret < 0) | ||
| 344 | return ret; | ||
| 345 | /* | ||
| 346 | * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. | ||
| 347 | * This allows the 3-wire interface communication to complete. | ||
| 348 | */ | ||
| 349 | return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, | ||
| 350 | AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); | ||
| 351 | } | ||
| 352 | |||
| 353 | static int ad5758_slew_rate_set(struct ad5758_state *st, | ||
| 354 | unsigned int sr_clk_idx, | ||
| 355 | unsigned int sr_step_idx) | ||
| 356 | { | ||
| 357 | unsigned int mode; | ||
| 358 | unsigned long int mask; | ||
| 359 | int ret; | ||
| 360 | |||
| 361 | mask = AD5758_DAC_CONFIG_SR_EN_MSK | | ||
| 362 | AD5758_DAC_CONFIG_SR_CLOCK_MSK | | ||
| 363 | AD5758_DAC_CONFIG_SR_STEP_MSK; | ||
| 364 | mode = AD5758_DAC_CONFIG_SR_EN_MODE(1) | | ||
| 365 | AD5758_DAC_CONFIG_SR_STEP_MODE(sr_step_idx) | | ||
| 366 | AD5758_DAC_CONFIG_SR_CLOCK_MODE(sr_clk_idx); | ||
| 367 | |||
| 368 | ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, mask, mode); | ||
| 369 | if (ret < 0) | ||
| 370 | return ret; | ||
| 371 | |||
| 372 | /* Wait to allow time for the internal calibrations to complete */ | ||
| 373 | return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, | ||
| 374 | AD5758_CAL_MEM_UNREFRESHED_MSK); | ||
| 375 | } | ||
| 376 | |||
| 377 | static int ad5758_slew_rate_config(struct ad5758_state *st) | ||
| 378 | { | ||
| 379 | unsigned int sr_clk_idx, sr_step_idx; | ||
| 380 | int i, res; | ||
| 381 | s64 diff_new, diff_old; | ||
| 382 | u64 sr_step, calc_slew_time; | ||
| 383 | |||
| 384 | sr_clk_idx = 0; | ||
| 385 | sr_step_idx = 0; | ||
| 386 | diff_old = S64_MAX; | ||
| 387 | /* | ||
| 388 | * The slew time can be determined by using the formula: | ||
| 389 | * Slew Time = (Full Scale Out / (Step Size x Update Clk Freq)) | ||
| 390 | * where Slew time is expressed in microseconds | ||
| 391 | * Given the desired slew time, the following algorithm determines the | ||
| 392 | * best match for the step size and the update clock frequency. | ||
| 393 | */ | ||
| 394 | for (i = 0; i < ARRAY_SIZE(ad5758_sr_clk); i++) { | ||
| 395 | /* | ||
| 396 | * Go through each valid update clock freq and determine a raw | ||
| 397 | * value for the step size by using the formula: | ||
| 398 | * Step Size = Full Scale Out / (Update Clk Freq * Slew Time) | ||
| 399 | */ | ||
| 400 | sr_step = AD5758_FULL_SCALE_MICRO; | ||
| 401 | do_div(sr_step, ad5758_sr_clk[i]); | ||
| 402 | do_div(sr_step, st->slew_time); | ||
| 403 | /* | ||
| 404 | * After a raw value for step size was determined, find the | ||
| 405 | * closest valid match | ||
| 406 | */ | ||
| 407 | res = ad5758_find_closest_match(ad5758_sr_step, | ||
| 408 | ARRAY_SIZE(ad5758_sr_step), | ||
| 409 | sr_step); | ||
| 410 | /* Calculate the slew time */ | ||
| 411 | calc_slew_time = AD5758_FULL_SCALE_MICRO; | ||
| 412 | do_div(calc_slew_time, ad5758_sr_step[res]); | ||
| 413 | do_div(calc_slew_time, ad5758_sr_clk[i]); | ||
| 414 | /* | ||
| 415 | * Determine with how many microseconds the calculated slew time | ||
| 416 | * is different from the desired slew time and store the diff | ||
| 417 | * for the next iteration | ||
| 418 | */ | ||
| 419 | diff_new = abs(st->slew_time - calc_slew_time); | ||
| 420 | if (diff_new < diff_old) { | ||
| 421 | diff_old = diff_new; | ||
| 422 | sr_clk_idx = i; | ||
| 423 | sr_step_idx = res; | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | return ad5758_slew_rate_set(st, sr_clk_idx, sr_step_idx); | ||
| 428 | } | ||
| 429 | |||
| 430 | static int ad5758_set_out_range(struct ad5758_state *st, int range) | ||
| 431 | { | ||
| 432 | int ret; | ||
| 433 | |||
| 434 | ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, | ||
| 435 | AD5758_DAC_CONFIG_RANGE_MSK, | ||
| 436 | AD5758_DAC_CONFIG_RANGE_MODE(range)); | ||
| 437 | if (ret < 0) | ||
| 438 | return ret; | ||
| 439 | |||
| 440 | /* Wait to allow time for the internal calibrations to complete */ | ||
| 441 | return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, | ||
| 442 | AD5758_CAL_MEM_UNREFRESHED_MSK); | ||
| 443 | } | ||
| 444 | |||
| 445 | static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable) | ||
| 446 | { | ||
| 447 | int ret; | ||
| 448 | |||
| 449 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | ||
| 450 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK, | ||
| 451 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable)); | ||
| 452 | if (ret < 0) | ||
| 453 | return ret; | ||
| 454 | /* | ||
| 455 | * Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0. | ||
| 456 | * This allows the 3-wire interface communication to complete. | ||
| 457 | */ | ||
| 458 | return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2, | ||
| 459 | AD5758_DCDC_CONFIG2_BUSY_3WI_MSK); | ||
| 460 | } | ||
| 461 | |||
| 462 | static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable) | ||
| 463 | { | ||
| 464 | int ret; | ||
| 465 | |||
| 466 | ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, | ||
| 467 | AD5758_DAC_CONFIG_INT_EN_MSK, | ||
| 468 | AD5758_DAC_CONFIG_INT_EN_MODE(enable)); | ||
| 469 | if (ret < 0) | ||
| 470 | return ret; | ||
| 471 | |||
| 472 | /* Wait to allow time for the internal calibrations to complete */ | ||
| 473 | return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS, | ||
| 474 | AD5758_CAL_MEM_UNREFRESHED_MSK); | ||
| 475 | } | ||
| 476 | |||
| 477 | static int ad5758_reg_access(struct iio_dev *indio_dev, | ||
| 478 | unsigned int reg, | ||
| 479 | unsigned int writeval, | ||
| 480 | unsigned int *readval) | ||
| 481 | { | ||
| 482 | struct ad5758_state *st = iio_priv(indio_dev); | ||
| 483 | int ret; | ||
| 484 | |||
| 485 | mutex_lock(&st->lock); | ||
| 486 | if (readval) { | ||
| 487 | ret = ad5758_spi_reg_read(st, reg); | ||
| 488 | if (ret < 0) { | ||
| 489 | mutex_unlock(&st->lock); | ||
| 490 | return ret; | ||
| 491 | } | ||
| 492 | |||
| 493 | *readval = ret; | ||
| 494 | ret = 0; | ||
| 495 | } else { | ||
| 496 | ret = ad5758_spi_reg_write(st, reg, writeval); | ||
| 497 | } | ||
| 498 | mutex_unlock(&st->lock); | ||
| 499 | |||
| 500 | return ret; | ||
| 501 | } | ||
| 502 | |||
| 503 | static int ad5758_read_raw(struct iio_dev *indio_dev, | ||
| 504 | struct iio_chan_spec const *chan, | ||
| 505 | int *val, int *val2, long info) | ||
| 506 | { | ||
| 507 | struct ad5758_state *st = iio_priv(indio_dev); | ||
| 508 | int max, min, ret; | ||
| 509 | |||
| 510 | switch (info) { | ||
| 511 | case IIO_CHAN_INFO_RAW: | ||
| 512 | mutex_lock(&st->lock); | ||
| 513 | ret = ad5758_spi_reg_read(st, AD5758_DAC_INPUT); | ||
| 514 | mutex_unlock(&st->lock); | ||
| 515 | if (ret < 0) | ||
| 516 | return ret; | ||
| 517 | |||
| 518 | *val = ret; | ||
| 519 | return IIO_VAL_INT; | ||
| 520 | case IIO_CHAN_INFO_SCALE: | ||
| 521 | min = st->out_range.min; | ||
| 522 | max = st->out_range.max; | ||
| 523 | *val = (max - min) / 1000; | ||
| 524 | *val2 = 16; | ||
| 525 | return IIO_VAL_FRACTIONAL_LOG2; | ||
| 526 | case IIO_CHAN_INFO_OFFSET: | ||
| 527 | min = st->out_range.min; | ||
| 528 | max = st->out_range.max; | ||
| 529 | *val = ((min * (1 << 16)) / (max - min)) / 1000; | ||
| 530 | return IIO_VAL_INT; | ||
| 531 | default: | ||
| 532 | return -EINVAL; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | static int ad5758_write_raw(struct iio_dev *indio_dev, | ||
| 537 | struct iio_chan_spec const *chan, | ||
| 538 | int val, int val2, long info) | ||
| 539 | { | ||
| 540 | struct ad5758_state *st = iio_priv(indio_dev); | ||
| 541 | int ret; | ||
| 542 | |||
| 543 | switch (info) { | ||
| 544 | case IIO_CHAN_INFO_RAW: | ||
| 545 | mutex_lock(&st->lock); | ||
| 546 | ret = ad5758_spi_reg_write(st, AD5758_DAC_INPUT, val); | ||
| 547 | mutex_unlock(&st->lock); | ||
| 548 | return ret; | ||
| 549 | default: | ||
| 550 | return -EINVAL; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 554 | static ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev, | ||
| 555 | uintptr_t priv, | ||
| 556 | const struct iio_chan_spec *chan, | ||
| 557 | char *buf) | ||
| 558 | { | ||
| 559 | struct ad5758_state *st = iio_priv(indio_dev); | ||
| 560 | |||
| 561 | return sprintf(buf, "%d\n", st->pwr_down); | ||
| 562 | } | ||
| 563 | |||
| 564 | static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev, | ||
| 565 | uintptr_t priv, | ||
| 566 | struct iio_chan_spec const *chan, | ||
| 567 | const char *buf, size_t len) | ||
| 568 | { | ||
| 569 | struct ad5758_state *st = iio_priv(indio_dev); | ||
| 570 | bool pwr_down; | ||
| 571 | unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val; | ||
| 572 | unsigned long int dcdc_config1_msk, dac_config_msk; | ||
| 573 | int ret; | ||
| 574 | |||
| 575 | ret = kstrtobool(buf, &pwr_down); | ||
| 576 | if (ret) | ||
| 577 | return ret; | ||
| 578 | |||
| 579 | mutex_lock(&st->lock); | ||
| 580 | if (pwr_down) { | ||
| 581 | dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF; | ||
| 582 | val = 0; | ||
| 583 | } else { | ||
| 584 | dc_dc_mode = st->dc_dc_mode; | ||
| 585 | val = 1; | ||
| 586 | } | ||
| 587 | |||
| 588 | dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) | | ||
| 589 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val); | ||
| 590 | dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK | | ||
| 591 | AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK; | ||
| 592 | |||
| 593 | ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1, | ||
| 594 | dcdc_config1_msk, | ||
| 595 | dcdc_config1_mode); | ||
| 596 | if (ret < 0) | ||
| 597 | goto err_unlock; | ||
| 598 | |||
| 599 | dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) | | ||
| 600 | AD5758_DAC_CONFIG_INT_EN_MODE(val); | ||
| 601 | dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK | | ||
| 602 | AD5758_DAC_CONFIG_INT_EN_MSK; | ||
| 603 | |||
| 604 | ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, | ||
| 605 | dac_config_msk, | ||
| 606 | dac_config_mode); | ||
| 607 | if (ret < 0) | ||
| 608 | goto err_unlock; | ||
| 609 | |||
| 610 | st->pwr_down = pwr_down; | ||
| 611 | |||
| 612 | err_unlock: | ||
| 613 | mutex_unlock(&st->lock); | ||
| 614 | |||
| 615 | return ret ? ret : len; | ||
| 616 | } | ||
| 617 | |||
| 618 | static const struct iio_info ad5758_info = { | ||
| 619 | .read_raw = ad5758_read_raw, | ||
| 620 | .write_raw = ad5758_write_raw, | ||
| 621 | .debugfs_reg_access = &ad5758_reg_access, | ||
| 622 | }; | ||
| 623 | |||
| 624 | static const struct iio_chan_spec_ext_info ad5758_ext_info[] = { | ||
| 625 | { | ||
| 626 | .name = "powerdown", | ||
| 627 | .read = ad5758_read_powerdown, | ||
| 628 | .write = ad5758_write_powerdown, | ||
| 629 | .shared = IIO_SHARED_BY_TYPE, | ||
| 630 | }, | ||
| 631 | { } | ||
| 632 | }; | ||
| 633 | |||
| 634 | #define AD5758_DAC_CHAN(_chan_type) { \ | ||
| 635 | .type = (_chan_type), \ | ||
| 636 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 637 | BIT(IIO_CHAN_INFO_SCALE) | \ | ||
| 638 | BIT(IIO_CHAN_INFO_OFFSET), \ | ||
| 639 | .indexed = 1, \ | ||
| 640 | .output = 1, \ | ||
| 641 | .ext_info = ad5758_ext_info, \ | ||
| 642 | } | ||
| 643 | |||
| 644 | static const struct iio_chan_spec ad5758_voltage_ch[] = { | ||
| 645 | AD5758_DAC_CHAN(IIO_VOLTAGE) | ||
| 646 | }; | ||
| 647 | |||
| 648 | static const struct iio_chan_spec ad5758_current_ch[] = { | ||
| 649 | AD5758_DAC_CHAN(IIO_CURRENT) | ||
| 650 | }; | ||
| 651 | |||
| 652 | static bool ad5758_is_valid_mode(enum ad5758_dc_dc_mode mode) | ||
| 653 | { | ||
| 654 | switch (mode) { | ||
| 655 | case AD5758_DCDC_MODE_DPC_CURRENT: | ||
| 656 | case AD5758_DCDC_MODE_DPC_VOLTAGE: | ||
| 657 | case AD5758_DCDC_MODE_PPC_CURRENT: | ||
| 658 | return true; | ||
| 659 | default: | ||
| 660 | return false; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | static int ad5758_crc_disable(struct ad5758_state *st) | ||
| 665 | { | ||
| 666 | unsigned int mask; | ||
| 667 | |||
| 668 | mask = (AD5758_WR_FLAG_MSK(AD5758_DIGITAL_DIAG_CONFIG) << 24) | 0x5C3A; | ||
| 669 | st->d32[0] = cpu_to_be32(mask); | ||
| 670 | |||
| 671 | return spi_write(st->spi, &st->d32[0], 4); | ||
| 672 | } | ||
| 673 | |||
| 674 | static int ad5758_find_out_range(struct ad5758_state *st, | ||
| 675 | const struct ad5758_range *range, | ||
| 676 | unsigned int size, | ||
| 677 | int min, int max) | ||
| 678 | { | ||
| 679 | int i; | ||
| 680 | |||
| 681 | for (i = 0; i < size; i++) { | ||
| 682 | if ((min == range[i].min) && (max == range[i].max)) { | ||
| 683 | st->out_range.reg = range[i].reg; | ||
| 684 | st->out_range.min = range[i].min; | ||
| 685 | st->out_range.max = range[i].max; | ||
| 686 | |||
| 687 | return 0; | ||
| 688 | } | ||
| 689 | } | ||
| 690 | |||
| 691 | return -EINVAL; | ||
| 692 | } | ||
| 693 | |||
| 694 | static int ad5758_parse_dt(struct ad5758_state *st) | ||
| 695 | { | ||
| 696 | unsigned int tmp, tmparray[2], size; | ||
| 697 | const struct ad5758_range *range; | ||
| 698 | int *index, ret; | ||
| 699 | |||
| 700 | st->dc_dc_ilim = 0; | ||
| 701 | ret = device_property_read_u32(&st->spi->dev, | ||
| 702 | "adi,dc-dc-ilim-microamp", &tmp); | ||
| 703 | if (ret) { | ||
| 704 | dev_dbg(&st->spi->dev, | ||
| 705 | "Missing \"dc-dc-ilim-microamp\" property\n"); | ||
| 706 | } else { | ||
| 707 | index = bsearch(&tmp, ad5758_dc_dc_ilim, | ||
| 708 | ARRAY_SIZE(ad5758_dc_dc_ilim), | ||
| 709 | sizeof(int), cmpfunc); | ||
| 710 | if (!index) | ||
| 711 | dev_dbg(&st->spi->dev, "dc-dc-ilim out of range\n"); | ||
| 712 | else | ||
| 713 | st->dc_dc_ilim = index - ad5758_dc_dc_ilim; | ||
| 714 | } | ||
| 715 | |||
| 716 | ret = device_property_read_u32(&st->spi->dev, "adi,dc-dc-mode", | ||
| 717 | &st->dc_dc_mode); | ||
| 718 | if (ret) { | ||
| 719 | dev_err(&st->spi->dev, "Missing \"dc-dc-mode\" property\n"); | ||
| 720 | return ret; | ||
| 721 | } | ||
| 722 | |||
| 723 | if (!ad5758_is_valid_mode(st->dc_dc_mode)) | ||
| 724 | return -EINVAL; | ||
| 725 | |||
| 726 | if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) { | ||
| 727 | ret = device_property_read_u32_array(&st->spi->dev, | ||
| 728 | "adi,range-microvolt", | ||
| 729 | tmparray, 2); | ||
| 730 | if (ret) { | ||
| 731 | dev_err(&st->spi->dev, | ||
| 732 | "Missing \"range-microvolt\" property\n"); | ||
| 733 | return ret; | ||
| 734 | } | ||
| 735 | range = ad5758_voltage_range; | ||
| 736 | size = ARRAY_SIZE(ad5758_voltage_range); | ||
| 737 | } else { | ||
| 738 | ret = device_property_read_u32_array(&st->spi->dev, | ||
| 739 | "adi,range-microamp", | ||
| 740 | tmparray, 2); | ||
| 741 | if (ret) { | ||
| 742 | dev_err(&st->spi->dev, | ||
| 743 | "Missing \"range-microamp\" property\n"); | ||
| 744 | return ret; | ||
| 745 | } | ||
| 746 | range = ad5758_current_range; | ||
| 747 | size = ARRAY_SIZE(ad5758_current_range); | ||
| 748 | } | ||
| 749 | |||
| 750 | ret = ad5758_find_out_range(st, range, size, tmparray[0], tmparray[1]); | ||
| 751 | if (ret) { | ||
| 752 | dev_err(&st->spi->dev, "range invalid\n"); | ||
| 753 | return ret; | ||
| 754 | } | ||
| 755 | |||
| 756 | ret = device_property_read_u32(&st->spi->dev, "adi,slew-time-us", &tmp); | ||
| 757 | if (ret) { | ||
| 758 | dev_dbg(&st->spi->dev, "Missing \"slew-time-us\" property\n"); | ||
| 759 | st->slew_time = 0; | ||
| 760 | } else { | ||
| 761 | st->slew_time = tmp; | ||
| 762 | } | ||
| 763 | |||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | static int ad5758_init(struct ad5758_state *st) | ||
| 768 | { | ||
| 769 | int regval, ret; | ||
| 770 | |||
| 771 | /* Disable CRC checks */ | ||
| 772 | ret = ad5758_crc_disable(st); | ||
| 773 | if (ret < 0) | ||
| 774 | return ret; | ||
| 775 | |||
| 776 | /* Perform a software reset */ | ||
| 777 | ret = ad5758_soft_reset(st); | ||
| 778 | if (ret < 0) | ||
| 779 | return ret; | ||
| 780 | |||
| 781 | /* Disable CRC checks */ | ||
| 782 | ret = ad5758_crc_disable(st); | ||
| 783 | if (ret < 0) | ||
| 784 | return ret; | ||
| 785 | |||
| 786 | /* Perform a calibration memory refresh */ | ||
| 787 | ret = ad5758_calib_mem_refresh(st); | ||
| 788 | if (ret < 0) | ||
| 789 | return ret; | ||
| 790 | |||
| 791 | regval = ad5758_spi_reg_read(st, AD5758_DIGITAL_DIAG_RESULTS); | ||
| 792 | if (regval < 0) | ||
| 793 | return regval; | ||
| 794 | |||
| 795 | /* Clear all the error flags */ | ||
| 796 | ret = ad5758_spi_reg_write(st, AD5758_DIGITAL_DIAG_RESULTS, regval); | ||
| 797 | if (ret < 0) | ||
| 798 | return ret; | ||
| 799 | |||
| 800 | /* Set the dc-to-dc current limit */ | ||
| 801 | ret = ad5758_set_dc_dc_ilim(st, st->dc_dc_ilim); | ||
| 802 | if (ret < 0) | ||
| 803 | return ret; | ||
| 804 | |||
| 805 | /* Configure the dc-to-dc controller mode */ | ||
| 806 | ret = ad5758_set_dc_dc_conv_mode(st, st->dc_dc_mode); | ||
| 807 | if (ret < 0) | ||
| 808 | return ret; | ||
| 809 | |||
| 810 | /* Configure the output range */ | ||
| 811 | ret = ad5758_set_out_range(st, st->out_range.reg); | ||
| 812 | if (ret < 0) | ||
| 813 | return ret; | ||
| 814 | |||
| 815 | /* Enable Slew Rate Control, set the slew rate clock and step */ | ||
| 816 | if (st->slew_time) { | ||
| 817 | ret = ad5758_slew_rate_config(st); | ||
| 818 | if (ret < 0) | ||
| 819 | return ret; | ||
| 820 | } | ||
| 821 | |||
| 822 | /* Enable the VIOUT fault protection switch (FPS is closed) */ | ||
| 823 | ret = ad5758_fault_prot_switch_en(st, 1); | ||
| 824 | if (ret < 0) | ||
| 825 | return ret; | ||
| 826 | |||
| 827 | /* Power up the DAC and internal (INT) amplifiers */ | ||
| 828 | ret = ad5758_internal_buffers_en(st, 1); | ||
| 829 | if (ret < 0) | ||
| 830 | return ret; | ||
| 831 | |||
| 832 | /* Enable VIOUT */ | ||
| 833 | return ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, | ||
| 834 | AD5758_DAC_CONFIG_OUT_EN_MSK, | ||
| 835 | AD5758_DAC_CONFIG_OUT_EN_MODE(1)); | ||
| 836 | } | ||
| 837 | |||
| 838 | static int ad5758_probe(struct spi_device *spi) | ||
| 839 | { | ||
| 840 | struct ad5758_state *st; | ||
| 841 | struct iio_dev *indio_dev; | ||
| 842 | int ret; | ||
| 843 | |||
| 844 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); | ||
| 845 | if (!indio_dev) | ||
| 846 | return -ENOMEM; | ||
| 847 | |||
| 848 | st = iio_priv(indio_dev); | ||
| 849 | spi_set_drvdata(spi, indio_dev); | ||
| 850 | |||
| 851 | st->spi = spi; | ||
| 852 | |||
| 853 | mutex_init(&st->lock); | ||
| 854 | |||
| 855 | indio_dev->dev.parent = &spi->dev; | ||
| 856 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 857 | indio_dev->info = &ad5758_info; | ||
| 858 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 859 | indio_dev->num_channels = 1; | ||
| 860 | |||
| 861 | ret = ad5758_parse_dt(st); | ||
| 862 | if (ret < 0) | ||
| 863 | return ret; | ||
| 864 | |||
| 865 | if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) | ||
| 866 | indio_dev->channels = ad5758_voltage_ch; | ||
| 867 | else | ||
| 868 | indio_dev->channels = ad5758_current_ch; | ||
| 869 | |||
| 870 | ret = ad5758_init(st); | ||
| 871 | if (ret < 0) { | ||
| 872 | dev_err(&spi->dev, "AD5758 init failed\n"); | ||
| 873 | return ret; | ||
| 874 | } | ||
| 875 | |||
| 876 | return devm_iio_device_register(&st->spi->dev, indio_dev); | ||
| 877 | } | ||
| 878 | |||
| 879 | static const struct spi_device_id ad5758_id[] = { | ||
| 880 | { "ad5758", 0 }, | ||
| 881 | {} | ||
| 882 | }; | ||
| 883 | MODULE_DEVICE_TABLE(spi, ad5758_id); | ||
| 884 | |||
| 885 | static struct spi_driver ad5758_driver = { | ||
| 886 | .driver = { | ||
| 887 | .name = KBUILD_MODNAME, | ||
| 888 | }, | ||
| 889 | .probe = ad5758_probe, | ||
| 890 | .id_table = ad5758_id, | ||
| 891 | }; | ||
| 892 | |||
| 893 | module_spi_driver(ad5758_driver); | ||
| 894 | |||
| 895 | MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); | ||
| 896 | MODULE_DESCRIPTION("Analog Devices AD5758 DAC"); | ||
| 897 | MODULE_LICENSE("GPL v2"); | ||
| @@ -87,12 +87,7 @@ static int ltc2632_read_raw(struct iio_dev *indio_dev, · 86 unmodified lines | |||
| 87 | int *val2, | 87 | int *val2, |
| 88 | long m) | 88 | long m) |
| 89 | { | 89 | { |
| 90 | struct ltc2632_chip_info *chip_info; | ||
| 91 | |||
| 92 | const struct ltc2632_state *st = iio_priv(indio_dev); | 90 | const struct ltc2632_state *st = iio_priv(indio_dev); |
| 93 | const struct spi_device_id *spi_dev_id = spi_get_device_id(st->spi_dev); | ||
| 94 | |||
| 95 | chip_info = (struct ltc2632_chip_info *)spi_dev_id->driver_data; | ||
| 96 | 91 | ||
| 97 | switch (m) { | 92 | switch (m) { |
| 98 | case IIO_CHAN_INFO_SCALE: | 93 | case IIO_CHAN_INFO_SCALE: |
| @@ -97,9 +97,6 @@ static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val) · 96 unmodified lines | |||
| 97 | 97 | ||
| 98 | static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn) | 98 | static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn) |
| 99 | { | 99 | { |
| 100 | unsigned int shift; | ||
| 101 | |||
| 102 | shift = 12 - data->spec->resolution; | ||
| 103 | data->buf[1] = 0; | 100 | data->buf[1] = 0; |
| 104 | data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS; | 101 | data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS; |
| 105 | 102 | ||
| @@ -111,9 +108,6 @@ static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrd · 5 unmodified lines | |||
| 111 | 108 | ||
| 112 | static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn) | 109 | static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn) |
| 113 | { | 110 | { |
| 114 | unsigned int shift; | ||
| 115 | |||
| 116 | shift = 16 - data->spec->resolution; | ||
| 117 | data->buf[2] = 0; | 111 | data->buf[2] = 0; |
| 118 | data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS; | 112 | data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS; |
| 119 | data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | | 113 | data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | |
| @@ -274,6 +274,15 @@ struct ad9523_state { · 273 unmodified lines | |||
| 274 | unsigned long vco_out_freq[AD9523_NUM_CLK_SRC]; | 274 | unsigned long vco_out_freq[AD9523_NUM_CLK_SRC]; |
| 275 | unsigned char vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC]; | 275 | unsigned char vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC]; |
| 276 | 276 | ||
| 277 | /* | ||
| 278 | * Lock for accessing device registers. Some operations require | ||
| 279 | * multiple consecutive R/W operations, during which the device | ||
| 280 | * shouldn't be interrupted. The buffers are also shared across | ||
| 281 | * all operations so need to be protected on stand alone reads and | ||
| 282 | * writes. | ||
| 283 | */ | ||
| 284 | struct mutex lock; | ||
| 285 | |||
| 277 | /* | 286 | /* |
| 278 | * DMA (thus cache coherency maintenance) requires the | 287 | * DMA (thus cache coherency maintenance) requires the |
| 279 | * transfer buffers to live in their own cache lines. | 288 | * transfer buffers to live in their own cache lines. |
| @@ -500,6 +509,7 @@ static ssize_t ad9523_store(struct device *dev, · 220 unmodified lines | |||
| 500 | { | 509 | { |
| 501 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | 510 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
| 502 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 511 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
| 512 | struct ad9523_state *st = iio_priv(indio_dev); | ||
| 503 | bool state; | 513 | bool state; |
| 504 | int ret; | 514 | int ret; |
| 505 | 515 | ||
| @@ -510,7 +520,7 @@ static ssize_t ad9523_store(struct device *dev, · 4 unmodified lines | |||
| 510 | if (!state) | 520 | if (!state) |
| 511 | return 0; | 521 | return 0; |
| 512 | 522 | ||
| 513 | mutex_lock(&indio_dev->mlock); | 523 | mutex_lock(&st->lock); |
| 514 | switch ((u32)this_attr->address) { | 524 | switch ((u32)this_attr->address) { |
| 515 | case AD9523_SYNC: | 525 | case AD9523_SYNC: |
| 516 | ret = ad9523_sync(indio_dev); | 526 | ret = ad9523_sync(indio_dev); |
| @@ -521,7 +531,7 @@ static ssize_t ad9523_store(struct device *dev, · 4 unmodified lines | |||
| 521 | default: | 531 | default: |
| 522 | ret = -ENODEV; | 532 | ret = -ENODEV; |
| 523 | } | 533 | } |
| 524 | mutex_unlock(&indio_dev->mlock); | 534 | mutex_unlock(&st->lock); |
| 525 | 535 | ||
| 526 | return ret ? ret : len; | 536 | return ret ? ret : len; |
| 527 | } | 537 | } |
| @@ -532,15 +542,16 @@ static ssize_t ad9523_show(struct device *dev, · 4 unmodified lines | |||
| 532 | { | 542 | { |
| 533 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | 543 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
| 534 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 544 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
| 545 | struct ad9523_state *st = iio_priv(indio_dev); | ||
| 535 | int ret; | 546 | int ret; |
| 536 | 547 | ||
| 537 | mutex_lock(&indio_dev->mlock); | 548 | mutex_lock(&st->lock); |
| 538 | ret = ad9523_read(indio_dev, AD9523_READBACK_0); | 549 | ret = ad9523_read(indio_dev, AD9523_READBACK_0); |
| 539 | if (ret >= 0) { | 550 | if (ret >= 0) { |
| 540 | ret = sprintf(buf, "%d\n", !!(ret & (1 << | 551 | ret = sprintf(buf, "%d\n", !!(ret & (1 << |
| 541 | (u32)this_attr->address))); | 552 | (u32)this_attr->address))); |
| 542 | } | 553 | } |
| 543 | mutex_unlock(&indio_dev->mlock); | 554 | mutex_unlock(&st->lock); |
| 544 | 555 | ||
| 545 | return ret; | 556 | return ret; |
| 546 | } | 557 | } |
| @@ -623,9 +634,9 @@ static int ad9523_read_raw(struct iio_dev *indio_dev, · 76 unmodified lines | |||
| 623 | unsigned int code; | 634 | unsigned int code; |
| 624 | int ret; | 635 | int ret; |
| 625 | 636 | ||
| 626 | mutex_lock(&indio_dev->mlock); | 637 | mutex_lock(&st->lock); |
| 627 | ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel)); | 638 | ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel)); |
| 628 | mutex_unlock(&indio_dev->mlock); | 639 | mutex_unlock(&st->lock); |
| 629 | 640 | ||
| 630 | if (ret < 0) | 641 | if (ret < 0) |
| 631 | return ret; | 642 | return ret; |
| @@ -642,7 +653,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev, · 10 unmodified lines | |||
| 642 | code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) / | 653 | code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) / |
| 643 | AD9523_CLK_DIST_DIV_REV(ret); | 654 | AD9523_CLK_DIST_DIV_REV(ret); |
| 644 | *val = code / 1000000; | 655 | *val = code / 1000000; |
| 645 | *val2 = (code % 1000000) * 10; | 656 | *val2 = code % 1000000; |
| 646 | return IIO_VAL_INT_PLUS_MICRO; | 657 | return IIO_VAL_INT_PLUS_MICRO; |
| 647 | default: | 658 | default: |
| 648 | return -EINVAL; | 659 | return -EINVAL; |
| @@ -659,7 +670,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev, · 10 unmodified lines | |||
| 659 | unsigned int reg; | 670 | unsigned int reg; |
| 660 | int ret, tmp, code; | 671 | int ret, tmp, code; |
| 661 | 672 | ||
| 662 | mutex_lock(&indio_dev->mlock); | 673 | mutex_lock(&st->lock); |
| 663 | ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel)); | 674 | ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel)); |
| 664 | if (ret < 0) | 675 | if (ret < 0) |
| 665 | goto out; | 676 | goto out; |
| @@ -705,7 +716,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev, · 39 unmodified lines | |||
| 705 | 716 | ||
| 706 | ad9523_io_update(indio_dev); | 717 | ad9523_io_update(indio_dev); |
| 707 | out: | 718 | out: |
| 708 | mutex_unlock(&indio_dev->mlock); | 719 | mutex_unlock(&st->lock); |
| 709 | return ret; | 720 | return ret; |
| 710 | } | 721 | } |
| 711 | 722 | ||
| @@ -713,9 +724,10 @@ static int ad9523_reg_access(struct iio_dev *indio_dev, · 1 unmodified line | |||
| 713 | unsigned int reg, unsigned int writeval, | 724 | unsigned int reg, unsigned int writeval, |
| 714 | unsigned int *readval) | 725 | unsigned int *readval) |
| 715 | { | 726 | { |
| 727 | struct ad9523_state *st = iio_priv(indio_dev); | ||
| 716 | int ret; | 728 | int ret; |
| 717 | 729 | ||
| 718 | mutex_lock(&indio_dev->mlock); | 730 | mutex_lock(&st->lock); |
| 719 | if (readval == NULL) { | 731 | if (readval == NULL) { |
| 720 | ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval); | 732 | ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval); |
| 721 | ad9523_io_update(indio_dev); | 733 | ad9523_io_update(indio_dev); |
| @@ -728,7 +740,7 @@ static int ad9523_reg_access(struct iio_dev *indio_dev, · 6 unmodified lines | |||
| 728 | } | 740 | } |
| 729 | 741 | ||
| 730 | out_unlock: | 742 | out_unlock: |
| 731 | mutex_unlock(&indio_dev->mlock); | 743 | mutex_unlock(&st->lock); |
| 732 | 744 | ||
| 733 | return ret; | 745 | return ret; |
| 734 | } | 746 | } |
| @@ -967,6 +979,8 @@ static int ad9523_probe(struct spi_device *spi) · 232 unmodified lines | |||
| 967 | 979 | ||
| 968 | st = iio_priv(indio_dev); | 980 | st = iio_priv(indio_dev); |
| 969 | 981 | ||
| 982 | mutex_init(&st->lock); | ||
| 983 | |||
| 970 | st->reg = devm_regulator_get(&spi->dev, "vcc"); | 984 | st->reg = devm_regulator_get(&spi->dev, "vcc"); |
| 971 | if (!IS_ERR(st->reg)) { | 985 | if (!IS_ERR(st->reg)) { |
| 972 | ret = regulator_enable(st->reg); | 986 | ret = regulator_enable(st->reg); |
| @@ -81,9 +81,11 @@ int adis_write_reg(struct adis *adis, unsigned int reg, · 80 unmodified lines | |||
| 81 | adis->tx[9] = (value >> 24) & 0xff; | 81 | adis->tx[9] = (value >> 24) & 0xff; |
| 82 | adis->tx[6] = ADIS_WRITE_REG(reg + 2); | 82 | adis->tx[6] = ADIS_WRITE_REG(reg + 2); |
| 83 | adis->tx[7] = (value >> 16) & 0xff; | 83 | adis->tx[7] = (value >> 16) & 0xff; |
| 84 | /* fall through */ | ||
| 84 | case 2: | 85 | case 2: |
| 85 | adis->tx[4] = ADIS_WRITE_REG(reg + 1); | 86 | adis->tx[4] = ADIS_WRITE_REG(reg + 1); |
| 86 | adis->tx[5] = (value >> 8) & 0xff; | 87 | adis->tx[5] = (value >> 8) & 0xff; |
| 88 | /* fall through */ | ||
| 87 | case 1: | 89 | case 1: |
| 88 | adis->tx[2] = ADIS_WRITE_REG(reg); | 90 | adis->tx[2] = ADIS_WRITE_REG(reg); |
| 89 | adis->tx[3] = value & 0xff; | 91 | adis->tx[3] = value & 0xff; |
| @@ -167,6 +169,7 @@ int adis_read_reg(struct adis *adis, unsigned int reg, · 77 unmodified lines | |||
| 167 | adis->tx[2] = ADIS_READ_REG(reg + 2); | 169 | adis->tx[2] = ADIS_READ_REG(reg + 2); |
| 168 | adis->tx[3] = 0; | 170 | adis->tx[3] = 0; |
| 169 | spi_message_add_tail(&xfers[1], &msg); | 171 | spi_message_add_tail(&xfers[1], &msg); |
| 172 | /* fall through */ | ||
| 170 | case 2: | 173 | case 2: |
| 171 | adis->tx[4] = ADIS_READ_REG(reg); | 174 | adis->tx[4] = ADIS_READ_REG(reg); |
| 172 | adis->tx[5] = 0; | 175 | adis->tx[5] = 0; |
| @@ -103,6 +103,12 @@ static const struct inv_mpu6050_hw hw_info[] = { · 102 unmodified lines | |||
| 103 | .reg = ®_set_6500, | 103 | .reg = ®_set_6500, |
| 104 | .config = &chip_config_6050, | 104 | .config = &chip_config_6050, |
| 105 | }, | 105 | }, |
| 106 | { | ||
| 107 | .whoami = INV_MPU6515_WHOAMI_VALUE, | ||
| 108 | .name = "MPU6515", | ||
| 109 | .reg = ®_set_6500, | ||
| 110 | .config = &chip_config_6050, | ||
| 111 | }, | ||
| 106 | { | 112 | { |
| 107 | .whoami = INV_MPU6000_WHOAMI_VALUE, | 113 | .whoami = INV_MPU6000_WHOAMI_VALUE, |
| 108 | .name = "MPU6000", | 114 | .name = "MPU6000", |
| @@ -174,6 +174,7 @@ static int inv_mpu_remove(struct i2c_client *client) · 173 unmodified lines | |||
| 174 | static const struct i2c_device_id inv_mpu_id[] = { | 174 | static const struct i2c_device_id inv_mpu_id[] = { |
| 175 | {"mpu6050", INV_MPU6050}, | 175 | {"mpu6050", INV_MPU6050}, |
| 176 | {"mpu6500", INV_MPU6500}, | 176 | {"mpu6500", INV_MPU6500}, |
| 177 | {"mpu6515", INV_MPU6515}, | ||
| 177 | {"mpu9150", INV_MPU9150}, | 178 | {"mpu9150", INV_MPU9150}, |
| 178 | {"mpu9250", INV_MPU9250}, | 179 | {"mpu9250", INV_MPU9250}, |
| 179 | {"mpu9255", INV_MPU9255}, | 180 | {"mpu9255", INV_MPU9255}, |
| @@ -192,6 +193,10 @@ static const struct of_device_id inv_of_match[] = { · 12 unmodified lines | |||
| 192 | .compatible = "invensense,mpu6500", | 193 | .compatible = "invensense,mpu6500", |
| 193 | .data = (void *)INV_MPU6500 | 194 | .data = (void *)INV_MPU6500 |
| 194 | }, | 195 | }, |
| 196 | { | ||
| 197 | .compatible = "invensense,mpu6515", | ||
| 198 | .data = (void *)INV_MPU6515 | ||
| 199 | }, | ||
| 195 | { | 200 | { |
| 196 | .compatible = "invensense,mpu9150", | 201 | .compatible = "invensense,mpu9150", |
| 197 | .data = (void *)INV_MPU9150 | 202 | .data = (void *)INV_MPU9150 |
| @@ -71,6 +71,7 @@ struct inv_mpu6050_reg_map { · 70 unmodified lines | |||
| 71 | enum inv_devices { | 71 | enum inv_devices { |
| 72 | INV_MPU6050, | 72 | INV_MPU6050, |
| 73 | INV_MPU6500, | 73 | INV_MPU6500, |
| 74 | INV_MPU6515, | ||
| 74 | INV_MPU6000, | 75 | INV_MPU6000, |
| 75 | INV_MPU9150, | 76 | INV_MPU9150, |
| 76 | INV_MPU9250, | 77 | INV_MPU9250, |
| @@ -256,6 +257,7 @@ struct inv_mpu6050_state { · 179 unmodified lines | |||
| 256 | #define INV_MPU9150_WHOAMI_VALUE 0x68 | 257 | #define INV_MPU9150_WHOAMI_VALUE 0x68 |
| 257 | #define INV_MPU9250_WHOAMI_VALUE 0x71 | 258 | #define INV_MPU9250_WHOAMI_VALUE 0x71 |
| 258 | #define INV_MPU9255_WHOAMI_VALUE 0x73 | 259 | #define INV_MPU9255_WHOAMI_VALUE 0x73 |
| 260 | #define INV_MPU6515_WHOAMI_VALUE 0x74 | ||
| 259 | #define INV_ICM20608_WHOAMI_VALUE 0xAF | 261 | #define INV_ICM20608_WHOAMI_VALUE 0xAF |
| 260 | 262 | ||
| 261 | /* scan element definition */ | 263 | /* scan element definition */ |
| @@ -298,8 +298,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) · 297 unmodified lines | |||
| 298 | err = regmap_bulk_read(hw->regmap, | 298 | err = regmap_bulk_read(hw->regmap, |
| 299 | hw->settings->fifo_ops.fifo_diff.addr, | 299 | hw->settings->fifo_ops.fifo_diff.addr, |
| 300 | &fifo_status, sizeof(fifo_status)); | 300 | &fifo_status, sizeof(fifo_status)); |
| 301 | if (err < 0) | 301 | if (err < 0) { |
| 302 | dev_err(hw->dev, "failed to read fifo status (err=%d)\n", | ||
| 303 | err); | ||
| 302 | return err; | 304 | return err; |
| 305 | } | ||
| 303 | 306 | ||
| 304 | if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK)) | 307 | if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK)) |
| 305 | return 0; | 308 | return 0; |
| @@ -313,8 +316,12 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) · 7 unmodified lines | |||
| 313 | 316 | ||
| 314 | for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { | 317 | for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { |
| 315 | err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len); | 318 | err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len); |
| 316 | if (err < 0) | 319 | if (err < 0) { |
| 320 | dev_err(hw->dev, | ||
| 321 | "failed to read pattern from fifo (err=%d)\n", | ||
| 322 | err); | ||
| 317 | return err; | 323 | return err; |
| 324 | } | ||
| 318 | 325 | ||
| 319 | /* | 326 | /* |
| 320 | * Data are written to the FIFO with a specific pattern | 327 | * Data are written to the FIFO with a specific pattern |
| @@ -385,8 +392,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) · 64 unmodified lines | |||
| 385 | 392 | ||
| 386 | if (unlikely(reset_ts)) { | 393 | if (unlikely(reset_ts)) { |
| 387 | err = st_lsm6dsx_reset_hw_ts(hw); | 394 | err = st_lsm6dsx_reset_hw_ts(hw); |
| 388 | if (err < 0) | 395 | if (err < 0) { |
| 396 | dev_err(hw->dev, "failed to reset hw ts (err=%d)\n", | ||
| 397 | err); | ||
| 389 | return err; | 398 | return err; |
| 399 | } | ||
| 390 | } | 400 | } |
| 391 | return read_len; | 401 | return read_len; |
| 392 | } | 402 | } |
| @@ -86,6 +86,7 @@ static const char * const iio_chan_type_name_spec[] = { · 85 unmodified lines | |||
| 86 | [IIO_INDEX] = "index", | 86 | [IIO_INDEX] = "index", |
| 87 | [IIO_GRAVITY] = "gravity", | 87 | [IIO_GRAVITY] = "gravity", |
| 88 | [IIO_POSITIONRELATIVE] = "positionrelative", | 88 | [IIO_POSITIONRELATIVE] = "positionrelative", |
| 89 | [IIO_PHASE] = "phase", | ||
| 89 | }; | 90 | }; |
| 90 | 91 | ||
| 91 | static const char * const iio_modifier_names[] = { | 92 | static const char * const iio_modifier_names[] = { |
| @@ -109,6 +110,7 @@ static const char * const iio_modifier_names[] = { · 17 unmodified lines | |||
| 109 | [IIO_MOD_LIGHT_GREEN] = "green", | 110 | [IIO_MOD_LIGHT_GREEN] = "green", |
| 110 | [IIO_MOD_LIGHT_BLUE] = "blue", | 111 | [IIO_MOD_LIGHT_BLUE] = "blue", |
| 111 | [IIO_MOD_LIGHT_UV] = "uv", | 112 | [IIO_MOD_LIGHT_UV] = "uv", |
| 113 | [IIO_MOD_LIGHT_DUV] = "duv", | ||
| 112 | [IIO_MOD_QUATERNION] = "quaternion", | 114 | [IIO_MOD_QUATERNION] = "quaternion", |
| 113 | [IIO_MOD_TEMP_AMBIENT] = "ambient", | 115 | [IIO_MOD_TEMP_AMBIENT] = "ambient", |
| 114 | [IIO_MOD_TEMP_OBJECT] = "object", | 116 | [IIO_MOD_TEMP_OBJECT] = "object", |
| @@ -1,3 +1,4 @@ | |||
| 1 | |||
| 1 | # | 2 | # |
| 2 | # Light sensors | 3 | # Light sensors |
| 3 | # | 4 | # |
| @@ -319,6 +320,17 @@ config PA12203001 · 315 unmodified lines | |||
| 319 | This driver can also be built as a module. If so, the module | 320 | This driver can also be built as a module. If so, the module |
| 320 | will be called pa12203001. | 321 | will be called pa12203001. |
| 321 | 322 | ||
| 323 | config SI1133 | ||
| 324 | tristate "SI1133 UV Index Sensor and Ambient Light Sensor" | ||
| 325 | depends on I2C | ||
| 326 | select REGMAP_I2C | ||
| 327 | help | ||
| 328 | Say Y here if you want to build a driver for the Silicon Labs SI1133 | ||
| 329 | UV Index Sensor and Ambient Light Sensor chip. | ||
| 330 | |||
| 331 | To compile this driver as a module, choose M here: the module will be | ||
| 332 | called si1133. | ||
| 333 | |||
| 322 | config SI1145 | 334 | config SI1145 |
| 323 | tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor" | 335 | tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor" |
| 324 | depends on I2C | 336 | depends on I2C |
| @@ -32,6 +32,7 @@ obj-$(CONFIG_OPT3001) += opt3001.o · 31 unmodified lines | |||
| 32 | obj-$(CONFIG_PA12203001) += pa12203001.o | 32 | obj-$(CONFIG_PA12203001) += pa12203001.o |
| 33 | obj-$(CONFIG_RPR0521) += rpr0521.o | 33 | obj-$(CONFIG_RPR0521) += rpr0521.o |
| 34 | obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o | 34 | obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o |
| 35 | obj-$(CONFIG_SI1133) += si1133.o | ||
| 35 | obj-$(CONFIG_SI1145) += si1145.o | 36 | obj-$(CONFIG_SI1145) += si1145.o |
| 36 | obj-$(CONFIG_STK3310) += stk3310.o | 37 | obj-$(CONFIG_STK3310) += stk3310.o |
| 37 | obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o | 38 | obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o |
| @@ -0,0 +1,1068 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * si1133.c - Support for Silabs SI1133 combined ambient | ||
| 4 | * light and UV index sensors | ||
| 5 | * | ||
| 6 | * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/delay.h> | ||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | |||
| 15 | #include <linux/iio/iio.h> | ||
| 16 | #include <linux/iio/sysfs.h> | ||
| 17 | |||
| 18 | #include <linux/util_macros.h> | ||
| 19 | |||
| 20 | #define SI1133_REG_PART_ID 0x00 | ||
| 21 | #define SI1133_REG_REV_ID 0x01 | ||
| 22 | #define SI1133_REG_MFR_ID 0x02 | ||
| 23 | #define SI1133_REG_INFO0 0x03 | ||
| 24 | #define SI1133_REG_INFO1 0x04 | ||
| 25 | |||
| 26 | #define SI1133_PART_ID 0x33 | ||
| 27 | |||
| 28 | #define SI1133_REG_HOSTIN0 0x0A | ||
| 29 | #define SI1133_REG_COMMAND 0x0B | ||
| 30 | #define SI1133_REG_IRQ_ENABLE 0x0F | ||
| 31 | #define SI1133_REG_RESPONSE1 0x10 | ||
| 32 | #define SI1133_REG_RESPONSE0 0x11 | ||
| 33 | #define SI1133_REG_IRQ_STATUS 0x12 | ||
| 34 | #define SI1133_REG_MEAS_RATE 0x1A | ||
| 35 | |||
| 36 | #define SI1133_IRQ_CHANNEL_ENABLE 0xF | ||
| 37 | |||
| 38 | #define SI1133_CMD_RESET_CTR 0x00 | ||
| 39 | #define SI1133_CMD_RESET_SW 0x01 | ||
| 40 | #define SI1133_CMD_FORCE 0x11 | ||
| 41 | #define SI1133_CMD_START_AUTONOMOUS 0x13 | ||
| 42 | #define SI1133_CMD_PARAM_SET 0x80 | ||
| 43 | #define SI1133_CMD_PARAM_QUERY 0x40 | ||
| 44 | #define SI1133_CMD_PARAM_MASK 0x3F | ||
| 45 | |||
| 46 | #define SI1133_CMD_ERR_MASK BIT(4) | ||
| 47 | #define SI1133_CMD_SEQ_MASK 0xF | ||
| 48 | #define SI1133_MAX_CMD_CTR 0xF | ||
| 49 | |||
| 50 | #define SI1133_PARAM_REG_CHAN_LIST 0x01 | ||
| 51 | #define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2 | ||
| 52 | #define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3 | ||
| 53 | #define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4 | ||
| 54 | |||
| 55 | #define SI1133_ADCMUX_MASK 0x1F | ||
| 56 | |||
| 57 | #define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5 | ||
| 58 | |||
| 59 | #define SI1133_ADCSENS_SCALE_MASK 0x70 | ||
| 60 | #define SI1133_ADCSENS_SCALE_SHIFT 4 | ||
| 61 | #define SI1133_ADCSENS_HSIG_MASK BIT(7) | ||
| 62 | #define SI1133_ADCSENS_HSIG_SHIFT 7 | ||
| 63 | #define SI1133_ADCSENS_HW_GAIN_MASK 0xF | ||
| 64 | #define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT | ||
| 65 | |||
| 66 | #define SI1133_ADCPOST_24BIT_EN BIT(6) | ||
| 67 | #define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3 | ||
| 68 | |||
| 69 | #define SI1133_PARAM_ADCMUX_SMALL_IR 0x0 | ||
| 70 | #define SI1133_PARAM_ADCMUX_MED_IR 0x1 | ||
| 71 | #define SI1133_PARAM_ADCMUX_LARGE_IR 0x2 | ||
| 72 | #define SI1133_PARAM_ADCMUX_WHITE 0xB | ||
| 73 | #define SI1133_PARAM_ADCMUX_LARGE_WHITE 0xD | ||
| 74 | #define SI1133_PARAM_ADCMUX_UV 0x18 | ||
| 75 | #define SI1133_PARAM_ADCMUX_UV_DEEP 0x19 | ||
| 76 | |||
| 77 | #define SI1133_ERR_INVALID_CMD 0x0 | ||
| 78 | #define SI1133_ERR_INVALID_LOCATION_CMD 0x1 | ||
| 79 | #define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x2 | ||
| 80 | #define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x3 | ||
| 81 | |||
| 82 | #define SI1133_COMPLETION_TIMEOUT_MS 500 | ||
| 83 | |||
| 84 | #define SI1133_CMD_MINSLEEP_US_LOW 5000 | ||
| 85 | #define SI1133_CMD_MINSLEEP_US_HIGH 7500 | ||
| 86 | #define SI1133_CMD_TIMEOUT_MS 25 | ||
| 87 | #define SI1133_CMD_LUX_TIMEOUT_MS 5000 | ||
| 88 | #define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000 | ||
| 89 | |||
| 90 | #define SI1133_REG_HOSTOUT(x) (x) + 0x13 | ||
| 91 | |||
| 92 | #define SI1133_MEASUREMENT_FREQUENCY 1250 | ||
| 93 | |||
| 94 | #define SI1133_X_ORDER_MASK 0x0070 | ||
| 95 | #define SI1133_Y_ORDER_MASK 0x0007 | ||
| 96 | #define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 | ||
| 97 | #define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK) | ||
| 98 | |||
| 99 | #define SI1133_LUX_ADC_MASK 0xE | ||
| 100 | #define SI1133_ADC_THRESHOLD 16000 | ||
| 101 | #define SI1133_INPUT_FRACTION_HIGH 7 | ||
| 102 | #define SI1133_INPUT_FRACTION_LOW 15 | ||
| 103 | #define SI1133_LUX_OUTPUT_FRACTION 12 | ||
| 104 | #define SI1133_LUX_BUFFER_SIZE 9 | ||
| 105 | |||
| 106 | static const int si1133_scale_available[] = { | ||
| 107 | 1, 2, 4, 8, 16, 32, 64, 128}; | ||
| 108 | |||
| 109 | static IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128"); | ||
| 110 | |||
| 111 | static IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 " | ||
| 112 | "1.560 3.120 6.24 12.48 25.0 50.0"); | ||
| 113 | |||
| 114 | /* A.K.A. HW_GAIN in datasheet */ | ||
| 115 | enum si1133_int_time { | ||
| 116 | _24_4_us = 0, | ||
| 117 | _48_8_us = 1, | ||
| 118 | _97_5_us = 2, | ||
| 119 | _195_0_us = 3, | ||
| 120 | _390_0_us = 4, | ||
| 121 | _780_0_us = 5, | ||
| 122 | _1_560_0_us = 6, | ||
| 123 | _3_120_0_us = 7, | ||
| 124 | _6_240_0_us = 8, | ||
| 125 | _12_480_0_us = 9, | ||
| 126 | _25_ms = 10, | ||
| 127 | _50_ms = 11, | ||
| 128 | }; | ||
| 129 | |||
| 130 | /* Integration time in milliseconds, nanoseconds */ | ||
| 131 | static const int si1133_int_time_table[][2] = { | ||
| 132 | [_24_4_us] = {0, 24400}, | ||
| 133 | [_48_8_us] = {0, 48800}, | ||
| 134 | [_97_5_us] = {0, 97500}, | ||
| 135 | [_195_0_us] = {0, 195000}, | ||
| 136 | [_390_0_us] = {0, 390000}, | ||
| 137 | [_780_0_us] = {0, 780000}, | ||
| 138 | [_1_560_0_us] = {1, 560000}, | ||
| 139 | [_3_120_0_us] = {3, 120000}, | ||
| 140 | [_6_240_0_us] = {6, 240000}, | ||
| 141 | [_12_480_0_us] = {12, 480000}, | ||
| 142 | [_25_ms] = {25, 000000}, | ||
| 143 | [_50_ms] = {50, 000000}, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static const struct regmap_range si1133_reg_ranges[] = { | ||
| 147 | regmap_reg_range(0x00, 0x02), | ||
| 148 | regmap_reg_range(0x0A, 0x0B), | ||
| 149 | regmap_reg_range(0x0F, 0x0F), | ||
| 150 | regmap_reg_range(0x10, 0x12), | ||
| 151 | regmap_reg_range(0x13, 0x2C), | ||
| 152 | }; | ||
| 153 | |||
| 154 | static const struct regmap_range si1133_reg_ro_ranges[] = { | ||
| 155 | regmap_reg_range(0x00, 0x02), | ||
| 156 | regmap_reg_range(0x10, 0x2C), | ||
| 157 | }; | ||
| 158 | |||
| 159 | static const struct regmap_range si1133_precious_ranges[] = { | ||
| 160 | regmap_reg_range(0x12, 0x12), | ||
| 161 | }; | ||
| 162 | |||
| 163 | static const struct regmap_access_table si1133_write_ranges_table = { | ||
| 164 | .yes_ranges = si1133_reg_ranges, | ||
| 165 | .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), | ||
| 166 | .no_ranges = si1133_reg_ro_ranges, | ||
| 167 | .n_no_ranges = ARRAY_SIZE(si1133_reg_ro_ranges), | ||
| 168 | }; | ||
| 169 | |||
| 170 | static const struct regmap_access_table si1133_read_ranges_table = { | ||
| 171 | .yes_ranges = si1133_reg_ranges, | ||
| 172 | .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), | ||
| 173 | }; | ||
| 174 | |||
| 175 | static const struct regmap_access_table si1133_precious_table = { | ||
| 176 | .yes_ranges = si1133_precious_ranges, | ||
| 177 | .n_yes_ranges = ARRAY_SIZE(si1133_precious_ranges), | ||
| 178 | }; | ||
| 179 | |||
| 180 | static const struct regmap_config si1133_regmap_config = { | ||
| 181 | .reg_bits = 8, | ||
| 182 | .val_bits = 8, | ||
| 183 | |||
| 184 | .max_register = 0x2C, | ||
| 185 | |||
| 186 | .wr_table = &si1133_write_ranges_table, | ||
| 187 | .rd_table = &si1133_read_ranges_table, | ||
| 188 | |||
| 189 | .precious_table = &si1133_precious_table, | ||
| 190 | }; | ||
| 191 | |||
| 192 | struct si1133_data { | ||
| 193 | struct regmap *regmap; | ||
| 194 | struct i2c_client *client; | ||
| 195 | |||
| 196 | /* Lock protecting one command at a time can be processed */ | ||
| 197 | struct mutex mutex; | ||
| 198 | |||
| 199 | int rsp_seq; | ||
| 200 | u8 scan_mask; | ||
| 201 | u8 adc_sens[6]; | ||
| 202 | u8 adc_config[6]; | ||
| 203 | |||
| 204 | struct completion completion; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct si1133_coeff { | ||
| 208 | s16 info; | ||
| 209 | u16 mag; | ||
| 210 | }; | ||
| 211 | |||
| 212 | struct si1133_lux_coeff { | ||
| 213 | struct si1133_coeff coeff_high[4]; | ||
| 214 | struct si1133_coeff coeff_low[9]; | ||
| 215 | }; | ||
| 216 | |||
| 217 | static const struct si1133_lux_coeff lux_coeff = { | ||
| 218 | { | ||
| 219 | { 0, 209}, | ||
| 220 | { 1665, 93}, | ||
| 221 | { 2064, 65}, | ||
| 222 | {-2671, 234} | ||
| 223 | }, | ||
| 224 | { | ||
| 225 | { 0, 0}, | ||
| 226 | { 1921, 29053}, | ||
| 227 | {-1022, 36363}, | ||
| 228 | { 2320, 20789}, | ||
| 229 | { -367, 57909}, | ||
| 230 | {-1774, 38240}, | ||
| 231 | { -608, 46775}, | ||
| 232 | {-1503, 51831}, | ||
| 233 | {-1886, 58928} | ||
| 234 | } | ||
| 235 | }; | ||
| 236 | |||
| 237 | static int si1133_calculate_polynomial_inner(u32 input, u8 fraction, u16 mag, | ||
| 238 | s8 shift) | ||
| 239 | { | ||
| 240 | return ((input << fraction) / mag) << shift; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int si1133_calculate_output(u32 x, u32 y, u8 x_order, u8 y_order, | ||
| 244 | u8 input_fraction, s8 sign, | ||
| 245 | const struct si1133_coeff *coeffs) | ||
| 246 | { | ||
| 247 | s8 shift; | ||
| 248 | int x1 = 1; | ||
| 249 | int x2 = 1; | ||
| 250 | int y1 = 1; | ||
| 251 | int y2 = 1; | ||
| 252 | |||
| 253 | shift = ((u16)coeffs->info & 0xFF00) >> 8; | ||
| 254 | shift ^= 0xFF; | ||
| 255 | shift += 1; | ||
| 256 | shift = -shift; | ||
| 257 | |||
| 258 | if (x_order > 0) { | ||
| 259 | x1 = si1133_calculate_polynomial_inner(x, input_fraction, | ||
| 260 | coeffs->mag, shift); | ||
| 261 | if (x_order > 1) | ||
| 262 | x2 = x1; | ||
| 263 | } | ||
| 264 | |||
| 265 | if (y_order > 0) { | ||
| 266 | y1 = si1133_calculate_polynomial_inner(y, input_fraction, | ||
| 267 | coeffs->mag, shift); | ||
| 268 | if (y_order > 1) | ||
| 269 | y2 = y1; | ||
| 270 | } | ||
| 271 | |||
| 272 | return sign * x1 * x2 * y1 * y2; | ||
| 273 | } | ||
| 274 | |||
| 275 | /* | ||
| 276 | * The algorithm is from: | ||
| 277 | * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716 | ||
| 278 | */ | ||
| 279 | static int si1133_calc_polynomial(u32 x, u32 y, u8 input_fraction, u8 num_coeff, | ||
| 280 | const struct si1133_coeff *coeffs) | ||
| 281 | { | ||
| 282 | u8 x_order, y_order; | ||
| 283 | u8 counter; | ||
| 284 | s8 sign; | ||
| 285 | int output = 0; | ||
| 286 | |||
| 287 | for (counter = 0; counter < num_coeff; counter++) { | ||
| 288 | if (coeffs->info < 0) | ||
| 289 | sign = -1; | ||
| 290 | else | ||
| 291 | sign = 1; | ||
| 292 | |||
| 293 | x_order = si1133_get_x_order(coeffs->info); | ||
| 294 | y_order = si1133_get_y_order(coeffs->info); | ||
| 295 | |||
| 296 | if ((x_order == 0) && (y_order == 0)) | ||
| 297 | output += | ||
| 298 | sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION; | ||
| 299 | else | ||
| 300 | output += si1133_calculate_output(x, y, x_order, | ||
| 301 | y_order, | ||
| 302 | input_fraction, sign, | ||
| 303 | coeffs); | ||
| 304 | coeffs++; | ||
| 305 | } | ||
| 306 | |||
| 307 | return abs(output); | ||
| 308 | } | ||
| 309 | |||
| 310 | static int si1133_cmd_reset_sw(struct si1133_data *data) | ||
| 311 | { | ||
| 312 | struct device *dev = &data->client->dev; | ||
| 313 | unsigned int resp; | ||
| 314 | unsigned long timeout; | ||
| 315 | int err; | ||
| 316 | |||
| 317 | err = regmap_write(data->regmap, SI1133_REG_COMMAND, | ||
| 318 | SI1133_CMD_RESET_SW); | ||
| 319 | if (err) | ||
| 320 | return err; | ||
| 321 | |||
| 322 | timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS); | ||
| 323 | while (true) { | ||
| 324 | err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); | ||
| 325 | if (err == -ENXIO) { | ||
| 326 | usleep_range(SI1133_CMD_MINSLEEP_US_LOW, | ||
| 327 | SI1133_CMD_MINSLEEP_US_HIGH); | ||
| 328 | continue; | ||
| 329 | } | ||
| 330 | |||
| 331 | if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR) | ||
| 332 | break; | ||
| 333 | |||
| 334 | if (time_after(jiffies, timeout)) { | ||
| 335 | dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp); | ||
| 336 | return -ETIMEDOUT; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | if (!err) | ||
| 341 | data->rsp_seq = SI1133_MAX_CMD_CTR; | ||
| 342 | |||
| 343 | return err; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd) | ||
| 347 | { | ||
| 348 | resp &= 0xF; | ||
| 349 | |||
| 350 | switch (resp) { | ||
| 351 | case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW: | ||
| 352 | dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd); | ||
| 353 | return -EOVERFLOW; | ||
| 354 | case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION: | ||
| 355 | dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n", | ||
| 356 | cmd); | ||
| 357 | return -EOVERFLOW; | ||
| 358 | case SI1133_ERR_INVALID_LOCATION_CMD: | ||
| 359 | dev_warn(dev, | ||
| 360 | "Parameter access to an invalid location: %#02hhx\n", | ||
| 361 | cmd); | ||
| 362 | return -EINVAL; | ||
| 363 | case SI1133_ERR_INVALID_CMD: | ||
| 364 | dev_warn(dev, "Invalid command %#02hhx\n", cmd); | ||
| 365 | return -EINVAL; | ||
| 366 | default: | ||
| 367 | dev_warn(dev, "Unknown error %#02hhx\n", cmd); | ||
| 368 | return -EINVAL; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | static int si1133_cmd_reset_counter(struct si1133_data *data) | ||
| 373 | { | ||
| 374 | int err = regmap_write(data->regmap, SI1133_REG_COMMAND, | ||
| 375 | SI1133_CMD_RESET_CTR); | ||
| 376 | if (err) | ||
| 377 | return err; | ||
| 378 | |||
| 379 | data->rsp_seq = 0; | ||
| 380 | |||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | static int si1133_command(struct si1133_data *data, u8 cmd) | ||
| 385 | { | ||
| 386 | struct device *dev = &data->client->dev; | ||
| 387 | u32 resp; | ||
| 388 | int err; | ||
| 389 | int expected_seq; | ||
| 390 | |||
| 391 | mutex_lock(&data->mutex); | ||
| 392 | |||
| 393 | expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; | ||
| 394 | |||
| 395 | if (cmd == SI1133_CMD_FORCE) | ||
| 396 | reinit_completion(&data->completion); | ||
| 397 | |||
| 398 | err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd); | ||
| 399 | if (err) { | ||
| 400 | dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd, | ||
| 401 | err); | ||
| 402 | goto out; | ||
| 403 | } | ||
| 404 | |||
| 405 | if (cmd == SI1133_CMD_FORCE) { | ||
| 406 | /* wait for irq */ | ||
| 407 | if (!wait_for_completion_timeout(&data->completion, | ||
| 408 | msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { | ||
| 409 | err = -ETIMEDOUT; | ||
| 410 | goto out; | ||
| 411 | } | ||
| 412 | } else { | ||
| 413 | err = regmap_read_poll_timeout(data->regmap, | ||
| 414 | SI1133_REG_RESPONSE0, resp, | ||
| 415 | (resp & SI1133_CMD_SEQ_MASK) == | ||
| 416 | expected_seq || | ||
| 417 | (resp & SI1133_CMD_ERR_MASK), | ||
| 418 | SI1133_CMD_MINSLEEP_US_LOW, | ||
| 419 | SI1133_CMD_TIMEOUT_MS * 1000); | ||
| 420 | if (err) { | ||
| 421 | dev_warn(dev, | ||
| 422 | "Failed to read command %#02hhx, ret=%d\n", | ||
| 423 | cmd, err); | ||
| 424 | goto out; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | if (resp & SI1133_CMD_ERR_MASK) { | ||
| 429 | err = si1133_parse_response_err(dev, resp, cmd); | ||
| 430 | si1133_cmd_reset_counter(data); | ||
| 431 | } else { | ||
| 432 | data->rsp_seq = expected_seq; | ||
| 433 | } | ||
| 434 | |||
| 435 | out: | ||
| 436 | mutex_unlock(&data->mutex); | ||
| 437 | |||
| 438 | return err; | ||
| 439 | } | ||
| 440 | |||
| 441 | static int si1133_param_set(struct si1133_data *data, u8 param, u32 value) | ||
| 442 | { | ||
| 443 | int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value); | ||
| 444 | |||
| 445 | if (err) | ||
| 446 | return err; | ||
| 447 | |||
| 448 | return si1133_command(data, SI1133_CMD_PARAM_SET | | ||
| 449 | (param & SI1133_CMD_PARAM_MASK)); | ||
| 450 | } | ||
| 451 | |||
| 452 | static int si1133_param_query(struct si1133_data *data, u8 param, u32 *result) | ||
| 453 | { | ||
| 454 | int err = si1133_command(data, SI1133_CMD_PARAM_QUERY | | ||
| 455 | (param & SI1133_CMD_PARAM_MASK)); | ||
| 456 | if (err) | ||
| 457 | return err; | ||
| 458 | |||
| 459 | return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result); | ||
| 460 | } | ||
| 461 | |||
| 462 | #define SI1133_CHANNEL(_ch, _type) \ | ||
| 463 | .type = _type, \ | ||
| 464 | .channel = _ch, \ | ||
| 465 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
| 466 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \ | ||
| 467 | BIT(IIO_CHAN_INFO_SCALE) | \ | ||
| 468 | BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ | ||
| 469 | |||
| 470 | static const struct iio_chan_spec si1133_channels[] = { | ||
| 471 | { | ||
| 472 | .type = IIO_LIGHT, | ||
| 473 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | ||
| 474 | .channel = 0, | ||
| 475 | }, | ||
| 476 | { | ||
| 477 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY) | ||
| 478 | .channel2 = IIO_MOD_LIGHT_BOTH, | ||
| 479 | }, | ||
| 480 | { | ||
| 481 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY) | ||
| 482 | .channel2 = IIO_MOD_LIGHT_BOTH, | ||
| 483 | .extend_name = "large", | ||
| 484 | }, | ||
| 485 | { | ||
| 486 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY) | ||
| 487 | .extend_name = "small", | ||
| 488 | .modified = 1, | ||
| 489 | .channel2 = IIO_MOD_LIGHT_IR, | ||
| 490 | }, | ||
| 491 | { | ||
| 492 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY) | ||
| 493 | .modified = 1, | ||
| 494 | .channel2 = IIO_MOD_LIGHT_IR, | ||
| 495 | }, | ||
| 496 | { | ||
| 497 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY) | ||
| 498 | .extend_name = "large", | ||
| 499 | .modified = 1, | ||
| 500 | .channel2 = IIO_MOD_LIGHT_IR, | ||
| 501 | }, | ||
| 502 | { | ||
| 503 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX) | ||
| 504 | }, | ||
| 505 | { | ||
| 506 | SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX) | ||
| 507 | .modified = 1, | ||
| 508 | .channel2 = IIO_MOD_LIGHT_DUV, | ||
| 509 | } | ||
| 510 | }; | ||
| 511 | |||
| 512 | static int si1133_get_int_time_index(int milliseconds, int nanoseconds) | ||
| 513 | { | ||
| 514 | int i; | ||
| 515 | |||
| 516 | for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) { | ||
| 517 | if (milliseconds == si1133_int_time_table[i][0] && | ||
| 518 | nanoseconds == si1133_int_time_table[i][1]) | ||
| 519 | return i; | ||
| 520 | } | ||
| 521 | return -EINVAL; | ||
| 522 | } | ||
| 523 | |||
| 524 | static int si1133_set_integration_time(struct si1133_data *data, u8 adc, | ||
| 525 | int milliseconds, int nanoseconds) | ||
| 526 | { | ||
| 527 | int index; | ||
| 528 | |||
| 529 | index = si1133_get_int_time_index(milliseconds, nanoseconds); | ||
| 530 | if (index < 0) | ||
| 531 | return index; | ||
| 532 | |||
| 533 | data->adc_sens[adc] &= 0xF0; | ||
| 534 | data->adc_sens[adc] |= index; | ||
| 535 | |||
| 536 | return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0), | ||
| 537 | data->adc_sens[adc]); | ||
| 538 | } | ||
| 539 | |||
| 540 | static int si1133_set_chlist(struct si1133_data *data, u8 scan_mask) | ||
| 541 | { | ||
| 542 | /* channel list already set, no need to reprogram */ | ||
| 543 | if (data->scan_mask == scan_mask) | ||
| 544 | return 0; | ||
| 545 | |||
| 546 | data->scan_mask = scan_mask; | ||
| 547 | |||
| 548 | return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask); | ||
| 549 | } | ||
| 550 | |||
| 551 | static int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc, | ||
| 552 | u8 adc_config) | ||
| 553 | { | ||
| 554 | int err; | ||
| 555 | |||
| 556 | err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc), | ||
| 557 | adc_config); | ||
| 558 | if (err) | ||
| 559 | return err; | ||
| 560 | |||
| 561 | data->adc_config[adc] = adc_config; | ||
| 562 | |||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc, | ||
| 567 | u8 mask, u8 shift, u8 value) | ||
| 568 | { | ||
| 569 | u32 adc_config; | ||
| 570 | int err; | ||
| 571 | |||
| 572 | err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc), | ||
| 573 | &adc_config); | ||
| 574 | if (err) | ||
| 575 | return err; | ||
| 576 | |||
| 577 | adc_config &= ~mask; | ||
| 578 | adc_config |= (value << shift); | ||
| 579 | |||
| 580 | return si1133_chan_set_adcconfig(data, adc, adc_config); | ||
| 581 | } | ||
| 582 | |||
| 583 | static int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux) | ||
| 584 | { | ||
| 585 | if ((mux & data->adc_config[adc]) == mux) | ||
| 586 | return 0; /* mux already set to correct value */ | ||
| 587 | |||
| 588 | return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux); | ||
| 589 | } | ||
| 590 | |||
| 591 | static int si1133_force_measurement(struct si1133_data *data) | ||
| 592 | { | ||
| 593 | return si1133_command(data, SI1133_CMD_FORCE); | ||
| 594 | } | ||
| 595 | |||
| 596 | static int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length, | ||
| 597 | u8 *buffer) | ||
| 598 | { | ||
| 599 | int err; | ||
| 600 | |||
| 601 | err = si1133_force_measurement(data); | ||
| 602 | if (err) | ||
| 603 | return err; | ||
| 604 | |||
| 605 | return regmap_bulk_read(data->regmap, start_reg, buffer, length); | ||
| 606 | } | ||
| 607 | |||
| 608 | static int si1133_measure(struct si1133_data *data, | ||
| 609 | struct iio_chan_spec const *chan, | ||
| 610 | int *val) | ||
| 611 | { | ||
| 612 | int err; | ||
| 613 | |||
| 614 | __be16 resp; | ||
| 615 | |||
| 616 | err = si1133_set_adcmux(data, 0, chan->channel); | ||
| 617 | if (err) | ||
| 618 | return err; | ||
| 619 | |||
| 620 | /* Deactivate lux measurements if they were active */ | ||
| 621 | err = si1133_set_chlist(data, BIT(0)); | ||
| 622 | if (err) | ||
| 623 | return err; | ||
| 624 | |||
| 625 | err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(resp), | ||
| 626 | (u8 *)&resp); | ||
| 627 | if (err) | ||
| 628 | return err; | ||
| 629 | |||
| 630 | *val = be16_to_cpu(resp); | ||
| 631 | |||
| 632 | return err; | ||
| 633 | } | ||
| 634 | |||
| 635 | static irqreturn_t si1133_threaded_irq_handler(int irq, void *private) | ||
| 636 | { | ||
| 637 | struct iio_dev *iio_dev = private; | ||
| 638 | struct si1133_data *data = iio_priv(iio_dev); | ||
| 639 | u32 irq_status; | ||
| 640 | int err; | ||
| 641 | |||
| 642 | err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status); | ||
| 643 | if (err) { | ||
| 644 | dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n"); | ||
| 645 | goto out; | ||
| 646 | } | ||
| 647 | |||
| 648 | if (irq_status != data->scan_mask) | ||
| 649 | return IRQ_NONE; | ||
| 650 | |||
| 651 | out: | ||
| 652 | complete(&data->completion); | ||
| 653 | |||
| 654 | return IRQ_HANDLED; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int si1133_scale_to_swgain(int scale_integer, int scale_fractional) | ||
| 658 | { | ||
| 659 | scale_integer = find_closest(scale_integer, si1133_scale_available, | ||
| 660 | ARRAY_SIZE(si1133_scale_available)); | ||
| 661 | if (scale_integer < 0 || | ||
| 662 | scale_integer > ARRAY_SIZE(si1133_scale_available) || | ||
| 663 | scale_fractional != 0) | ||
| 664 | return -EINVAL; | ||
| 665 | |||
| 666 | return scale_integer; | ||
| 667 | } | ||
| 668 | |||
| 669 | static int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc, | ||
| 670 | u8 adc_sens) | ||
| 671 | { | ||
| 672 | int err; | ||
| 673 | |||
| 674 | err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens); | ||
| 675 | if (err) | ||
| 676 | return err; | ||
| 677 | |||
| 678 | data->adc_sens[adc] = adc_sens; | ||
| 679 | |||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 683 | static int si1133_update_adcsens(struct si1133_data *data, u8 mask, | ||
| 684 | u8 shift, u8 value) | ||
| 685 | { | ||
| 686 | int err; | ||
| 687 | u32 adc_sens; | ||
| 688 | |||
| 689 | err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0), | ||
| 690 | &adc_sens); | ||
| 691 | if (err) | ||
| 692 | return err; | ||
| 693 | |||
| 694 | adc_sens &= ~mask; | ||
| 695 | adc_sens |= (value << shift); | ||
| 696 | |||
| 697 | return si1133_chan_set_adcsens(data, 0, adc_sens); | ||
| 698 | } | ||
| 699 | |||
| 700 | static int si1133_get_lux(struct si1133_data *data, int *val) | ||
| 701 | { | ||
| 702 | int err; | ||
| 703 | int lux; | ||
| 704 | u32 high_vis; | ||
| 705 | u32 low_vis; | ||
| 706 | u32 ir; | ||
| 707 | u8 buffer[SI1133_LUX_BUFFER_SIZE]; | ||
| 708 | |||
| 709 | /* Activate lux channels */ | ||
| 710 | err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK); | ||
| 711 | if (err) | ||
| 712 | return err; | ||
| 713 | |||
| 714 | err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), | ||
| 715 | SI1133_LUX_BUFFER_SIZE, buffer); | ||
| 716 | if (err) | ||
| 717 | return err; | ||
| 718 | |||
| 719 | high_vis = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; | ||
| 720 | low_vis = (buffer[3] << 16) | (buffer[4] << 8) | buffer[5]; | ||
| 721 | ir = (buffer[6] << 16) | (buffer[7] << 8) | buffer[8]; | ||
| 722 | |||
| 723 | if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD) | ||
| 724 | lux = si1133_calc_polynomial(high_vis, ir, | ||
| 725 | SI1133_INPUT_FRACTION_HIGH, | ||
| 726 | ARRAY_SIZE(lux_coeff.coeff_high), | ||
| 727 | &lux_coeff.coeff_high[0]); | ||
| 728 | else | ||
| 729 | lux = si1133_calc_polynomial(low_vis, ir, | ||
| 730 | SI1133_INPUT_FRACTION_LOW, | ||
| 731 | ARRAY_SIZE(lux_coeff.coeff_low), | ||
| 732 | &lux_coeff.coeff_low[0]); | ||
| 733 | |||
| 734 | *val = lux >> SI1133_LUX_OUTPUT_FRACTION; | ||
| 735 | |||
| 736 | return err; | ||
| 737 | } | ||
| 738 | |||
| 739 | static int si1133_read_raw(struct iio_dev *iio_dev, | ||
| 740 | struct iio_chan_spec const *chan, | ||
| 741 | int *val, int *val2, long mask) | ||
| 742 | { | ||
| 743 | struct si1133_data *data = iio_priv(iio_dev); | ||
| 744 | u8 adc_sens = data->adc_sens[0]; | ||
| 745 | int err; | ||
| 746 | |||
| 747 | switch (mask) { | ||
| 748 | case IIO_CHAN_INFO_PROCESSED: | ||
| 749 | switch (chan->type) { | ||
| 750 | case IIO_LIGHT: | ||
| 751 | err = si1133_get_lux(data, val); | ||
| 752 | if (err) | ||
| 753 | return err; | ||
| 754 | |||
| 755 | return IIO_VAL_INT; | ||
| 756 | default: | ||
| 757 | return -EINVAL; | ||
| 758 | } | ||
| 759 | case IIO_CHAN_INFO_RAW: | ||
| 760 | switch (chan->type) { | ||
| 761 | case IIO_INTENSITY: | ||
| 762 | case IIO_UVINDEX: | ||
| 763 | err = si1133_measure(data, chan, val); | ||
| 764 | if (err) | ||
| 765 | return err; | ||
| 766 | |||
| 767 | return IIO_VAL_INT; | ||
| 768 | default: | ||
| 769 | return -EINVAL; | ||
| 770 | } | ||
| 771 | case IIO_CHAN_INFO_INT_TIME: | ||
| 772 | switch (chan->type) { | ||
| 773 | case IIO_INTENSITY: | ||
| 774 | case IIO_UVINDEX: | ||
| 775 | adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK; | ||
| 776 | |||
| 777 | *val = si1133_int_time_table[adc_sens][0]; | ||
| 778 | *val2 = si1133_int_time_table[adc_sens][1]; | ||
| 779 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 780 | default: | ||
| 781 | return -EINVAL; | ||
| 782 | } | ||
| 783 | case IIO_CHAN_INFO_SCALE: | ||
| 784 | switch (chan->type) { | ||
| 785 | case IIO_INTENSITY: | ||
| 786 | case IIO_UVINDEX: | ||
| 787 | adc_sens &= SI1133_ADCSENS_SCALE_MASK; | ||
| 788 | adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT; | ||
| 789 | |||
| 790 | *val = BIT(adc_sens); | ||
| 791 | |||
| 792 | return IIO_VAL_INT; | ||
| 793 | default: | ||
| 794 | return -EINVAL; | ||
| 795 | } | ||
| 796 | case IIO_CHAN_INFO_HARDWAREGAIN: | ||
| 797 | switch (chan->type) { | ||
| 798 | case IIO_INTENSITY: | ||
| 799 | case IIO_UVINDEX: | ||
| 800 | adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT; | ||
| 801 | |||
| 802 | *val = adc_sens; | ||
| 803 | |||
| 804 | return IIO_VAL_INT; | ||
| 805 | default: | ||
| 806 | return -EINVAL; | ||
| 807 | } | ||
| 808 | default: | ||
| 809 | return -EINVAL; | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | static int si1133_write_raw(struct iio_dev *iio_dev, | ||
| 814 | struct iio_chan_spec const *chan, | ||
| 815 | int val, int val2, long mask) | ||
| 816 | { | ||
| 817 | struct si1133_data *data = iio_priv(iio_dev); | ||
| 818 | |||
| 819 | switch (mask) { | ||
| 820 | case IIO_CHAN_INFO_SCALE: | ||
| 821 | switch (chan->type) { | ||
| 822 | case IIO_INTENSITY: | ||
| 823 | case IIO_UVINDEX: | ||
| 824 | val = si1133_scale_to_swgain(val, val2); | ||
| 825 | if (val < 0) | ||
| 826 | return val; | ||
| 827 | |||
| 828 | return si1133_update_adcsens(data, | ||
| 829 | SI1133_ADCSENS_SCALE_MASK, | ||
| 830 | SI1133_ADCSENS_SCALE_SHIFT, | ||
| 831 | val); | ||
| 832 | default: | ||
| 833 | return -EINVAL; | ||
| 834 | } | ||
| 835 | case IIO_CHAN_INFO_INT_TIME: | ||
| 836 | return si1133_set_integration_time(data, 0, val, val2); | ||
| 837 | case IIO_CHAN_INFO_HARDWAREGAIN: | ||
| 838 | switch (chan->type) { | ||
| 839 | case IIO_INTENSITY: | ||
| 840 | case IIO_UVINDEX: | ||
| 841 | if (val != 0 || val != 1) | ||
| 842 | return -EINVAL; | ||
| 843 | |||
| 844 | return si1133_update_adcsens(data, | ||
| 845 | SI1133_ADCSENS_HSIG_MASK, | ||
| 846 | SI1133_ADCSENS_HSIG_SHIFT, | ||
| 847 | val); | ||
| 848 | default: | ||
| 849 | return -EINVAL; | ||
| 850 | } | ||
| 851 | default: | ||
| 852 | return -EINVAL; | ||
| 853 | } | ||
| 854 | } | ||
| 855 | |||
| 856 | static struct attribute *si1133_attributes[] = { | ||
| 857 | &iio_const_attr_integration_time_available.dev_attr.attr, | ||
| 858 | &iio_const_attr_scale_available.dev_attr.attr, | ||
| 859 | NULL, | ||
| 860 | }; | ||
| 861 | |||
| 862 | static const struct attribute_group si1133_attribute_group = { | ||
| 863 | .attrs = si1133_attributes, | ||
| 864 | }; | ||
| 865 | |||
| 866 | static const struct iio_info si1133_info = { | ||
| 867 | .read_raw = si1133_read_raw, | ||
| 868 | .write_raw = si1133_write_raw, | ||
| 869 | .attrs = &si1133_attribute_group, | ||
| 870 | }; | ||
| 871 | |||
| 872 | /* | ||
| 873 | * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3) | ||
| 874 | * The channel configuration for the lux measurement was taken from : | ||
| 875 | * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578 | ||
| 876 | * | ||
| 877 | * Reserved the channel 0 for the other raw measurements | ||
| 878 | */ | ||
| 879 | static int si1133_init_lux_channels(struct si1133_data *data) | ||
| 880 | { | ||
| 881 | int err; | ||
| 882 | |||
| 883 | err = si1133_chan_set_adcconfig(data, 1, | ||
| 884 | SI1133_ADCCONFIG_DECIM_RATE(1) | | ||
| 885 | SI1133_PARAM_ADCMUX_LARGE_WHITE); | ||
| 886 | if (err) | ||
| 887 | return err; | ||
| 888 | |||
| 889 | err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1), | ||
| 890 | SI1133_ADCPOST_24BIT_EN | | ||
| 891 | SI1133_ADCPOST_POSTSHIFT_BITQTY(0)); | ||
| 892 | if (err) | ||
| 893 | return err; | ||
| 894 | err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK | | ||
| 895 | SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); | ||
| 896 | if (err) | ||
| 897 | return err; | ||
| 898 | |||
| 899 | err = si1133_chan_set_adcconfig(data, 2, | ||
| 900 | SI1133_ADCCONFIG_DECIM_RATE(1) | | ||
| 901 | SI1133_PARAM_ADCMUX_LARGE_WHITE); | ||
| 902 | if (err) | ||
| 903 | return err; | ||
| 904 | |||
| 905 | err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2), | ||
| 906 | SI1133_ADCPOST_24BIT_EN | | ||
| 907 | SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); | ||
| 908 | if (err) | ||
| 909 | return err; | ||
| 910 | |||
| 911 | err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK | | ||
| 912 | SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us); | ||
| 913 | if (err) | ||
| 914 | return err; | ||
| 915 | |||
| 916 | err = si1133_chan_set_adcconfig(data, 3, | ||
| 917 | SI1133_ADCCONFIG_DECIM_RATE(1) | | ||
| 918 | SI1133_PARAM_ADCMUX_MED_IR); | ||
| 919 | if (err) | ||
| 920 | return err; | ||
| 921 | |||
| 922 | err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3), | ||
| 923 | SI1133_ADCPOST_24BIT_EN | | ||
| 924 | SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); | ||
| 925 | if (err) | ||
| 926 | return err; | ||
| 927 | |||
| 928 | return si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK | | ||
| 929 | SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); | ||
| 930 | } | ||
| 931 | |||
| 932 | static int si1133_initialize(struct si1133_data *data) | ||
| 933 | { | ||
| 934 | int err; | ||
| 935 | |||
| 936 | err = si1133_cmd_reset_sw(data); | ||
| 937 | if (err) | ||
| 938 | return err; | ||
| 939 | |||
| 940 | /* Turn off autonomous mode */ | ||
| 941 | err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0); | ||
| 942 | if (err) | ||
| 943 | return err; | ||
| 944 | |||
| 945 | err = si1133_init_lux_channels(data); | ||
| 946 | if (err) | ||
| 947 | return err; | ||
| 948 | |||
| 949 | return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, | ||
| 950 | SI1133_IRQ_CHANNEL_ENABLE); | ||
| 951 | } | ||
| 952 | |||
| 953 | static int si1133_validate_ids(struct iio_dev *iio_dev) | ||
| 954 | { | ||
| 955 | struct si1133_data *data = iio_priv(iio_dev); | ||
| 956 | |||
| 957 | unsigned int part_id, rev_id, mfr_id; | ||
| 958 | int err; | ||
| 959 | |||
| 960 | err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id); | ||
| 961 | if (err) | ||
| 962 | return err; | ||
| 963 | |||
| 964 | err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id); | ||
| 965 | if (err) | ||
| 966 | return err; | ||
| 967 | |||
| 968 | err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id); | ||
| 969 | if (err) | ||
| 970 | return err; | ||
| 971 | |||
| 972 | dev_info(&iio_dev->dev, | ||
| 973 | "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n", | ||
| 974 | part_id, rev_id, mfr_id); | ||
| 975 | if (part_id != SI1133_PART_ID) { | ||
| 976 | dev_err(&iio_dev->dev, | ||
| 977 | "Part ID mismatch got %#02hhx, expected %#02x\n", | ||
| 978 | part_id, SI1133_PART_ID); | ||
| 979 | return -ENODEV; | ||
| 980 | } | ||
| 981 | |||
| 982 | return 0; | ||
| 983 | } | ||
| 984 | |||
| 985 | static int si1133_probe(struct i2c_client *client, | ||
| 986 | const struct i2c_device_id *id) | ||
| 987 | { | ||
| 988 | struct si1133_data *data; | ||
| 989 | struct iio_dev *iio_dev; | ||
| 990 | int err; | ||
| 991 | |||
| 992 | iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | ||
| 993 | if (!iio_dev) | ||
| 994 | return -ENOMEM; | ||
| 995 | |||
| 996 | data = iio_priv(iio_dev); | ||
| 997 | |||
| 998 | init_completion(&data->completion); | ||
| 999 | |||
| 1000 | data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config); | ||
| 1001 | if (IS_ERR(data->regmap)) { | ||
| 1002 | err = PTR_ERR(data->regmap); | ||
| 1003 | dev_err(&client->dev, "Failed to initialise regmap: %d\n", err); | ||
| 1004 | return err; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | i2c_set_clientdata(client, iio_dev); | ||
| 1008 | data->client = client; | ||
| 1009 | |||
| 1010 | iio_dev->dev.parent = &client->dev; | ||
| 1011 | iio_dev->name = id->name; | ||
| 1012 | iio_dev->channels = si1133_channels; | ||
| 1013 | iio_dev->num_channels = ARRAY_SIZE(si1133_channels); | ||
| 1014 | iio_dev->info = &si1133_info; | ||
| 1015 | iio_dev->modes = INDIO_DIRECT_MODE; | ||
| 1016 | |||
| 1017 | mutex_init(&data->mutex); | ||
| 1018 | |||
| 1019 | err = si1133_validate_ids(iio_dev); | ||
| 1020 | if (err) | ||
| 1021 | return err; | ||
| 1022 | |||
| 1023 | err = si1133_initialize(data); | ||
| 1024 | if (err) { | ||
| 1025 | dev_err(&client->dev, | ||
| 1026 | "Error when initializing chip: %d\n", err); | ||
| 1027 | return err; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | if (!client->irq) { | ||
| 1031 | dev_err(&client->dev, | ||
| 1032 | "Required interrupt not provided, cannot proceed\n"); | ||
| 1033 | return -EINVAL; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | err = devm_request_threaded_irq(&client->dev, client->irq, | ||
| 1037 | NULL, | ||
| 1038 | si1133_threaded_irq_handler, | ||
| 1039 | IRQF_ONESHOT | IRQF_SHARED, | ||
| 1040 | client->name, iio_dev); | ||
| 1041 | if (err) { | ||
| 1042 | dev_warn(&client->dev, "Request irq %d failed: %i\n", | ||
| 1043 | client->irq, err); | ||
| 1044 | return err; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | return devm_iio_device_register(&client->dev, iio_dev); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static const struct i2c_device_id si1133_ids[] = { | ||
| 1051 | { "si1133", 0 }, | ||
| 1052 | { } | ||
| 1053 | }; | ||
| 1054 | MODULE_DEVICE_TABLE(i2c, si1133_ids); | ||
| 1055 | |||
| 1056 | static struct i2c_driver si1133_driver = { | ||
| 1057 | .driver = { | ||
| 1058 | .name = "si1133", | ||
| 1059 | }, | ||
| 1060 | .probe = si1133_probe, | ||
| 1061 | .id_table = si1133_ids, | ||
| 1062 | }; | ||
| 1063 | |||
| 1064 | module_i2c_driver(si1133_driver); | ||
| 1065 | |||
| 1066 | MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); | ||
| 1067 | MODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver"); | ||
| 1068 | MODULE_LICENSE("GPL"); | ||
| @@ -94,9 +94,8 @@ static int st_press_i2c_probe(struct i2c_client *client, · 93 unmodified lines | |||
| 94 | if ((ret < 0) || (ret >= ST_PRESS_MAX)) | 94 | if ((ret < 0) || (ret >= ST_PRESS_MAX)) |
| 95 | return -ENODEV; | 95 | return -ENODEV; |
| 96 | 96 | ||
| 97 | strncpy(client->name, st_press_id_table[ret].name, | 97 | strlcpy(client->name, st_press_id_table[ret].name, |
| 98 | sizeof(client->name)); | 98 | sizeof(client->name)); |
| 99 | client->name[sizeof(client->name) - 1] = '\0'; | ||
| 100 | } else if (!id) | 99 | } else if (!id) |
| 101 | return -ENODEV; | 100 | return -ENODEV; |
| 102 | 101 | ||
| @@ -20,6 +20,19 @@ endmenu · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | menu "Proximity and distance sensors" | 21 | menu "Proximity and distance sensors" |
| 22 | 22 | ||
| 23 | config ISL29501 | ||
| 24 | tristate "Intersil ISL29501 Time Of Flight sensor" | ||
| 25 | depends on I2C | ||
| 26 | select IIO_BUFFER | ||
| 27 | select IIO_TRIGGERED_BUFFER | ||
| 28 | select IIO_KFIFO_BUF | ||
| 29 | help | ||
| 30 | Say Y here if you want to build a driver for the Intersil ISL29501 | ||
| 31 | Time of Flight sensor. | ||
| 32 | |||
| 33 | To compile this driver as a module, choose M here: the module will be | ||
| 34 | called isl29501. | ||
| 35 | |||
| 23 | config LIDAR_LITE_V2 | 36 | config LIDAR_LITE_V2 |
| 24 | tristate "PulsedLight LIDAR sensor" | 37 | tristate "PulsedLight LIDAR sensor" |
| 25 | select IIO_BUFFER | 38 | select IIO_BUFFER |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | # When adding new entries keep the list in alphabetical order | 6 | # When adding new entries keep the list in alphabetical order |
| 7 | obj-$(CONFIG_AS3935) += as3935.o | 7 | obj-$(CONFIG_AS3935) += as3935.o |
| 8 | obj-$(CONFIG_ISL29501) += isl29501.o | ||
| 8 | obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o | 9 | obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o |
| 9 | obj-$(CONFIG_RFD77402) += rfd77402.o | 10 | obj-$(CONFIG_RFD77402) += rfd77402.o |
| 10 | obj-$(CONFIG_SRF04) += srf04.o | 11 | obj-$(CONFIG_SRF04) += srf04.o |
| @@ -0,0 +1,1027 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * isl29501.c: ISL29501 Time of Flight sensor driver. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018 | ||
| 6 | * Author: Mathieu Othacehe <m.othacehe@gmail.com> | ||
| 7 | * | ||
| 8 | * 7-bit I2C slave address: 0x57 | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/err.h> | ||
| 15 | #include <linux/of_device.h> | ||
| 16 | #include <linux/iio/iio.h> | ||
| 17 | #include <linux/iio/sysfs.h> | ||
| 18 | |||
| 19 | #include <linux/iio/trigger_consumer.h> | ||
| 20 | #include <linux/iio/buffer.h> | ||
| 21 | #include <linux/iio/triggered_buffer.h> | ||
| 22 | |||
| 23 | /* Control, setting and status registers */ | ||
| 24 | #define ISL29501_DEVICE_ID 0x00 | ||
| 25 | #define ISL29501_ID 0x0A | ||
| 26 | |||
| 27 | /* Sampling control registers */ | ||
| 28 | #define ISL29501_INTEGRATION_PERIOD 0x10 | ||
| 29 | #define ISL29501_SAMPLE_PERIOD 0x11 | ||
| 30 | |||
| 31 | /* Closed loop calibration registers */ | ||
| 32 | #define ISL29501_CROSSTALK_I_MSB 0x24 | ||
| 33 | #define ISL29501_CROSSTALK_I_LSB 0x25 | ||
| 34 | #define ISL29501_CROSSTALK_I_EXPONENT 0x26 | ||
| 35 | #define ISL29501_CROSSTALK_Q_MSB 0x27 | ||
| 36 | #define ISL29501_CROSSTALK_Q_LSB 0x28 | ||
| 37 | #define ISL29501_CROSSTALK_Q_EXPONENT 0x29 | ||
| 38 | #define ISL29501_CROSSTALK_GAIN_MSB 0x2A | ||
| 39 | #define ISL29501_CROSSTALK_GAIN_LSB 0x2B | ||
| 40 | #define ISL29501_MAGNITUDE_REF_EXP 0x2C | ||
| 41 | #define ISL29501_MAGNITUDE_REF_MSB 0x2D | ||
| 42 | #define ISL29501_MAGNITUDE_REF_LSB 0x2E | ||
| 43 | #define ISL29501_PHASE_OFFSET_MSB 0x2F | ||
| 44 | #define ISL29501_PHASE_OFFSET_LSB 0x30 | ||
| 45 | |||
| 46 | /* Analog control registers */ | ||
| 47 | #define ISL29501_DRIVER_RANGE 0x90 | ||
| 48 | #define ISL29501_EMITTER_DAC 0x91 | ||
| 49 | |||
| 50 | #define ISL29501_COMMAND_REGISTER 0xB0 | ||
| 51 | |||
| 52 | /* Commands */ | ||
| 53 | #define ISL29501_EMUL_SAMPLE_START_PIN 0x49 | ||
| 54 | #define ISL29501_RESET_ALL_REGISTERS 0xD7 | ||
| 55 | #define ISL29501_RESET_INT_SM 0xD1 | ||
| 56 | |||
| 57 | /* Ambiant light and temperature corrections */ | ||
| 58 | #define ISL29501_TEMP_REFERENCE 0x31 | ||
| 59 | #define ISL29501_PHASE_EXPONENT 0x33 | ||
| 60 | #define ISL29501_TEMP_COEFF_A 0x34 | ||
| 61 | #define ISL29501_TEMP_COEFF_B 0x39 | ||
| 62 | #define ISL29501_AMBIANT_COEFF_A 0x36 | ||
| 63 | #define ISL29501_AMBIANT_COEFF_B 0x3B | ||
| 64 | |||
| 65 | /* Data output registers */ | ||
| 66 | #define ISL29501_DISTANCE_MSB_DATA 0xD1 | ||
| 67 | #define ISL29501_DISTANCE_LSB_DATA 0xD2 | ||
| 68 | #define ISL29501_PRECISION_MSB 0xD3 | ||
| 69 | #define ISL29501_PRECISION_LSB 0xD4 | ||
| 70 | #define ISL29501_MAGNITUDE_EXPONENT 0xD5 | ||
| 71 | #define ISL29501_MAGNITUDE_MSB 0xD6 | ||
| 72 | #define ISL29501_MAGNITUDE_LSB 0xD7 | ||
| 73 | #define ISL29501_PHASE_MSB 0xD8 | ||
| 74 | #define ISL29501_PHASE_LSB 0xD9 | ||
| 75 | #define ISL29501_I_RAW_EXPONENT 0xDA | ||
| 76 | #define ISL29501_I_RAW_MSB 0xDB | ||
| 77 | #define ISL29501_I_RAW_LSB 0xDC | ||
| 78 | #define ISL29501_Q_RAW_EXPONENT 0xDD | ||
| 79 | #define ISL29501_Q_RAW_MSB 0xDE | ||
| 80 | #define ISL29501_Q_RAW_LSB 0xDF | ||
| 81 | #define ISL29501_DIE_TEMPERATURE 0xE2 | ||
| 82 | #define ISL29501_AMBIENT_LIGHT 0xE3 | ||
| 83 | #define ISL29501_GAIN_MSB 0xE6 | ||
| 84 | #define ISL29501_GAIN_LSB 0xE7 | ||
| 85 | |||
| 86 | #define ISL29501_MAX_EXP_VAL 15 | ||
| 87 | |||
| 88 | #define ISL29501_INT_TIME_AVAILABLE \ | ||
| 89 | "0.00007 0.00014 0.00028 0.00057 0.00114 " \ | ||
| 90 | "0.00228 0.00455 0.00910 0.01820 0.03640 " \ | ||
| 91 | "0.07281 0.14561" | ||
| 92 | |||
| 93 | #define ISL29501_CURRENT_SCALE_AVAILABLE \ | ||
| 94 | "0.0039 0.0078 0.0118 0.0157 0.0196 " \ | ||
| 95 | "0.0235 0.0275 0.0314 0.0352 0.0392 " \ | ||
| 96 | "0.0431 0.0471 0.0510 0.0549 0.0588" | ||
| 97 | |||
| 98 | enum isl29501_correction_coeff { | ||
| 99 | COEFF_TEMP_A, | ||
| 100 | COEFF_TEMP_B, | ||
| 101 | COEFF_LIGHT_A, | ||
| 102 | COEFF_LIGHT_B, | ||
| 103 | COEFF_MAX, | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct isl29501_private { | ||
| 107 | struct i2c_client *client; | ||
| 108 | struct mutex lock; | ||
| 109 | /* Exact representation of correction coefficients. */ | ||
| 110 | unsigned int shadow_coeffs[COEFF_MAX]; | ||
| 111 | }; | ||
| 112 | |||
| 113 | enum isl29501_register_name { | ||
| 114 | REG_DISTANCE, | ||
| 115 | REG_PHASE, | ||
| 116 | REG_TEMPERATURE, | ||
| 117 | REG_AMBIENT_LIGHT, | ||
| 118 | REG_GAIN, | ||
| 119 | REG_GAIN_BIAS, | ||
| 120 | REG_PHASE_EXP, | ||
| 121 | REG_CALIB_PHASE_TEMP_A, | ||
| 122 | REG_CALIB_PHASE_TEMP_B, | ||
| 123 | REG_CALIB_PHASE_LIGHT_A, | ||
| 124 | REG_CALIB_PHASE_LIGHT_B, | ||
| 125 | REG_DISTANCE_BIAS, | ||
| 126 | REG_TEMPERATURE_BIAS, | ||
| 127 | REG_INT_TIME, | ||
| 128 | REG_SAMPLE_TIME, | ||
| 129 | REG_DRIVER_RANGE, | ||
| 130 | REG_EMITTER_DAC, | ||
| 131 | }; | ||
| 132 | |||
| 133 | struct isl29501_register_desc { | ||
| 134 | u8 msb; | ||
| 135 | u8 lsb; | ||
| 136 | }; | ||
| 137 | |||
| 138 | static const struct isl29501_register_desc isl29501_registers[] = { | ||
| 139 | [REG_DISTANCE] = { | ||
| 140 | .msb = ISL29501_DISTANCE_MSB_DATA, | ||
| 141 | .lsb = ISL29501_DISTANCE_LSB_DATA, | ||
| 142 | }, | ||
| 143 | [REG_PHASE] = { | ||
| 144 | .msb = ISL29501_PHASE_MSB, | ||
| 145 | .lsb = ISL29501_PHASE_LSB, | ||
| 146 | }, | ||
| 147 | [REG_TEMPERATURE] = { | ||
| 148 | .lsb = ISL29501_DIE_TEMPERATURE, | ||
| 149 | }, | ||
| 150 | [REG_AMBIENT_LIGHT] = { | ||
| 151 | .lsb = ISL29501_AMBIENT_LIGHT, | ||
| 152 | }, | ||
| 153 | [REG_GAIN] = { | ||
| 154 | .msb = ISL29501_GAIN_MSB, | ||
| 155 | .lsb = ISL29501_GAIN_LSB, | ||
| 156 | }, | ||
| 157 | [REG_GAIN_BIAS] = { | ||
| 158 | .msb = ISL29501_CROSSTALK_GAIN_MSB, | ||
| 159 | .lsb = ISL29501_CROSSTALK_GAIN_LSB, | ||
| 160 | }, | ||
| 161 | [REG_PHASE_EXP] = { | ||
| 162 | .lsb = ISL29501_PHASE_EXPONENT, | ||
| 163 | }, | ||
| 164 | [REG_CALIB_PHASE_TEMP_A] = { | ||
| 165 | .lsb = ISL29501_TEMP_COEFF_A, | ||
| 166 | }, | ||
| 167 | [REG_CALIB_PHASE_TEMP_B] = { | ||
| 168 | .lsb = ISL29501_TEMP_COEFF_B, | ||
| 169 | }, | ||
| 170 | [REG_CALIB_PHASE_LIGHT_A] = { | ||
| 171 | .lsb = ISL29501_AMBIANT_COEFF_A, | ||
| 172 | }, | ||
| 173 | [REG_CALIB_PHASE_LIGHT_B] = { | ||
| 174 | .lsb = ISL29501_AMBIANT_COEFF_B, | ||
| 175 | }, | ||
| 176 | [REG_DISTANCE_BIAS] = { | ||
| 177 | .msb = ISL29501_PHASE_OFFSET_MSB, | ||
| 178 | .lsb = ISL29501_PHASE_OFFSET_LSB, | ||
| 179 | }, | ||
| 180 | [REG_TEMPERATURE_BIAS] = { | ||
| 181 | .lsb = ISL29501_TEMP_REFERENCE, | ||
| 182 | }, | ||
| 183 | [REG_INT_TIME] = { | ||
| 184 | .lsb = ISL29501_INTEGRATION_PERIOD, | ||
| 185 | }, | ||
| 186 | [REG_SAMPLE_TIME] = { | ||
| 187 | .lsb = ISL29501_SAMPLE_PERIOD, | ||
| 188 | }, | ||
| 189 | [REG_DRIVER_RANGE] = { | ||
| 190 | .lsb = ISL29501_DRIVER_RANGE, | ||
| 191 | }, | ||
| 192 | [REG_EMITTER_DAC] = { | ||
| 193 | .lsb = ISL29501_EMITTER_DAC, | ||
| 194 | }, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static int isl29501_register_read(struct isl29501_private *isl29501, | ||
| 198 | enum isl29501_register_name name, | ||
| 199 | u32 *val) | ||
| 200 | { | ||
| 201 | const struct isl29501_register_desc *reg = &isl29501_registers[name]; | ||
| 202 | u8 msb = 0, lsb = 0; | ||
| 203 | s32 ret; | ||
| 204 | |||
| 205 | mutex_lock(&isl29501->lock); | ||
| 206 | if (reg->msb) { | ||
| 207 | ret = i2c_smbus_read_byte_data(isl29501->client, reg->msb); | ||
| 208 | if (ret < 0) | ||
| 209 | goto err; | ||
| 210 | msb = ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (reg->lsb) { | ||
| 214 | ret = i2c_smbus_read_byte_data(isl29501->client, reg->lsb); | ||
| 215 | if (ret < 0) | ||
| 216 | goto err; | ||
| 217 | lsb = ret; | ||
| 218 | } | ||
| 219 | mutex_unlock(&isl29501->lock); | ||
| 220 | |||
| 221 | *val = (msb << 8) + lsb; | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | err: | ||
| 225 | mutex_unlock(&isl29501->lock); | ||
| 226 | |||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | |||
| 230 | static u32 isl29501_register_write(struct isl29501_private *isl29501, | ||
| 231 | enum isl29501_register_name name, | ||
| 232 | u32 value) | ||
| 233 | { | ||
| 234 | const struct isl29501_register_desc *reg = &isl29501_registers[name]; | ||
| 235 | u8 msb, lsb; | ||
| 236 | int ret; | ||
| 237 | |||
| 238 | if (!reg->msb && value > U8_MAX) | ||
| 239 | return -ERANGE; | ||
| 240 | |||
| 241 | if (value > U16_MAX) | ||
| 242 | return -ERANGE; | ||
| 243 | |||
| 244 | if (!reg->msb) { | ||
| 245 | lsb = value & 0xFF; | ||
| 246 | } else { | ||
| 247 | msb = (value >> 8) & 0xFF; | ||
| 248 | lsb = value & 0xFF; | ||
| 249 | } | ||
| 250 | |||
| 251 | mutex_lock(&isl29501->lock); | ||
| 252 | if (reg->msb) { | ||
| 253 | ret = i2c_smbus_write_byte_data(isl29501->client, | ||
| 254 | reg->msb, msb); | ||
| 255 | if (ret < 0) | ||
| 256 | goto err; | ||
| 257 | } | ||
| 258 | |||
| 259 | ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, lsb); | ||
| 260 | |||
| 261 | err: | ||
| 262 | mutex_unlock(&isl29501->lock); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 266 | static ssize_t isl29501_read_ext(struct iio_dev *indio_dev, | ||
| 267 | uintptr_t private, | ||
| 268 | const struct iio_chan_spec *chan, | ||
| 269 | char *buf) | ||
| 270 | { | ||
| 271 | struct isl29501_private *isl29501 = iio_priv(indio_dev); | ||
| 272 | enum isl29501_register_name reg = private; | ||
| 273 | int ret; | ||
| 274 | u32 value, gain, coeff, exp; | ||
| 275 | |||
| 276 | switch (reg) { | ||
| 277 | case REG_GAIN: | ||
| 278 | case REG_GAIN_BIAS: | ||
| 279 | ret = isl29501_register_read(isl29501, reg, &gain); | ||
| 280 | if (ret < 0) | ||
| 281 | return ret; | ||
| 282 | |||
| 283 | value = gain; | ||
| 284 | break; | ||
| 285 | case REG_CALIB_PHASE_TEMP_A: | ||
| 286 | case REG_CALIB_PHASE_TEMP_B: | ||
| 287 | case REG_CALIB_PHASE_LIGHT_A: | ||
| 288 | case REG_CALIB_PHASE_LIGHT_B: | ||
| 289 | ret = isl29501_register_read(isl29501, REG_PHASE_EXP, &exp); | ||
| 290 | if (ret < 0) | ||
| 291 | return ret; | ||
| 292 | |||
| 293 | ret = isl29501_register_read(isl29501, reg, &coeff); | ||
| 294 | if (ret < 0) | ||
| 295 | return ret; | ||
| 296 | |||
| 297 | value = coeff << exp; | ||
| 298 | break; | ||
| 299 | default: | ||
| 300 | return -EINVAL; | ||
| 301 | } | ||
| 302 | |||
| 303 | return sprintf(buf, "%u\n", value); | ||
| 304 | } | ||
| 305 | |||
| 306 | static int isl29501_set_shadow_coeff(struct isl29501_private *isl29501, | ||
| 307 | enum isl29501_register_name reg, | ||
| 308 | unsigned int val) | ||
| 309 | { | ||
| 310 | enum isl29501_correction_coeff coeff; | ||
| 311 | |||
| 312 | switch (reg) { | ||
| 313 | case REG_CALIB_PHASE_TEMP_A: | ||
| 314 | coeff = COEFF_TEMP_A; | ||
| 315 | break; | ||
| 316 | case REG_CALIB_PHASE_TEMP_B: | ||
| 317 | coeff = COEFF_TEMP_B; | ||
| 318 | break; | ||
| 319 | case REG_CALIB_PHASE_LIGHT_A: | ||
| 320 | coeff = COEFF_LIGHT_A; | ||
| 321 | break; | ||
| 322 | case REG_CALIB_PHASE_LIGHT_B: | ||
| 323 | coeff = COEFF_LIGHT_B; | ||
| 324 | break; | ||
| 325 | default: | ||
| 326 | return -EINVAL; | ||
| 327 | } | ||
| 328 | isl29501->shadow_coeffs[coeff] = val; | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | static int isl29501_write_coeff(struct isl29501_private *isl29501, | ||
| 334 | enum isl29501_correction_coeff coeff, | ||
| 335 | int val) | ||
| 336 | { | ||
| 337 | enum isl29501_register_name reg; | ||
| 338 | |||
| 339 | switch (coeff) { | ||
| 340 | case COEFF_TEMP_A: | ||
| 341 | reg = REG_CALIB_PHASE_TEMP_A; | ||
| 342 | break; | ||
| 343 | case COEFF_TEMP_B: | ||
| 344 | reg = REG_CALIB_PHASE_TEMP_B; | ||
| 345 | break; | ||
| 346 | case COEFF_LIGHT_A: | ||
| 347 | reg = REG_CALIB_PHASE_LIGHT_A; | ||
| 348 | break; | ||
| 349 | case COEFF_LIGHT_B: | ||
| 350 | reg = REG_CALIB_PHASE_LIGHT_B; | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | return -EINVAL; | ||
| 354 | } | ||
| 355 | |||
| 356 | return isl29501_register_write(isl29501, reg, val); | ||
| 357 | } | ||
| 358 | |||
| 359 | static unsigned int isl29501_find_corr_exp(unsigned int val, | ||
| 360 | unsigned int max_exp, | ||
| 361 | unsigned int max_mantissa) | ||
| 362 | { | ||
| 363 | unsigned int exp = 1; | ||
| 364 | |||
| 365 | /* | ||
| 366 | * Correction coefficients are represented under | ||
| 367 | * mantissa * 2^exponent form, where mantissa and exponent | ||
| 368 | * are stored in two separate registers of the sensor. | ||
| 369 | * | ||
| 370 | * Compute and return the lowest exponent such as: | ||
| 371 | * mantissa = value / 2^exponent | ||
| 372 | * | ||
| 373 | * where mantissa < max_mantissa. | ||
| 374 | */ | ||
| 375 | if (val <= max_mantissa) | ||
| 376 | return 0; | ||
| 377 | |||
| 378 | while ((val >> exp) > max_mantissa) { | ||
| 379 | exp++; | ||
| 380 | |||
| 381 | if (exp > max_exp) | ||
| 382 | return max_exp; | ||
| 383 | } | ||
| 384 | |||
| 385 | return exp; | ||
| 386 | } | ||
| 387 | |||
| 388 | static ssize_t isl29501_write_ext(struct iio_dev *indio_dev, | ||
| 389 | uintptr_t private, | ||
| 390 | const struct iio_chan_spec *chan, | ||
| 391 | const char *buf, size_t len) | ||
| 392 | { | ||
| 393 | struct isl29501_private *isl29501 = iio_priv(indio_dev); | ||
| 394 | enum isl29501_register_name reg = private; | ||
| 395 | unsigned int val; | ||
| 396 | int max_exp = 0; | ||
| 397 | int ret; | ||
| 398 | int i; | ||
| 399 | |||
| 400 | ret = kstrtouint(buf, 10, &val); | ||
| 401 | if (ret) | ||
| 402 | return ret; | ||
| 403 | |||
| 404 | switch (reg) { | ||
| 405 | case REG_GAIN_BIAS: | ||
| 406 | if (val > U16_MAX) | ||
| 407 | return -ERANGE; | ||
| 408 | |||
| 409 | ret = isl29501_register_write(isl29501, reg, val); | ||
| 410 | if (ret < 0) | ||
| 411 | return ret; | ||
| 412 | |||
| 413 | break; | ||
| 414 | case REG_CALIB_PHASE_TEMP_A: | ||
| 415 | case REG_CALIB_PHASE_TEMP_B: | ||
| 416 | case REG_CALIB_PHASE_LIGHT_A: | ||
| 417 | case REG_CALIB_PHASE_LIGHT_B: | ||
| 418 | |||
| 419 | if (val > (U8_MAX << ISL29501_MAX_EXP_VAL)) | ||
| 420 | return -ERANGE; | ||
| 421 | |||
| 422 | /* Store the correction coefficient under its exact form. */ | ||
| 423 | ret = isl29501_set_shadow_coeff(isl29501, reg, val); | ||
| 424 | if (ret < 0) | ||
| 425 | return ret; | ||
| 426 | |||
| 427 | /* | ||
| 428 | * Find the highest exponent needed to represent | ||
| 429 | * correction coefficients. | ||
| 430 | */ | ||
| 431 | for (i = 0; i < COEFF_MAX; i++) { | ||
| 432 | int corr; | ||
| 433 | int corr_exp; | ||
| 434 | |||
| 435 | corr = isl29501->shadow_coeffs[i]; | ||
| 436 | corr_exp = isl29501_find_corr_exp(corr, | ||
| 437 | ISL29501_MAX_EXP_VAL, | ||
| 438 | U8_MAX / 2); | ||
| 439 | dev_dbg(&isl29501->client->dev, | ||
| 440 | "found exp of corr(%d) = %d\n", corr, corr_exp); | ||
| 441 | |||
| 442 | max_exp = max(max_exp, corr_exp); | ||
| 443 | } | ||
| 444 | |||
| 445 | /* | ||
| 446 | * Represent every correction coefficient under | ||
| 447 | * mantissa * 2^max_exponent form and force the | ||
| 448 | * writing of those coefficients on the sensor. | ||
| 449 | */ | ||
| 450 | for (i = 0; i < COEFF_MAX; i++) { | ||
| 451 | int corr; | ||
| 452 | int mantissa; | ||
| 453 | |||
| 454 | corr = isl29501->shadow_coeffs[i]; | ||
| 455 | if (!corr) | ||
| 456 | continue; | ||
| 457 | |||
| 458 | mantissa = corr >> max_exp; | ||
| 459 | |||
| 460 | ret = isl29501_write_coeff(isl29501, i, mantissa); | ||
| 461 | if (ret < 0) | ||
| 462 | return ret; | ||
| 463 | } | ||
| 464 | |||
| 465 | ret = isl29501_register_write(isl29501, REG_PHASE_EXP, max_exp); | ||
| 466 | if (ret < 0) | ||
| 467 | return ret; | ||
| 468 | |||
| 469 | break; | ||
| 470 | default: | ||
| 471 | return -EINVAL; | ||
| 472 | } | ||
| 473 | |||
| 474 | return len; | ||
| 475 | } | ||
| 476 | |||
| 477 | #define _ISL29501_EXT_INFO(_name, _ident) { \ | ||
| 478 | .name = _name, \ | ||
| 479 | .read = isl29501_read_ext, \ | ||
| 480 | .write = isl29501_write_ext, \ | ||
| 481 | .private = _ident, \ | ||
| 482 | .shared = IIO_SEPARATE, \ | ||
| 483 | } | ||
| 484 | |||
| 485 | static const struct iio_chan_spec_ext_info isl29501_ext_info[] = { | ||
| 486 | _ISL29501_EXT_INFO("agc_gain", REG_GAIN), | ||
| 487 | _ISL29501_EXT_INFO("agc_gain_bias", REG_GAIN_BIAS), | ||
| 488 | _ISL29501_EXT_INFO("calib_phase_temp_a", REG_CALIB_PHASE_TEMP_A), | ||
| 489 | _ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B), | ||
| 490 | _ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A), | ||
| 491 | _ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B), | ||
| 492 | { }, | ||
| 493 | }; | ||
| 494 | |||
| 495 | #define ISL29501_DISTANCE_SCAN_INDEX 0 | ||
| 496 | #define ISL29501_TIMESTAMP_SCAN_INDEX 1 | ||
| 497 | |||
| 498 | static const struct iio_chan_spec isl29501_channels[] = { | ||
| 499 | { | ||
| 500 | .type = IIO_PROXIMITY, | ||
| 501 | .scan_index = ISL29501_DISTANCE_SCAN_INDEX, | ||
| 502 | .info_mask_separate = | ||
| 503 | BIT(IIO_CHAN_INFO_RAW) | | ||
| 504 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 505 | BIT(IIO_CHAN_INFO_CALIBBIAS), | ||
| 506 | .scan_type = { | ||
| 507 | .sign = 'u', | ||
| 508 | .realbits = 16, | ||
| 509 | .storagebits = 16, | ||
| 510 | .endianness = IIO_CPU, | ||
| 511 | }, | ||
| 512 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | | ||
| 513 | BIT(IIO_CHAN_INFO_SAMP_FREQ), | ||
| 514 | .ext_info = isl29501_ext_info, | ||
| 515 | }, | ||
| 516 | { | ||
| 517 | .type = IIO_PHASE, | ||
| 518 | .scan_index = -1, | ||
| 519 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 520 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 521 | }, | ||
| 522 | { | ||
| 523 | .type = IIO_CURRENT, | ||
| 524 | .scan_index = -1, | ||
| 525 | .output = 1, | ||
| 526 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 527 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 528 | }, | ||
| 529 | { | ||
| 530 | .type = IIO_TEMP, | ||
| 531 | .scan_index = -1, | ||
| 532 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 533 | BIT(IIO_CHAN_INFO_SCALE) | | ||
| 534 | BIT(IIO_CHAN_INFO_CALIBBIAS), | ||
| 535 | }, | ||
| 536 | { | ||
| 537 | .type = IIO_INTENSITY, | ||
| 538 | .scan_index = -1, | ||
| 539 | .modified = 1, | ||
| 540 | .channel2 = IIO_MOD_LIGHT_CLEAR, | ||
| 541 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
| 542 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 543 | }, | ||
| 544 | IIO_CHAN_SOFT_TIMESTAMP(ISL29501_TIMESTAMP_SCAN_INDEX), | ||
| 545 | }; | ||
| 546 | |||
| 547 | static int isl29501_reset_registers(struct isl29501_private *isl29501) | ||
| 548 | { | ||
| 549 | int ret; | ||
| 550 | |||
| 551 | ret = i2c_smbus_write_byte_data(isl29501->client, | ||
| 552 | ISL29501_COMMAND_REGISTER, | ||
| 553 | ISL29501_RESET_ALL_REGISTERS); | ||
| 554 | if (ret < 0) { | ||
| 555 | dev_err(&isl29501->client->dev, | ||
| 556 | "cannot reset registers %d\n", ret); | ||
| 557 | return ret; | ||
| 558 | } | ||
| 559 | |||
| 560 | ret = i2c_smbus_write_byte_data(isl29501->client, | ||
| 561 | ISL29501_COMMAND_REGISTER, | ||
| 562 | ISL29501_RESET_INT_SM); | ||
| 563 | if (ret < 0) | ||
| 564 | dev_err(&isl29501->client->dev, | ||
| 565 | "cannot reset state machine %d\n", ret); | ||
| 566 | |||
| 567 | return ret; | ||
| 568 | } | ||
| 569 | |||
| 570 | static int isl29501_begin_acquisition(struct isl29501_private *isl29501) | ||
| 571 | { | ||
| 572 | int ret; | ||
| 573 | |||
| 574 | ret = i2c_smbus_write_byte_data(isl29501->client, | ||
| 575 | ISL29501_COMMAND_REGISTER, | ||
| 576 | ISL29501_EMUL_SAMPLE_START_PIN); | ||
| 577 | if (ret < 0) | ||
| 578 | dev_err(&isl29501->client->dev, | ||
| 579 | "cannot begin acquisition %d\n", ret); | ||
| 580 | |||
| 581 | return ret; | ||
| 582 | } | ||
| 583 | |||
| 584 | static IIO_CONST_ATTR_INT_TIME_AVAIL(ISL29501_INT_TIME_AVAILABLE); | ||
| 585 | static IIO_CONST_ATTR(out_current_scale_available, | ||
| 586 | ISL29501_CURRENT_SCALE_AVAILABLE); | ||
| 587 | |||
| 588 | static struct attribute *isl29501_attributes[] = { | ||
| 589 | &iio_const_attr_integration_time_available.dev_attr.attr, | ||
| 590 | &iio_const_attr_out_current_scale_available.dev_attr.attr, | ||
| 591 | NULL | ||
| 592 | }; | ||
| 593 | |||
| 594 | static const struct attribute_group isl29501_attribute_group = { | ||
| 595 | .attrs = isl29501_attributes, | ||
| 596 | }; | ||
| 597 | |||
| 598 | static const int isl29501_current_scale_table[][2] = { | ||
| 599 | {0, 3900}, {0, 7800}, {0, 11800}, {0, 15700}, | ||
| 600 | {0, 19600}, {0, 23500}, {0, 27500}, {0, 31400}, | ||
| 601 | {0, 35200}, {0, 39200}, {0, 43100}, {0, 47100}, | ||
| 602 | {0, 51000}, {0, 54900}, {0, 58800}, | ||
| 603 | }; | ||
| 604 | |||
| 605 | static const int isl29501_int_time[][2] = { | ||
| 606 | {0, 70}, /* 0.07 ms */ | ||
| 607 | {0, 140}, /* 0.14 ms */ | ||
| 608 | {0, 280}, /* 0.28 ms */ | ||
| 609 | {0, 570}, /* 0.57 ms */ | ||
| 610 | {0, 1140}, /* 1.14 ms */ | ||
| 611 | {0, 2280}, /* 2.28 ms */ | ||
| 612 | {0, 4550}, /* 4.55 ms */ | ||
| 613 | {0, 9100}, /* 9.11 ms */ | ||
| 614 | {0, 18200}, /* 18.2 ms */ | ||
| 615 | {0, 36400}, /* 36.4 ms */ | ||
| 616 | {0, 72810}, /* 72.81 ms */ | ||
| 617 | {0, 145610} /* 145.28 ms */ | ||
| 618 | }; | ||
| 619 | |||
| 620 | static int isl29501_get_raw(struct isl29501_private *isl29501, | ||
| 621 | const struct iio_chan_spec *chan, | ||
| 622 | int *raw) | ||
| 623 | { | ||
| 624 | int ret; | ||
| 625 | |||
| 626 | switch (chan->type) { | ||
| 627 | case IIO_PROXIMITY: | ||
| 628 | ret = isl29501_register_read(isl29501, REG_DISTANCE, raw); | ||
| 629 | if (ret < 0) | ||
| 630 | return ret; | ||
| 631 | |||
| 632 | return IIO_VAL_INT; | ||
| 633 | case IIO_INTENSITY: | ||
| 634 | ret = isl29501_register_read(isl29501, | ||
| 635 | REG_AMBIENT_LIGHT, | ||
| 636 | raw); | ||
| 637 | if (ret < 0) | ||
| 638 | return ret; | ||
| 639 | |||
| 640 | return IIO_VAL_INT; | ||
| 641 | case IIO_PHASE: | ||
| 642 | ret = isl29501_register_read(isl29501, REG_PHASE, raw); | ||
| 643 | if (ret < 0) | ||
| 644 | return ret; | ||
| 645 | |||
| 646 | return IIO_VAL_INT; | ||
| 647 | case IIO_CURRENT: | ||
| 648 | ret = isl29501_register_read(isl29501, REG_EMITTER_DAC, raw); | ||
| 649 | if (ret < 0) | ||
| 650 | return ret; | ||
| 651 | |||
| 652 | return IIO_VAL_INT; | ||
| 653 | case IIO_TEMP: | ||
| 654 | ret = isl29501_register_read(isl29501, REG_TEMPERATURE, raw); | ||
| 655 | if (ret < 0) | ||
| 656 | return ret; | ||
| 657 | |||
| 658 | return IIO_VAL_INT; | ||
| 659 | default: | ||
| 660 | return -EINVAL; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | static int isl29501_get_scale(struct isl29501_private *isl29501, | ||
| 665 | const struct iio_chan_spec *chan, | ||
| 666 | int *val, int *val2) | ||
| 667 | { | ||
| 668 | int ret; | ||
| 669 | u32 current_scale; | ||
| 670 | |||
| 671 | switch (chan->type) { | ||
| 672 | case IIO_PROXIMITY: | ||
| 673 | /* distance = raw_distance * 33.31 / 65536 (m) */ | ||
| 674 | *val = 3331; | ||
| 675 | *val2 = 6553600; | ||
| 676 | |||
| 677 | return IIO_VAL_FRACTIONAL; | ||
| 678 | case IIO_PHASE: | ||
| 679 | /* phase = raw_phase * 2pi / 65536 (rad) */ | ||
| 680 | *val = 0; | ||
| 681 | *val2 = 95874; | ||
| 682 | |||
| 683 | return IIO_VAL_INT_PLUS_NANO; | ||
| 684 | case IIO_INTENSITY: | ||
| 685 | /* light = raw_light * 35 / 10000 (mA) */ | ||
| 686 | *val = 35; | ||
| 687 | *val2 = 10000; | ||
| 688 | |||
| 689 | return IIO_VAL_FRACTIONAL; | ||
| 690 | case IIO_CURRENT: | ||
| 691 | ret = isl29501_register_read(isl29501, | ||
| 692 | REG_DRIVER_RANGE, | ||
| 693 | ¤t_scale); | ||
| 694 | if (ret < 0) | ||
| 695 | return ret; | ||
| 696 | |||
| 697 | if (current_scale > ARRAY_SIZE(isl29501_current_scale_table)) | ||
| 698 | return -EINVAL; | ||
| 699 | |||
| 700 | if (!current_scale) { | ||
| 701 | *val = 0; | ||
| 702 | *val2 = 0; | ||
| 703 | return IIO_VAL_INT; | ||
| 704 | } | ||
| 705 | |||
| 706 | *val = isl29501_current_scale_table[current_scale - 1][0]; | ||
| 707 | *val2 = isl29501_current_scale_table[current_scale - 1][1]; | ||
| 708 | |||
| 709 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 710 | case IIO_TEMP: | ||
| 711 | /* temperature = raw_temperature * 125 / 100000 (milli °C) */ | ||
| 712 | *val = 125; | ||
| 713 | *val2 = 100000; | ||
| 714 | |||
| 715 | return IIO_VAL_FRACTIONAL; | ||
| 716 | default: | ||
| 717 | return -EINVAL; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | static int isl29501_get_calibbias(struct isl29501_private *isl29501, | ||
| 722 | const struct iio_chan_spec *chan, | ||
| 723 | int *bias) | ||
| 724 | { | ||
| 725 | switch (chan->type) { | ||
| 726 | case IIO_PROXIMITY: | ||
| 727 | return isl29501_register_read(isl29501, | ||
| 728 | REG_DISTANCE_BIAS, | ||
| 729 | bias); | ||
| 730 | case IIO_TEMP: | ||
| 731 | return isl29501_register_read(isl29501, | ||
| 732 | REG_TEMPERATURE_BIAS, | ||
| 733 | bias); | ||
| 734 | default: | ||
| 735 | return -EINVAL; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | static int isl29501_get_inttime(struct isl29501_private *isl29501, | ||
| 740 | int *val, int *val2) | ||
| 741 | { | ||
| 742 | int ret; | ||
| 743 | u32 inttime; | ||
| 744 | |||
| 745 | ret = isl29501_register_read(isl29501, REG_INT_TIME, &inttime); | ||
| 746 | if (ret < 0) | ||
| 747 | return ret; | ||
| 748 | |||
| 749 | if (inttime >= ARRAY_SIZE(isl29501_int_time)) | ||
| 750 | return -EINVAL; | ||
| 751 | |||
| 752 | *val = isl29501_int_time[inttime][0]; | ||
| 753 | *val2 = isl29501_int_time[inttime][1]; | ||
| 754 | |||
| 755 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 756 | } | ||
| 757 | |||
| 758 | static int isl29501_get_freq(struct isl29501_private *isl29501, | ||
| 759 | int *val, int *val2) | ||
| 760 | { | ||
| 761 | int ret; | ||
| 762 | int sample_time; | ||
| 763 | unsigned long long freq; | ||
| 764 | u32 temp; | ||
| 765 | |||
| 766 | ret = isl29501_register_read(isl29501, REG_SAMPLE_TIME, &sample_time); | ||
| 767 | if (ret < 0) | ||
| 768 | return ret; | ||
| 769 | |||
| 770 | /* freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */ | ||
| 771 | freq = 1000000ULL * 1000000ULL; | ||
| 772 | |||
| 773 | do_div(freq, 450 * (sample_time + 1)); | ||
| 774 | |||
| 775 | temp = do_div(freq, 1000000); | ||
| 776 | *val = freq; | ||
| 777 | *val2 = temp; | ||
| 778 | |||
| 779 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int isl29501_read_raw(struct iio_dev *indio_dev, | ||
| 783 | struct iio_chan_spec const *chan, int *val, | ||
| 784 | int *val2, long mask) | ||
| 785 | { | ||
| 786 | struct isl29501_private *isl29501 = iio_priv(indio_dev); | ||
| 787 | |||
| 788 | switch (mask) { | ||
| 789 | case IIO_CHAN_INFO_RAW: | ||
| 790 | return isl29501_get_raw(isl29501, chan, val); | ||
| 791 | case IIO_CHAN_INFO_SCALE: | ||
| 792 | return isl29501_get_scale(isl29501, chan, val, val2); | ||
| 793 | case IIO_CHAN_INFO_INT_TIME: | ||
| 794 | return isl29501_get_inttime(isl29501, val, val2); | ||
| 795 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 796 | return isl29501_get_freq(isl29501, val, val2); | ||
| 797 | case IIO_CHAN_INFO_CALIBBIAS: | ||
| 798 | return isl29501_get_calibbias(isl29501, chan, val); | ||
| 799 | default: | ||
| 800 | return -EINVAL; | ||
| 801 | } | ||
| 802 | } | ||
| 803 | |||
| 804 | static int isl29501_set_raw(struct isl29501_private *isl29501, | ||
| 805 | const struct iio_chan_spec *chan, | ||
| 806 | int raw) | ||
| 807 | { | ||
| 808 | switch (chan->type) { | ||
| 809 | case IIO_CURRENT: | ||
| 810 | return isl29501_register_write(isl29501, REG_EMITTER_DAC, raw); | ||
| 811 | default: | ||
| 812 | return -EINVAL; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | static int isl29501_set_inttime(struct isl29501_private *isl29501, | ||
| 817 | int val, int val2) | ||
| 818 | { | ||
| 819 | int i; | ||
| 820 | |||
| 821 | for (i = 0; i < ARRAY_SIZE(isl29501_int_time); i++) { | ||
| 822 | if (isl29501_int_time[i][0] == val && | ||
| 823 | isl29501_int_time[i][1] == val2) { | ||
| 824 | return isl29501_register_write(isl29501, | ||
| 825 | REG_INT_TIME, | ||
| 826 | i); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | return -EINVAL; | ||
| 831 | } | ||
| 832 | |||
| 833 | static int isl29501_set_scale(struct isl29501_private *isl29501, | ||
| 834 | const struct iio_chan_spec *chan, | ||
| 835 | int val, int val2) | ||
| 836 | { | ||
| 837 | int i; | ||
| 838 | |||
| 839 | if (chan->type != IIO_CURRENT) | ||
| 840 | return -EINVAL; | ||
| 841 | |||
| 842 | for (i = 0; i < ARRAY_SIZE(isl29501_current_scale_table); i++) { | ||
| 843 | if (isl29501_current_scale_table[i][0] == val && | ||
| 844 | isl29501_current_scale_table[i][1] == val2) { | ||
| 845 | return isl29501_register_write(isl29501, | ||
| 846 | REG_DRIVER_RANGE, | ||
| 847 | i + 1); | ||
| 848 | } | ||
| 849 | } | ||
| 850 | |||
| 851 | return -EINVAL; | ||
| 852 | } | ||
| 853 | |||
| 854 | static int isl29501_set_calibbias(struct isl29501_private *isl29501, | ||
| 855 | const struct iio_chan_spec *chan, | ||
| 856 | int bias) | ||
| 857 | { | ||
| 858 | switch (chan->type) { | ||
| 859 | case IIO_PROXIMITY: | ||
| 860 | return isl29501_register_write(isl29501, | ||
| 861 | REG_DISTANCE_BIAS, | ||
| 862 | bias); | ||
| 863 | case IIO_TEMP: | ||
| 864 | return isl29501_register_write(isl29501, | ||
| 865 | REG_TEMPERATURE_BIAS, | ||
| 866 | bias); | ||
| 867 | default: | ||
| 868 | return -EINVAL; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 872 | static int isl29501_set_freq(struct isl29501_private *isl29501, | ||
| 873 | int val, int val2) | ||
| 874 | { | ||
| 875 | int freq; | ||
| 876 | unsigned long long sample_time; | ||
| 877 | |||
| 878 | /* sample_freq = 1 / (0.000450 * (sample_time + 1) * 10^-6) */ | ||
| 879 | freq = val * 1000000 + val2 % 1000000; | ||
| 880 | sample_time = 2222ULL * 1000000ULL; | ||
| 881 | do_div(sample_time, freq); | ||
| 882 | |||
| 883 | sample_time -= 1; | ||
| 884 | |||
| 885 | if (sample_time > 255) | ||
| 886 | return -ERANGE; | ||
| 887 | |||
| 888 | return isl29501_register_write(isl29501, REG_SAMPLE_TIME, sample_time); | ||
| 889 | } | ||
| 890 | |||
| 891 | static int isl29501_write_raw(struct iio_dev *indio_dev, | ||
| 892 | struct iio_chan_spec const *chan, | ||
| 893 | int val, int val2, long mask) | ||
| 894 | { | ||
| 895 | struct isl29501_private *isl29501 = iio_priv(indio_dev); | ||
| 896 | |||
| 897 | switch (mask) { | ||
| 898 | case IIO_CHAN_INFO_RAW: | ||
| 899 | return isl29501_set_raw(isl29501, chan, val); | ||
| 900 | case IIO_CHAN_INFO_INT_TIME: | ||
| 901 | return isl29501_set_inttime(isl29501, val, val2); | ||
| 902 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
| 903 | return isl29501_set_freq(isl29501, val, val2); | ||
| 904 | case IIO_CHAN_INFO_SCALE: | ||
| 905 | return isl29501_set_scale(isl29501, chan, val, val2); | ||
| 906 | case IIO_CHAN_INFO_CALIBBIAS: | ||
| 907 | return isl29501_set_calibbias(isl29501, chan, val); | ||
| 908 | default: | ||
| 909 | return -EINVAL; | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 913 | static const struct iio_info isl29501_info = { | ||
| 914 | .read_raw = &isl29501_read_raw, | ||
| 915 | .write_raw = &isl29501_write_raw, | ||
| 916 | .attrs = &isl29501_attribute_group, | ||
| 917 | }; | ||
| 918 | |||
| 919 | static int isl29501_init_chip(struct isl29501_private *isl29501) | ||
| 920 | { | ||
| 921 | int ret; | ||
| 922 | |||
| 923 | ret = i2c_smbus_read_byte_data(isl29501->client, ISL29501_DEVICE_ID); | ||
| 924 | if (ret < 0) { | ||
| 925 | dev_err(&isl29501->client->dev, "Error reading device id\n"); | ||
| 926 | return ret; | ||
| 927 | } | ||
| 928 | |||
| 929 | if (ret != ISL29501_ID) { | ||
| 930 | dev_err(&isl29501->client->dev, | ||
| 931 | "Wrong chip id, got %x expected %x\n", | ||
| 932 | ret, ISL29501_DEVICE_ID); | ||
| 933 | return -ENODEV; | ||
| 934 | } | ||
| 935 | |||
| 936 | ret = isl29501_reset_registers(isl29501); | ||
| 937 | if (ret < 0) | ||
| 938 | return ret; | ||
| 939 | |||
| 940 | return isl29501_begin_acquisition(isl29501); | ||
| 941 | } | ||
| 942 | |||
| 943 | static irqreturn_t isl29501_trigger_handler(int irq, void *p) | ||
| 944 | { | ||
| 945 | struct iio_poll_func *pf = p; | ||
| 946 | struct iio_dev *indio_dev = pf->indio_dev; | ||
| 947 | struct isl29501_private *isl29501 = iio_priv(indio_dev); | ||
| 948 | const unsigned long *active_mask = indio_dev->active_scan_mask; | ||
| 949 | u32 buffer[4] = {}; /* 1x16-bit + ts */ | ||
| 950 | |||
| 951 | if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask)) | ||
| 952 | isl29501_register_read(isl29501, REG_DISTANCE, buffer); | ||
| 953 | |||
| 954 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); | ||
| 955 | iio_trigger_notify_done(indio_dev->trig); | ||
| 956 | |||
| 957 | return IRQ_HANDLED; | ||
| 958 | } | ||
| 959 | |||
| 960 | static int isl29501_probe(struct i2c_client *client, | ||
| 961 | const struct i2c_device_id *id) | ||
| 962 | { | ||
| 963 | struct iio_dev *indio_dev; | ||
| 964 | struct isl29501_private *isl29501; | ||
| 965 | int ret; | ||
| 966 | |||
| 967 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*isl29501)); | ||
| 968 | if (!indio_dev) | ||
| 969 | return -ENOMEM; | ||
| 970 | |||
| 971 | isl29501 = iio_priv(indio_dev); | ||
| 972 | |||
| 973 | i2c_set_clientdata(client, indio_dev); | ||
| 974 | isl29501->client = client; | ||
| 975 | |||
| 976 | mutex_init(&isl29501->lock); | ||
| 977 | |||
| 978 | ret = isl29501_init_chip(isl29501); | ||
| 979 | if (ret < 0) | ||
| 980 | return ret; | ||
| 981 | |||
| 982 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 983 | indio_dev->dev.parent = &client->dev; | ||
| 984 | indio_dev->channels = isl29501_channels; | ||
| 985 | indio_dev->num_channels = ARRAY_SIZE(isl29501_channels); | ||
| 986 | indio_dev->name = client->name; | ||
| 987 | indio_dev->info = &isl29501_info; | ||
| 988 | |||
| 989 | ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, | ||
| 990 | iio_pollfunc_store_time, | ||
| 991 | isl29501_trigger_handler, | ||
| 992 | NULL); | ||
| 993 | if (ret < 0) { | ||
| 994 | dev_err(&client->dev, "unable to setup iio triggered buffer\n"); | ||
| 995 | return ret; | ||
| 996 | } | ||
| 997 | |||
| 998 | return devm_iio_device_register(&client->dev, indio_dev); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static const struct i2c_device_id isl29501_id[] = { | ||
| 1002 | {"isl29501", 0}, | ||
| 1003 | {} | ||
| 1004 | }; | ||
| 1005 | |||
| 1006 | MODULE_DEVICE_TABLE(i2c, isl29501_id); | ||
| 1007 | |||
| 1008 | #if defined(CONFIG_OF) | ||
| 1009 | static const struct of_device_id isl29501_i2c_matches[] = { | ||
| 1010 | { .compatible = "renesas,isl29501" }, | ||
| 1011 | { } | ||
| 1012 | }; | ||
| 1013 | MODULE_DEVICE_TABLE(of, isl29501_i2c_matches); | ||
| 1014 | #endif | ||
| 1015 | |||
| 1016 | static struct i2c_driver isl29501_driver = { | ||
| 1017 | .driver = { | ||
| 1018 | .name = "isl29501", | ||
| 1019 | }, | ||
| 1020 | .id_table = isl29501_id, | ||
| 1021 | .probe = isl29501_probe, | ||
| 1022 | }; | ||
| 1023 | module_i2c_driver(isl29501_driver); | ||
| 1024 | |||
| 1025 | MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>"); | ||
| 1026 | MODULE_DESCRIPTION("ISL29501 Time of Flight sensor driver"); | ||
| 1027 | MODULE_LICENSE("GPL v2"); | ||
| @@ -116,45 +116,26 @@ static struct ad5933_platform_data ad5933_default_pdata = { · 115 unmodified lines | |||
| 116 | .vref_mv = 3300, | 116 | .vref_mv = 3300, |
| 117 | }; | 117 | }; |
| 118 | 118 | ||
| 119 | #define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \ | ||
| 120 | _scan_index, _realbits) { \ | ||
| 121 | .type = (_type), \ | ||
| 122 | .extend_name = (_extend_name), \ | ||
| 123 | .info_mask_separate = (_info_mask_separate), \ | ||
| 124 | .address = (_address), \ | ||
| 125 | .scan_index = (_scan_index), \ | ||
| 126 | .scan_type = { \ | ||
| 127 | .sign = 's', \ | ||
| 128 | .realbits = (_realbits), \ | ||
| 129 | .storagebits = 16, \ | ||
| 130 | }, \ | ||
| 131 | } | ||
| 132 | |||
| 119 | static const struct iio_chan_spec ad5933_channels[] = { | 133 | static const struct iio_chan_spec ad5933_channels[] = { |
| 120 | { | 134 | AD5933_CHANNEL(IIO_TEMP, NULL, BIT(IIO_CHAN_INFO_RAW) | |
| 121 | .type = IIO_TEMP, | 135 | BIT(IIO_CHAN_INFO_SCALE), AD5933_REG_TEMP_DATA, -1, 14), |
| 122 | .indexed = 1, | 136 | /* Ring Channels */ |
| 123 | .channel = 0, | 137 | AD5933_CHANNEL(IIO_VOLTAGE, "real", 0, AD5933_REG_REAL_DATA, 0, 16), |
| 124 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | 138 | AD5933_CHANNEL(IIO_VOLTAGE, "imag", 0, AD5933_REG_IMAG_DATA, 1, 16), |
| 125 | BIT(IIO_CHAN_INFO_SCALE), | ||
| 126 | .address = AD5933_REG_TEMP_DATA, | ||
| 127 | .scan_index = -1, | ||
| 128 | .scan_type = { | ||
| 129 | .sign = 's', | ||
| 130 | .realbits = 14, | ||
| 131 | .storagebits = 16, | ||
| 132 | }, | ||
| 133 | }, { /* Ring Channels */ | ||
| 134 | .type = IIO_VOLTAGE, | ||
| 135 | .indexed = 1, | ||
| 136 | .channel = 0, | ||
| 137 | .extend_name = "real", | ||
| 138 | .address = AD5933_REG_REAL_DATA, | ||
| 139 | .scan_index = 0, | ||
| 140 | .scan_type = { | ||
| 141 | .sign = 's', | ||
| 142 | .realbits = 16, | ||
| 143 | .storagebits = 16, | ||
| 144 | }, | ||
| 145 | }, { | ||
| 146 | .type = IIO_VOLTAGE, | ||
| 147 | .indexed = 1, | ||
| 148 | .channel = 0, | ||
| 149 | .extend_name = "imag", | ||
| 150 | .address = AD5933_REG_IMAG_DATA, | ||
| 151 | .scan_index = 1, | ||
| 152 | .scan_type = { | ||
| 153 | .sign = 's', | ||
| 154 | .realbits = 16, | ||
| 155 | .storagebits = 16, | ||
| 156 | }, | ||
| 157 | }, | ||
| 158 | }; | 139 | }; |
| 159 | 140 | ||
| 160 | static int ad5933_i2c_write(struct i2c_client *client, u8 reg, u8 len, u8 *data) | 141 | static int ad5933_i2c_write(struct i2c_client *client, u8 reg, u8 len, u8 *data) |
| @@ -45,6 +45,7 @@ enum iio_chan_type { · 44 unmodified lines | |||
| 45 | IIO_INDEX, | 45 | IIO_INDEX, |
| 46 | IIO_GRAVITY, | 46 | IIO_GRAVITY, |
| 47 | IIO_POSITIONRELATIVE, | 47 | IIO_POSITIONRELATIVE, |
| 48 | IIO_PHASE, | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | enum iio_modifier { | 51 | enum iio_modifier { |
| @@ -85,6 +86,7 @@ enum iio_modifier { · 34 unmodified lines | |||
| 85 | IIO_MOD_CO2, | 86 | IIO_MOD_CO2, |
| 86 | IIO_MOD_VOC, | 87 | IIO_MOD_VOC, |
| 87 | IIO_MOD_LIGHT_UV, | 88 | IIO_MOD_LIGHT_UV, |
| 89 | IIO_MOD_LIGHT_DUV, | ||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | enum iio_event_type { | 92 | enum iio_event_type { |
| @@ -59,6 +59,7 @@ static const char * const iio_chan_type_name_spec[] = { · 58 unmodified lines | |||
| 59 | [IIO_UVINDEX] = "uvindex", | 59 | [IIO_UVINDEX] = "uvindex", |
| 60 | [IIO_GRAVITY] = "gravity", | 60 | [IIO_GRAVITY] = "gravity", |
| 61 | [IIO_POSITIONRELATIVE] = "positionrelative", | 61 | [IIO_POSITIONRELATIVE] = "positionrelative", |
| 62 | [IIO_PHASE] = "phase", | ||
| 62 | }; | 63 | }; |
| 63 | 64 | ||
| 64 | static const char * const iio_ev_type_text[] = { | 65 | static const char * const iio_ev_type_text[] = { |
| @@ -97,6 +98,7 @@ static const char * const iio_modifier_names[] = { · 32 unmodified lines | |||
| 97 | [IIO_MOD_LIGHT_GREEN] = "green", | 98 | [IIO_MOD_LIGHT_GREEN] = "green", |
| 98 | [IIO_MOD_LIGHT_BLUE] = "blue", | 99 | [IIO_MOD_LIGHT_BLUE] = "blue", |
| 99 | [IIO_MOD_LIGHT_UV] = "uv", | 100 | [IIO_MOD_LIGHT_UV] = "uv", |
| 101 | [IIO_MOD_LIGHT_DUV] = "duv", | ||
| 100 | [IIO_MOD_QUATERNION] = "quaternion", | 102 | [IIO_MOD_QUATERNION] = "quaternion", |
| 101 | [IIO_MOD_TEMP_AMBIENT] = "ambient", | 103 | [IIO_MOD_TEMP_AMBIENT] = "ambient", |
| 102 | [IIO_MOD_TEMP_OBJECT] = "object", | 104 | [IIO_MOD_TEMP_OBJECT] = "object", |
| @@ -153,6 +155,7 @@ static bool event_is_known(struct iio_event_data *event) · 50 unmodified lines | |||
| 153 | case IIO_UVINDEX: | 155 | case IIO_UVINDEX: |
| 154 | case IIO_GRAVITY: | 156 | case IIO_GRAVITY: |
| 155 | case IIO_POSITIONRELATIVE: | 157 | case IIO_POSITIONRELATIVE: |
| 158 | case IIO_PHASE: | ||
| 156 | break; | 159 | break; |
| 157 | default: | 160 | default: |
| 158 | return false; | 161 | return false; |
| @@ -180,6 +183,7 @@ static bool event_is_known(struct iio_event_data *event) · 21 unmodified lines | |||
| 180 | case IIO_MOD_LIGHT_GREEN: | 183 | case IIO_MOD_LIGHT_GREEN: |
| 181 | case IIO_MOD_LIGHT_BLUE: | 184 | case IIO_MOD_LIGHT_BLUE: |
| 182 | case IIO_MOD_LIGHT_UV: | 185 | case IIO_MOD_LIGHT_UV: |
| 186 | case IIO_MOD_LIGHT_DUV: | ||
| 183 | case IIO_MOD_QUATERNION: | 187 | case IIO_MOD_QUATERNION: |
| 184 | case IIO_MOD_TEMP_AMBIENT: | 188 | case IIO_MOD_TEMP_AMBIENT: |
| 185 | case IIO_MOD_TEMP_OBJECT: | 189 | case IIO_MOD_TEMP_OBJECT: |