1
0
Fork 0

Second set of IIO new device support, features and cleanups for the 4.21 cycle.

Staging graduation
 * ad2s90
   - Driver for this resolver to digital chip.
 
 New drivers and device support.
 * ad5686
   - Add support for ad5310r DAC and associated fix in value read back.
 * exynos-adc
   - Support for S5PV210 which is slightly different from other parts.
 * mcp41010
   - Driver supporting MCP41010, MCP41050, MCP41100, MCP42010, MCP42050 and
   MCP42100 microchip potentiometers.
 
 New ACPI ids.
 * ak8975
   - AKM9911 ACPI HID.
 * kxcjk-1013
   - KXJ2109 ACPI HID.
   - KIOX010A ACPI HID.
 
 New features
 * ad5933
   - Explicit DT binding.
 * ad2s90
   - Explicit DT binding including dropping spi setup that is done via dt
     in favour of verifying the settings form DT.
 * adt7316
   - Explicit DT binding and support for gpio, irq_flags etc.
 * stm32-adc
   - Runtime power management.
 
 Minor fixes and cleanups
 * core
   - Protect against missing info structure.
 * ad2s90
   - SPDX
   - Add documentation fo the mutex.
 * ad7280a
   - Check allocation failure.
   - Fix an accidental replacement of an error return.
 * adt7316
   - Switch some variables to be local and rename for consistency with other
     drivers.
   - Revert a false handling of 0 as an error introduced earlier this cycle.
 * bmi160
   - Use devm functions throughout probe() to avoid need for remove().
 * hid-sensor-hub
   - White space cleanup.
 * hts221
   - MAINTAINERS entry.
 * lis302
   - Use generic name in the DT binding doc.
 * Messon-saradc
   - Check for allocation error.
   - Fix some presented clock names that break clk debugfs.
 * qcom-spmi-adc
   - A fix for initialization of the prescale property. Came late in the
     cycle, so merge window is probably the best route for this.
 * st_lsm6dsx
   - Allow for variable read length to support wider range of slave devices.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAlwRULkRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FojIIQ/+PSR0V3gW/eXZIoVFcqbjqAYvYQQkK5rH
 zOstRvKkgs+gTTB1S+dhTQL80PJBrrfSDRB1E85fJ2hx2kh80k0/zukAG73PsIF0
 uqJazrHx5W6WeTj4xmN4rpLRG25DwkCHRMmDdfM6atCVhdz1bYSM56vEGAnXfVMf
 fPMbZ7EviN6EnKTtFSPI4F8BhVzesHAzIYGp+DYpMZdqa4nhr2dZyxVuRz3jpPEI
 xutODWVKP/0O7vQGBjSlCjx/BMSWGQM5+B0gandKzQULuMwHqi2QMXeD13pxaKQm
 Vy2cAEd6YLTGxIHKcw93qCWJjDZz06owvwMHvkoUmPTZXvPavLo+TyYia7rOTzPu
 IimDIPf0ci5qIDksxqtSiEzkFDF5YMyfnDJnAC8Ogm98NRC7FNnD5edXsc9sfI23
 CBOH5fdGoIV4lNxvuEarnFJ0VdV8ifY8tubrI2l0kf/v0D5tGbcddClFpennkfjf
 vjqmkBc2KgD+83SSNgSAcqUKbqxfh4JsXVPpHx8WMLDUA/4S3GcBwVF7fkLqwmCQ
 jEuF/zYOoGwvmzDNY1LSkhlWCE16MmXhu0yDQgekA0XLQ2ODynbkV3LQCwdq4dNR
 /ZMoBRJ9PSZC35sGkNcFIKm5Nw6Ibl8R1c7WEqxA8vkLhBjJ99CwIsK0M5YcHaak
 fCWXUnJzpF4=
 =+vyl
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Second set of IIO new device support, features and cleanups for the 4.21 cycle.

Staging graduation
* ad2s90
  - Driver for this resolver to digital chip.

New drivers and device support.
* ad5686
  - Add support for ad5310r DAC and associated fix in value read back.
* exynos-adc
  - Support for S5PV210 which is slightly different from other parts.
* mcp41010
  - Driver supporting MCP41010, MCP41050, MCP41100, MCP42010, MCP42050 and
  MCP42100 microchip potentiometers.

New ACPI ids.
* ak8975
  - AKM9911 ACPI HID.
* kxcjk-1013
  - KXJ2109 ACPI HID.
  - KIOX010A ACPI HID.

New features
* ad5933
  - Explicit DT binding.
* ad2s90
  - Explicit DT binding including dropping spi setup that is done via dt
    in favour of verifying the settings form DT.
* adt7316
  - Explicit DT binding and support for gpio, irq_flags etc.
* stm32-adc
  - Runtime power management.

Minor fixes and cleanups
* core
  - Protect against missing info structure.
* ad2s90
  - SPDX
  - Add documentation fo the mutex.
* ad7280a
  - Check allocation failure.
  - Fix an accidental replacement of an error return.
* adt7316
  - Switch some variables to be local and rename for consistency with other
    drivers.
  - Revert a false handling of 0 as an error introduced earlier this cycle.
* bmi160
  - Use devm functions throughout probe() to avoid need for remove().
* hid-sensor-hub
  - White space cleanup.
* hts221
  - MAINTAINERS entry.
* lis302
  - Use generic name in the DT binding doc.
* Messon-saradc
  - Check for allocation error.
  - Fix some presented clock names that break clk debugfs.
* qcom-spmi-adc
  - A fix for initialization of the prescale property. Came late in the
    cycle, so merge window is probably the best route for this.
* st_lsm6dsx
  - Allow for variable read length to support wider range of slave devices.

* tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (37 commits)
  iio: adc: qcom-spmi-adc5: Initialize prescale properly
  dt-bindings: iio: adc: exynos-adc: Add S5PV210 variant
  iio: adc: Allow selection of Exynos ADC on S5PV210
  iio: adc: exynos-adc: Add S5PV210 variant
  iio: bmi160: use all devm functions in probe
  iio: dac: ad5686: fix bit shift read register
  iio:dac:ad5686: Add AD5310R support
  Revert "Staging: iio: adt7316: Add an extra check for 'ret' equals to 0"
  dt-bindings: iio: accel: use a generic node name for lis302
  iio: core: check 'info' value before registering the device
  staging: iio: adc: ad7280a: fix overwrite of the returned value
  staging: iio: adc: ad7280a: check for devm_kasprint() failure
  iio: humidity: hts221: add entry in MAINTAINERS file
  iio: magnetometer: ak8975: Add the "AKM9911" ACPI HID
  staging:iio:ad2s90: Move out of staging
  staging:iio:ad2s90: Add comment to device state mutex
  staging:iio:ad2s90: Replace license text w/ SPDX identifier
  dt-bindings:iio:resolver: Add docs for ad2s90
  staging:iio:ad2s90: Add max frequency check at probe
  staging:iio:ad2s90: Remove spi setup that should be done via dt
  ...
hifive-unleashed-5.1
Greg Kroah-Hartman 2018-12-13 13:37:24 +01:00
commit c6cbcdea7a
37 changed files with 852 additions and 298 deletions

View File

@ -64,7 +64,7 @@ Optional properties for all bus drivers:
Example for a SPI device node:
lis302@0 {
accelerometer@0 {
compatible = "st,lis302dl-spi";
reg = <0>;
spi-max-frequency = <1000000>;
@ -89,7 +89,7 @@ Example for a SPI device node:
Example for a I2C device node:
lis331dlh: lis331dlh@18 {
lis331dlh: accelerometer@18 {
compatible = "st,lis331dlh", "st,lis3lv02d";
reg = <0x18>;
Vdd-supply = <&lis3_reg>;

View File

@ -11,7 +11,7 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
for exynos4412/5250 and s5pv210 controllers.
for exynos4412/5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
@ -28,6 +28,8 @@ Required properties:
the ADC in s3c2443 and compatibles
Must be "samsung,s3c6410-adc" for
the ADC in s3c6410 and compatibles
Must be "samsung,s5pv210-adc" for
the ADC in s5pv210 and compatibles
- reg: List of ADC register address range
- The base address and range of ADC register
- The base address and range of ADC_PHY register (every

View File

@ -0,0 +1,28 @@
* Microchip MCP41010/41050/41100/42010/42050/42100 Digital Potentiometer
Datasheet publicly available at:
http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"microchip,mcp41010"
"microchip,mcp41050"
"microchip,mcp41100"
"microchip,mcp42010"
"microchip,mcp42050"
"microchip,mcp42100"
Example:
potentiometer@0 {
compatible = "microchip,mcp41010";
reg = <0>;
spi-max-frequency = <500000>;
};

View File

@ -0,0 +1,31 @@
Analog Devices AD2S90 Resolver-to-Digital Converter
https://www.analog.com/en/products/ad2s90.html
Required properties:
- compatible: should be "adi,ad2s90"
- reg: SPI chip select number for the device
- spi-max-frequency: set maximum clock frequency, must be 830000
- spi-cpol and spi-cpha:
Either SPI mode (0,0) or (1,1) must be used, so specify none or both of
spi-cpha, spi-cpol.
See for more details:
Documentation/devicetree/bindings/spi/spi-bus.txt
Note about max frequency:
Chip's max frequency, as specified in its datasheet, is 2Mhz. But a 600ns
delay is expected between the application of a logic LO to CS and the
application of SCLK, as also specified. And since the delay is not
implemented in the spi code, to satisfy it, SCLK's period should be at most
2 * 600ns, so the max frequency should be 1 / (2 * 6e-7), which gives
roughly 830000Hz.
Example:
resolver@0 {
compatible = "adi,ad2s90";
reg = <0>;
spi-max-frequency = <830000>;
spi-cpol;
spi-cpha;
};

View File

@ -6866,6 +6866,14 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/htcpen.c
HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
L: linux-iio@vger.kernel.org
W: http://www.st.com/
S: Maintained
F: drivers/iio/humidity/hts221*
F: Documentation/devicetree/bindings/iio/humidity/hts221.txt
HUAWEI ETHERNET DRIVER
M: Aviad Krawczyk <aviad.krawczyk@huawei.com>
L: netdev@vger.kernel.org

View File

@ -1491,7 +1491,9 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ9000", KXCJ91008},
{"KIOX0009", KXTJ21009},
{"KIOX000A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
{"KXTJ1009", KXTJ21009},
{"KXJ2109", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
};

View File

@ -295,7 +295,7 @@ config EP93XX_ADC
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST)
depends on HAS_IOMEM
help
Core support for the ADC block found in the Samsung EXYNOS series

View File

@ -115,6 +115,7 @@
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
#define MAX_S5PV210_ADC_CHANNELS 10
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
@ -282,6 +283,16 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
.start_conv = exynos_adc_v1_start_conv,
};
static const struct exynos_adc_data exynos_adc_s5pv210_data = {
.num_channels = MAX_S5PV210_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
};
static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
unsigned long addr)
{
@ -478,6 +489,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
.compatible = "samsung,s5pv210-adc",
.data = &exynos_adc_s5pv210_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,

View File

@ -656,8 +656,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
struct clk_init_data init;
const char *clk_parents[1];
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div",
indio_dev->dev.of_node);
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
dev_name(indio_dev->dev.parent));
if (!init.name)
return -ENOMEM;
init.flags = 0;
init.ops = &clk_divider_ops;
clk_parents[0] = __clk_get_name(priv->clkin);
@ -675,8 +678,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
if (WARN_ON(IS_ERR(priv->adc_div_clk)))
return PTR_ERR(priv->adc_div_clk);
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en",
indio_dev->dev.of_node);
init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
dev_name(indio_dev->dev.parent));
if (!init.name)
return -ENOMEM;
init.flags = CLK_SET_RATE_PARENT;
init.ops = &clk_gate_ops;
clk_parents[0] = __clk_get_name(priv->adc_div_clk);

View File

@ -423,6 +423,7 @@ struct adc5_channels {
enum vadc_scale_fn_type scale_fn_type;
};
/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \
{ \
.datasheet_name = _dname, \
@ -443,63 +444,63 @@ struct adc5_channels {
_pre, _scale) \
static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 8,
SCALE_HW_CALIB_DEFAULT)
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1,
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0,
SCALE_HW_CALIB_PM5_CHG_TEMP)
/* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3,
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6,
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0,
SCALE_HW_CALIB_XOTHERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1,
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 0,
SCALE_HW_CALIB_PM5_SMB_TEMP)
};
static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3,
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
};
@ -558,6 +559,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
return ret;
}
prop->prescale = ret;
} else {
prop->prescale =
adc->data->adc_chans[prop->channel].prescale_index;
}
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);

View File

@ -16,6 +16,7 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -48,15 +49,19 @@
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset
* @ccr: common control register offset
* @eoc1: adc1 end of conversion flag in @csr
* @eoc2: adc2 end of conversion flag in @csr
* @eoc3: adc3 end of conversion flag in @csr
*/
struct stm32_adc_common_regs {
u32 csr;
u32 ccr;
u32 eoc1_msk;
u32 eoc2_msk;
u32 eoc3_msk;
@ -85,6 +90,7 @@ struct stm32_adc_priv_cfg {
* @vref: regulator reference
* @cfg: compatible configuration data
* @common: common data for all ADC instances
* @ccr_bak: backup CCR in low power mode
*/
struct stm32_adc_priv {
int irq[STM32_ADC_MAX_ADCS];
@ -94,6 +100,7 @@ struct stm32_adc_priv {
struct regulator *vref;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common;
u32 ccr_bak;
};
static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
@ -265,6 +272,7 @@ out:
/* STM32F4 common registers definitions */
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
@ -273,6 +281,7 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
};
@ -379,6 +388,61 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
}
}
static int stm32_adc_core_hw_start(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
int ret;
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
return ret;
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(dev, "bus clk enable failed\n");
goto err_regulator_disable;
}
}
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(dev, "adc clk enable failed\n");
goto err_bclk_disable;
}
}
writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr);
return 0;
err_bclk_disable:
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
return ret;
}
static void stm32_adc_core_hw_stop(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
/* Backup CCR that may be lost (depends on power state to achieve) */
priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
}
static int stm32_adc_probe(struct platform_device *pdev)
{
struct stm32_adc_priv *priv;
@ -393,6 +457,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
priv->cfg = (const struct stm32_adc_priv_cfg *)
of_match_device(dev->driver->of_match_table, dev)->data;
@ -410,67 +475,51 @@ static int stm32_adc_probe(struct platform_device *pdev)
return ret;
}
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref enable failed\n");
return ret;
}
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
goto err_regulator_disable;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
priv->aclk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk);
if (ret == -ENOENT) {
priv->aclk = NULL;
} else {
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
goto err_regulator_disable;
}
}
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_regulator_disable;
return ret;
}
priv->aclk = NULL;
}
priv->bclk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(priv->bclk)) {
ret = PTR_ERR(priv->bclk);
if (ret == -ENOENT) {
priv->bclk = NULL;
} else {
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
goto err_aclk_disable;
return ret;
}
priv->bclk = NULL;
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_aclk_disable;
}
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
ret = stm32_adc_core_hw_start(dev);
if (ret)
goto err_pm_stop;
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
goto err_hw_stop;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
ret = priv->cfg->clk_sel(pdev, priv);
if (ret < 0)
goto err_bclk_disable;
goto err_hw_stop;
ret = stm32_adc_irq_probe(pdev, priv);
if (ret < 0)
goto err_bclk_disable;
platform_set_drvdata(pdev, &priv->common);
goto err_hw_stop;
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
if (ret < 0) {
@ -478,21 +527,19 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_irq_remove;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_irq_remove:
stm32_adc_irq_remove(pdev, priv);
err_bclk_disable:
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
err_aclk_disable:
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
err_regulator_disable:
regulator_disable(priv->vref);
err_hw_stop:
stm32_adc_core_hw_stop(dev);
err_pm_stop:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
return ret;
}
@ -502,17 +549,39 @@ static int stm32_adc_remove(struct platform_device *pdev)
struct stm32_adc_common *common = platform_get_drvdata(pdev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
stm32_adc_irq_remove(pdev, priv);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
regulator_disable(priv->vref);
stm32_adc_core_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
#if defined(CONFIG_PM)
static int stm32_adc_core_runtime_suspend(struct device *dev)
{
stm32_adc_core_hw_stop(dev);
return 0;
}
static int stm32_adc_core_runtime_resume(struct device *dev)
{
return stm32_adc_core_hw_start(dev);
}
#endif
static const struct dev_pm_ops stm32_adc_core_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
stm32_adc_core_runtime_resume,
NULL)
};
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel,
@ -552,6 +621,7 @@ static struct platform_driver stm32_adc_driver = {
.driver = {
.name = "stm32-adc-core",
.of_match_table = stm32_adc_of_match,
.pm = &stm32_adc_core_pm_ops,
},
};
module_platform_driver(stm32_adc_driver);

View File

@ -22,6 +22,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
@ -148,6 +149,7 @@ enum stm32h7_adc_dmngt {
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
#define STM32_ADC_TIMEOUT_US 100000
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
#define STM32_ADC_HW_STOP_DELAY_MS 100
#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
@ -199,11 +201,13 @@ struct stm32_adc_trig_info {
* @calfact_s: Calibration offset for single ended channels
* @calfact_d: Calibration offset in differential
* @lincalfact: Linearity calibration factor
* @calibrated: Indicates calibration status
*/
struct stm32_adc_calib {
u32 calfact_s;
u32 calfact_d;
u32 lincalfact[STM32H7_LINCALFACT_NUM];
bool calibrated;
};
/**
@ -251,7 +255,6 @@ struct stm32_adc;
* @trigs: external trigger sources
* @clk_required: clock is required
* @has_vregready: vregready status flag presence
* @selfcalib: optional routine for self-calibration
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
* @stop_conv: routine to stop conversions
@ -264,7 +267,6 @@ struct stm32_adc_cfg {
struct stm32_adc_trig_info *trigs;
bool clk_required;
bool has_vregready;
int (*selfcalib)(struct stm32_adc *);
int (*prepare)(struct stm32_adc *);
void (*start_conv)(struct stm32_adc *, bool dma);
void (*stop_conv)(struct stm32_adc *);
@ -623,6 +625,47 @@ static void stm32_adc_set_res(struct stm32_adc *adc)
stm32_adc_writel(adc, res->reg, val);
}
static int stm32_adc_hw_stop(struct device *dev)
{
struct stm32_adc *adc = dev_get_drvdata(dev);
if (adc->cfg->unprepare)
adc->cfg->unprepare(adc);
if (adc->clk)
clk_disable_unprepare(adc->clk);
return 0;
}
static int stm32_adc_hw_start(struct device *dev)
{
struct stm32_adc *adc = dev_get_drvdata(dev);
int ret;
if (adc->clk) {
ret = clk_prepare_enable(adc->clk);
if (ret)
return ret;
}
stm32_adc_set_res(adc);
if (adc->cfg->prepare) {
ret = adc->cfg->prepare(adc);
if (ret)
goto err_clk_dis;
}
return 0;
err_clk_dis:
if (adc->clk)
clk_disable_unprepare(adc->clk);
return ret;
}
/**
* stm32f4_adc_start_conv() - Start conversions for regular channels.
* @adc: stm32 adc instance
@ -777,6 +820,7 @@ static void stm32h7_adc_disable(struct stm32_adc *adc)
/**
* stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result
* @adc: stm32 adc instance
* Note: Must be called once ADC is enabled, so LINCALRDYW[1..6] are writable
*/
static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
{
@ -784,11 +828,6 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
int i, ret;
u32 lincalrdyw_mask, val;
/* Enable adc so LINCALRDYW1..6 bits are writable */
ret = stm32h7_adc_enable(adc);
if (ret)
return ret;
/* Read linearity calibration */
lincalrdyw_mask = STM32H7_LINCALRDYW6;
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
@ -801,7 +840,7 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
100, STM32_ADC_TIMEOUT_US);
if (ret) {
dev_err(&indio_dev->dev, "Failed to read calfact\n");
goto disable;
return ret;
}
val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2);
@ -817,11 +856,9 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc)
adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT;
adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK);
adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT;
adc->cal.calibrated = true;
disable:
stm32h7_adc_disable(adc);
return ret;
return 0;
}
/**
@ -898,9 +935,9 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc)
#define STM32H7_ADC_CALIB_TIMEOUT_US 100000
/**
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC (from power down)
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC
* @adc: stm32 adc instance
* Exit from power down, calibrate ADC, then return to power down.
* Note: Must be called once ADC is out of power down.
*/
static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
{
@ -908,9 +945,8 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
int ret;
u32 val;
ret = stm32h7_adc_exit_pwr_down(adc);
if (ret)
return ret;
if (adc->cal.calibrated)
return true;
/*
* Select calibration mode:
@ -927,7 +963,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
dev_err(&indio_dev->dev, "calibration failed\n");
goto pwr_dwn;
goto out;
}
/*
@ -944,18 +980,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
dev_err(&indio_dev->dev, "calibration failed\n");
goto pwr_dwn;
goto out;
}
out:
stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
STM32H7_ADCALDIF | STM32H7_ADCALLIN);
/* Read calibration result for future reference */
ret = stm32h7_adc_read_selfcalib(adc);
pwr_dwn:
stm32h7_adc_enter_pwr_down(adc);
return ret;
}
@ -972,19 +1003,28 @@ pwr_dwn:
*/
static int stm32h7_adc_prepare(struct stm32_adc *adc)
{
int ret;
int calib, ret;
ret = stm32h7_adc_exit_pwr_down(adc);
if (ret)
return ret;
ret = stm32h7_adc_selfcalib(adc);
if (ret < 0)
goto pwr_dwn;
calib = ret;
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(adc);
if (ret)
goto pwr_dwn;
ret = stm32h7_adc_restore_selfcalib(adc);
/* Either restore or read calibration result for future reference */
if (calib)
ret = stm32h7_adc_restore_selfcalib(adc);
else
ret = stm32h7_adc_read_selfcalib(adc);
if (ret)
goto disable;
@ -1174,6 +1214,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
int *res)
{
struct stm32_adc *adc = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
const struct stm32_adc_regspec *regs = adc->cfg->regs;
long timeout;
u32 val;
@ -1183,10 +1224,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
adc->bufi = 0;
if (adc->cfg->prepare) {
ret = adc->cfg->prepare(adc);
if (ret)
return ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
/* Apply sampling time settings */
@ -1224,8 +1265,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
stm32_adc_conv_irq_disable(adc);
if (adc->cfg->unprepare)
adc->cfg->unprepare(adc);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@ -1333,15 +1374,22 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct stm32_adc *adc = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
int ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength);
ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask);
if (ret)
return ret;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
return ret;
}
static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
@ -1371,12 +1419,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned *readval)
{
struct stm32_adc *adc = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
int ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
if (!readval)
stm32_adc_writel(adc, reg, writeval);
else
*readval = stm32_adc_readl(adc, reg);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
@ -1459,21 +1518,22 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev)
return 0;
}
static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
int ret;
if (adc->cfg->prepare) {
ret = adc->cfg->prepare(adc);
if (ret)
return ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
ret = stm32_adc_set_trig(indio_dev, indio_dev->trig);
if (ret) {
dev_err(&indio_dev->dev, "Can't set trigger\n");
goto err_unprepare;
goto err_pm_put;
}
ret = stm32_adc_dma_start(indio_dev);
@ -1482,10 +1542,6 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
goto err_clr_trig;
}
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret < 0)
goto err_stop_dma;
/* Reset adc buffer index */
adc->bufi = 0;
@ -1496,39 +1552,58 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
return 0;
err_stop_dma:
if (adc->dma_chan)
dmaengine_terminate_all(adc->dma_chan);
err_clr_trig:
stm32_adc_set_trig(indio_dev, NULL);
err_unprepare:
if (adc->cfg->unprepare)
adc->cfg->unprepare(adc);
err_pm_put:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
{
int ret;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret < 0)
return ret;
ret = __stm32_adc_buffer_postenable(indio_dev);
if (ret < 0)
iio_triggered_buffer_predisable(indio_dev);
return ret;
}
static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
int ret;
struct device *dev = indio_dev->dev.parent;
adc->cfg->stop_conv(adc);
if (!adc->dma_chan)
stm32_adc_conv_irq_disable(adc);
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
dev_err(&indio_dev->dev, "predisable failed\n");
if (adc->dma_chan)
dmaengine_terminate_all(adc->dma_chan);
if (stm32_adc_set_trig(indio_dev, NULL))
dev_err(&indio_dev->dev, "Can't clear trigger\n");
if (adc->cfg->unprepare)
adc->cfg->unprepare(adc);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
{
int ret;
__stm32_adc_buffer_predisable(indio_dev);
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
dev_err(&indio_dev->dev, "predisable failed\n");
return ret;
}
@ -1867,32 +1942,17 @@ static int stm32_adc_probe(struct platform_device *pdev)
}
}
if (adc->clk) {
ret = clk_prepare_enable(adc->clk);
if (ret < 0) {
dev_err(&pdev->dev, "clk enable failed\n");
return ret;
}
}
ret = stm32_adc_of_get_resolution(indio_dev);
if (ret < 0)
goto err_clk_disable;
stm32_adc_set_res(adc);
if (adc->cfg->selfcalib) {
ret = adc->cfg->selfcalib(adc);
if (ret)
goto err_clk_disable;
}
return ret;
ret = stm32_adc_chan_of_init(indio_dev);
if (ret < 0)
goto err_clk_disable;
return ret;
ret = stm32_adc_dma_request(indio_dev);
if (ret < 0)
goto err_clk_disable;
return ret;
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time,
@ -1903,15 +1963,35 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_dma_disable;
}
/* Get stm32-adc-core PM online */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
ret = stm32_adc_hw_start(dev);
if (ret)
goto err_buffer_cleanup;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "iio dev register failed\n");
goto err_buffer_cleanup;
goto err_hw_stop;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_hw_stop:
stm32_adc_hw_stop(dev);
err_buffer_cleanup:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
iio_triggered_buffer_cleanup(indio_dev);
err_dma_disable:
@ -1921,9 +2001,6 @@ err_dma_disable:
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
}
err_clk_disable:
if (adc->clk)
clk_disable_unprepare(adc->clk);
return ret;
}
@ -1933,7 +2010,12 @@ static int stm32_adc_remove(struct platform_device *pdev)
struct stm32_adc *adc = platform_get_drvdata(pdev);
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
pm_runtime_get_sync(&pdev->dev);
iio_device_unregister(indio_dev);
stm32_adc_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
iio_triggered_buffer_cleanup(indio_dev);
if (adc->dma_chan) {
dma_free_coherent(adc->dma_chan->device->dev,
@ -1941,12 +2023,62 @@ static int stm32_adc_remove(struct platform_device *pdev)
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
}
if (adc->clk)
clk_disable_unprepare(adc->clk);
return 0;
}
#if defined(CONFIG_PM_SLEEP)
static int stm32_adc_suspend(struct device *dev)
{
struct stm32_adc *adc = dev_get_drvdata(dev);
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
if (iio_buffer_enabled(indio_dev))
__stm32_adc_buffer_predisable(indio_dev);
return pm_runtime_force_suspend(dev);
}
static int stm32_adc_resume(struct device *dev)
{
struct stm32_adc *adc = dev_get_drvdata(dev);
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
if (!iio_buffer_enabled(indio_dev))
return 0;
ret = stm32_adc_update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
if (ret < 0)
return ret;
return __stm32_adc_buffer_postenable(indio_dev);
}
#endif
#if defined(CONFIG_PM)
static int stm32_adc_runtime_suspend(struct device *dev)
{
return stm32_adc_hw_stop(dev);
}
static int stm32_adc_runtime_resume(struct device *dev)
{
return stm32_adc_hw_start(dev);
}
#endif
static const struct dev_pm_ops stm32_adc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume)
SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume,
NULL)
};
static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.regs = &stm32f4_adc_regspec,
.adc_info = &stm32f4_adc_info,
@ -1961,7 +2093,6 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.regs = &stm32h7_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
.selfcalib = stm32h7_adc_selfcalib,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@ -1974,7 +2105,6 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
.has_vregready = true,
.selfcalib = stm32h7_adc_selfcalib,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@ -1996,6 +2126,7 @@ static struct platform_driver stm32_adc_driver = {
.driver = {
.name = "stm32-adc",
.of_match_table = stm32_adc_of_match,
.pm = &stm32_adc_pm_ops,
},
};
module_platform_driver(stm32_adc_driver);

View File

@ -336,7 +336,7 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0,
scale1 = scale1 % pow_10(8 - i);
}
*val0 += res;
*val1 = scale1 * pow_10(exp);
*val1 = scale1 * pow_10(exp);
} else if (exp < 0) {
exp = abs(exp);
if (exp > 9) {

View File

@ -19,6 +19,12 @@ static int ad5686_spi_write(struct ad5686_state *st,
u8 tx_len, *buf;
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
val);
buf = &st->data[0].d8[0];
tx_len = 2;
break;
case AD5683_REGMAP:
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5683_DATA(val));
@ -56,10 +62,18 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
u8 cmd = 0;
int ret;
if (st->chip_info->regmap_type == AD5686_REGMAP)
cmd = AD5686_CMD_READBACK_ENABLE;
else if (st->chip_info->regmap_type == AD5683_REGMAP)
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
return -ENOTSUPP;
case AD5683_REGMAP:
cmd = AD5686_CMD_READBACK_ENABLE_V2;
break;
case AD5686_REGMAP:
cmd = AD5686_CMD_READBACK_ENABLE;
break;
default:
return -EINVAL;
}
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr));
@ -86,6 +100,7 @@ static int ad5686_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id ad5686_spi_id[] = {
{"ad5310r", ID_AD5310R},
{"ad5672r", ID_AD5672R},
{"ad5676", ID_AD5676},
{"ad5676r", ID_AD5676R},

View File

@ -83,6 +83,10 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
shift = 9;
ref_bit_msk = AD5310_REF_BIT_MSK;
break;
case AD5683_REGMAP:
shift = 13;
ref_bit_msk = AD5683_REF_BIT_MSK;
@ -124,7 +128,8 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
@ -221,6 +226,7 @@ static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(7, 7, bits, _shift), \
}
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
@ -232,6 +238,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
[ID_AD5310R] = {
.channels = ad5310r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5310_REGMAP,
},
[ID_AD5311R] = {
.channels = ad5311r_channels,
.int_vref_mv = 2500,
@ -419,6 +431,11 @@ int ad5686_probe(struct device *dev,
indio_dev->num_channels = st->chip_info->num_channels;
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5310_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
break;
case AD5683_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5683_REF_BIT_MSK;

View File

@ -13,7 +13,10 @@
#include <linux/mutex.h>
#include <linux/kernel.h>
#define AD5310_CMD(x) ((x) << 12)
#define AD5683_DATA(x) ((x) << 4)
#define AD5686_ADDR(x) ((x) << 16)
#define AD5686_CMD(x) ((x) << 20)
@ -38,6 +41,8 @@
#define AD5686_CMD_CONTROL_REG 0x4
#define AD5686_CMD_READBACK_ENABLE_V2 0x5
#define AD5310_REF_BIT_MSK BIT(8)
#define AD5683_REF_BIT_MSK BIT(12)
#define AD5693_REF_BIT_MSK BIT(12)
@ -45,6 +50,7 @@
* ad5686_supported_device_ids:
*/
enum ad5686_supported_device_ids {
ID_AD5310R,
ID_AD5311R,
ID_AD5671R,
ID_AD5672R,
@ -72,6 +78,7 @@ enum ad5686_supported_device_ids {
};
enum ad5686_regmap_type {
AD5310_REGMAP,
AD5683_REGMAP,
AD5686_REGMAP,
AD5693_REGMAP

View File

@ -6,6 +6,5 @@ extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
void bmi160_core_remove(struct device *dev);
#endif /* BMI160_H_ */

View File

@ -542,10 +542,12 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
return 0;
}
static void bmi160_chip_uninit(struct bmi160_data *data)
static void bmi160_chip_uninit(void *data)
{
bmi160_set_mode(data, BMI160_GYRO, false);
bmi160_set_mode(data, BMI160_ACCEL, false);
struct bmi160_data *bmi_data = data;
bmi160_set_mode(bmi_data, BMI160_GYRO, false);
bmi160_set_mode(bmi_data, BMI160_ACCEL, false);
}
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
@ -567,6 +569,10 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data);
if (ret < 0)
return ret;
if (!name && ACPI_HANDLE(dev))
name = bmi160_match_acpi_device(dev);
@ -577,35 +583,19 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmi160_info;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bmi160_trigger_handler, NULL);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
bmi160_trigger_handler, NULL);
if (ret < 0)
goto uninit;
return ret;
ret = iio_device_register(indio_dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0)
goto buffer_cleanup;
return ret;
return 0;
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
uninit:
bmi160_chip_uninit(data);
return ret;
}
EXPORT_SYMBOL_GPL(bmi160_core_probe);
void bmi160_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmi160_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
bmi160_chip_uninit(data);
}
EXPORT_SYMBOL_GPL(bmi160_core_remove);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
MODULE_DESCRIPTION("Bosch BMI160 driver");
MODULE_LICENSE("GPL v2");

View File

@ -38,13 +38,6 @@ static int bmi160_i2c_probe(struct i2c_client *client,
return bmi160_core_probe(&client->dev, regmap, name, false);
}
static int bmi160_i2c_remove(struct i2c_client *client)
{
bmi160_core_remove(&client->dev);
return 0;
}
static const struct i2c_device_id bmi160_i2c_id[] = {
{"bmi160", 0},
{}
@ -72,7 +65,6 @@ static struct i2c_driver bmi160_i2c_driver = {
.of_match_table = of_match_ptr(bmi160_of_match),
},
.probe = bmi160_i2c_probe,
.remove = bmi160_i2c_remove,
.id_table = bmi160_i2c_id,
};
module_i2c_driver(bmi160_i2c_driver);

View File

@ -29,13 +29,6 @@ static int bmi160_spi_probe(struct spi_device *spi)
return bmi160_core_probe(&spi->dev, regmap, id->name, true);
}
static int bmi160_spi_remove(struct spi_device *spi)
{
bmi160_core_remove(&spi->dev);
return 0;
}
static const struct spi_device_id bmi160_spi_id[] = {
{"bmi160", 0},
{}
@ -58,7 +51,6 @@ MODULE_DEVICE_TABLE(of, bmi160_of_match);
static struct spi_driver bmi160_spi_driver = {
.probe = bmi160_spi_probe,
.remove = bmi160_spi_remove,
.id_table = bmi160_spi_id,
.driver = {
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),

View File

@ -432,8 +432,8 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
struct iio_chan_spec const *ch,
int *val)
{
int err, delay, len = ch->scan_type.realbits >> 3;
__le16 data;
int err, delay, len;
u8 data[4];
err = st_lsm6dsx_shub_set_enable(sensor, true);
if (err < 0)
@ -442,15 +442,17 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
delay = 1000000 / sensor->odr;
usleep_range(delay, 2 * delay);
err = st_lsm6dsx_shub_read(sensor, ch->address, (u8 *)&data, len);
if (err < 0)
return err;
len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3);
err = st_lsm6dsx_shub_read(sensor, ch->address, data, len);
st_lsm6dsx_shub_set_enable(sensor, false);
if (err < 0)
return err;
switch (len) {
case 2:
*val = (s16)le16_to_cpu(data);
*val = (s16)le16_to_cpu(*((__le16 *)data));
break;
default:
return -EINVAL;

View File

@ -1671,6 +1671,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (ret < 0)
return ret;
if (!indio_dev->info)
return -EINVAL;
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);

View File

@ -790,6 +790,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"INVN6500", AK8963},
{"AK009911", AK09911},
{"AK09911", AK09911},
{"AKM9911", AK09911},
{"AK09912", AK09912},
{ },
};

View File

@ -90,6 +90,18 @@ config MCP4531
To compile this driver as a module, choose M here: the
module will be called mcp4531.
config MCP41010
tristate "Microchip MCP41xxx/MCP42xxx Digital Potentiometer driver"
depends on SPI
help
Say yes here to build support for the Microchip
MCP41010, MCP41050, MCP41100,
MCP42010, MCP42050, MCP42100
digital potentiometer chips.
To compile this driver as a module, choose M here: the
module will be called mcp41010.
config TPL0102
tristate "Texas Instruments digital potentiometer driver"
depends on I2C

View File

@ -11,4 +11,5 @@ obj-$(CONFIG_MAX5487) += max5487.o
obj-$(CONFIG_MCP4018) += mcp4018.o
obj-$(CONFIG_MCP4131) += mcp4131.o
obj-$(CONFIG_MCP4531) += mcp4531.o
obj-$(CONFIG_MCP41010) += mcp41010.o
obj-$(CONFIG_TPL0102) += tpl0102.o

View File

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Industrial I/O driver for Microchip digital potentiometers
*
* Copyright (c) 2018 Chris Coffey <cmc@babblebit.net>
* Based on: Slawomir Stepien's code from mcp4131.c
*
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
*
* DEVID #Wipers #Positions Resistance (kOhm)
* mcp41010 1 256 10
* mcp41050 1 256 50
* mcp41100 1 256 100
* mcp42010 2 256 10
* mcp42050 2 256 50
* mcp42100 2 256 100
*/
#include <linux/cache.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#define MCP41010_MAX_WIPERS 2
#define MCP41010_WRITE BIT(4)
#define MCP41010_WIPER_MAX 255
#define MCP41010_WIPER_CHANNEL BIT(0)
struct mcp41010_cfg {
char name[16];
int wipers;
int kohms;
};
enum mcp41010_type {
MCP41010,
MCP41050,
MCP41100,
MCP42010,
MCP42050,
MCP42100,
};
static const struct mcp41010_cfg mcp41010_cfg[] = {
[MCP41010] = { .name = "mcp41010", .wipers = 1, .kohms = 10, },
[MCP41050] = { .name = "mcp41050", .wipers = 1, .kohms = 50, },
[MCP41100] = { .name = "mcp41100", .wipers = 1, .kohms = 100, },
[MCP42010] = { .name = "mcp42010", .wipers = 2, .kohms = 10, },
[MCP42050] = { .name = "mcp42050", .wipers = 2, .kohms = 50, },
[MCP42100] = { .name = "mcp42100", .wipers = 2, .kohms = 100, },
};
struct mcp41010_data {
struct spi_device *spi;
const struct mcp41010_cfg *cfg;
struct mutex lock; /* Protect write sequences */
unsigned int value[MCP41010_MAX_WIPERS]; /* Cache wiper values */
u8 buf[2] ____cacheline_aligned;
};
#define MCP41010_CHANNEL(ch) { \
.type = IIO_RESISTANCE, \
.indexed = 1, \
.output = 1, \
.channel = (ch), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mcp41010_channels[] = {
MCP41010_CHANNEL(0),
MCP41010_CHANNEL(1),
};
static int mcp41010_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mcp41010_data *data = iio_priv(indio_dev);
int channel = chan->channel;
switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = data->value[channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 1000 * data->cfg->kohms;
*val2 = MCP41010_WIPER_MAX;
return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
}
static int mcp41010_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int err;
struct mcp41010_data *data = iio_priv(indio_dev);
int channel = chan->channel;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
if (val > MCP41010_WIPER_MAX || val < 0)
return -EINVAL;
mutex_lock(&data->lock);
data->buf[0] = MCP41010_WIPER_CHANNEL << channel;
data->buf[0] |= MCP41010_WRITE;
data->buf[1] = val & 0xff;
err = spi_write(data->spi, data->buf, sizeof(data->buf));
if (!err)
data->value[channel] = val;
mutex_unlock(&data->lock);
return err;
}
static const struct iio_info mcp41010_info = {
.read_raw = mcp41010_read_raw,
.write_raw = mcp41010_write_raw,
};
static int mcp41010_probe(struct spi_device *spi)
{
int err;
struct device *dev = &spi->dev;
struct mcp41010_data *data;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
data->spi = spi;
data->cfg = of_device_get_match_data(&spi->dev);
if (!data->cfg)
data->cfg = &mcp41010_cfg[spi_get_device_id(spi)->driver_data];
mutex_init(&data->lock);
indio_dev->dev.parent = dev;
indio_dev->info = &mcp41010_info;
indio_dev->channels = mcp41010_channels;
indio_dev->num_channels = data->cfg->wipers;
indio_dev->name = data->cfg->name;
err = devm_iio_device_register(dev, indio_dev);
if (err)
dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
return err;
}
static const struct of_device_id mcp41010_match[] = {
{ .compatible = "microchip,mcp41010", .data = &mcp41010_cfg[MCP41010] },
{ .compatible = "microchip,mcp41050", .data = &mcp41010_cfg[MCP41050] },
{ .compatible = "microchip,mcp41100", .data = &mcp41010_cfg[MCP41100] },
{ .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] },
{ .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] },
{ .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] },
{}
};
MODULE_DEVICE_TABLE(of, mcp41010_match);
static const struct spi_device_id mcp41010_id[] = {
{ "mcp41010", MCP41010 },
{ "mcp41050", MCP41050 },
{ "mcp41100", MCP41100 },
{ "mcp42010", MCP42010 },
{ "mcp42050", MCP42050 },
{ "mcp42100", MCP42100 },
{}
};
MODULE_DEVICE_TABLE(spi, mcp41010_id);
static struct spi_driver mcp41010_driver = {
.driver = {
.name = "mcp41010",
.of_match_table = mcp41010_match,
},
.probe = mcp41010_probe,
.id_table = mcp41010_id,
};
module_spi_driver(mcp41010_driver);
MODULE_AUTHOR("Chris Coffey <cmc@babblebit.net>");
MODULE_DESCRIPTION("MCP41010 digital potentiometer");
MODULE_LICENSE("GPL v2");

View File

@ -3,6 +3,16 @@
#
menu "Resolver to digital converters"
config AD2S90
tristate "Analog Devices ad2s90 driver"
depends on SPI
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s90, provides direct access via sysfs.
To compile this driver as a module, choose M here: the
module will be called ad2s90.
config AD2S1200
tristate "Analog Devices ad2s1200/ad2s1205 driver"
depends on SPI

View File

@ -2,4 +2,5 @@
# Makefile for Resolver/Synchro drivers
#
obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S1200) += ad2s1200.o

View File

@ -1,12 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90
*
* Copyright (c) 2010-2010 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/types.h>
#include <linux/mutex.h>
@ -19,8 +15,14 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/*
* Although chip's max frequency is 2Mhz, it needs 600ns between CS and the
* first falling edge of SCLK, so frequency should be at most 1 / (2 * 6e-7)
*/
#define AD2S90_MAX_SPI_FREQ_HZ 830000
struct ad2s90_state {
struct mutex lock;
struct mutex lock; /* lock to protect rx buffer */
struct spi_device *sdev;
u8 rx[2] ____cacheline_aligned;
};
@ -77,7 +79,12 @@ static int ad2s90_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad2s90_state *st;
int ret;
if (spi->max_speed_hz > AD2S90_MAX_SPI_FREQ_HZ) {
dev_err(&spi->dev, "SPI CLK, %d Hz exceeds %d Hz\n",
spi->max_speed_hz, AD2S90_MAX_SPI_FREQ_HZ);
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@ -94,19 +101,15 @@ static int ad2s90_probe(struct spi_device *spi)
indio_dev->num_channels = 1;
indio_dev->name = spi_get_device_id(spi)->name;
/* need 600ns between CS and the first falling edge of SCLK */
spi->max_speed_hz = 830000;
spi->mode = SPI_MODE_3;
ret = spi_setup(spi);
if (ret < 0) {
dev_err(&spi->dev, "spi_setup failed!\n");
return ret;
}
return devm_iio_device_register(indio_dev->dev.parent, indio_dev);
}
static const struct of_device_id ad2s90_of_match[] = {
{ .compatible = "adi,ad2s90", },
{}
};
MODULE_DEVICE_TABLE(of, ad2s90_of_match);
static const struct spi_device_id ad2s90_id[] = {
{ "ad2s90" },
{}
@ -116,6 +119,7 @@ MODULE_DEVICE_TABLE(spi, ad2s90_id);
static struct spi_driver ad2s90_driver = {
.driver = {
.name = "ad2s90",
.of_match_table = ad2s90_of_match,
},
.probe = ad2s90_probe,
.id_table = ad2s90_id,

View File

@ -561,6 +561,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
{
int dev, ch, cnt;
unsigned int index;
struct iio_dev_attr *iio_attr;
st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) *
(st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
@ -571,37 +572,35 @@ static int ad7280_attr_init(struct ad7280_state *st)
for (dev = 0, cnt = 0; dev <= st->slave_num; dev++)
for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6;
ch++, cnt++) {
iio_attr = &st->iio_attr[cnt];
index = dev * AD7280A_CELLS_PER_DEV + ch;
st->iio_attr[cnt].address =
ad7280a_devaddr(dev) << 8 | ch;
st->iio_attr[cnt].dev_attr.attr.mode =
0644;
st->iio_attr[cnt].dev_attr.show =
ad7280_show_balance_sw;
st->iio_attr[cnt].dev_attr.store =
ad7280_store_balance_sw;
st->iio_attr[cnt].dev_attr.attr.name =
iio_attr->address = ad7280a_devaddr(dev) << 8 | ch;
iio_attr->dev_attr.attr.mode = 0644;
iio_attr->dev_attr.show = ad7280_show_balance_sw;
iio_attr->dev_attr.store = ad7280_store_balance_sw;
iio_attr->dev_attr.attr.name =
devm_kasprintf(&st->spi->dev, GFP_KERNEL,
"in%d-in%d_balance_switch_en",
index, index + 1);
ad7280_attributes[cnt] =
&st->iio_attr[cnt].dev_attr.attr;
if (!iio_attr->dev_attr.attr.name)
return -ENOMEM;
ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
cnt++;
st->iio_attr[cnt].address =
ad7280a_devaddr(dev) << 8 |
iio_attr = &st->iio_attr[cnt];
iio_attr->address = ad7280a_devaddr(dev) << 8 |
(AD7280A_CB1_TIMER + ch);
st->iio_attr[cnt].dev_attr.attr.mode =
0644;
st->iio_attr[cnt].dev_attr.show =
ad7280_show_balance_timer;
st->iio_attr[cnt].dev_attr.store =
ad7280_store_balance_timer;
st->iio_attr[cnt].dev_attr.attr.name =
iio_attr->dev_attr.attr.mode = 0644;
iio_attr->dev_attr.show = ad7280_show_balance_timer;
iio_attr->dev_attr.store = ad7280_store_balance_timer;
iio_attr->dev_attr.attr.name =
devm_kasprintf(&st->spi->dev, GFP_KERNEL,
"in%d-in%d_balance_timer",
index, index + 1);
ad7280_attributes[cnt] =
&st->iio_attr[cnt].dev_attr.attr;
if (!iio_attr->dev_attr.attr.name)
return -ENOMEM;
ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
}
ad7280_attributes[cnt] = NULL;
@ -880,15 +879,15 @@ static int ad7280_probe(struct spi_device *spi)
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
if (ret)
return ret;
st->slave_num = ret;
st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH;
st->cell_threshhigh = 0xFF;
st->aux_threshhigh = 0xFF;
ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
if (ret)
return ret;
/*
* Total Conversion Time = ((tACQ + tCONV) *
* (Number of Conversions per Part))

View File

@ -30,10 +30,6 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
}
ret = i2c_smbus_read_byte(client);
if (!ret)
return -EIO;
if (ret < 0) {
dev_err(&cl->dev, "I2C read error\n");
return ret;
@ -104,7 +100,6 @@ static int adt7316_i2c_probe(struct i2c_client *client,
struct adt7316_bus bus = {
.client = client,
.irq = client->irq,
.irq_flags = IRQF_TRIGGER_LOW,
.read = adt7316_i2c_read,
.write = adt7316_i2c_write,
.multi_read = adt7316_i2c_multi_read,
@ -126,9 +121,22 @@ static const struct i2c_device_id adt7316_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
static const struct of_device_id adt7316_of_match[] = {
{ .compatible = "adi,adt7316" },
{ .compatible = "adi,adt7317" },
{ .compatible = "adi,adt7318" },
{ .compatible = "adi,adt7516" },
{ .compatible = "adi,adt7517" },
{ .compatible = "adi,adt7519" },
{ },
};
MODULE_DEVICE_TABLE(of, adt7316_of_match);
static struct i2c_driver adt7316_driver = {
.driver = {
.name = "adt7316",
.of_match_table = adt7316_of_match,
.pm = ADT7316_PM_OPS,
},
.probe = adt7316_i2c_probe,

View File

@ -94,7 +94,6 @@ static int adt7316_spi_probe(struct spi_device *spi_dev)
struct adt7316_bus bus = {
.client = spi_dev,
.irq = spi_dev->irq,
.irq_flags = IRQF_TRIGGER_LOW,
.read = adt7316_spi_read,
.write = adt7316_spi_write,
.multi_read = adt7316_spi_multi_read,

View File

@ -177,7 +177,7 @@
struct adt7316_chip_info {
struct adt7316_bus bus;
u16 ldac_pin;
struct gpio_desc *ldac_pin;
u16 int_mask; /* 0x2f */
u8 config1;
u8 config2;
@ -950,8 +950,8 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
if (ret)
return -EIO;
} else {
gpio_set_value(chip->ldac_pin, 0);
gpio_set_value(chip->ldac_pin, 1);
gpiod_set_value(chip->ldac_pin, 0);
gpiod_set_value(chip->ldac_pin, 1);
}
return len;
@ -2104,6 +2104,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
struct adt7316_chip_info *chip;
struct iio_dev *indio_dev;
unsigned short *adt7316_platform_data = dev->platform_data;
int irq_type = IRQF_TRIGGER_LOW;
int ret = 0;
indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
@ -2122,7 +2123,13 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
else
return -ENODEV;
chip->ldac_pin = adt7316_platform_data[1];
chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac", GPIOD_OUT_LOW);
if (IS_ERR(chip->ldac_pin)) {
ret = PTR_ERR(chip->ldac_pin);
dev_err(dev, "Failed to request ldac GPIO: %d\n", ret);
return ret;
}
if (chip->ldac_pin) {
chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@ -2142,19 +2149,18 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
if (chip->bus.irq > 0) {
if (adt7316_platform_data[0])
chip->bus.irq_flags = adt7316_platform_data[0];
irq_type = adt7316_platform_data[0];
ret = devm_request_threaded_irq(dev, chip->bus.irq,
NULL,
adt7316_event_handler,
chip->bus.irq_flags |
IRQF_ONESHOT,
irq_type | IRQF_ONESHOT,
indio_dev->name,
indio_dev);
if (ret)
return ret;
if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH)
if (irq_type & IRQF_TRIGGER_HIGH)
chip->config1 |= ADT7316_INT_POLARITY;
}

View File

@ -17,7 +17,6 @@
struct adt7316_bus {
void *client;
int irq;
int irq_flags;
int (*read)(void *client, u8 reg, u8 *data);
int (*write)(void *client, u8 reg, u8 val);
int (*multi_read)(void *client, u8 first_reg, u8 count, u8 *data);

View File

@ -786,9 +786,18 @@ static const struct i2c_device_id ad5933_id[] = {
MODULE_DEVICE_TABLE(i2c, ad5933_id);
static const struct of_device_id ad5933_of_match[] = {
{ .compatible = "adi,ad5933" },
{ .compatible = "adi,ad5934" },
{ },
};
MODULE_DEVICE_TABLE(of, ad5933_of_match);
static struct i2c_driver ad5933_driver = {
.driver = {
.name = "ad5933",
.of_match_table = ad5933_of_match,
},
.probe = ad5933_probe,
.remove = ad5933_remove,

View File

@ -3,16 +3,6 @@
#
menu "Resolver to digital converters"
config AD2S90
tristate "Analog Devices ad2s90 driver"
depends on SPI
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s90, provides direct access via sysfs.
To compile this driver as a module, choose M here: the
module will be called ad2s90.
config AD2S1210
tristate "Analog Devices ad2s1210 driver"
depends on SPI

View File

@ -2,5 +2,4 @@
# Makefile for Resolver/Synchro drivers
#
obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S1210) += ad2s1210.o