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:
Greg Kroah-Hartman
2017-04-18 17:13:31 +02:00
35 changed files with 3709 additions and 444 deletions
@@ -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 = <&reg_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
View File
@@ -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
+4
View File
@@ -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
+307
View File
@@ -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
+15 -310
View File
@@ -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];
+230
View File
@@ -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);
+108
View File
@@ -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 */
+49 -1
View File
@@ -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;
+138 -32
View File
@@ -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);
+15
View File
@@ -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
+2
View File
@@ -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