You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'iio-for-4.12d' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: Fourth set of IIO new device support, features and cleanups for the 4.12 cycle New device support * max1117, 1118 and 1119 - new ADC driver * max9611 - new ADC driver * pm8xxx hk/xoadc - new driver with some shared features broken out from the SPMI vadc. * sun4i-gpadc - A33 thermal sensor support (with associated rework) * stm32-dac - new driver and bindings * stm32 trigger - enable support of quadrature encoder device and counter modes Features * apds9960 - use the runtime pm for normal suspend * stm32-adc - add opition to sest resolution via devicetree * xoadc - augment DT bindings to deal with some weird mux cases Cleanups * ad5933 - protect direct mode using claim and release helpers * ade7759 - S_IRUGO and friends to octal in two goes * adis16203 - drop unnecessary brackets * hid-sensor - fix unbalanced pm_runtieme_enable error when probing after remove * lsm6dsx - use actual part numbers for device name when known - simplify data read pin parsing * mpu3050 - avoid double reporting errors
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_power_shunt_resistor
|
||||
Date: March 2017
|
||||
KernelVersion: 4.12
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description: The value of the shunt resistor used to compute power drain on
|
||||
common input voltage pin (RS+). In Ohms.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_shunt_resistor
|
||||
Date: March 2017
|
||||
KernelVersion: 4.12
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description: The value of the shunt resistor used to compute current flowing
|
||||
between RS+ and RS- voltage sense inputs. In Ohms.
|
||||
|
||||
These attributes describe a single physical component, exposed as two distinct
|
||||
attributes as it is used to calculate two different values: power load and
|
||||
current flowing between RS+ and RS- inputs.
|
||||
@@ -3,11 +3,15 @@ KernelVersion: 4.11
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Reading returns the list possible master modes which are:
|
||||
- "reset" : The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
|
||||
- "enable" : The Counter Enable signal CNT_EN is used as trigger output.
|
||||
- "reset" : The UG bit from the TIMx_EGR register is
|
||||
used as trigger output (TRGO).
|
||||
- "enable" : The Counter Enable signal CNT_EN is used
|
||||
as trigger output.
|
||||
- "update" : The update event is selected as trigger output.
|
||||
For instance a master timer can then be used as a prescaler for a slave timer.
|
||||
- "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
|
||||
For instance a master timer can then be used
|
||||
as a prescaler for a slave timer.
|
||||
- "compare_pulse" : The trigger output send a positive pulse
|
||||
when the CC1IF flag is to be set.
|
||||
- "OC1REF" : OC1REF signal is used as trigger output.
|
||||
- "OC2REF" : OC2REF signal is used as trigger output.
|
||||
- "OC3REF" : OC3REF signal is used as trigger output.
|
||||
@@ -27,3 +31,62 @@ Description:
|
||||
Reading returns the current sampling frequency.
|
||||
Writing an value different of 0 set and start sampling.
|
||||
Writing 0 stop sampling.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_count0_preset
|
||||
KernelVersion: 4.12
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Reading returns the current preset value.
|
||||
Writing sets the preset value.
|
||||
When counting up the counter starts from 0 and fires an
|
||||
event when reach preset value.
|
||||
When counting down the counter start from preset value
|
||||
and fire event when reach 0.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available
|
||||
KernelVersion: 4.12
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Reading returns the list possible quadrature modes.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode
|
||||
KernelVersion: 4.12
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Configure the device counter quadrature modes:
|
||||
channel_A:
|
||||
Encoder A input servers as the count input and B as
|
||||
the UP/DOWN direction control input.
|
||||
|
||||
channel_B:
|
||||
Encoder B input serves as the count input and A as
|
||||
the UP/DOWN direction control input.
|
||||
|
||||
quadrature:
|
||||
Encoder A and B inputs are mixed to get direction
|
||||
and count with a scale of 0.25.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_count_enable_mode_available
|
||||
KernelVersion: 4.12
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Reading returns the list possible enable modes.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_count0_enable_mode
|
||||
KernelVersion: 4.12
|
||||
Contact: benjamin.gaignard@st.com
|
||||
Description:
|
||||
Configure the device counter enable modes, in all case
|
||||
counting direction is set by in_count0_count_direction
|
||||
attribute and the counter is clocked by the internal clock.
|
||||
always:
|
||||
Counter is always ON.
|
||||
|
||||
gated:
|
||||
Counting is enabled when connected trigger signal
|
||||
level is high else counting is disabled.
|
||||
|
||||
triggered:
|
||||
Counting is enabled on rising edge of the connected
|
||||
trigger, and remains enabled for the duration of this
|
||||
selected mode.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
* "maxim,max1117"
|
||||
* "maxim,max1118"
|
||||
* "maxim,max1119"
|
||||
- reg: spi chip select number for the device
|
||||
- (max1118 only) vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "maxim,max1118";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
* Maxim max9611/max9612 current sense amplifier with 12-bits ADC interface
|
||||
|
||||
Maxim max9611/max9612 is an high-side current sense amplifier with integrated
|
||||
12-bits ADC communicating over I2c bus.
|
||||
The device node for this driver shall be a child of a I2c controller.
|
||||
|
||||
Required properties
|
||||
- compatible: Should be "maxim,max9611" or "maxim,max9612"
|
||||
- reg: The 7-bits long I2c address of the device
|
||||
- shunt-resistor-micro-ohms: Value, in micro Ohms, of the current sense shunt
|
||||
resistor
|
||||
|
||||
Example:
|
||||
|
||||
&i2c4 {
|
||||
csa: adc@7c {
|
||||
compatible = "maxim,max9611";
|
||||
reg = <0x7c>;
|
||||
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
};
|
||||
|
||||
This device node describes a current sense amplifier sitting on I2c4 bus
|
||||
with address 0x7c (read address is 0xf9, write address is 0xf8).
|
||||
A sense resistor of 0,005 Ohm is installed between RS+ and RS- current-sensing
|
||||
inputs.
|
||||
@@ -19,32 +19,42 @@ Required properties:
|
||||
with PMIC variant but is typically something like 2.2 or 1.8V.
|
||||
|
||||
The following required properties are standard for IO channels, see
|
||||
iio-bindings.txt for more details:
|
||||
iio-bindings.txt for more details, but notice that this particular
|
||||
ADC has a special addressing scheme that require two cells for
|
||||
identifying each ADC channel:
|
||||
|
||||
- #address-cells: should be set to <1>
|
||||
- #address-cells: should be set to <2>, the first cell is the
|
||||
prescaler (on PM8058) or premux (on PM8921) with two valid bits
|
||||
so legal values are 0x00, 0x01 or 0x02. The second cell
|
||||
is the main analog mux setting (0x00..0x0f). The combination
|
||||
of prescaler/premux and analog mux uniquely addresses a hardware
|
||||
channel on all systems.
|
||||
|
||||
- #size-cells: should be set to <0>
|
||||
|
||||
- #io-channel-cells: should be set to <1>
|
||||
- #io-channel-cells: should be set to <2>, again the cells are
|
||||
precaler or premux followed by the analog muxing line.
|
||||
|
||||
- interrupts: should refer to the parent PMIC interrupt controller
|
||||
and reference the proper ADC interrupt.
|
||||
|
||||
Required subnodes:
|
||||
|
||||
The ADC channels are configured as subnodes of the ADC. Since some of
|
||||
them are used for calibrating the ADC, these nodes are compulsory:
|
||||
The ADC channels are configured as subnodes of the ADC.
|
||||
|
||||
Since some of them are used for calibrating the ADC, these nodes are
|
||||
compulsory:
|
||||
|
||||
adc-channel@c {
|
||||
reg = <0x0c>;
|
||||
reg = <0x00 0x0c>;
|
||||
};
|
||||
|
||||
adc-channel@d {
|
||||
reg = <0x0d>;
|
||||
reg = <0x00 0x0d>;
|
||||
};
|
||||
|
||||
adc-channel@f {
|
||||
reg = <0x0f>;
|
||||
reg = <0x00 0x0f>;
|
||||
};
|
||||
|
||||
These three nodes are used for absolute and ratiometric calibration
|
||||
@@ -52,13 +62,13 @@ and only need to have these reg values: they are by hardware definition
|
||||
1:1 ratio converters that sample 625, 1250 and 0 milliV and create
|
||||
an interpolation calibration for all other ADCs.
|
||||
|
||||
Optional subnodes: any channels other than channel 0x0c, 0x0d and
|
||||
0x0f are optional.
|
||||
Optional subnodes: any channels other than channels [0x00 0x0c],
|
||||
[0x00 0x0d] and [0x00 0x0f] are optional.
|
||||
|
||||
Required channel node properties:
|
||||
|
||||
- reg: should contain the hardware channel number in the range
|
||||
0 .. 0x0f (4 bits). The hardware only supports 16 channels.
|
||||
0 .. 0xff (8 bits).
|
||||
|
||||
Optional channel node properties:
|
||||
|
||||
@@ -94,56 +104,54 @@ Example:
|
||||
xoadc: xoadc@197 {
|
||||
compatible = "qcom,pm8058-adc";
|
||||
reg = <0x197>;
|
||||
interrupt-parent = <&pm8058>;
|
||||
interrupts = <76 1>;
|
||||
#address-cells = <1>;
|
||||
interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
#io-channel-cells = <1>;
|
||||
#io-channel-cells = <2>;
|
||||
|
||||
vcoin: adc-channel@0 {
|
||||
reg = <0x00>;
|
||||
reg = <0x00 0x00>;
|
||||
};
|
||||
vbat: adc-channel@1 {
|
||||
reg = <0x01>;
|
||||
reg = <0x00 0x01>;
|
||||
};
|
||||
dcin: adc-channel@2 {
|
||||
reg = <0x02>;
|
||||
reg = <0x00 0x02>;
|
||||
};
|
||||
ichg: adc-channel@3 {
|
||||
reg = <0x03>;
|
||||
reg = <0x00 0x03>;
|
||||
};
|
||||
vph_pwr: adc-channel@4 {
|
||||
reg = <0x04>;
|
||||
reg = <0x00 0x04>;
|
||||
};
|
||||
usb_vbus: adc-channel@a {
|
||||
reg = <0x0a>;
|
||||
reg = <0x00 0x0a>;
|
||||
};
|
||||
die_temp: adc-channel@b {
|
||||
reg = <0x0b>;
|
||||
reg = <0x00 0x0b>;
|
||||
};
|
||||
ref_625mv: adc-channel@c {
|
||||
reg = <0x0c>;
|
||||
reg = <0x00 0x0c>;
|
||||
};
|
||||
ref_1250mv: adc-channel@d {
|
||||
reg = <0x0d>;
|
||||
reg = <0x00 0x0d>;
|
||||
};
|
||||
ref_325mv: adc-channel@e {
|
||||
reg = <0x0e>;
|
||||
reg = <0x00 0x0e>;
|
||||
};
|
||||
ref_muxoff: adc-channel@f {
|
||||
reg = <0x0f>;
|
||||
reg = <0x00 0x0f>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* IIO client node */
|
||||
iio-hwmon {
|
||||
compatible = "iio-hwmon";
|
||||
io-channels = <&xoadc 0x01>, /* Battery */
|
||||
<&xoadc 0x02>, /* DC in (charger) */
|
||||
<&xoadc 0x04>, /* VPH the main system voltage */
|
||||
<&xoadc 0x0b>, /* Die temperature */
|
||||
<&xoadc 0x0c>, /* Reference voltage 1.25V */
|
||||
<&xoadc 0x0d>, /* Reference voltage 0.625V */
|
||||
<&xoadc 0x0e>; /* Reference voltage 0.325V */
|
||||
io-channels = <&xoadc 0x00 0x01>, /* Battery */
|
||||
<&xoadc 0x00 0x02>, /* DC in (charger) */
|
||||
<&xoadc 0x00 0x04>, /* VPH the main system voltage */
|
||||
<&xoadc 0x00 0x0b>, /* Die temperature */
|
||||
<&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */
|
||||
<&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */
|
||||
<&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */
|
||||
};
|
||||
|
||||
@@ -57,6 +57,9 @@ Optional properties:
|
||||
- dmas: Phandle to dma channel for this ADC instance.
|
||||
See ../../dma/dma.txt for details.
|
||||
- dma-names: Must be "rx" when dmas property is being used.
|
||||
- assigned-resolution-bits: Resolution (bits) to use for conversions. Must
|
||||
match device available resolutions (e.g. can be 6, 8, 10 or 12 on stm32f4).
|
||||
Default is maximum resolution if unset.
|
||||
|
||||
Example:
|
||||
adc: adc@40012000 {
|
||||
@@ -84,6 +87,7 @@ Example:
|
||||
st,adc-channels = <8>;
|
||||
dmas = <&dma2 0 0 0x400 0x0>;
|
||||
dma-names = "rx";
|
||||
assigned-resolution-bits = <8>;
|
||||
};
|
||||
...
|
||||
other adc child nodes follow...
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
STMicroelectronics STM32 DAC
|
||||
|
||||
The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC
|
||||
may be configured in 8 or 12-bit mode. It has two output channels, each with
|
||||
its own converter.
|
||||
It has built-in noise and triangle waveform generator and supports external
|
||||
triggers for conversions. The DAC's output buffer allows a high drive output
|
||||
current.
|
||||
|
||||
Contents of a stm32 dac root node:
|
||||
-----------------------------------
|
||||
Required properties:
|
||||
- compatible: Must be "st,stm32h7-dac-core".
|
||||
- reg: Offset and length of the device's register set.
|
||||
- clocks: Must contain an entry for pclk (which feeds the peripheral bus
|
||||
interface)
|
||||
- clock-names: Must be "pclk".
|
||||
- vref-supply: Phandle to the vref+ input analog reference supply.
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
|
||||
Optional properties:
|
||||
- resets: Must contain the phandle to the reset controller.
|
||||
- A pinctrl state named "default" for each DAC channel may be defined to set
|
||||
DAC_OUTx pin in mode of operation for analog output on external pin.
|
||||
|
||||
Contents of a stm32 dac child node:
|
||||
-----------------------------------
|
||||
DAC core node should contain at least one subnode, representing a
|
||||
DAC instance/channel available on the machine.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "st,stm32-dac".
|
||||
- reg: Must be either 1 or 2, to define (single) channel in use
|
||||
- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
|
||||
Documentation/devicetree/bindings/iio/iio-bindings.txt
|
||||
|
||||
Example:
|
||||
dac: dac@40007400 {
|
||||
compatible = "st,stm32h7-dac-core";
|
||||
reg = <0x40007400 0x400>;
|
||||
clocks = <&clk>;
|
||||
clock-names = "pclk";
|
||||
vref-supply = <®_vref>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&dac_out1 &dac_out2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac1: dac@1 {
|
||||
compatible = "st,stm32-dac";
|
||||
#io-channels-cells = <1>;
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
dac2: dac@2 {
|
||||
compatible = "st,stm32-dac";
|
||||
#io-channels-cells = <1>;
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
+38
-1
@@ -379,6 +379,18 @@ config MAX11100
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max11100.
|
||||
|
||||
config MAX1118
|
||||
tristate "Maxim max1117/max1118/max1119 ADCs driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Maxim max1117/max1118/max1119
|
||||
8-bit, dual-channel ADCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1118.
|
||||
|
||||
config MAX1363
|
||||
tristate "Maxim max1363 ADC driver"
|
||||
depends on I2C
|
||||
@@ -398,6 +410,16 @@ config MAX1363
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1363.
|
||||
|
||||
config MAX9611
|
||||
tristate "Maxim max9611/max9612 ADC driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Maxim max9611/max9612 current sense
|
||||
amplifier with 12-bits ADC interface.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max9611.
|
||||
|
||||
config MCP320X
|
||||
tristate "Microchip Technology MCP3x01/02/04/08"
|
||||
depends on SPI
|
||||
@@ -486,6 +508,20 @@ config PALMAS_GPADC
|
||||
is used in smartphones and tablets and supports a 16 channel
|
||||
general purpose ADC.
|
||||
|
||||
config QCOM_VADC_COMMON
|
||||
tristate
|
||||
|
||||
config QCOM_PM8XXX_XOADC
|
||||
tristate "Qualcomm SSBI PM8xxx PMIC XOADCs"
|
||||
depends on MFD_PM8XXX
|
||||
select QCOM_VADC_COMMON
|
||||
help
|
||||
ADC driver for the XOADC portions of the Qualcomm PM8xxx PMICs
|
||||
using SSBI transport: PM8018, PM8038, PM8058, PM8921.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called qcom-pm8xxx-xoadc.
|
||||
|
||||
config QCOM_SPMI_IADC
|
||||
tristate "Qualcomm SPMI PMIC current ADC"
|
||||
depends on SPMI
|
||||
@@ -504,6 +540,7 @@ config QCOM_SPMI_VADC
|
||||
tristate "Qualcomm SPMI PMIC voltage ADC"
|
||||
depends on SPMI
|
||||
select REGMAP_SPMI
|
||||
select QCOM_VADC_COMMON
|
||||
help
|
||||
This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip.
|
||||
|
||||
@@ -594,7 +631,7 @@ config STX104
|
||||
config SUN4I_GPADC
|
||||
tristate "Support for the Allwinner SoCs GPADC"
|
||||
depends on IIO
|
||||
depends on MFD_SUN4I_GPADC
|
||||
depends on MFD_SUN4I_GPADC || MACH_SUN8I
|
||||
depends on THERMAL || !THERMAL_OF
|
||||
help
|
||||
Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
|
||||
|
||||
@@ -37,7 +37,9 @@ obj-$(CONFIG_LTC2485) += ltc2485.o
|
||||
obj-$(CONFIG_LTC2497) += ltc2497.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX11100) += max11100.o
|
||||
obj-$(CONFIG_MAX1118) += max1118.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
obj-$(CONFIG_MAX9611) += max9611.o
|
||||
obj-$(CONFIG_MCP320X) += mcp320x.o
|
||||
obj-$(CONFIG_MCP3422) += mcp3422.o
|
||||
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
|
||||
@@ -47,7 +49,9 @@ obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
|
||||
obj-$(CONFIG_NAU7802) += nau7802.o
|
||||
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
|
||||
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
|
||||
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
||||
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs driver
|
||||
*
|
||||
* Copyright (c) 2017 Akinobu Mita <akinobu.mita@gmail.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1117-MAX1119.pdf
|
||||
*
|
||||
* SPI interface connections
|
||||
*
|
||||
* SPI MAXIM
|
||||
* Master Direction MAX1117/8/9
|
||||
* ------ --------- -----------
|
||||
* nCS --> CNVST
|
||||
* SCK --> SCLK
|
||||
* MISO <-- DOUT
|
||||
* ------ --------- -----------
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
enum max1118_id {
|
||||
max1117,
|
||||
max1118,
|
||||
max1119,
|
||||
};
|
||||
|
||||
struct max1118 {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
struct regulator *reg;
|
||||
|
||||
u8 data ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#define MAX1118_CHANNEL(ch) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (ch), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = ch, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 8, \
|
||||
.storagebits = 8, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec max1118_channels[] = {
|
||||
MAX1118_CHANNEL(0),
|
||||
MAX1118_CHANNEL(1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
};
|
||||
|
||||
static int max1118_read(struct spi_device *spi, int channel)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct max1118 *adc = iio_priv(indio_dev);
|
||||
struct spi_transfer xfers[] = {
|
||||
/*
|
||||
* To select CH1 for conversion, CNVST pin must be brought high
|
||||
* and low for a second time.
|
||||
*/
|
||||
{
|
||||
.len = 0,
|
||||
.delay_usecs = 1, /* > CNVST Low Time 100 ns */
|
||||
.cs_change = 1,
|
||||
},
|
||||
/*
|
||||
* The acquisition interval begins with the falling edge of
|
||||
* CNVST. The total acquisition and conversion process takes
|
||||
* <7.5us.
|
||||
*/
|
||||
{
|
||||
.len = 0,
|
||||
.delay_usecs = 8,
|
||||
},
|
||||
{
|
||||
.rx_buf = &adc->data,
|
||||
.len = 1,
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (channel == 0)
|
||||
ret = spi_sync_transfer(spi, xfers + 1, 2);
|
||||
else
|
||||
ret = spi_sync_transfer(spi, xfers, 3);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adc->data;
|
||||
}
|
||||
|
||||
static int max1118_get_vref_mV(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct max1118 *adc = iio_priv(indio_dev);
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
int vref_uV;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case max1117:
|
||||
return 2048;
|
||||
case max1119:
|
||||
return 4096;
|
||||
case max1118:
|
||||
vref_uV = regulator_get_voltage(adc->reg);
|
||||
if (vref_uV < 0)
|
||||
return vref_uV;
|
||||
return vref_uV / 1000;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int max1118_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct max1118 *adc = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&adc->lock);
|
||||
*val = max1118_read(adc->spi, chan->channel);
|
||||
mutex_unlock(&adc->lock);
|
||||
if (*val < 0)
|
||||
return *val;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = max1118_get_vref_mV(adc->spi);
|
||||
if (*val < 0)
|
||||
return *val;
|
||||
*val2 = 8;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info max1118_info = {
|
||||
.read_raw = max1118_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t max1118_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct max1118 *adc = iio_priv(indio_dev);
|
||||
u8 data[16] = { }; /* 2x 8-bit ADC data + padding + 8 bytes timestamp */
|
||||
int scan_index;
|
||||
int i = 0;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
const struct iio_chan_spec *scan_chan =
|
||||
&indio_dev->channels[scan_index];
|
||||
int ret = max1118_read(adc->spi, scan_chan->channel);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_warn(&adc->spi->dev,
|
||||
"failed to get conversion data\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
data[i] = ret;
|
||||
i++;
|
||||
}
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
mutex_unlock(&adc->lock);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int max1118_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct max1118 *adc;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->spi = spi;
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
if (id->driver_data == max1118) {
|
||||
adc->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(adc->reg)) {
|
||||
dev_err(&spi->dev, "failed to get vref regulator\n");
|
||||
return PTR_ERR(adc->reg);
|
||||
}
|
||||
ret = regulator_enable(adc->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &max1118_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = max1118_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(max1118_channels);
|
||||
|
||||
/*
|
||||
* To reinitiate a conversion on CH0, it is necessary to allow for a
|
||||
* conversion to be complete and all of the data to be read out. Once
|
||||
* a conversion has been completed, the MAX1117/MAX1118/MAX1119 will go
|
||||
* into AutoShutdown mode until the next conversion is initiated.
|
||||
*/
|
||||
max1118_read(spi, 0);
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
max1118_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto err_reg_disable;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_reg_disable:
|
||||
if (id->driver_data == max1118)
|
||||
regulator_disable(adc->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max1118_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct max1118 *adc = iio_priv(indio_dev);
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (id->driver_data == max1118)
|
||||
return regulator_disable(adc->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id max1118_id[] = {
|
||||
{ "max1117", max1117 },
|
||||
{ "max1118", max1118 },
|
||||
{ "max1119", max1119 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max1118_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
static const struct of_device_id max1118_dt_ids[] = {
|
||||
{ .compatible = "maxim,max1117" },
|
||||
{ .compatible = "maxim,max1118" },
|
||||
{ .compatible = "maxim,max1119" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1118_dt_ids);
|
||||
|
||||
#endif
|
||||
|
||||
static struct spi_driver max1118_spi_driver = {
|
||||
.driver = {
|
||||
.name = "max1118",
|
||||
.of_match_table = of_match_ptr(max1118_dt_ids),
|
||||
},
|
||||
.probe = max1118_probe,
|
||||
.remove = max1118_remove,
|
||||
.id_table = max1118_id,
|
||||
};
|
||||
module_spi_driver(max1118_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
|
||||
MODULE_DESCRIPTION("MAXIM MAX1117/MAX1118/MAX1119 ADCs driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,8 @@
|
||||
|
||||
#include <dt-bindings/iio/qcom,spmi-vadc.h>
|
||||
|
||||
#include "qcom-vadc-common.h"
|
||||
|
||||
/* VADC register and bit definitions */
|
||||
#define VADC_REVISION2 0x1
|
||||
#define VADC_REVISION2_SUPPORTED_VADC 1
|
||||
@@ -75,83 +77,9 @@
|
||||
|
||||
#define VADC_DATA 0x60 /* 16 bits */
|
||||
|
||||
#define VADC_CONV_TIME_MIN_US 2000
|
||||
#define VADC_CONV_TIME_MAX_US 2100
|
||||
|
||||
/* Min ADC code represents 0V */
|
||||
#define VADC_MIN_ADC_CODE 0x6000
|
||||
/* Max ADC code represents full-scale range of 1.8V */
|
||||
#define VADC_MAX_ADC_CODE 0xa800
|
||||
|
||||
#define VADC_ABSOLUTE_RANGE_UV 625000
|
||||
#define VADC_RATIOMETRIC_RANGE 1800
|
||||
|
||||
#define VADC_DEF_PRESCALING 0 /* 1:1 */
|
||||
#define VADC_DEF_DECIMATION 0 /* 512 */
|
||||
#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
|
||||
#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
|
||||
#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
|
||||
|
||||
#define VADC_DECIMATION_MIN 512
|
||||
#define VADC_DECIMATION_MAX 4096
|
||||
|
||||
#define VADC_HW_SETTLE_DELAY_MAX 10000
|
||||
#define VADC_AVG_SAMPLES_MAX 512
|
||||
|
||||
#define KELVINMIL_CELSIUSMIL 273150
|
||||
|
||||
#define PMI_CHG_SCALE_1 -138890
|
||||
#define PMI_CHG_SCALE_2 391750000000LL
|
||||
|
||||
#define VADC_CHAN_MIN VADC_USBIN
|
||||
#define VADC_CHAN_MAX VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
|
||||
|
||||
/**
|
||||
* struct vadc_map_pt - Map the graph representation for ADC channel
|
||||
* @x: Represent the ADC digitized code.
|
||||
* @y: Represent the physical data which can be temperature, voltage,
|
||||
* resistance.
|
||||
*/
|
||||
struct vadc_map_pt {
|
||||
s32 x;
|
||||
s32 y;
|
||||
};
|
||||
|
||||
/*
|
||||
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
|
||||
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
|
||||
* calibration.
|
||||
*/
|
||||
enum vadc_calibration {
|
||||
VADC_CALIB_ABSOLUTE = 0,
|
||||
VADC_CALIB_RATIOMETRIC
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_linear_graph - Represent ADC characteristics.
|
||||
* @dy: numerator slope to calculate the gain.
|
||||
* @dx: denominator slope to calculate the gain.
|
||||
* @gnd: A/D word of the ground reference used for the channel.
|
||||
*
|
||||
* Each ADC device has different offset and gain parameters which are
|
||||
* computed to calibrate the device.
|
||||
*/
|
||||
struct vadc_linear_graph {
|
||||
s32 dy;
|
||||
s32 dx;
|
||||
s32 gnd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
|
||||
* @num: the inverse numerator of the gain applied to the input channel.
|
||||
* @den: the inverse denominator of the gain applied to the input channel.
|
||||
*/
|
||||
struct vadc_prescale_ratio {
|
||||
u32 num;
|
||||
u32 den;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_channel_prop - VADC channel property.
|
||||
* @channel: channel number, refer to the channel list.
|
||||
@@ -162,9 +90,8 @@ struct vadc_prescale_ratio {
|
||||
* start of conversion.
|
||||
* @avg_samples: ability to provide single result from the ADC
|
||||
* that is an average of multiple measurements.
|
||||
* @scale_fn: Represents the scaling function to convert voltage
|
||||
* @scale_fn_type: Represents the scaling function to convert voltage
|
||||
* physical units desired by the client for the channel.
|
||||
* Referenced from enum vadc_scale_fn_type.
|
||||
*/
|
||||
struct vadc_channel_prop {
|
||||
unsigned int channel;
|
||||
@@ -173,7 +100,7 @@ struct vadc_channel_prop {
|
||||
unsigned int prescale;
|
||||
unsigned int hw_settle_time;
|
||||
unsigned int avg_samples;
|
||||
unsigned int scale_fn;
|
||||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -204,35 +131,6 @@ struct vadc_priv {
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_scale_fn - Scaling function prototype
|
||||
* @scale: Function pointer to one of the scaling functions
|
||||
* which takes the adc properties, channel properties,
|
||||
* and returns the physical result.
|
||||
*/
|
||||
struct vadc_scale_fn {
|
||||
int (*scale)(struct vadc_priv *, const struct vadc_channel_prop *,
|
||||
u16, int *);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vadc_scale_fn_type - Scaling function to convert ADC code to
|
||||
* physical scaled units for the channel.
|
||||
* SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
|
||||
* SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
|
||||
* Uses a mapping table with 100K pullup.
|
||||
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
|
||||
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
|
||||
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
|
||||
*/
|
||||
enum vadc_scale_fn_type {
|
||||
SCALE_DEFAULT = 0,
|
||||
SCALE_THERM_100K_PULLUP,
|
||||
SCALE_PMIC_THERM,
|
||||
SCALE_XOTHERM,
|
||||
SCALE_PMI_CHG_TEMP,
|
||||
};
|
||||
|
||||
static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
|
||||
{.num = 1, .den = 1},
|
||||
{.num = 1, .den = 3},
|
||||
@@ -244,44 +142,6 @@ static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
|
||||
{.num = 1, .den = 10}
|
||||
};
|
||||
|
||||
/* Voltage to temperature */
|
||||
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
|
||||
{1758, -40},
|
||||
{1742, -35},
|
||||
{1719, -30},
|
||||
{1691, -25},
|
||||
{1654, -20},
|
||||
{1608, -15},
|
||||
{1551, -10},
|
||||
{1483, -5},
|
||||
{1404, 0},
|
||||
{1315, 5},
|
||||
{1218, 10},
|
||||
{1114, 15},
|
||||
{1007, 20},
|
||||
{900, 25},
|
||||
{795, 30},
|
||||
{696, 35},
|
||||
{605, 40},
|
||||
{522, 45},
|
||||
{448, 50},
|
||||
{383, 55},
|
||||
{327, 60},
|
||||
{278, 65},
|
||||
{237, 70},
|
||||
{202, 75},
|
||||
{172, 80},
|
||||
{146, 85},
|
||||
{125, 90},
|
||||
{107, 95},
|
||||
{92, 100},
|
||||
{79, 105},
|
||||
{68, 110},
|
||||
{59, 115},
|
||||
{51, 120},
|
||||
{44, 125}
|
||||
};
|
||||
|
||||
static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
|
||||
{
|
||||
return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
|
||||
@@ -553,159 +413,6 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vadc_map_voltage_temp(const struct vadc_map_pt *pts,
|
||||
u32 tablesize, s32 input, s64 *output)
|
||||
{
|
||||
bool descending = 1;
|
||||
u32 i = 0;
|
||||
|
||||
if (!pts)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if table is descending or ascending */
|
||||
if (tablesize > 1) {
|
||||
if (pts[0].x < pts[1].x)
|
||||
descending = 0;
|
||||
}
|
||||
|
||||
while (i < tablesize) {
|
||||
if ((descending) && (pts[i].x < input)) {
|
||||
/* table entry is less than measured*/
|
||||
/* value and table is descending, stop */
|
||||
break;
|
||||
} else if ((!descending) &&
|
||||
(pts[i].x > input)) {
|
||||
/* table entry is greater than measured*/
|
||||
/*value and table is ascending, stop */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
*output = pts[0].y;
|
||||
} else if (i == tablesize) {
|
||||
*output = pts[tablesize - 1].y;
|
||||
} else {
|
||||
/* result is between search_index and search_index-1 */
|
||||
/* interpolate linearly */
|
||||
*output = (((s32)((pts[i].y - pts[i - 1].y) *
|
||||
(input - pts[i - 1].x)) /
|
||||
(pts[i].x - pts[i - 1].x)) +
|
||||
pts[i - 1].y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vadc_scale_calib(struct vadc_priv *vadc, u16 adc_code,
|
||||
const struct vadc_channel_prop *prop,
|
||||
s64 *scale_voltage)
|
||||
{
|
||||
*scale_voltage = (adc_code -
|
||||
vadc->graph[prop->calibration].gnd);
|
||||
*scale_voltage *= vadc->graph[prop->calibration].dx;
|
||||
*scale_voltage = div64_s64(*scale_voltage,
|
||||
vadc->graph[prop->calibration].dy);
|
||||
if (prop->calibration == VADC_CALIB_ABSOLUTE)
|
||||
*scale_voltage +=
|
||||
vadc->graph[prop->calibration].dx;
|
||||
|
||||
if (*scale_voltage < 0)
|
||||
*scale_voltage = 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_volt(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop, u16 adc_code,
|
||||
int *result_uv)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
voltage = voltage * prescale->den;
|
||||
result = div64_s64(voltage, prescale->num);
|
||||
*result_uv = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_therm(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop, u16 adc_code,
|
||||
int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
if (prop->calibration == VADC_CALIB_ABSOLUTE)
|
||||
voltage = div64_s64(voltage, 1000);
|
||||
|
||||
vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
|
||||
ARRAY_SIZE(adcmap_100k_104ef_104fb),
|
||||
voltage, &result);
|
||||
result *= 1000;
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_die_temp(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0;
|
||||
u64 temp; /* Temporary variable for do_div */
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
if (voltage > 0) {
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
temp = voltage * prescale->den;
|
||||
do_div(temp, prescale->num * 2);
|
||||
voltage = temp;
|
||||
} else {
|
||||
voltage = 0;
|
||||
}
|
||||
|
||||
voltage -= KELVINMIL_CELSIUSMIL;
|
||||
*result_mdec = voltage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_chg_temp(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
voltage = voltage * prescale->den;
|
||||
voltage = div64_s64(voltage, prescale->num);
|
||||
voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
|
||||
voltage = (voltage + PMI_CHG_SCALE_2);
|
||||
result = div64_s64(voltage, 1000000);
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_decimation_from_dt(u32 value)
|
||||
{
|
||||
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
|
||||
value > VADC_DECIMATION_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return __ffs64(value / VADC_DECIMATION_MIN);
|
||||
}
|
||||
|
||||
static int vadc_prescaling_from_dt(u32 num, u32 den)
|
||||
{
|
||||
unsigned int pre;
|
||||
@@ -742,14 +449,6 @@ static int vadc_avg_samples_from_dt(u32 value)
|
||||
return __ffs64(value);
|
||||
}
|
||||
|
||||
static struct vadc_scale_fn scale_fn[] = {
|
||||
[SCALE_DEFAULT] = {vadc_scale_volt},
|
||||
[SCALE_THERM_100K_PULLUP] = {vadc_scale_therm},
|
||||
[SCALE_PMIC_THERM] = {vadc_scale_die_temp},
|
||||
[SCALE_XOTHERM] = {vadc_scale_therm},
|
||||
[SCALE_PMI_CHG_TEMP] = {vadc_scale_chg_temp},
|
||||
};
|
||||
|
||||
static int vadc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2,
|
||||
long mask)
|
||||
@@ -766,7 +465,13 @@ static int vadc_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
scale_fn[prop->scale_fn].scale(vadc, prop, adc_code, val);
|
||||
ret = qcom_vadc_scale(prop->scale_fn_type,
|
||||
&vadc->graph[prop->calibration],
|
||||
&vadc_prescale_ratios[prop->prescale],
|
||||
(prop->calibration == VADC_CALIB_ABSOLUTE),
|
||||
adc_code, val);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
@@ -809,7 +514,7 @@ struct vadc_channels {
|
||||
unsigned int prescale_index;
|
||||
enum iio_chan_type type;
|
||||
long info_mask;
|
||||
unsigned int scale_fn;
|
||||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
#define VADC_CHAN(_dname, _type, _mask, _pre, _scale) \
|
||||
@@ -818,7 +523,7 @@ struct vadc_channels {
|
||||
.prescale_index = _pre, \
|
||||
.type = _type, \
|
||||
.info_mask = _mask, \
|
||||
.scale_fn = _scale \
|
||||
.scale_fn_type = _scale \
|
||||
}, \
|
||||
|
||||
#define VADC_NO_CHAN(_dname, _type, _mask, _pre) \
|
||||
@@ -976,7 +681,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,decimation", &value);
|
||||
if (!ret) {
|
||||
ret = vadc_decimation_from_dt(value);
|
||||
ret = qcom_vadc_decimation_from_dt(value);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%02x invalid decimation %d\n",
|
||||
chan, value);
|
||||
@@ -1068,7 +773,7 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
|
||||
return ret;
|
||||
}
|
||||
|
||||
prop.scale_fn = vadc_chans[prop.channel].scale_fn;
|
||||
prop.scale_fn_type = vadc_chans[prop.channel].scale_fn_type;
|
||||
vadc->chan_props[index] = prop;
|
||||
|
||||
vadc_chan = &vadc_chans[prop.channel];
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "qcom-vadc-common.h"
|
||||
|
||||
/* Voltage to temperature */
|
||||
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
|
||||
{1758, -40},
|
||||
{1742, -35},
|
||||
{1719, -30},
|
||||
{1691, -25},
|
||||
{1654, -20},
|
||||
{1608, -15},
|
||||
{1551, -10},
|
||||
{1483, -5},
|
||||
{1404, 0},
|
||||
{1315, 5},
|
||||
{1218, 10},
|
||||
{1114, 15},
|
||||
{1007, 20},
|
||||
{900, 25},
|
||||
{795, 30},
|
||||
{696, 35},
|
||||
{605, 40},
|
||||
{522, 45},
|
||||
{448, 50},
|
||||
{383, 55},
|
||||
{327, 60},
|
||||
{278, 65},
|
||||
{237, 70},
|
||||
{202, 75},
|
||||
{172, 80},
|
||||
{146, 85},
|
||||
{125, 90},
|
||||
{107, 95},
|
||||
{92, 100},
|
||||
{79, 105},
|
||||
{68, 110},
|
||||
{59, 115},
|
||||
{51, 120},
|
||||
{44, 125}
|
||||
};
|
||||
|
||||
static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
|
||||
u32 tablesize, s32 input, s64 *output)
|
||||
{
|
||||
bool descending = 1;
|
||||
u32 i = 0;
|
||||
|
||||
if (!pts)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if table is descending or ascending */
|
||||
if (tablesize > 1) {
|
||||
if (pts[0].x < pts[1].x)
|
||||
descending = 0;
|
||||
}
|
||||
|
||||
while (i < tablesize) {
|
||||
if ((descending) && (pts[i].x < input)) {
|
||||
/* table entry is less than measured*/
|
||||
/* value and table is descending, stop */
|
||||
break;
|
||||
} else if ((!descending) &&
|
||||
(pts[i].x > input)) {
|
||||
/* table entry is greater than measured*/
|
||||
/*value and table is ascending, stop */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
*output = pts[0].y;
|
||||
} else if (i == tablesize) {
|
||||
*output = pts[tablesize - 1].y;
|
||||
} else {
|
||||
/* result is between search_index and search_index-1 */
|
||||
/* interpolate linearly */
|
||||
*output = (((s32)((pts[i].y - pts[i - 1].y) *
|
||||
(input - pts[i - 1].x)) /
|
||||
(pts[i].x - pts[i - 1].x)) +
|
||||
pts[i - 1].y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
|
||||
u16 adc_code,
|
||||
bool absolute,
|
||||
s64 *scale_voltage)
|
||||
{
|
||||
*scale_voltage = (adc_code - calib_graph->gnd);
|
||||
*scale_voltage *= calib_graph->dx;
|
||||
*scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
|
||||
if (absolute)
|
||||
*scale_voltage += calib_graph->dx;
|
||||
|
||||
if (*scale_voltage < 0)
|
||||
*scale_voltage = 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute, u16 adc_code,
|
||||
int *result_uv)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
voltage = voltage * prescale->den;
|
||||
result = div64_s64(voltage, prescale->num);
|
||||
*result_uv = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute, u16 adc_code,
|
||||
int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
int ret;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
if (absolute)
|
||||
voltage = div64_s64(voltage, 1000);
|
||||
|
||||
ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
|
||||
ARRAY_SIZE(adcmap_100k_104ef_104fb),
|
||||
voltage, &result);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
result *= 1000;
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0;
|
||||
u64 temp; /* Temporary variable for do_div */
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
if (voltage > 0) {
|
||||
temp = voltage * prescale->den;
|
||||
do_div(temp, prescale->num * 2);
|
||||
voltage = temp;
|
||||
} else {
|
||||
voltage = 0;
|
||||
}
|
||||
|
||||
voltage -= KELVINMIL_CELSIUSMIL;
|
||||
*result_mdec = voltage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
voltage = voltage * prescale->den;
|
||||
voltage = div64_s64(voltage, prescale->num);
|
||||
voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
|
||||
voltage = (voltage + PMI_CHG_SCALE_2);
|
||||
result = div64_s64(voltage, 1000000);
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
|
||||
const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result)
|
||||
{
|
||||
switch (scaletype) {
|
||||
case SCALE_DEFAULT:
|
||||
return qcom_vadc_scale_volt(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_THERM_100K_PULLUP:
|
||||
case SCALE_XOTHERM:
|
||||
return qcom_vadc_scale_therm(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_PMIC_THERM:
|
||||
return qcom_vadc_scale_die_temp(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_PMI_CHG_TEMP:
|
||||
return qcom_vadc_scale_chg_temp(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_vadc_scale);
|
||||
|
||||
int qcom_vadc_decimation_from_dt(u32 value)
|
||||
{
|
||||
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
|
||||
value > VADC_DECIMATION_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return __ffs64(value / VADC_DECIMATION_MIN);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Code shared between the different Qualcomm PMIC voltage ADCs
|
||||
*/
|
||||
|
||||
#ifndef QCOM_VADC_COMMON_H
|
||||
#define QCOM_VADC_COMMON_H
|
||||
|
||||
#define VADC_CONV_TIME_MIN_US 2000
|
||||
#define VADC_CONV_TIME_MAX_US 2100
|
||||
|
||||
/* Min ADC code represents 0V */
|
||||
#define VADC_MIN_ADC_CODE 0x6000
|
||||
/* Max ADC code represents full-scale range of 1.8V */
|
||||
#define VADC_MAX_ADC_CODE 0xa800
|
||||
|
||||
#define VADC_ABSOLUTE_RANGE_UV 625000
|
||||
#define VADC_RATIOMETRIC_RANGE 1800
|
||||
|
||||
#define VADC_DEF_PRESCALING 0 /* 1:1 */
|
||||
#define VADC_DEF_DECIMATION 0 /* 512 */
|
||||
#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
|
||||
#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
|
||||
#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
|
||||
|
||||
#define VADC_DECIMATION_MIN 512
|
||||
#define VADC_DECIMATION_MAX 4096
|
||||
|
||||
#define VADC_HW_SETTLE_DELAY_MAX 10000
|
||||
#define VADC_AVG_SAMPLES_MAX 512
|
||||
|
||||
#define KELVINMIL_CELSIUSMIL 273150
|
||||
|
||||
#define PMI_CHG_SCALE_1 -138890
|
||||
#define PMI_CHG_SCALE_2 391750000000LL
|
||||
|
||||
/**
|
||||
* struct vadc_map_pt - Map the graph representation for ADC channel
|
||||
* @x: Represent the ADC digitized code.
|
||||
* @y: Represent the physical data which can be temperature, voltage,
|
||||
* resistance.
|
||||
*/
|
||||
struct vadc_map_pt {
|
||||
s32 x;
|
||||
s32 y;
|
||||
};
|
||||
|
||||
/*
|
||||
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
|
||||
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
|
||||
* calibration.
|
||||
*/
|
||||
enum vadc_calibration {
|
||||
VADC_CALIB_ABSOLUTE = 0,
|
||||
VADC_CALIB_RATIOMETRIC
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_linear_graph - Represent ADC characteristics.
|
||||
* @dy: numerator slope to calculate the gain.
|
||||
* @dx: denominator slope to calculate the gain.
|
||||
* @gnd: A/D word of the ground reference used for the channel.
|
||||
*
|
||||
* Each ADC device has different offset and gain parameters which are
|
||||
* computed to calibrate the device.
|
||||
*/
|
||||
struct vadc_linear_graph {
|
||||
s32 dy;
|
||||
s32 dx;
|
||||
s32 gnd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
|
||||
* @num: the inverse numerator of the gain applied to the input channel.
|
||||
* @den: the inverse denominator of the gain applied to the input channel.
|
||||
*/
|
||||
struct vadc_prescale_ratio {
|
||||
u32 num;
|
||||
u32 den;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vadc_scale_fn_type - Scaling function to convert ADC code to
|
||||
* physical scaled units for the channel.
|
||||
* SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
|
||||
* SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
|
||||
* Uses a mapping table with 100K pullup.
|
||||
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
|
||||
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
|
||||
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
|
||||
*/
|
||||
enum vadc_scale_fn_type {
|
||||
SCALE_DEFAULT = 0,
|
||||
SCALE_THERM_100K_PULLUP,
|
||||
SCALE_PMIC_THERM,
|
||||
SCALE_XOTHERM,
|
||||
SCALE_PMI_CHG_TEMP,
|
||||
};
|
||||
|
||||
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
|
||||
const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec);
|
||||
|
||||
int qcom_vadc_decimation_from_dt(u32 value);
|
||||
|
||||
#endif /* QCOM_VADC_COMMON_H */
|
||||
@@ -60,6 +60,8 @@
|
||||
#define STM32F4_EOC BIT(1)
|
||||
|
||||
/* STM32F4_ADC_CR1 - bit fields */
|
||||
#define STM32F4_RES_SHIFT 24
|
||||
#define STM32F4_RES_MASK GENMASK(25, 24)
|
||||
#define STM32F4_SCAN BIT(8)
|
||||
#define STM32F4_EOCIE BIT(5)
|
||||
|
||||
@@ -141,6 +143,7 @@ struct stm32_adc_regs {
|
||||
* @lock: spinlock
|
||||
* @bufi: data buffer index
|
||||
* @num_conv: expected number of scan conversions
|
||||
* @res: data resolution (e.g. RES bitfield value)
|
||||
* @trigger_polarity: external trigger polarity (e.g. exten)
|
||||
* @dma_chan: dma channel
|
||||
* @rx_buf: dma rx buffer cpu address
|
||||
@@ -157,6 +160,7 @@ struct stm32_adc {
|
||||
spinlock_t lock; /* interrupt lock */
|
||||
unsigned int bufi;
|
||||
unsigned int num_conv;
|
||||
u32 res;
|
||||
u32 trigger_polarity;
|
||||
struct dma_chan *dma_chan;
|
||||
u8 *rx_buf;
|
||||
@@ -196,6 +200,11 @@ static const struct stm32_adc_chan_spec stm32f4_adc123_channels[] = {
|
||||
{ IIO_VOLTAGE, 15, "in15" },
|
||||
};
|
||||
|
||||
static const unsigned int stm32f4_adc_resolutions[] = {
|
||||
/* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */
|
||||
12, 10, 8, 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32f4_sq - describe regular sequence registers
|
||||
* - L: sequence len (register & bit field)
|
||||
@@ -302,6 +311,14 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc)
|
||||
stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_EOCIE);
|
||||
}
|
||||
|
||||
static void stm32_adc_set_res(struct stm32_adc *adc)
|
||||
{
|
||||
u32 val = stm32_adc_readl(adc, STM32F4_ADC_CR1);
|
||||
|
||||
val = (val & ~STM32F4_RES_MASK) | (adc->res << STM32F4_RES_SHIFT);
|
||||
stm32_adc_writel(adc, STM32F4_ADC_CR1, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_adc_start_conv() - Start conversions for regular channels.
|
||||
* @adc: stm32 adc instance
|
||||
@@ -870,11 +887,37 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
unsigned int i;
|
||||
u32 res;
|
||||
|
||||
if (of_property_read_u32(node, "assigned-resolution-bits", &res))
|
||||
res = stm32f4_adc_resolutions[0];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stm32f4_adc_resolutions); i++)
|
||||
if (res == stm32f4_adc_resolutions[i])
|
||||
break;
|
||||
if (i >= ARRAY_SIZE(stm32f4_adc_resolutions)) {
|
||||
dev_err(&indio_dev->dev, "Bad resolution: %u bits\n", res);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&indio_dev->dev, "Using %u bits resolution\n", res);
|
||||
adc->res = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan,
|
||||
const struct stm32_adc_chan_spec *channel,
|
||||
int scan_index)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
chan->type = channel->type;
|
||||
chan->channel = channel->channel;
|
||||
chan->datasheet_name = channel->name;
|
||||
@@ -883,7 +926,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
|
||||
chan->scan_type.sign = 'u';
|
||||
chan->scan_type.realbits = 12;
|
||||
chan->scan_type.realbits = stm32f4_adc_resolutions[adc->res];
|
||||
chan->scan_type.storagebits = 16;
|
||||
chan->ext_info = stm32_adc_ext_info;
|
||||
}
|
||||
@@ -1022,6 +1065,11 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32_adc_of_get_resolution(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_clk_disable;
|
||||
stm32_adc_set_res(adc);
|
||||
|
||||
ret = stm32_adc_chan_of_init(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_clk_disable;
|
||||
|
||||
@@ -85,6 +85,12 @@ static const struct gpadc_data sun6i_gpadc_data = {
|
||||
.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
|
||||
};
|
||||
|
||||
static const struct gpadc_data sun8i_a33_gpadc_data = {
|
||||
.temp_offset = -1662,
|
||||
.temp_scale = 162,
|
||||
.tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
|
||||
};
|
||||
|
||||
struct sun4i_gpadc_iio {
|
||||
struct iio_dev *indio_dev;
|
||||
struct completion completion;
|
||||
@@ -96,6 +102,7 @@ struct sun4i_gpadc_iio {
|
||||
unsigned int temp_data_irq;
|
||||
atomic_t ignore_temp_data_irq;
|
||||
const struct gpadc_data *data;
|
||||
bool no_irq;
|
||||
/* prevents concurrent reads of temperature and ADC */
|
||||
struct mutex mutex;
|
||||
};
|
||||
@@ -138,6 +145,23 @@ static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = {
|
||||
SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec sun8i_a33_gpadc_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.datasheet_name = "temp_adc",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config sun4i_gpadc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
|
||||
unsigned int irq)
|
||||
{
|
||||
@@ -247,6 +271,17 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
|
||||
{
|
||||
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
|
||||
|
||||
if (info->no_irq) {
|
||||
pm_runtime_get_sync(indio_dev->dev.parent);
|
||||
|
||||
regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
|
||||
|
||||
pm_runtime_mark_last_busy(indio_dev->dev.parent);
|
||||
pm_runtime_put_autosuspend(indio_dev->dev.parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
|
||||
}
|
||||
|
||||
@@ -454,31 +489,69 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_gpadc_probe(struct platform_device *pdev)
|
||||
static const struct of_device_id sun4i_gpadc_of_id[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun8i-a33-ths",
|
||||
.data = &sun8i_a33_gpadc_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
struct sun4i_gpadc_iio *info;
|
||||
struct iio_dev *indio_dev;
|
||||
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
|
||||
const struct of_device_id *of_dev;
|
||||
struct thermal_zone_device *tzd;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
struct sun4i_gpadc_dev *sun4i_gpadc_dev;
|
||||
|
||||
sun4i_gpadc_dev = dev_get_drvdata(pdev->dev.parent);
|
||||
of_dev = of_match_device(sun4i_gpadc_of_id, &pdev->dev);
|
||||
if (!of_dev)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
info->no_irq = true;
|
||||
info->data = (struct gpadc_data *)of_dev->data;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
|
||||
indio_dev->channels = sun8i_a33_gpadc_channels;
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
mutex_init(&info->mutex);
|
||||
info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&sun4i_gpadc_regmap_config);
|
||||
if (IS_ERR(info->regmap)) {
|
||||
ret = PTR_ERR(info->regmap);
|
||||
dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_THERMAL_OF))
|
||||
return 0;
|
||||
|
||||
tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, info,
|
||||
&sun4i_ts_tz_ops);
|
||||
if (IS_ERR(tzd))
|
||||
dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
|
||||
PTR_ERR(tzd));
|
||||
|
||||
return PTR_ERR_OR_ZERO(tzd);
|
||||
}
|
||||
|
||||
static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
|
||||
struct sun4i_gpadc_dev *sun4i_gpadc_dev =
|
||||
dev_get_drvdata(pdev->dev.parent);
|
||||
int ret;
|
||||
|
||||
info->no_irq = false;
|
||||
info->regmap = sun4i_gpadc_dev->regmap;
|
||||
info->indio_dev = indio_dev;
|
||||
init_completion(&info->completion);
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->dev.of_node = pdev->dev.of_node;
|
||||
indio_dev->info = &sun4i_gpadc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
|
||||
indio_dev->channels = sun4i_gpadc_channels;
|
||||
|
||||
@@ -519,8 +592,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev,
|
||||
"could not register thermal sensor: %ld\n",
|
||||
PTR_ERR(tzd));
|
||||
ret = PTR_ERR(tzd);
|
||||
goto err;
|
||||
return PTR_ERR(tzd);
|
||||
}
|
||||
} else {
|
||||
indio_dev->num_channels =
|
||||
@@ -528,36 +600,69 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
|
||||
indio_dev->channels = sun4i_gpadc_channels_no_temp;
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev,
|
||||
SUN4I_GPADC_AUTOSUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
|
||||
ret = sun4i_irq_init(pdev, "TEMP_DATA_PENDING",
|
||||
sun4i_gpadc_temp_data_irq_handler,
|
||||
"temp_data", &info->temp_data_irq,
|
||||
&info->ignore_temp_data_irq);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sun4i_irq_init(pdev, "FIFO_DATA_PENDING",
|
||||
sun4i_gpadc_fifo_data_irq_handler, "fifo_data",
|
||||
&info->fifo_data_irq, &info->ignore_fifo_data_irq);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
|
||||
ret = iio_map_array_register(indio_dev, sun4i_gpadc_hwmon_maps);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register iio map array\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_gpadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sun4i_gpadc_iio *info;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
mutex_init(&info->mutex);
|
||||
info->indio_dev = indio_dev;
|
||||
init_completion(&info->completion);
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->dev.of_node = pdev->dev.of_node;
|
||||
indio_dev->info = &sun4i_gpadc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
ret = sun4i_gpadc_probe_dt(pdev, indio_dev);
|
||||
else
|
||||
ret = sun4i_gpadc_probe_mfd(pdev, indio_dev);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev,
|
||||
SUN4I_GPADC_AUTOSUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "could not register the device\n");
|
||||
@@ -567,10 +672,9 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_map:
|
||||
if (IS_ENABLED(CONFIG_THERMAL_OF))
|
||||
if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
err:
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
@@ -580,10 +684,11 @@ err:
|
||||
static int sun4i_gpadc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (IS_ENABLED(CONFIG_THERMAL_OF))
|
||||
if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
return 0;
|
||||
@@ -599,6 +704,7 @@ static const struct platform_device_id sun4i_gpadc_id[] = {
|
||||
static struct platform_driver sun4i_gpadc_driver = {
|
||||
.driver = {
|
||||
.name = "sun4i-gpadc-iio",
|
||||
.of_match_table = sun4i_gpadc_of_id,
|
||||
.pm = &sun4i_gpadc_pm_ops,
|
||||
},
|
||||
.id_table = sun4i_gpadc_id,
|
||||
|
||||
@@ -138,6 +138,10 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
|
||||
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
|
||||
{
|
||||
pm_runtime_disable(&attrb->pdev->dev);
|
||||
pm_runtime_set_suspended(&attrb->pdev->dev);
|
||||
pm_runtime_put_noidle(&attrb->pdev->dev);
|
||||
|
||||
cancel_work_sync(&attrb->work);
|
||||
iio_trigger_unregister(attrb->trigger);
|
||||
iio_trigger_free(attrb->trigger);
|
||||
|
||||
@@ -284,6 +284,21 @@ config MCP4922
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mcp4922.
|
||||
|
||||
config STM32_DAC
|
||||
tristate "STMicroelectronics STM32 DAC"
|
||||
depends on (ARCH_STM32 && OF) || COMPILE_TEST
|
||||
depends on REGULATOR
|
||||
select STM32_DAC_CORE
|
||||
help
|
||||
Say yes here to build support for STMicroelectronics STM32 Digital
|
||||
to Analog Converter (DAC).
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called stm32-dac.
|
||||
|
||||
config STM32_DAC_CORE
|
||||
tristate
|
||||
|
||||
config VF610_DAC
|
||||
tristate "Vybrid vf610 DAC driver"
|
||||
depends on OF
|
||||
|
||||
@@ -30,4 +30,6 @@ obj-$(CONFIG_MAX517) += max517.o
|
||||
obj-$(CONFIG_MAX5821) += max5821.o
|
||||
obj-$(CONFIG_MCP4725) += mcp4725.o
|
||||
obj-$(CONFIG_MCP4922) += mcp4922.o
|
||||
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
|
||||
obj-$(CONFIG_STM32_DAC) += stm32-dac.o
|
||||
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user