mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 05:39:42 -04:00
Merge tag 'iio-for-6.12b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: IIO: 2nd set of new device support features and cleanup for 6.12 Late pull request as I was planing to include another series that is waiting for a fix to end up in char-misc-next. That can wait for next cycle. Includes one immutable branch merge from MFD to get a necessary header change. Usual mix of a few new drivers, additional device support for existing drivers, new features and a bunch of cleanup across tree. New device support ================== asahi-kasei,ak8975 - A few minor fixes as precursors to support for the AK09118 magnetometer that is very similar to the already supported AK09112 awinic,aw96103 - New driver for this capacitive proximity sensor. x-powers,axp202 - Add support for the axp717 (including merge of MFD immutable branch). sophgo,saradc - New driver for this SOC ADC. Features ======== adi,ad4695 - Add calibration support. bosch,bmi323 - Ensure device is in lowest power state on suspend. Cleanup and minor fixes ======================= treewide - Start to standardize formatting of id tables (ADC drivers done so far). adi,ad5449 - Drop platform data support as long unused in upstream kernel. bosch,bmc150 - Use fwnode_irq_get_by_name() in place of of_ variant. - Use ACPI_HANDLE() to get the handle directly rather than via ACPI_COMPANION() google,cros_ec_mkbp_proximity - Include mod_devicetable.h instead of broader of.h mirochip,mcp320x - Drop vendorless compatible entries as not needed for backwards compatibility and should not be used in new boards. st,lsm6dsx - Use iio_read_acpi_mount_matrix() helper instead of open coding the same. - Drop some unnecessary dev_fwnode() calls to check if a fwnode is available. All the calls made handle this anyway. xilinx,ams - Use device_for_each_child_node_scoped() to avoid manual release of fwnode handle. tools,generic-buffer - Handle failure to allocate trigger name. - Cleanup .*.cmd files if present. * tag 'iio-for-6.12b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (28 commits) iio: adc: axp20x_adc: add support for AXP717 ADC dt-bindings: iio: adc: Add AXP717 compatible iio: adc: axp20x_adc: Add adc_en1 and adc_en2 to axp_data tools: iio: rm .*.cmd when make clean iio: adc: standardize on formatting for id match tables iio: proximity: aw96103: Add support for aw96103/aw96105 proximity sensor dt-bindings: iio: aw96103: Add bindings for aw96103/aw96105 sensor iio: adc: sophgo-saradc: Add driver for Sophgo CV1800B SARADC dt-bindings: iio: adc: sophgo,cv1800b-saradc: Add Sophgo CV1800B SARADC tools/iio: Add memory allocation failure check for trigger_name iio: imu: st_lsm6dsx: Remove useless dev_fwnode() calls iio: imu: st_lsm6dsx: Use iio_read_acpi_mount_matrix() helper iio: adc: mcp320x: Drop vendorless compatible strings iio: dac: ad5449: drop support for platform data iio: adc: xilinx-ams: use device_* to iterate over device child nodes iio: ABI: document ad4695 new attributes doc: iio: ad4695: update for calibration support iio: adc: ad4695: implement calibration support iio: adc: ad4695: add 2nd regmap for 16-bit registers iio: bmi323: peripheral in lowest power state on suspend ...
This commit is contained in:
@@ -541,6 +541,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_proximity_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibbias
|
||||
KernelVersion: 2.6.35
|
||||
@@ -556,6 +557,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibbias_available
|
||||
KernelVersion: 5.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@@ -603,6 +605,7 @@ Description:
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminanceY_calibscale_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_calibscale_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximityY_calibscale_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale_available
|
||||
KernelVersion: 4.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/sophgo,cv1800b-saradc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title:
|
||||
Sophgo CV1800B SoC 3 channels Successive Approximation Analog to
|
||||
Digital Converters
|
||||
|
||||
maintainers:
|
||||
- Thomas Bonnefille <thomas.bonnefille@bootlin.com>
|
||||
|
||||
description:
|
||||
Datasheet at https://github.com/sophgo/sophgo-doc/releases
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sophgo,cv1800b-saradc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-2]$":
|
||||
$ref: adc.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- minimum: 0
|
||||
maximum: 2
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sophgo,cv1800.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
adc@30f0000 {
|
||||
compatible = "sophgo,cv1800b-saradc";
|
||||
reg = <0x030f0000 0x1000>;
|
||||
clocks = <&clk CLK_SARADC>;
|
||||
interrupts = <100 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
@@ -37,6 +37,17 @@ description: |
|
||||
3 | batt_dischrg_i
|
||||
4 | ts_v
|
||||
|
||||
AXP717
|
||||
------
|
||||
0 | batt_v
|
||||
1 | ts_v
|
||||
2 | vbus_v
|
||||
3 | vsys_v
|
||||
4 | pmic_temp
|
||||
5 | batt_chrg_i
|
||||
6 | vmid_v
|
||||
7 | bkup_batt_v
|
||||
|
||||
AXP813
|
||||
------
|
||||
0 | pmic_temp
|
||||
@@ -52,6 +63,7 @@ properties:
|
||||
oneOf:
|
||||
- const: x-powers,axp209-adc
|
||||
- const: x-powers,axp221-adc
|
||||
- const: x-powers,axp717-adc
|
||||
- const: x-powers,axp813-adc
|
||||
|
||||
- items:
|
||||
|
||||
@@ -18,6 +18,10 @@ properties:
|
||||
- asahi-kasei,ak09911
|
||||
- asahi-kasei,ak09912
|
||||
- asahi-kasei,ak09916
|
||||
- items:
|
||||
# ak09918 is register compatible with ak09912.
|
||||
- const: asahi-kasei,ak09918
|
||||
- const: asahi-kasei,ak09912
|
||||
- enum:
|
||||
- ak8975
|
||||
- ak8963
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/awinic,aw96103.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Awinic's AW96103 capacitive proximity sensor and similar
|
||||
|
||||
maintainers:
|
||||
- Wang Shuaijie <wangshuaijie@awinic.com>
|
||||
|
||||
description: |
|
||||
Awinic's AW96103/AW96105 proximity sensor.
|
||||
The specific absorption rate (SAR) is a metric that measures
|
||||
the degree of absorption of electromagnetic radiation emitted by
|
||||
wireless devices, such as mobile phones and tablets, by human tissue.
|
||||
In mobile phone applications, the proximity sensor is primarily
|
||||
used to detect the proximity of the human body to the phone. When the
|
||||
phone approaches the human body, it will actively reduce the transmit
|
||||
power of the antenna to keep the SAR within a safe range. Therefore,
|
||||
we also refer to the proximity sensor as a SAR sensor.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- awinic,aw96103
|
||||
- awinic,aw96105
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
Generated by the device to announce that a close/far
|
||||
proximity event has happened.
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
proximity@12 {
|
||||
compatible = "awinic,aw96103";
|
||||
reg = <0x12>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
|
||||
vcc-supply = <&pp1800_prox>;
|
||||
};
|
||||
};
|
||||
@@ -143,13 +143,18 @@ present, then the external reference voltage is used and the internal buffer is
|
||||
disabled. If ``refin-supply`` is present, then the internal buffered reference
|
||||
voltage is used.
|
||||
|
||||
Gain/offset calibration
|
||||
-----------------------
|
||||
|
||||
System calibration is supported using the channel gain and offset registers via
|
||||
the ``calibscale`` and ``calibbias`` attributes respectively.
|
||||
|
||||
Unimplemented features
|
||||
----------------------
|
||||
|
||||
- Additional wiring modes
|
||||
- Threshold events
|
||||
- Oversampling
|
||||
- Gain/offset calibration
|
||||
- GPIO support
|
||||
- CRC support
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
@@ -387,7 +387,7 @@ static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
char *name, *alt_name, *label;
|
||||
|
||||
if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
|
||||
@@ -398,9 +398,9 @@ static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
|
||||
label = "accel-display";
|
||||
}
|
||||
|
||||
if (acpi_has_method(adev->handle, "ROTM")) {
|
||||
if (acpi_has_method(handle, "ROTM")) {
|
||||
name = "ROTM";
|
||||
} else if (acpi_has_method(adev->handle, alt_name)) {
|
||||
} else if (acpi_has_method(handle, alt_name)) {
|
||||
name = alt_name;
|
||||
indio_dev->label = label;
|
||||
} else {
|
||||
@@ -514,7 +514,7 @@ static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
|
||||
*/
|
||||
irq_info = bmc150_accel_interrupts_int1;
|
||||
if (data->type == BOSCH_BMC156 ||
|
||||
irq == of_irq_get_byname(dev->of_node, "INT2"))
|
||||
irq == fwnode_irq_get_byname(dev_fwnode(dev), "INT2"))
|
||||
irq_info = bmc150_accel_interrupts_int2;
|
||||
|
||||
for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
|
||||
|
||||
@@ -1192,6 +1192,16 @@ config SC27XX_ADC
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sc27xx_adc.
|
||||
|
||||
config SOPHGO_CV1800B_ADC
|
||||
tristate "Sophgo CV1800B SARADC"
|
||||
depends on ARCH_SOPHGO || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for the SARADC integrated inside
|
||||
the Sophgo CV1800B SoC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sophgo_cv1800b_adc.
|
||||
|
||||
config SPEAR_ADC
|
||||
tristate "ST SPEAr ADC"
|
||||
depends on PLAT_SPEAR || COMPILE_TEST
|
||||
|
||||
@@ -108,6 +108,7 @@ obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
|
||||
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
||||
obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
|
||||
obj-$(CONFIG_SOPHGO_CV1800B_ADC) += sophgo-cv1800b-adc.o
|
||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||
obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
|
||||
obj-$(CONFIG_STM32_ADC) += stm32-adc.o
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
/* AD4695 registers */
|
||||
#define AD4695_REG_SPI_CONFIG_A 0x0000
|
||||
#define AD4695_REG_SPI_CONFIG_A_SW_RST (BIT(7) | BIT(0))
|
||||
#define AD4695_REG_SPI_CONFIG_A_ADDR_DIR BIT(5)
|
||||
#define AD4695_REG_SPI_CONFIG_B 0x0001
|
||||
#define AD4695_REG_SPI_CONFIG_B_INST_MODE BIT(7)
|
||||
#define AD4695_REG_DEVICE_TYPE 0x0003
|
||||
@@ -77,7 +79,6 @@
|
||||
#define AD4695_REG_GAIN_IN(n) (0x00C0 | (2 * (n)))
|
||||
#define AD4695_REG_AS_SLOT(n) (0x0100 | (n))
|
||||
#define AD4695_REG_AS_SLOT_INX GENMASK(3, 0)
|
||||
#define AD4695_MAX_REG 0x017F
|
||||
|
||||
/* Conversion mode commands */
|
||||
#define AD4695_CMD_EXIT_CNV_MODE 0x0A
|
||||
@@ -121,6 +122,7 @@ struct ad4695_channel_config {
|
||||
struct ad4695_state {
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap16;
|
||||
struct gpio_desc *reset_gpio;
|
||||
/* voltages channels plus temperature and timestamp */
|
||||
struct iio_chan_spec iio_chan[AD4695_MAX_CHANNELS + 2];
|
||||
@@ -150,8 +152,10 @@ static const struct regmap_range ad4695_regmap_rd_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_C, AD4695_REG_SPI_STATUS),
|
||||
regmap_reg_range(AD4695_REG_STATUS, AD4695_REG_ALERT_STATUS2),
|
||||
regmap_reg_range(AD4695_REG_CLAMP_STATUS, AD4695_REG_CLAMP_STATUS),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_MAX_REG),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_AC_CTRL),
|
||||
regmap_reg_range(AD4695_REG_GPIO_CTRL, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_REG_CONFIG_IN(15)),
|
||||
regmap_reg_range(AD4695_REG_AS_SLOT(0), AD4695_REG_AS_SLOT(127)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap_rd_table = {
|
||||
@@ -164,8 +168,10 @@ static const struct regmap_range ad4695_regmap_wr_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_SCRATCH_PAD, AD4695_REG_SCRATCH_PAD),
|
||||
regmap_reg_range(AD4695_REG_LOOP_MODE, AD4695_REG_LOOP_MODE),
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_C, AD4695_REG_SPI_STATUS),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_MAX_REG),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_AC_CTRL),
|
||||
regmap_reg_range(AD4695_REG_GPIO_CTRL, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_REG_CONFIG_IN(15)),
|
||||
regmap_reg_range(AD4695_REG_AS_SLOT(0), AD4695_REG_AS_SLOT(127)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap_wr_table = {
|
||||
@@ -174,21 +180,57 @@ static const struct regmap_access_table ad4695_regmap_wr_table = {
|
||||
};
|
||||
|
||||
static const struct regmap_config ad4695_regmap_config = {
|
||||
.name = "ad4695",
|
||||
.name = "ad4695-8",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = AD4695_MAX_REG,
|
||||
.max_register = AD4695_REG_AS_SLOT(127),
|
||||
.rd_table = &ad4695_regmap_rd_table,
|
||||
.wr_table = &ad4695_regmap_wr_table,
|
||||
.can_multi_write = true,
|
||||
};
|
||||
|
||||
static const struct regmap_range ad4695_regmap16_rd_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_STD_SEQ_CONFIG, AD4695_REG_STD_SEQ_CONFIG),
|
||||
regmap_reg_range(AD4695_REG_UPPER_IN(0), AD4695_REG_GAIN_IN(15)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap16_rd_table = {
|
||||
.yes_ranges = ad4695_regmap16_rd_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ad4695_regmap16_rd_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range ad4695_regmap16_wr_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_STD_SEQ_CONFIG, AD4695_REG_STD_SEQ_CONFIG),
|
||||
regmap_reg_range(AD4695_REG_UPPER_IN(0), AD4695_REG_GAIN_IN(15)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap16_wr_table = {
|
||||
.yes_ranges = ad4695_regmap16_wr_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ad4695_regmap16_wr_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config ad4695_regmap16_config = {
|
||||
.name = "ad4695-16",
|
||||
.reg_bits = 16,
|
||||
.reg_stride = 2,
|
||||
.val_bits = 16,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.max_register = AD4695_REG_GAIN_IN(15),
|
||||
.rd_table = &ad4695_regmap16_rd_table,
|
||||
.wr_table = &ad4695_regmap16_wr_table,
|
||||
.can_multi_write = true,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad4695_channel_template = {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
.info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBSCALE) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
@@ -582,7 +624,8 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
struct ad4695_channel_config *cfg = &st->channels_cfg[chan->scan_index];
|
||||
u8 realbits = chan->scan_type.realbits;
|
||||
int ret;
|
||||
unsigned int reg_val;
|
||||
int ret, tmp;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
@@ -633,6 +676,152 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBSCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
ret = regmap_read(st->regmap16,
|
||||
AD4695_REG_GAIN_IN(chan->scan_index),
|
||||
®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = reg_val;
|
||||
*val2 = 15;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
unreachable();
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
ret = regmap_read(st->regmap16,
|
||||
AD4695_REG_OFFSET_IN(chan->scan_index),
|
||||
®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tmp = sign_extend32(reg_val, 15);
|
||||
|
||||
*val = tmp / 4;
|
||||
*val2 = abs(tmp) % 4 * MICRO / 4;
|
||||
|
||||
if (tmp < 0 && *val2) {
|
||||
*val *= -1;
|
||||
*val2 *= -1;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
unreachable();
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4695_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
unsigned int reg_val;
|
||||
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBSCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (val < 0 || val2 < 0)
|
||||
reg_val = 0;
|
||||
else if (val > 1)
|
||||
reg_val = U16_MAX;
|
||||
else
|
||||
reg_val = (val * (1 << 16) +
|
||||
mul_u64_u32_div(val2, 1 << 16,
|
||||
MICRO)) / 2;
|
||||
|
||||
return regmap_write(st->regmap16,
|
||||
AD4695_REG_GAIN_IN(chan->scan_index),
|
||||
reg_val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (val2 >= 0 && val > S16_MAX / 4)
|
||||
reg_val = S16_MAX;
|
||||
else if ((val2 < 0 ? -val : val) < S16_MIN / 4)
|
||||
reg_val = S16_MIN;
|
||||
else if (val2 < 0)
|
||||
reg_val = clamp_t(int,
|
||||
-(val * 4 + -val2 * 4 / MICRO),
|
||||
S16_MIN, S16_MAX);
|
||||
else if (val < 0)
|
||||
reg_val = clamp_t(int,
|
||||
val * 4 - val2 * 4 / MICRO,
|
||||
S16_MIN, S16_MAX);
|
||||
else
|
||||
reg_val = clamp_t(int,
|
||||
val * 4 + val2 * 4 / MICRO,
|
||||
S16_MIN, S16_MAX);
|
||||
|
||||
return regmap_write(st->regmap16,
|
||||
AD4695_REG_OFFSET_IN(chan->scan_index),
|
||||
reg_val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static int ad4695_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
static const int ad4695_calibscale_available[6] = {
|
||||
/* Range of 0 (inclusive) to 2 (exclusive) */
|
||||
0, 15, 1, 15, U16_MAX, 15
|
||||
};
|
||||
static const int ad4695_calibbias_available[6] = {
|
||||
/*
|
||||
* Datasheet says FSR/8 which translates to signed/4. The step
|
||||
* depends on oversampling ratio which is always 1 for now.
|
||||
*/
|
||||
S16_MIN / 4, 0, 0, MICRO / 4, S16_MAX / 4, S16_MAX % 4 * MICRO / 4
|
||||
};
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBSCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
*vals = ad4695_calibscale_available;
|
||||
*type = IIO_VAL_FRACTIONAL_LOG2;
|
||||
return IIO_AVAIL_RANGE;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
*vals = ad4695_calibbias_available;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
return IIO_AVAIL_RANGE;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -646,17 +835,30 @@ static int ad4695_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
if (readval)
|
||||
return regmap_read(st->regmap, reg, readval);
|
||||
|
||||
return regmap_write(st->regmap, reg, writeval);
|
||||
if (readval) {
|
||||
if (regmap_check_range_table(st->regmap, reg,
|
||||
&ad4695_regmap_rd_table))
|
||||
return regmap_read(st->regmap, reg, readval);
|
||||
if (regmap_check_range_table(st->regmap16, reg,
|
||||
&ad4695_regmap16_rd_table))
|
||||
return regmap_read(st->regmap16, reg, readval);
|
||||
} else {
|
||||
if (regmap_check_range_table(st->regmap, reg,
|
||||
&ad4695_regmap_wr_table))
|
||||
return regmap_write(st->regmap, reg, writeval);
|
||||
if (regmap_check_range_table(st->regmap16, reg,
|
||||
&ad4695_regmap16_wr_table))
|
||||
return regmap_write(st->regmap16, reg, writeval);
|
||||
}
|
||||
}
|
||||
|
||||
unreachable();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info ad4695_info = {
|
||||
.read_raw = &ad4695_read_raw,
|
||||
.write_raw = &ad4695_write_raw,
|
||||
.read_avail = &ad4695_read_avail,
|
||||
.debugfs_reg_access = &ad4695_debugfs_reg_access,
|
||||
};
|
||||
|
||||
@@ -807,6 +1009,11 @@ static int ad4695_probe(struct spi_device *spi)
|
||||
return dev_err_probe(dev, PTR_ERR(st->regmap),
|
||||
"Failed to initialize regmap\n");
|
||||
|
||||
st->regmap16 = devm_regmap_init_spi(spi, &ad4695_regmap16_config);
|
||||
if (IS_ERR(st->regmap16))
|
||||
return dev_err_probe(dev, PTR_ERR(st->regmap16),
|
||||
"Failed to initialize regmap16\n");
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev,
|
||||
ARRAY_SIZE(ad4695_power_supplies),
|
||||
ad4695_power_supplies);
|
||||
@@ -876,9 +1083,9 @@ static int ad4695_probe(struct spi_device *spi)
|
||||
msleep(AD4695_T_WAKEUP_SW_MS);
|
||||
}
|
||||
|
||||
/* Needed for debugfs since it only access registers 1 byte at a time. */
|
||||
ret = regmap_set_bits(st->regmap, AD4695_REG_SPI_CONFIG_C,
|
||||
AD4695_REG_SPI_CONFIG_C_MB_STRICT);
|
||||
/* Needed for regmap16 to be able to work correctly. */
|
||||
ret = regmap_set_bits(st->regmap, AD4695_REG_SPI_CONFIG_A,
|
||||
AD4695_REG_SPI_CONFIG_A_ADDR_DIR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -112,13 +112,13 @@ static int ad7091r5_i2c_probe(struct i2c_client *i2c)
|
||||
|
||||
static const struct of_device_id ad7091r5_dt_ids[] = {
|
||||
{ .compatible = "adi,ad7091r5", .data = &ad7091r5_init_info },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids);
|
||||
|
||||
static const struct i2c_device_id ad7091r5_i2c_ids[] = {
|
||||
{"ad7091r5", (kernel_ulong_t)&ad7091r5_init_info },
|
||||
{}
|
||||
{ "ad7091r5", (kernel_ulong_t)&ad7091r5_init_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids);
|
||||
|
||||
|
||||
@@ -1008,14 +1008,14 @@ static const struct of_device_id ad7124_of_match[] = {
|
||||
.data = &ad7124_chip_info_tbl[ID_AD7124_4], },
|
||||
{ .compatible = "adi,ad7124-8",
|
||||
.data = &ad7124_chip_info_tbl[ID_AD7124_8], },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7124_of_match);
|
||||
|
||||
static const struct spi_device_id ad71124_ids[] = {
|
||||
{ "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
|
||||
{ "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad71124_ids);
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ static const struct iio_chan_spec_ext_info ad7192_calibsys_ext_info[] = {
|
||||
&ad7192_syscalib_mode_enum),
|
||||
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
|
||||
&ad7192_syscalib_mode_enum),
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ad7192_state *ad_sigma_delta_to_ad7192(struct ad_sigma_delta *sd)
|
||||
@@ -1431,7 +1431,7 @@ static const struct of_device_id ad7192_of_match[] = {
|
||||
{ .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] },
|
||||
{ .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] },
|
||||
{ .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7192_of_match);
|
||||
|
||||
@@ -1441,7 +1441,7 @@ static const struct spi_device_id ad7192_ids[] = {
|
||||
{ "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
|
||||
{ "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
|
||||
{ "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7192_ids);
|
||||
|
||||
|
||||
@@ -457,8 +457,8 @@ static int ad7266_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7266_id[] = {
|
||||
{"ad7265", 0},
|
||||
{"ad7266", 0},
|
||||
{ "ad7265", 0 },
|
||||
{ "ad7266", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7266_id);
|
||||
|
||||
@@ -1090,8 +1090,8 @@ static int ad7280_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7280_id[] = {
|
||||
{"ad7280a", 0},
|
||||
{}
|
||||
{ "ad7280a", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7280_id);
|
||||
|
||||
|
||||
@@ -537,14 +537,14 @@ static int ad7291_probe(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id ad7291_id[] = {
|
||||
{ "ad7291" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ad7291_id);
|
||||
|
||||
static const struct of_device_id ad7291_of_match[] = {
|
||||
{ .compatible = "adi,ad7291" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7291_of_match);
|
||||
|
||||
|
||||
@@ -301,13 +301,13 @@ static int ad7292_probe(struct spi_device *spi)
|
||||
|
||||
static const struct spi_device_id ad7292_id_table[] = {
|
||||
{ "ad7292", 0 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7292_id_table);
|
||||
|
||||
static const struct of_device_id ad7292_of_match[] = {
|
||||
{ .compatible = "adi,ad7292" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7292_of_match);
|
||||
|
||||
|
||||
@@ -355,8 +355,8 @@ static const struct acpi_device_id ad7298_acpi_ids[] = {
|
||||
MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids);
|
||||
|
||||
static const struct spi_device_id ad7298_id[] = {
|
||||
{"ad7298", 0},
|
||||
{}
|
||||
{ "ad7298", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7298_id);
|
||||
|
||||
|
||||
@@ -409,35 +409,35 @@ static int ad7476_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7476_id[] = {
|
||||
{"ad7091", ID_AD7091},
|
||||
{"ad7091r", ID_AD7091R},
|
||||
{"ad7273", ID_AD7273},
|
||||
{"ad7274", ID_AD7274},
|
||||
{"ad7276", ID_AD7276},
|
||||
{"ad7277", ID_AD7277},
|
||||
{"ad7278", ID_AD7278},
|
||||
{"ad7466", ID_AD7466},
|
||||
{"ad7467", ID_AD7467},
|
||||
{"ad7468", ID_AD7468},
|
||||
{"ad7475", ID_AD7475},
|
||||
{"ad7476", ID_AD7466},
|
||||
{"ad7476a", ID_AD7466},
|
||||
{"ad7477", ID_AD7467},
|
||||
{"ad7477a", ID_AD7467},
|
||||
{"ad7478", ID_AD7468},
|
||||
{"ad7478a", ID_AD7468},
|
||||
{"ad7495", ID_AD7495},
|
||||
{"ad7910", ID_AD7467},
|
||||
{"ad7920", ID_AD7466},
|
||||
{"ad7940", ID_AD7940},
|
||||
{"adc081s", ID_ADC081S},
|
||||
{"adc101s", ID_ADC101S},
|
||||
{"adc121s", ID_ADC121S},
|
||||
{"ads7866", ID_ADS7866},
|
||||
{"ads7867", ID_ADS7867},
|
||||
{"ads7868", ID_ADS7868},
|
||||
{"ltc2314-14", ID_LTC2314_14},
|
||||
{}
|
||||
{ "ad7091", ID_AD7091 },
|
||||
{ "ad7091r", ID_AD7091R },
|
||||
{ "ad7273", ID_AD7273 },
|
||||
{ "ad7274", ID_AD7274 },
|
||||
{ "ad7276", ID_AD7276},
|
||||
{ "ad7277", ID_AD7277 },
|
||||
{ "ad7278", ID_AD7278 },
|
||||
{ "ad7466", ID_AD7466 },
|
||||
{ "ad7467", ID_AD7467 },
|
||||
{ "ad7468", ID_AD7468 },
|
||||
{ "ad7475", ID_AD7475 },
|
||||
{ "ad7476", ID_AD7466 },
|
||||
{ "ad7476a", ID_AD7466 },
|
||||
{ "ad7477", ID_AD7467 },
|
||||
{ "ad7477a", ID_AD7467 },
|
||||
{ "ad7478", ID_AD7468 },
|
||||
{ "ad7478a", ID_AD7468 },
|
||||
{ "ad7495", ID_AD7495 },
|
||||
{ "ad7910", ID_AD7467 },
|
||||
{ "ad7920", ID_AD7466 },
|
||||
{ "ad7940", ID_AD7940 },
|
||||
{ "adc081s", ID_ADC081S },
|
||||
{ "adc101s", ID_ADC101S },
|
||||
{ "adc121s", ID_ADC121S },
|
||||
{ "ads7866", ID_ADS7866 },
|
||||
{ "ads7867", ID_ADS7867 },
|
||||
{ "ads7868", ID_ADS7868 },
|
||||
{ "ltc2314-14", ID_LTC2314_14 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7476_id);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ static const struct of_device_id ad7606_of_match[] = {
|
||||
{ .compatible = "adi,ad7606-4" },
|
||||
{ .compatible = "adi,ad7606-6" },
|
||||
{ .compatible = "adi,ad7606-8" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7606_of_match);
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ static const struct spi_device_id ad7606_id_table[] = {
|
||||
{ "ad7606-8", ID_AD7606_8 },
|
||||
{ "ad7606b", ID_AD7606B },
|
||||
{ "ad7616", ID_AD7616 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7606_id_table);
|
||||
|
||||
@@ -345,7 +345,7 @@ static const struct of_device_id ad7606_of_match[] = {
|
||||
{ .compatible = "adi,ad7606-8" },
|
||||
{ .compatible = "adi,ad7606b" },
|
||||
{ .compatible = "adi,ad7616" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7606_of_match);
|
||||
|
||||
|
||||
@@ -291,13 +291,13 @@ static int ad7766_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7766_id[] = {
|
||||
{"ad7766", ID_AD7766},
|
||||
{"ad7766-1", ID_AD7766_1},
|
||||
{"ad7766-2", ID_AD7766_2},
|
||||
{"ad7767", ID_AD7766},
|
||||
{"ad7767-1", ID_AD7766_1},
|
||||
{"ad7767-2", ID_AD7766_2},
|
||||
{}
|
||||
{ "ad7766", ID_AD7766 },
|
||||
{ "ad7766-1", ID_AD7766_1 },
|
||||
{ "ad7766-2", ID_AD7766_2 },
|
||||
{ "ad7767", ID_AD7766 },
|
||||
{ "ad7767-1", ID_AD7766_1 },
|
||||
{ "ad7767-2", ID_AD7766_2 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7766_id);
|
||||
|
||||
|
||||
@@ -655,7 +655,7 @@ MODULE_DEVICE_TABLE(spi, ad7768_id_table);
|
||||
|
||||
static const struct of_device_id ad7768_of_match[] = {
|
||||
{ .compatible = "adi,ad7768-1" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7768_of_match);
|
||||
|
||||
|
||||
@@ -355,11 +355,11 @@ static int ad7780_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7780_id[] = {
|
||||
{"ad7170", ID_AD7170},
|
||||
{"ad7171", ID_AD7171},
|
||||
{"ad7780", ID_AD7780},
|
||||
{"ad7781", ID_AD7781},
|
||||
{}
|
||||
{ "ad7170", ID_AD7170 },
|
||||
{ "ad7171", ID_AD7171 },
|
||||
{ "ad7780", ID_AD7780 },
|
||||
{ "ad7781", ID_AD7781 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7780_id);
|
||||
|
||||
|
||||
@@ -824,16 +824,16 @@ static int ad7793_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7793_id[] = {
|
||||
{"ad7785", ID_AD7785},
|
||||
{"ad7792", ID_AD7792},
|
||||
{"ad7793", ID_AD7793},
|
||||
{"ad7794", ID_AD7794},
|
||||
{"ad7795", ID_AD7795},
|
||||
{"ad7796", ID_AD7796},
|
||||
{"ad7797", ID_AD7797},
|
||||
{"ad7798", ID_AD7798},
|
||||
{"ad7799", ID_AD7799},
|
||||
{}
|
||||
{ "ad7785", ID_AD7785 },
|
||||
{ "ad7792", ID_AD7792 },
|
||||
{ "ad7793", ID_AD7793 },
|
||||
{ "ad7794", ID_AD7794 },
|
||||
{ "ad7795", ID_AD7795 },
|
||||
{ "ad7796", ID_AD7796 },
|
||||
{ "ad7797", ID_AD7797 },
|
||||
{ "ad7798", ID_AD7798 },
|
||||
{ "ad7799", ID_AD7799 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7793_id);
|
||||
|
||||
|
||||
@@ -329,8 +329,8 @@ static int ad7887_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7887_id[] = {
|
||||
{"ad7887", ID_AD7887},
|
||||
{}
|
||||
{ "ad7887", ID_AD7887 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7887_id);
|
||||
|
||||
|
||||
@@ -361,14 +361,14 @@ static int ad7923_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7923_id[] = {
|
||||
{"ad7904", AD7904},
|
||||
{"ad7914", AD7914},
|
||||
{"ad7923", AD7924},
|
||||
{"ad7924", AD7924},
|
||||
{"ad7908", AD7908},
|
||||
{"ad7918", AD7918},
|
||||
{"ad7928", AD7928},
|
||||
{}
|
||||
{ "ad7904", AD7904 },
|
||||
{ "ad7914", AD7914 },
|
||||
{ "ad7923", AD7924 },
|
||||
{ "ad7924", AD7924 },
|
||||
{ "ad7908", AD7908 },
|
||||
{ "ad7918", AD7918 },
|
||||
{ "ad7928", AD7928 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7923_id);
|
||||
|
||||
@@ -380,7 +380,7 @@ static const struct of_device_id ad7923_of_match[] = {
|
||||
{ .compatible = "adi,ad7908", },
|
||||
{ .compatible = "adi,ad7918", },
|
||||
{ .compatible = "adi,ad7928", },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7923_of_match);
|
||||
|
||||
|
||||
@@ -1252,7 +1252,7 @@ static const struct of_device_id ad9467_of_match[] = {
|
||||
{ .compatible = "adi,ad9643", .data = &ad9643_chip_tbl, },
|
||||
{ .compatible = "adi,ad9649", .data = &ad9649_chip_tbl, },
|
||||
{ .compatible = "adi,ad9652", .data = &ad9652_chip_tbl, },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad9467_of_match);
|
||||
|
||||
@@ -1263,7 +1263,7 @@ static const struct spi_device_id ad9467_ids[] = {
|
||||
{ "ad9643", (kernel_ulong_t)&ad9643_chip_tbl },
|
||||
{ "ad9649", (kernel_ulong_t)&ad9649_chip_tbl, },
|
||||
{ "ad9652", (kernel_ulong_t)&ad9652_chip_tbl, },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad9467_ids);
|
||||
|
||||
|
||||
@@ -694,7 +694,7 @@ static const struct of_device_id aspeed_adc_matches[] = {
|
||||
{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
|
||||
{ .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
|
||||
{ .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
|
||||
|
||||
|
||||
@@ -1335,7 +1335,7 @@ static const struct of_device_id at91_adc_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
|
||||
{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
|
||||
{ .compatible = "atmel,sama5d3-adc", .data = &sama5d3_caps },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Quentin Schulz <quentin.schulz@free-electrons.com>
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -30,6 +31,8 @@
|
||||
|
||||
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
|
||||
|
||||
#define AXP717_ADC_EN1_MASK GENMASK(7, 0)
|
||||
|
||||
#define AXP192_GPIO30_IN_RANGE_GPIO0 BIT(0)
|
||||
#define AXP192_GPIO30_IN_RANGE_GPIO1 BIT(1)
|
||||
#define AXP192_GPIO30_IN_RANGE_GPIO2 BIT(2)
|
||||
@@ -43,6 +46,13 @@
|
||||
|
||||
#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
|
||||
|
||||
#define AXP717_ADC_DATA_TS 0x00
|
||||
#define AXP717_ADC_DATA_TEMP 0x01
|
||||
#define AXP717_ADC_DATA_VMID 0x02
|
||||
#define AXP717_ADC_DATA_BKUP_BATT 0x03
|
||||
|
||||
#define AXP717_ADC_DATA_MASK GENMASK(13, 0)
|
||||
|
||||
#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
|
||||
#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
|
||||
#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
|
||||
@@ -125,6 +135,20 @@ enum axp22x_adc_channel_i {
|
||||
AXP22X_BATT_DISCHRG_I,
|
||||
};
|
||||
|
||||
enum axp717_adc_channel_v {
|
||||
AXP717_BATT_V = 0,
|
||||
AXP717_TS_IN,
|
||||
AXP717_VBUS_V,
|
||||
AXP717_VSYS_V,
|
||||
AXP717_DIE_TEMP_V,
|
||||
AXP717_VMID_V = 6,
|
||||
AXP717_BKUP_BATT_V,
|
||||
};
|
||||
|
||||
enum axp717_adc_channel_i {
|
||||
AXP717_BATT_CHRG_I = 5,
|
||||
};
|
||||
|
||||
enum axp813_adc_channel_v {
|
||||
AXP813_TS_IN = 0,
|
||||
AXP813_GPIO0_V,
|
||||
@@ -179,6 +203,22 @@ static struct iio_map axp22x_maps[] = {
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct iio_map axp717_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "axp20x-usb-power-supply",
|
||||
.consumer_channel = "vbus_v",
|
||||
.adc_channel_label = "vbus_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_v",
|
||||
.adc_channel_label = "batt_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_chrg_i",
|
||||
.adc_channel_label = "batt_chrg_i",
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Channels are mapped by physical system. Their channels share the same index.
|
||||
* i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
|
||||
@@ -274,6 +314,29 @@ static const struct iio_chan_spec axp22x_adc_channels[] = {
|
||||
AXP22X_TS_ADC_H),
|
||||
};
|
||||
|
||||
/*
|
||||
* Scale and offset is unknown for temp, ts, batt_chrg_i, vmid_v, and
|
||||
* bkup_batt_v channels. Leaving scale and offset undefined for now.
|
||||
*/
|
||||
static const struct iio_chan_spec axp717_adc_channels[] = {
|
||||
AXP20X_ADC_CHANNEL(AXP717_BATT_V, "batt_v", IIO_VOLTAGE,
|
||||
AXP717_BATT_V_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_TS_IN, "ts_v", IIO_VOLTAGE,
|
||||
AXP717_ADC_DATA_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_VBUS_V, "vbus_v", IIO_VOLTAGE,
|
||||
AXP717_VBUS_V_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_VSYS_V, "vsys_v", IIO_VOLTAGE,
|
||||
AXP717_VSYS_V_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_DIE_TEMP_V, "pmic_temp", IIO_TEMP,
|
||||
AXP717_ADC_DATA_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
|
||||
AXP717_BATT_CHRG_I_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_VMID_V, "vmid_v", IIO_VOLTAGE,
|
||||
AXP717_ADC_DATA_H),
|
||||
AXP20X_ADC_CHANNEL(AXP717_BKUP_BATT_V, "bkup_batt_v", IIO_VOLTAGE,
|
||||
AXP717_ADC_DATA_H),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec axp813_adc_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
@@ -354,6 +417,51 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int axp717_adc_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
struct axp20x_adc_iio *info = iio_priv(indio_dev);
|
||||
u8 bulk_reg[2];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* A generic "ADC data" channel is used for TS, tdie, vmid,
|
||||
* and vbackup. This channel must both first be enabled and
|
||||
* also selected before it can be read.
|
||||
*/
|
||||
switch (chan->channel) {
|
||||
case AXP717_TS_IN:
|
||||
regmap_write(info->regmap, AXP717_ADC_DATA_SEL,
|
||||
AXP717_ADC_DATA_TS);
|
||||
break;
|
||||
case AXP717_DIE_TEMP_V:
|
||||
regmap_write(info->regmap, AXP717_ADC_DATA_SEL,
|
||||
AXP717_ADC_DATA_TEMP);
|
||||
break;
|
||||
case AXP717_VMID_V:
|
||||
regmap_write(info->regmap, AXP717_ADC_DATA_SEL,
|
||||
AXP717_ADC_DATA_VMID);
|
||||
break;
|
||||
case AXP717_BKUP_BATT_V:
|
||||
regmap_write(info->regmap, AXP717_ADC_DATA_SEL,
|
||||
AXP717_ADC_DATA_BKUP_BATT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* All channels are 14 bits, with the first 2 bits on the high
|
||||
* register reserved and the remaining bits as the ADC value.
|
||||
*/
|
||||
ret = regmap_bulk_read(info->regmap, chan->address, bulk_reg, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = FIELD_GET(AXP717_ADC_DATA_MASK, get_unaligned_be16(bulk_reg));
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int axp813_adc_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
@@ -571,6 +679,27 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
|
||||
}
|
||||
}
|
||||
|
||||
static int axp717_adc_scale(struct iio_chan_spec const *chan, int *val,
|
||||
int *val2)
|
||||
{
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
*val = 1;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CURRENT:
|
||||
*val = 1;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_TEMP:
|
||||
*val = 100;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
|
||||
int *val2)
|
||||
{
|
||||
@@ -746,6 +875,22 @@ static int axp22x_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int axp717_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return axp717_adc_scale(chan, val, val2);
|
||||
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return axp717_adc_raw(indio_dev, chan, val);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int axp813_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
@@ -860,6 +1005,10 @@ static const struct iio_info axp22x_adc_iio_info = {
|
||||
.read_raw = axp22x_read_raw,
|
||||
};
|
||||
|
||||
static const struct iio_info axp717_adc_iio_info = {
|
||||
.read_raw = axp717_read_raw,
|
||||
};
|
||||
|
||||
static const struct iio_info axp813_adc_iio_info = {
|
||||
.read_raw = axp813_read_raw,
|
||||
};
|
||||
@@ -889,7 +1038,9 @@ struct axp_data {
|
||||
const struct iio_info *iio_info;
|
||||
int num_channels;
|
||||
struct iio_chan_spec const *channels;
|
||||
unsigned long adc_en1;
|
||||
unsigned long adc_en1_mask;
|
||||
unsigned long adc_en2;
|
||||
unsigned long adc_en2_mask;
|
||||
int (*adc_rate)(struct axp20x_adc_iio *info,
|
||||
int rate);
|
||||
@@ -910,7 +1061,9 @@ static const struct axp_data axp20x_data = {
|
||||
.iio_info = &axp20x_adc_iio_info,
|
||||
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
|
||||
.channels = axp20x_adc_channels,
|
||||
.adc_en1 = AXP20X_ADC_EN1,
|
||||
.adc_en1_mask = AXP20X_ADC_EN1_MASK,
|
||||
.adc_en2 = AXP20X_ADC_EN2,
|
||||
.adc_en2_mask = AXP20X_ADC_EN2_MASK,
|
||||
.adc_rate = axp20x_adc_rate,
|
||||
.maps = axp20x_maps,
|
||||
@@ -920,15 +1073,26 @@ static const struct axp_data axp22x_data = {
|
||||
.iio_info = &axp22x_adc_iio_info,
|
||||
.num_channels = ARRAY_SIZE(axp22x_adc_channels),
|
||||
.channels = axp22x_adc_channels,
|
||||
.adc_en1 = AXP20X_ADC_EN1,
|
||||
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
|
||||
.adc_rate = axp22x_adc_rate,
|
||||
.maps = axp22x_maps,
|
||||
};
|
||||
|
||||
static const struct axp_data axp717_data = {
|
||||
.iio_info = &axp717_adc_iio_info,
|
||||
.num_channels = ARRAY_SIZE(axp717_adc_channels),
|
||||
.channels = axp717_adc_channels,
|
||||
.adc_en1 = AXP717_ADC_CH_EN_CONTROL,
|
||||
.adc_en1_mask = AXP717_ADC_EN1_MASK,
|
||||
.maps = axp717_maps,
|
||||
};
|
||||
|
||||
static const struct axp_data axp813_data = {
|
||||
.iio_info = &axp813_adc_iio_info,
|
||||
.num_channels = ARRAY_SIZE(axp813_adc_channels),
|
||||
.channels = axp813_adc_channels,
|
||||
.adc_en1 = AXP20X_ADC_EN1,
|
||||
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
|
||||
.adc_rate = axp813_adc_rate,
|
||||
.maps = axp22x_maps,
|
||||
@@ -938,6 +1102,7 @@ static const struct of_device_id axp20x_adc_of_match[] = {
|
||||
{ .compatible = "x-powers,axp192-adc", .data = (void *)&axp192_data, },
|
||||
{ .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
|
||||
{ .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
|
||||
{ .compatible = "x-powers,axp717-adc", .data = (void *)&axp717_data, },
|
||||
{ .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
@@ -947,6 +1112,7 @@ static const struct platform_device_id axp20x_adc_id_match[] = {
|
||||
{ .name = "axp192-adc", .driver_data = (kernel_ulong_t)&axp192_data, },
|
||||
{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
|
||||
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
|
||||
{ .name = "axp717-adc", .driver_data = (kernel_ulong_t)&axp717_data, },
|
||||
{ .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
@@ -988,14 +1154,16 @@ static int axp20x_probe(struct platform_device *pdev)
|
||||
indio_dev->channels = info->data->channels;
|
||||
|
||||
/* Enable the ADCs on IP */
|
||||
regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
|
||||
regmap_write(info->regmap, info->data->adc_en1,
|
||||
info->data->adc_en1_mask);
|
||||
|
||||
if (info->data->adc_en2_mask)
|
||||
regmap_set_bits(info->regmap, AXP20X_ADC_EN2,
|
||||
regmap_set_bits(info->regmap, info->data->adc_en2,
|
||||
info->data->adc_en2_mask);
|
||||
|
||||
/* Configure ADCs rate */
|
||||
info->data->adc_rate(info, 100);
|
||||
if (info->data->adc_rate)
|
||||
info->data->adc_rate(info, 100);
|
||||
|
||||
ret = iio_map_array_register(indio_dev, info->data->maps);
|
||||
if (ret < 0) {
|
||||
@@ -1015,10 +1183,10 @@ static int axp20x_probe(struct platform_device *pdev)
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
fail_map:
|
||||
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
|
||||
regmap_write(info->regmap, info->data->adc_en1, 0);
|
||||
|
||||
if (info->data->adc_en2_mask)
|
||||
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
|
||||
regmap_write(info->regmap, info->data->adc_en2, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1031,10 +1199,10 @@ static void axp20x_remove(struct platform_device *pdev)
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
|
||||
regmap_write(info->regmap, info->data->adc_en1, 0);
|
||||
|
||||
if (info->data->adc_en2_mask)
|
||||
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
|
||||
regmap_write(info->regmap, info->data->adc_en2, 0);
|
||||
}
|
||||
|
||||
static struct platform_driver axp20x_adc_driver = {
|
||||
|
||||
@@ -299,7 +299,7 @@ static int axp288_adc_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id axp288_adc_id_table[] = {
|
||||
{ .name = "axp288_adc" },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver axp288_adc_driver = {
|
||||
|
||||
@@ -606,7 +606,7 @@ static void iproc_adc_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id iproc_adc_of_match[] = {
|
||||
{.compatible = "brcm,iproc-static-adc", },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ static int berlin2_adc_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id berlin2_adc_match[] = {
|
||||
{ .compatible = "marvell,berlin2-adc", },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, berlin2_adc_match);
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ static void ep93xx_adc_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id ep93xx_adc_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-adc" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_adc_of_ids);
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ static const struct of_device_id exynos_adc_match[] = {
|
||||
.compatible = "samsung,exynos7-adc",
|
||||
.data = &exynos7_adc_data,
|
||||
},
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_adc_match);
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@ static int hi8435_probe(struct spi_device *spi)
|
||||
|
||||
static const struct of_device_id hi8435_dt_ids[] = {
|
||||
{ .compatible = "holt,hi8435" },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
|
||||
|
||||
|
||||
@@ -552,7 +552,7 @@ static int hx711_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id of_hx711_match[] = {
|
||||
{ .compatible = "avia,hx711", },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, of_hx711_match);
|
||||
|
||||
@@ -1052,12 +1052,12 @@ static void ina2xx_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ina2xx_id[] = {
|
||||
{"ina219", ina219},
|
||||
{"ina220", ina219},
|
||||
{"ina226", ina226},
|
||||
{"ina230", ina226},
|
||||
{"ina231", ina226},
|
||||
{}
|
||||
{ "ina219", ina219 },
|
||||
{ "ina220", ina219 },
|
||||
{ "ina226", ina226 },
|
||||
{ "ina230", ina226 },
|
||||
{ "ina231", ina226 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
|
||||
|
||||
@@ -1082,7 +1082,7 @@ static const struct of_device_id ina2xx_of_match[] = {
|
||||
.compatible = "ti,ina231",
|
||||
.data = (void *)ina226
|
||||
},
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ina2xx_of_match);
|
||||
|
||||
|
||||
@@ -908,7 +908,7 @@ static const struct of_device_id ingenic_adc_of_match[] = {
|
||||
{ .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id lpc32xx_adc_match[] = {
|
||||
{ .compatible = "nxp,lpc3220-adc" },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ static const struct ltc2497_chip_info ltc2496_info = {
|
||||
|
||||
static const struct of_device_id ltc2496_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2496", .data = <c2496_info, },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2496_of_match);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ MODULE_DEVICE_TABLE(i2c, ltc2497_id);
|
||||
static const struct of_device_id ltc2497_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2497", .data = <c2497_info[TYPE_LTC2497] },
|
||||
{ .compatible = "lltc,ltc2499", .data = <c2497_info[TYPE_LTC2499] },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2497_of_match);
|
||||
|
||||
|
||||
@@ -73,13 +73,13 @@ enum max1027_id {
|
||||
};
|
||||
|
||||
static const struct spi_device_id max1027_id[] = {
|
||||
{"max1027", max1027},
|
||||
{"max1029", max1029},
|
||||
{"max1031", max1031},
|
||||
{"max1227", max1227},
|
||||
{"max1229", max1229},
|
||||
{"max1231", max1231},
|
||||
{}
|
||||
{ "max1027", max1027 },
|
||||
{ "max1029", max1029 },
|
||||
{ "max1031", max1031 },
|
||||
{ "max1227", max1227 },
|
||||
{ "max1229", max1229 },
|
||||
{ "max1231", max1231 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max1027_id);
|
||||
|
||||
@@ -90,7 +90,7 @@ static const struct of_device_id max1027_adc_dt_ids[] = {
|
||||
{ .compatible = "maxim,max1227" },
|
||||
{ .compatible = "maxim,max1229" },
|
||||
{ .compatible = "maxim,max1231" },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
|
||||
|
||||
|
||||
@@ -143,8 +143,8 @@ static int max11100_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct of_device_id max11100_ids[] = {
|
||||
{.compatible = "maxim,max11100"},
|
||||
{ },
|
||||
{ .compatible = "maxim,max11100" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max11100_ids);
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ static const struct spi_device_id max1118_id[] = {
|
||||
{ "max1117", max1117 },
|
||||
{ "max1118", max1118 },
|
||||
{ "max1119", max1119 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max1118_id);
|
||||
|
||||
@@ -268,7 +268,7 @@ 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);
|
||||
|
||||
|
||||
@@ -177,12 +177,12 @@ static int max1241_probe(struct spi_device *spi)
|
||||
|
||||
static const struct spi_device_id max1241_id[] = {
|
||||
{ "max1241", max1241 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct of_device_id max1241_dt_ids[] = {
|
||||
{ .compatible = "maxim,max1241" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1241_dt_ids);
|
||||
|
||||
|
||||
@@ -250,14 +250,14 @@ static const struct of_device_id max34408_of_match[] = {
|
||||
.compatible = "maxim,max34409",
|
||||
.data = &max34409_model_data,
|
||||
},
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max34408_of_match);
|
||||
|
||||
static const struct i2c_device_id max34408_id[] = {
|
||||
{ "max34408", (kernel_ulong_t)&max34408_model_data },
|
||||
{ "max34409", (kernel_ulong_t)&max34409_model_data },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max34408_id);
|
||||
|
||||
|
||||
@@ -504,9 +504,9 @@ static int max9611_init(struct max9611_dev *max9611)
|
||||
}
|
||||
|
||||
static const struct of_device_id max9611_of_table[] = {
|
||||
{.compatible = "maxim,max9611", .data = "max9611"},
|
||||
{.compatible = "maxim,max9612", .data = "max9612"},
|
||||
{ },
|
||||
{ .compatible = "maxim,max9611", .data = "max9611" },
|
||||
{ .compatible = "maxim,max9612", .data = "max9612" },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, max9611_of_table);
|
||||
|
||||
@@ -459,16 +459,6 @@ static int mcp320x_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct of_device_id mcp320x_dt_ids[] = {
|
||||
/* NOTE: The use of compatibles with no vendor prefix is deprecated. */
|
||||
{ .compatible = "mcp3001" },
|
||||
{ .compatible = "mcp3002" },
|
||||
{ .compatible = "mcp3004" },
|
||||
{ .compatible = "mcp3008" },
|
||||
{ .compatible = "mcp3201" },
|
||||
{ .compatible = "mcp3202" },
|
||||
{ .compatible = "mcp3204" },
|
||||
{ .compatible = "mcp3208" },
|
||||
{ .compatible = "mcp3301" },
|
||||
{ .compatible = "microchip,mcp3001" },
|
||||
{ .compatible = "microchip,mcp3002" },
|
||||
{ .compatible = "microchip,mcp3004" },
|
||||
|
||||
@@ -184,8 +184,8 @@ static void mp2629_adc_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id mp2629_adc_of_match[] = {
|
||||
{ .compatible = "mps,mp2629_adc"},
|
||||
{}
|
||||
{ .compatible = "mps,mp2629_adc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mp2629_adc_of_match);
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ static int mt6360_adc_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id mt6360_adc_of_id[] = {
|
||||
{ .compatible = "mediatek,mt6360-adc", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6360_adc_of_id);
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@ MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
|
||||
|
||||
static const struct of_device_id nau7802_dt_ids[] = {
|
||||
{ .compatible = "nuvoton,nau7802" },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
|
||||
|
||||
|
||||
@@ -1234,13 +1234,13 @@ static int pac1921_probe(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id pac1921_id[] = {
|
||||
{ .name = "pac1921", 0 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pac1921_id);
|
||||
|
||||
static const struct of_device_id pac1921_of_match[] = {
|
||||
{ .compatible = "microchip,pac1921" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pac1921_of_match);
|
||||
|
||||
|
||||
@@ -1571,7 +1571,7 @@ static const struct i2c_device_id pac1934_id[] = {
|
||||
{ .name = "pac1932", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1932] },
|
||||
{ .name = "pac1933", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1933] },
|
||||
{ .name = "pac1934", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pac1934_id);
|
||||
|
||||
@@ -1592,7 +1592,7 @@ static const struct of_device_id pac1934_of_match[] = {
|
||||
.compatible = "microchip,pac1934",
|
||||
.data = &pac1934_chip_config[PAC1934]
|
||||
},
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pac1934_of_match);
|
||||
|
||||
@@ -1602,7 +1602,7 @@ MODULE_DEVICE_TABLE(of, pac1934_of_match);
|
||||
*/
|
||||
static const struct acpi_device_id pac1934_acpi_match[] = {
|
||||
{ "MCHP1930", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pac1934_acpi_match);
|
||||
|
||||
|
||||
@@ -1006,7 +1006,7 @@ static const struct of_device_id pm8xxx_xoadc_id_table[] = {
|
||||
.compatible = "qcom,pm8921-adc",
|
||||
.data = &pm8921_variant,
|
||||
},
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm8xxx_xoadc_id_table);
|
||||
|
||||
|
||||
@@ -1002,7 +1002,7 @@ static int rradc_probe(struct platform_device *pdev)
|
||||
static const struct of_device_id rradc_match_table[] = {
|
||||
{ .compatible = "qcom,pm660-rradc" },
|
||||
{ .compatible = "qcom,pmi8998-rradc" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rradc_match_table);
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ static const struct of_device_id rockchip_saradc_match[] = {
|
||||
.compatible = "rockchip,rk3588-saradc",
|
||||
.data = &rk3588_saradc_data,
|
||||
},
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
|
||||
|
||||
|
||||
@@ -865,7 +865,7 @@ static const struct richtek_dev_data rtq6059_devdata = {
|
||||
static const struct of_device_id rtq6056_device_match[] = {
|
||||
{ .compatible = "richtek,rtq6056", .data = &rtq6056_devdata },
|
||||
{ .compatible = "richtek,rtq6059", .data = &rtq6059_devdata },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rtq6056_device_match);
|
||||
|
||||
|
||||
227
drivers/iio/adc/sophgo-cv1800b-adc.c
Normal file
227
drivers/iio/adc/sophgo-cv1800b-adc.c
Normal file
@@ -0,0 +1,227 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Sophgo CV1800B SARADC Driver
|
||||
*
|
||||
* Copyright (C) Bootlin 2024
|
||||
* Author: Thomas Bonnefille <thomas.bonnefille@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define CV1800B_ADC_CTRL_REG 0x04
|
||||
#define CV1800B_ADC_EN BIT(0)
|
||||
#define CV1800B_ADC_SEL(x) BIT((x) + 5)
|
||||
#define CV1800B_ADC_STATUS_REG 0x08
|
||||
#define CV1800B_ADC_BUSY BIT(0)
|
||||
#define CV1800B_ADC_CYC_SET_REG 0x0C
|
||||
#define CV1800B_MASK_STARTUP_CYCLE GENMASK(4, 0)
|
||||
#define CV1800B_MASK_SAMPLE_WINDOW GENMASK(11, 8)
|
||||
#define CV1800B_MASK_CLKDIV GENMASK(15, 12)
|
||||
#define CV1800B_MASK_COMPARE_CYCLE GENMASK(19, 16)
|
||||
#define CV1800B_ADC_CH_RESULT_REG(x) (0x14 + 4 * (x))
|
||||
#define CV1800B_ADC_CH_RESULT GENMASK(11, 0)
|
||||
#define CV1800B_ADC_CH_VALID BIT(15)
|
||||
#define CV1800B_ADC_INTR_EN_REG 0x20
|
||||
#define CV1800B_ADC_INTR_CLR_REG 0x24
|
||||
#define CV1800B_ADC_INTR_CLR_BIT BIT(0)
|
||||
#define CV1800B_ADC_INTR_STA_REG 0x28
|
||||
#define CV1800B_ADC_INTR_STA_BIT BIT(0)
|
||||
#define CV1800B_READ_TIMEOUT_MS 1000
|
||||
#define CV1800B_READ_TIMEOUT_US (CV1800B_READ_TIMEOUT_MS * 1000)
|
||||
|
||||
#define CV1800B_ADC_CHANNEL(index) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
|
||||
.scan_index = index, \
|
||||
}
|
||||
|
||||
struct cv1800b_adc {
|
||||
struct completion completion;
|
||||
void __iomem *regs;
|
||||
struct mutex lock; /* ADC Control and Result register */
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec sophgo_channels[] = {
|
||||
CV1800B_ADC_CHANNEL(0),
|
||||
CV1800B_ADC_CHANNEL(1),
|
||||
CV1800B_ADC_CHANNEL(2),
|
||||
};
|
||||
|
||||
static void cv1800b_adc_start_measurement(struct cv1800b_adc *saradc,
|
||||
int channel)
|
||||
{
|
||||
writel(0, saradc->regs + CV1800B_ADC_CTRL_REG);
|
||||
writel(CV1800B_ADC_SEL(channel) | CV1800B_ADC_EN,
|
||||
saradc->regs + CV1800B_ADC_CTRL_REG);
|
||||
}
|
||||
|
||||
static int cv1800b_adc_wait(struct cv1800b_adc *saradc)
|
||||
{
|
||||
if (saradc->irq < 0) {
|
||||
u32 reg;
|
||||
|
||||
return readl_poll_timeout(saradc->regs + CV1800B_ADC_STATUS_REG,
|
||||
reg, !(reg & CV1800B_ADC_BUSY),
|
||||
500, CV1800B_READ_TIMEOUT_US);
|
||||
}
|
||||
|
||||
return wait_for_completion_timeout(&saradc->completion,
|
||||
msecs_to_jiffies(CV1800B_READ_TIMEOUT_MS)) > 0 ?
|
||||
0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int cv1800b_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct cv1800b_adc *saradc = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
u32 sample;
|
||||
|
||||
scoped_guard(mutex, &saradc->lock) {
|
||||
int ret;
|
||||
|
||||
cv1800b_adc_start_measurement(saradc, chan->scan_index);
|
||||
ret = cv1800b_adc_wait(saradc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
sample = readl(saradc->regs + CV1800B_ADC_CH_RESULT_REG(chan->scan_index));
|
||||
}
|
||||
if (!(sample & CV1800B_ADC_CH_VALID))
|
||||
return -ENODATA;
|
||||
|
||||
*val = sample & CV1800B_ADC_CH_RESULT;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 3300;
|
||||
*val2 = 12;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ: {
|
||||
u32 status_reg = readl(saradc->regs + CV1800B_ADC_CYC_SET_REG);
|
||||
unsigned int clk_div = (1 + FIELD_GET(CV1800B_MASK_CLKDIV, status_reg));
|
||||
unsigned int freq = clk_get_rate(saradc->clk) / clk_div;
|
||||
unsigned int nb_startup_cycle = 1 + FIELD_GET(CV1800B_MASK_STARTUP_CYCLE, status_reg);
|
||||
unsigned int nb_sample_cycle = 1 + FIELD_GET(CV1800B_MASK_SAMPLE_WINDOW, status_reg);
|
||||
unsigned int nb_compare_cycle = 1 + FIELD_GET(CV1800B_MASK_COMPARE_CYCLE, status_reg);
|
||||
|
||||
*val = freq / (nb_startup_cycle + nb_sample_cycle + nb_compare_cycle);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t cv1800b_adc_interrupt_handler(int irq, void *private)
|
||||
{
|
||||
struct cv1800b_adc *saradc = private;
|
||||
u32 reg = readl(saradc->regs + CV1800B_ADC_INTR_STA_REG);
|
||||
|
||||
if (!(FIELD_GET(CV1800B_ADC_INTR_STA_BIT, reg)))
|
||||
return IRQ_NONE;
|
||||
|
||||
writel(CV1800B_ADC_INTR_CLR_BIT, saradc->regs + CV1800B_ADC_INTR_CLR_REG);
|
||||
complete(&saradc->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info cv1800b_adc_info = {
|
||||
.read_raw = &cv1800b_adc_read_raw,
|
||||
};
|
||||
|
||||
static int cv1800b_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cv1800b_adc *saradc;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*saradc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
saradc = iio_priv(indio_dev);
|
||||
indio_dev->name = "sophgo-cv1800b-adc";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &cv1800b_adc_info;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sophgo_channels);
|
||||
indio_dev->channels = sophgo_channels;
|
||||
|
||||
saradc->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(saradc->clk))
|
||||
return PTR_ERR(saradc->clk);
|
||||
|
||||
saradc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(saradc->regs))
|
||||
return PTR_ERR(saradc->regs);
|
||||
|
||||
saradc->irq = platform_get_irq_optional(pdev, 0);
|
||||
if (saradc->irq > 0) {
|
||||
init_completion(&saradc->completion);
|
||||
ret = devm_request_irq(dev, saradc->irq,
|
||||
cv1800b_adc_interrupt_handler, 0,
|
||||
dev_name(dev), saradc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(1, saradc->regs + CV1800B_ADC_INTR_EN_REG);
|
||||
}
|
||||
|
||||
ret = devm_mutex_init(dev, &saradc->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(FIELD_PREP(CV1800B_MASK_STARTUP_CYCLE, 15) |
|
||||
FIELD_PREP(CV1800B_MASK_SAMPLE_WINDOW, 15) |
|
||||
FIELD_PREP(CV1800B_MASK_CLKDIV, 1) |
|
||||
FIELD_PREP(CV1800B_MASK_COMPARE_CYCLE, 15),
|
||||
saradc->regs + CV1800B_ADC_CYC_SET_REG);
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id cv1800b_adc_match[] = {
|
||||
{ .compatible = "sophgo,cv1800b-saradc", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cv1800b_adc_match);
|
||||
|
||||
static struct platform_driver cv1800b_adc_driver = {
|
||||
.driver = {
|
||||
.name = "sophgo-cv1800b-saradc",
|
||||
.of_match_table = cv1800b_adc_match,
|
||||
},
|
||||
.probe = cv1800b_adc_probe,
|
||||
};
|
||||
module_platform_driver(cv1800b_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Thomas Bonnefille <thomas.bonnefille@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Sophgo CV1800B SARADC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -2638,7 +2638,7 @@ static const struct of_device_id stm32_adc_of_match[] = {
|
||||
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
|
||||
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
|
||||
{ .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
|
||||
|
||||
|
||||
@@ -1466,7 +1466,7 @@ static const struct iio_chan_spec_ext_info dfsdm_adc_audio_ext_info[] = {
|
||||
.read = dfsdm_adc_audio_get_spiclk,
|
||||
.write = dfsdm_adc_audio_set_spiclk,
|
||||
},
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev)
|
||||
|
||||
@@ -299,7 +299,7 @@ static const struct of_device_id stm32_dfsdm_of_match[] = {
|
||||
.compatible = "st,stm32mp1-dfsdm",
|
||||
.data = &stm32mp1_dfsdm_data,
|
||||
},
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume);
|
||||
|
||||
static const struct of_device_id stmpe_adc_ids[] = {
|
||||
{ .compatible = "st,stmpe-adc", },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmpe_adc_ids);
|
||||
|
||||
|
||||
@@ -309,7 +309,7 @@ static const struct of_device_id adc0832_dt_ids[] = {
|
||||
{ .compatible = "ti,adc0832", },
|
||||
{ .compatible = "ti,adc0834", },
|
||||
{ .compatible = "ti,adc0838", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc0832_dt_ids);
|
||||
|
||||
@@ -318,7 +318,7 @@ static const struct spi_device_id adc0832_id[] = {
|
||||
{ "adc0832", adc0832 },
|
||||
{ "adc0834", adc0834 },
|
||||
{ "adc0838", adc0838 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc0832_id);
|
||||
|
||||
|
||||
@@ -242,13 +242,13 @@ static int adc084s021_probe(struct spi_device *spi)
|
||||
|
||||
static const struct of_device_id adc084s021_of_match[] = {
|
||||
{ .compatible = "ti,adc084s021", },
|
||||
{},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc084s021_of_match);
|
||||
|
||||
static const struct spi_device_id adc084s021_id[] = {
|
||||
{ ADC084S021_DRIVER_NAME, 0 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc084s021_id);
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ static const struct of_device_id adc12138_dt_ids[] = {
|
||||
{ .compatible = "ti,adc12130", },
|
||||
{ .compatible = "ti,adc12132", },
|
||||
{ .compatible = "ti,adc12138", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc12138_dt_ids);
|
||||
|
||||
@@ -527,7 +527,7 @@ static const struct spi_device_id adc12138_id[] = {
|
||||
{ "adc12130", adc12130 },
|
||||
{ "adc12132", adc12132 },
|
||||
{ "adc12138", adc12138 },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc12138_id);
|
||||
|
||||
|
||||
@@ -226,14 +226,14 @@ static int ti_adc_probe(struct spi_device *spi)
|
||||
static const struct of_device_id ti_adc_dt_ids[] = {
|
||||
{ .compatible = "ti,adc141s626", },
|
||||
{ .compatible = "ti,adc161s626", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
|
||||
|
||||
static const struct spi_device_id ti_adc_id[] = {
|
||||
{"adc141s626", TI_ADC141S626},
|
||||
{"adc161s626", TI_ADC161S626},
|
||||
{},
|
||||
{ "adc141s626", TI_ADC141S626 },
|
||||
{ "adc161s626", TI_ADC161S626 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ti_adc_id);
|
||||
|
||||
|
||||
@@ -1173,7 +1173,7 @@ static const struct i2c_device_id ads1015_id[] = {
|
||||
{ "ads1015", (kernel_ulong_t)&ads1015_data },
|
||||
{ "ads1115", (kernel_ulong_t)&ads1115_data },
|
||||
{ "tla2024", (kernel_ulong_t)&tla2024_data },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads1015_id);
|
||||
|
||||
@@ -1181,7 +1181,7 @@ static const struct of_device_id ads1015_of_match[] = {
|
||||
{ .compatible = "ti,ads1015", .data = &ads1015_data },
|
||||
{ .compatible = "ti,ads1115", .data = &ads1115_data },
|
||||
{ .compatible = "ti,tla2024", .data = &tla2024_data },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads1015_of_match);
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@ MODULE_DEVICE_TABLE(spi, ads124s_id);
|
||||
static const struct of_device_id ads124s_of_table[] = {
|
||||
{ .compatible = "ti,ads124s06" },
|
||||
{ .compatible = "ti,ads124s08" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads124s_of_table);
|
||||
|
||||
|
||||
@@ -918,7 +918,7 @@ static const struct of_device_id ads131e08_of_match[] = {
|
||||
.data = &ads131e08_info_tbl[ads131e06], },
|
||||
{ .compatible = "ti,ads131e08",
|
||||
.data = &ads131e08_info_tbl[ads131e08], },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads131e08_of_match);
|
||||
|
||||
@@ -926,7 +926,7 @@ static const struct spi_device_id ads131e08_ids[] = {
|
||||
{ "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] },
|
||||
{ "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] },
|
||||
{ "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ads131e08_ids);
|
||||
|
||||
|
||||
@@ -448,13 +448,13 @@ static int ads7924_probe(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id ads7924_id[] = {
|
||||
{ "ads7924" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads7924_id);
|
||||
|
||||
static const struct of_device_id ads7924_of_match[] = {
|
||||
{ .compatible = "ti,ads7924", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7924_of_match);
|
||||
|
||||
|
||||
@@ -705,7 +705,7 @@ static const struct of_device_id ads7950_of_table[] = {
|
||||
{ .compatible = "ti,ads7959", .data = &ti_ads7950_chip_info[TI_ADS7959] },
|
||||
{ .compatible = "ti,ads7960", .data = &ti_ads7950_chip_info[TI_ADS7960] },
|
||||
{ .compatible = "ti,ads7961", .data = &ti_ads7950_chip_info[TI_ADS7961] },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7950_of_table);
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ static int ads8344_probe(struct spi_device *spi)
|
||||
|
||||
static const struct of_device_id ads8344_of_match[] = {
|
||||
{ .compatible = "ti,ads8344", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads8344_of_match);
|
||||
|
||||
|
||||
@@ -452,9 +452,9 @@ static int ads8688_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ads8688_id[] = {
|
||||
{"ads8684", ID_ADS8684},
|
||||
{"ads8688", ID_ADS8688},
|
||||
{}
|
||||
{ "ads8684", ID_ADS8684 },
|
||||
{ "ads8688", ID_ADS8688 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ads8688_id);
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ static int lmp92064_adc_probe(struct spi_device *spi)
|
||||
|
||||
static const struct spi_device_id lmp92064_id_table[] = {
|
||||
{ "lmp92064" },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, lmp92064_id_table);
|
||||
|
||||
|
||||
@@ -237,14 +237,14 @@ static void tlc4541_remove(struct spi_device *spi)
|
||||
static const struct of_device_id tlc4541_dt_ids[] = {
|
||||
{ .compatible = "ti,tlc3541", },
|
||||
{ .compatible = "ti,tlc4541", },
|
||||
{}
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tlc4541_dt_ids);
|
||||
|
||||
static const struct spi_device_id tlc4541_id[] = {
|
||||
{"tlc3541", TLC3541},
|
||||
{"tlc4541", TLC4541},
|
||||
{}
|
||||
{ "tlc3541", TLC3541 },
|
||||
{ "tlc4541", TLC4541 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, tlc4541_id);
|
||||
|
||||
|
||||
@@ -1275,7 +1275,6 @@ static int ams_parse_firmware(struct iio_dev *indio_dev)
|
||||
struct ams *ams = iio_priv(indio_dev);
|
||||
struct iio_chan_spec *ams_channels, *dev_channels;
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
struct fwnode_handle *child = NULL;
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
size_t ams_size;
|
||||
int ret, ch_cnt = 0, i, rising_off, falling_off;
|
||||
@@ -1297,16 +1296,12 @@ static int ams_parse_firmware(struct iio_dev *indio_dev)
|
||||
num_channels += ret;
|
||||
}
|
||||
|
||||
fwnode_for_each_child_node(fwnode, child) {
|
||||
if (fwnode_device_is_available(child)) {
|
||||
ret = ams_init_module(indio_dev, child, ams_channels + num_channels);
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
ret = ams_init_module(indio_dev, child, ams_channels + num_channels);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_channels += ret;
|
||||
}
|
||||
num_channels += ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_channels; i++) {
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#include <linux/platform_data/ad5449.h>
|
||||
|
||||
#define AD5449_MAX_CHANNELS 2
|
||||
#define AD5449_MAX_VREFS 2
|
||||
|
||||
@@ -268,7 +266,6 @@ static const char *ad5449_vref_name(struct ad5449 *st, int n)
|
||||
|
||||
static int ad5449_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad5449_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad5449 *st;
|
||||
@@ -306,16 +303,8 @@ static int ad5449_spi_probe(struct spi_device *spi)
|
||||
mutex_init(&st->lock);
|
||||
|
||||
if (st->chip_info->has_ctrl) {
|
||||
unsigned int ctrl = 0x00;
|
||||
if (pdata) {
|
||||
if (pdata->hardware_clear_to_midscale)
|
||||
ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE;
|
||||
ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET;
|
||||
st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED;
|
||||
} else {
|
||||
st->has_sdo = true;
|
||||
}
|
||||
ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl);
|
||||
st->has_sdo = true;
|
||||
ad5449_write(indio_dev, AD5449_CMD_CTRL, 0x0);
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
||||
@@ -118,6 +118,38 @@ static const struct bmi323_hw bmi323_hw[2] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const unsigned int bmi323_reg_savestate[] = {
|
||||
BMI323_INT_MAP1_REG,
|
||||
BMI323_INT_MAP2_REG,
|
||||
BMI323_IO_INT_CTR_REG,
|
||||
BMI323_IO_INT_CONF_REG,
|
||||
BMI323_ACC_CONF_REG,
|
||||
BMI323_GYRO_CONF_REG,
|
||||
BMI323_FEAT_IO0_REG,
|
||||
BMI323_FIFO_WTRMRK_REG,
|
||||
BMI323_FIFO_CONF_REG
|
||||
};
|
||||
|
||||
static const unsigned int bmi323_ext_reg_savestate[] = {
|
||||
BMI323_GEN_SET1_REG,
|
||||
BMI323_TAP1_REG,
|
||||
BMI323_TAP2_REG,
|
||||
BMI323_TAP3_REG,
|
||||
BMI323_FEAT_IO0_S_TAP_MSK,
|
||||
BMI323_STEP_SC1_REG,
|
||||
BMI323_ANYMO1_REG,
|
||||
BMI323_NOMO1_REG,
|
||||
BMI323_ANYMO1_REG + BMI323_MO2_OFFSET,
|
||||
BMI323_NOMO1_REG + BMI323_MO2_OFFSET,
|
||||
BMI323_ANYMO1_REG + BMI323_MO3_OFFSET,
|
||||
BMI323_NOMO1_REG + BMI323_MO3_OFFSET
|
||||
};
|
||||
|
||||
struct bmi323_regs_runtime_pm {
|
||||
unsigned int reg_settings[ARRAY_SIZE(bmi323_reg_savestate)];
|
||||
unsigned int ext_reg_settings[ARRAY_SIZE(bmi323_ext_reg_savestate)];
|
||||
};
|
||||
|
||||
struct bmi323_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
@@ -130,6 +162,7 @@ struct bmi323_data {
|
||||
u32 odrns[BMI323_SENSORS_CNT];
|
||||
u32 odrhz[BMI323_SENSORS_CNT];
|
||||
unsigned int feature_events;
|
||||
struct bmi323_regs_runtime_pm runtime_pm_status;
|
||||
|
||||
/*
|
||||
* Lock to protect the members of device's private data from concurrent
|
||||
@@ -1972,6 +2005,11 @@ static void bmi323_disable(void *data_ptr)
|
||||
|
||||
bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE);
|
||||
bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE);
|
||||
|
||||
/*
|
||||
* Place the peripheral in its lowest power consuming state.
|
||||
*/
|
||||
regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL);
|
||||
}
|
||||
|
||||
static int bmi323_set_bw(struct bmi323_data *data,
|
||||
@@ -2030,6 +2068,13 @@ static int bmi323_init(struct bmi323_data *data)
|
||||
return dev_err_probe(data->dev, -EINVAL,
|
||||
"Sensor power error = 0x%x\n", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmi323_init_reset(struct bmi323_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Set the Bandwidth coefficient which defines the 3 dB cutoff
|
||||
* frequency in relation to the ODR.
|
||||
@@ -2078,12 +2123,18 @@ int bmi323_core_probe(struct device *dev)
|
||||
data = iio_priv(indio_dev);
|
||||
data->dev = dev;
|
||||
data->regmap = regmap;
|
||||
data->irq_pin = BMI323_IRQ_DISABLED;
|
||||
data->state = BMI323_IDLE;
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
ret = bmi323_init(data);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
ret = bmi323_init_reset(data);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) {
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
@@ -2117,7 +2168,7 @@ int bmi323_core_probe(struct device *dev)
|
||||
return dev_err_probe(data->dev, ret,
|
||||
"Unable to register iio device\n");
|
||||
|
||||
return 0;
|
||||
return bmi323_fifo_disable(data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323);
|
||||
|
||||
@@ -2125,13 +2176,119 @@ EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323);
|
||||
static int bmi323_core_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmi323_data *data = iio_priv(indio_dev);
|
||||
struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status;
|
||||
int ret;
|
||||
|
||||
return iio_device_suspend_triggering(indio_dev);
|
||||
guard(mutex)(&data->mutex);
|
||||
|
||||
ret = iio_device_suspend_triggering(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Save registers meant to be restored by resume pm callback. */
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) {
|
||||
ret = regmap_read(data->regmap, bmi323_reg_savestate[i],
|
||||
&savestate->reg_settings[i]);
|
||||
if (ret) {
|
||||
dev_err(data->dev,
|
||||
"Error reading bmi323 reg 0x%x: %d\n",
|
||||
bmi323_reg_savestate[i], ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) {
|
||||
ret = bmi323_read_ext_reg(data, bmi323_reg_savestate[i],
|
||||
&savestate->reg_settings[i]);
|
||||
if (ret) {
|
||||
dev_err(data->dev,
|
||||
"Error reading bmi323 external reg 0x%x: %d\n",
|
||||
bmi323_reg_savestate[i], ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform soft reset to place the device in its lowest power state. */
|
||||
ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmi323_core_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmi323_data *data = iio_priv(indio_dev);
|
||||
struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&data->mutex);
|
||||
|
||||
/*
|
||||
* Perform the device power-on and initial setup once again
|
||||
* after being reset in the lower power state by runtime-pm.
|
||||
*/
|
||||
ret = bmi323_init(data);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
/* Register must be cleared before changing an active config */
|
||||
ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "Error stopping feature engine\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) {
|
||||
ret = bmi323_write_ext_reg(data, bmi323_reg_savestate[i],
|
||||
savestate->reg_settings[i]);
|
||||
if (ret) {
|
||||
dev_err(data->dev,
|
||||
"Error writing bmi323 external reg 0x%x: %d\n",
|
||||
bmi323_reg_savestate[i], ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) {
|
||||
ret = regmap_write(data->regmap, bmi323_reg_savestate[i],
|
||||
savestate->reg_settings[i]);
|
||||
if (ret) {
|
||||
dev_err(data->dev,
|
||||
"Error writing bmi323 reg 0x%x: %d\n",
|
||||
bmi323_reg_savestate[i], ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear old FIFO samples that might be generated before suspend
|
||||
* or generated from a peripheral state not equal to the saved one.
|
||||
*/
|
||||
if (data->state == BMI323_BUFFER_FIFO) {
|
||||
ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG,
|
||||
BMI323_FIFO_FLUSH_MSK);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "Error flushing FIFO buffer: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, BMI323_ERR_REG, &val);
|
||||
if (ret) {
|
||||
dev_err(data->dev,
|
||||
"Error reading bmi323 error register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
dev_err(data->dev,
|
||||
"Sensor power error in PM = 0x%x\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return iio_device_resume_triggering(indio_dev);
|
||||
}
|
||||
|
||||
@@ -2127,25 +2127,15 @@ static const struct iio_info st_lsm6dsx_gyro_info = {
|
||||
.write_raw_get_fmt = st_lsm6dsx_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static int st_lsm6dsx_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
|
||||
{
|
||||
struct device *dev = hw->dev;
|
||||
|
||||
if (!dev_fwnode(dev))
|
||||
return -EINVAL;
|
||||
|
||||
return device_property_read_u32(dev, "st,drdy-int-pin", drdy_pin);
|
||||
}
|
||||
|
||||
static int
|
||||
st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw,
|
||||
const struct st_lsm6dsx_reg **drdy_reg)
|
||||
{
|
||||
struct device *dev = hw->dev;
|
||||
int err = 0, drdy_pin;
|
||||
|
||||
if (st_lsm6dsx_get_drdy_pin(hw, &drdy_pin) < 0) {
|
||||
if (device_property_read_u32(dev, "st,drdy-int-pin", &drdy_pin) < 0) {
|
||||
struct st_sensors_platform_data *pdata;
|
||||
struct device *dev = hw->dev;
|
||||
|
||||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
|
||||
drdy_pin = pdata ? pdata->drdy_int_pin : 1;
|
||||
@@ -2180,7 +2170,7 @@ static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
|
||||
hub_settings = &hw->settings->shub_settings;
|
||||
|
||||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
|
||||
if ((dev_fwnode(dev) && device_property_read_bool(dev, "st,pullups")) ||
|
||||
if (device_property_read_bool(dev, "st,pullups") ||
|
||||
(pdata && pdata->pullups)) {
|
||||
if (hub_settings->pullup_en.sec_page) {
|
||||
err = st_lsm6dsx_set_page(hw, true);
|
||||
@@ -2565,7 +2555,7 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
|
||||
return err;
|
||||
|
||||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
|
||||
if ((dev_fwnode(dev) && device_property_read_bool(dev, "drive-open-drain")) ||
|
||||
if (device_property_read_bool(dev, "drive-open-drain") ||
|
||||
(pdata && pdata->open_drain)) {
|
||||
reg = &hw->settings->irq_config.od;
|
||||
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
|
||||
@@ -2646,73 +2636,6 @@ static int st_lsm6dsx_init_regulators(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
static int lsm6dsx_get_acpi_mount_matrix(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
union acpi_object *obj, *elements;
|
||||
acpi_status status;
|
||||
int i, j, val[3];
|
||||
char *str;
|
||||
|
||||
if (!has_acpi_companion(dev))
|
||||
return -EINVAL;
|
||||
|
||||
if (!acpi_has_method(adev->handle, "ROTM"))
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3)
|
||||
goto unknown_format;
|
||||
|
||||
elements = obj->package.elements;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (elements[i].type != ACPI_TYPE_STRING)
|
||||
goto unknown_format;
|
||||
|
||||
str = elements[i].string.pointer;
|
||||
if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3)
|
||||
goto unknown_format;
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
switch (val[j]) {
|
||||
case -1: str = "-1"; break;
|
||||
case 0: str = "0"; break;
|
||||
case 1: str = "1"; break;
|
||||
default: goto unknown_format;
|
||||
}
|
||||
orientation->rotation[i * 3 + j] = str;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return 0;
|
||||
|
||||
unknown_format:
|
||||
dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n");
|
||||
kfree(buffer.pointer);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int lsm6dsx_get_acpi_mount_matrix(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
@@ -2760,8 +2683,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
|
||||
hub_settings = &hw->settings->shub_settings;
|
||||
if (hub_settings->master_en.addr &&
|
||||
(!dev_fwnode(dev) ||
|
||||
!device_property_read_bool(dev, "st,disable-sensor-hub"))) {
|
||||
!device_property_read_bool(dev, "st,disable-sensor-hub")) {
|
||||
err = st_lsm6dsx_shub_probe(hw, name);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -2787,8 +2709,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lsm6dsx_get_acpi_mount_matrix(hw->dev, &hw->orientation);
|
||||
if (err) {
|
||||
if (!iio_read_acpi_mount_matrix(hw->dev, &hw->orientation, "ROTM")) {
|
||||
err = iio_read_mount_matrix(hw->dev, &hw->orientation);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -2803,7 +2724,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((dev_fwnode(dev) && device_property_read_bool(dev, "wakeup-source")) ||
|
||||
if (device_property_read_bool(dev, "wakeup-source") ||
|
||||
(pdata && pdata->wakeup_source))
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ config AK8975
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Asahi Kasei AK8975, AK8963,
|
||||
AK09911, AK09912 or AK09916 3-Axis Magnetometer.
|
||||
AK09911, AK09912, AK09916 or AK09918 3-Axis Magnetometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak8975.
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
*/
|
||||
#define AK09912_REG_WIA1 0x00
|
||||
#define AK09912_REG_WIA2 0x01
|
||||
#define AK09918_DEVICE_ID 0x0C
|
||||
#define AK09916_DEVICE_ID 0x09
|
||||
#define AK09912_DEVICE_ID 0x04
|
||||
#define AK09911_DEVICE_ID 0x05
|
||||
@@ -209,6 +210,7 @@ enum asahi_compass_chipset {
|
||||
AK09911,
|
||||
AK09912,
|
||||
AK09916,
|
||||
AK09918,
|
||||
};
|
||||
|
||||
enum ak_ctrl_reg_addr {
|
||||
@@ -371,6 +373,34 @@ static const struct ak_def ak_def_array[] = {
|
||||
AK09912_REG_HXL,
|
||||
AK09912_REG_HYL,
|
||||
AK09912_REG_HZL},
|
||||
},
|
||||
[AK09918] = {
|
||||
/* ak09918 is register compatible with ak09912 this is for avoid
|
||||
* unknown id messages.
|
||||
*/
|
||||
.type = AK09918,
|
||||
.raw_to_gauss = ak09912_raw_to_gauss,
|
||||
.range = 32752,
|
||||
.ctrl_regs = {
|
||||
AK09912_REG_ST1,
|
||||
AK09912_REG_ST2,
|
||||
AK09912_REG_CNTL2,
|
||||
AK09912_REG_ASAX,
|
||||
AK09912_MAX_REGS},
|
||||
.ctrl_masks = {
|
||||
AK09912_REG_ST1_DRDY_MASK,
|
||||
AK09912_REG_ST2_HOFL_MASK,
|
||||
0,
|
||||
AK09912_REG_CNTL2_MODE_MASK},
|
||||
.ctrl_modes = {
|
||||
AK09912_REG_CNTL_MODE_POWER_DOWN,
|
||||
AK09912_REG_CNTL_MODE_ONCE,
|
||||
AK09912_REG_CNTL_MODE_SELF_TEST,
|
||||
AK09912_REG_CNTL_MODE_FUSE_ROM},
|
||||
.data_regs = {
|
||||
AK09912_REG_HXL,
|
||||
AK09912_REG_HYL,
|
||||
AK09912_REG_HZL},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -452,6 +482,7 @@ static int ak8975_who_i_am(struct i2c_client *client,
|
||||
/*
|
||||
* Signature for each device:
|
||||
* Device | WIA1 | WIA2
|
||||
* AK09918 | DEVICE_ID_| AK09918_DEVICE_ID
|
||||
* AK09916 | DEVICE_ID_| AK09916_DEVICE_ID
|
||||
* AK09912 | DEVICE_ID | AK09912_DEVICE_ID
|
||||
* AK09911 | DEVICE_ID | AK09911_DEVICE_ID
|
||||
@@ -484,10 +515,18 @@ static int ak8975_who_i_am(struct i2c_client *client,
|
||||
if (wia_val[1] == AK09916_DEVICE_ID)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "Type %d unknown\n", type);
|
||||
case AK09918:
|
||||
if (wia_val[1] == AK09918_DEVICE_ID)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return -ENODEV;
|
||||
|
||||
dev_info(&client->dev, "Device ID %x is unknown.\n", wia_val[1]);
|
||||
/*
|
||||
* Let driver to probe on unknown id for support more register
|
||||
* compatible variants.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -692,22 +731,8 @@ static int ak8975_start_read_axis(struct ak8975_data *data,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* This will be executed only for non-interrupt based waiting case */
|
||||
if (ret & data->def->ctrl_masks[ST1_DRDY]) {
|
||||
ret = i2c_smbus_read_byte_data(client,
|
||||
data->def->ctrl_regs[ST2]);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error in reading ST2\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret & (data->def->ctrl_masks[ST2_DERR] |
|
||||
data->def->ctrl_masks[ST2_HOFL])) {
|
||||
dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Return with zero if the data is ready. */
|
||||
return !data->def->ctrl_regs[ST1_DRDY];
|
||||
}
|
||||
|
||||
/* Retrieve raw flux value for one of the x, y, or z axis. */
|
||||
@@ -734,6 +759,20 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
/* Read out ST2 for release lock on measurment data. */
|
||||
ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error in reading ST2\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ret & (data->def->ctrl_masks[ST2_DERR] |
|
||||
data->def->ctrl_masks[ST2_HOFL])) {
|
||||
dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
@@ -1067,6 +1106,7 @@ static const struct i2c_device_id ak8975_id[] = {
|
||||
{"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] },
|
||||
{"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
|
||||
{"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
|
||||
{"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak8975_id);
|
||||
@@ -1081,6 +1121,7 @@ static const struct of_device_id ak8975_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] },
|
||||
{ .compatible = "ak09912", .data = &ak_def_array[AK09912] },
|
||||
{ .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] },
|
||||
{ .compatible = "asahi-kasei,ak09918", .data = &ak_def_array[AK09918] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak8975_of_match);
|
||||
|
||||
@@ -233,4 +233,15 @@ config VL53L0X_I2C
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vl53l0x-i2c.
|
||||
|
||||
config AW96103
|
||||
tristate "AW96103/AW96105 Awinic proximity sensor"
|
||||
select REGMAP_I2C
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to build a driver for Awinic's AW96103/AW96105 capacitive
|
||||
proximity sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called aw96103.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -22,4 +22,5 @@ obj-$(CONFIG_SX_COMMON) += sx_common.o
|
||||
obj-$(CONFIG_SX9500) += sx9500.o
|
||||
obj-$(CONFIG_VCNL3020) += vcnl3020.o
|
||||
obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o
|
||||
obj-$(CONFIG_AW96103) += aw96103.o
|
||||
|
||||
|
||||
846
drivers/iio/proximity/aw96103.c
Normal file
846
drivers/iio/proximity/aw96103.c
Normal file
@@ -0,0 +1,846 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AWINIC aw96103 proximity sensor driver
|
||||
*
|
||||
* Author: Wang Shuaijie <wangshuaijie@awinic.com>
|
||||
*
|
||||
* Copyright (c) 2024 awinic Technology CO., LTD
|
||||
*/
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define AW_DATA_PROCESS_FACTOR 1024
|
||||
#define AW96103_CHIP_ID 0xa961
|
||||
#define AW96103_BIN_VALID_DATA_OFFSET 64
|
||||
#define AW96103_BIN_DATA_LEN_OFFSET 16
|
||||
#define AW96103_BIN_DATA_REG_NUM_SIZE 4
|
||||
#define AW96103_BIN_CHIP_TYPE_SIZE 8
|
||||
#define AW96103_BIN_CHIP_TYPE_OFFSET 24
|
||||
|
||||
#define AW96103_REG_SCANCTRL0 0x0000
|
||||
#define AW96103_REG_STAT0 0x0090
|
||||
#define AW96103_REG_BLFILT_CH0 0x00A8
|
||||
#define AW96103_REG_BLRSTRNG_CH0 0x00B4
|
||||
#define AW96103_REG_DIFF_CH0 0x0240
|
||||
#define AW96103_REG_FWVER2 0x0410
|
||||
#define AW96103_REG_CMD 0xF008
|
||||
#define AW96103_REG_IRQSRC 0xF080
|
||||
#define AW96103_REG_IRQEN 0xF084
|
||||
#define AW96103_REG_RESET 0xFF0C
|
||||
#define AW96103_REG_CHIPID 0xFF10
|
||||
#define AW96103_REG_EEDA0 0x0408
|
||||
#define AW96103_REG_EEDA1 0x040C
|
||||
#define AW96103_REG_PROXCTRL_CH0 0x00B0
|
||||
#define AW96103_REG_PROXTH0_CH0 0x00B8
|
||||
#define AW96103_PROXTH_CH_STEP 0x3C
|
||||
#define AW96103_THHYST_MASK GENMASK(13, 12)
|
||||
#define AW96103_INDEB_MASK GENMASK(11, 10)
|
||||
#define AW96103_OUTDEB_MASK GENMASK(9, 8)
|
||||
#define AW96103_INITOVERIRQ_MASK BIT(0)
|
||||
#define AW96103_BLFILT_CH_STEP 0x3C
|
||||
#define AW96103_BLRSTRNG_MASK GENMASK(5, 0)
|
||||
#define AW96103_CHIPID_MASK GENMASK(31, 16)
|
||||
#define AW96103_BLERRTRIG_MASK BIT(25)
|
||||
#define AW96103_CHAN_EN_MASK GENMASK(5, 0)
|
||||
#define AW96103_REG_PROXCTRL_CH(x) \
|
||||
(AW96103_REG_PROXCTRL_CH0 + (x) * AW96103_PROXTH_CH_STEP)
|
||||
|
||||
#define AW96103_REG_PROXTH0_CH(x) \
|
||||
(AW96103_REG_PROXTH0_CH0 + (x) * AW96103_PROXTH_CH_STEP)
|
||||
|
||||
/**
|
||||
* struct aw_bin - Store the data obtained from parsing the configuration file.
|
||||
* @chip_type: Frame header information-chip type
|
||||
* @valid_data_len: Length of valid data obtained after parsing
|
||||
* @valid_data_addr: The offset address of the valid data obtained
|
||||
* after parsing relative to info
|
||||
* @len: The size of the bin file obtained from the firmware
|
||||
* @data: Store the bin file obtained from the firmware
|
||||
*/
|
||||
struct aw_bin {
|
||||
unsigned char chip_type[8];
|
||||
unsigned int valid_data_len;
|
||||
unsigned int valid_data_addr;
|
||||
unsigned int len;
|
||||
unsigned char data[] __counted_by(len);
|
||||
};
|
||||
|
||||
enum aw96103_sar_vers {
|
||||
AW96103 = 2,
|
||||
AW96103A = 6,
|
||||
AW96103B = 0xa,
|
||||
};
|
||||
|
||||
enum aw96103_operation_mode {
|
||||
AW96103_ACTIVE_MODE = 1,
|
||||
AW96103_SLEEP_MODE = 2,
|
||||
AW96103_DEEPSLEEP_MODE = 3,
|
||||
AW96103B_DEEPSLEEP_MODE = 4,
|
||||
};
|
||||
|
||||
enum aw96103_sensor_type {
|
||||
AW96103_VAL,
|
||||
AW96105_VAL,
|
||||
};
|
||||
|
||||
struct aw_channels_info {
|
||||
bool used;
|
||||
unsigned int old_irq_status;
|
||||
};
|
||||
|
||||
struct aw_chip_info {
|
||||
const char *name;
|
||||
struct iio_chan_spec const *channels;
|
||||
int num_channels;
|
||||
};
|
||||
|
||||
struct aw96103 {
|
||||
unsigned int hostirqen;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
/*
|
||||
* There is one more logical channel than the actual channels,
|
||||
* and the extra logical channel is used for temperature detection
|
||||
* but not for status detection. The specific channel used for
|
||||
* temperature detection is determined by the register configuration.
|
||||
*/
|
||||
struct aw_channels_info channels_arr[6];
|
||||
unsigned int max_channels;
|
||||
unsigned int chan_en;
|
||||
};
|
||||
|
||||
static const unsigned int aw96103_reg_default[] = {
|
||||
0x0000, 0x00003f3f, 0x0004, 0x00000064, 0x0008, 0x0017c11e,
|
||||
0x000c, 0x05000000, 0x0010, 0x00093ffd, 0x0014, 0x19240009,
|
||||
0x0018, 0xd81c0207, 0x001c, 0xff000000, 0x0020, 0x00241900,
|
||||
0x0024, 0x00093ff7, 0x0028, 0x58020009, 0x002c, 0xd81c0207,
|
||||
0x0030, 0xff000000, 0x0034, 0x00025800, 0x0038, 0x00093fdf,
|
||||
0x003c, 0x7d3b0009, 0x0040, 0xd81c0207, 0x0044, 0xff000000,
|
||||
0x0048, 0x003b7d00, 0x004c, 0x00093f7f, 0x0050, 0xe9310009,
|
||||
0x0054, 0xd81c0207, 0x0058, 0xff000000, 0x005c, 0x0031e900,
|
||||
0x0060, 0x00093dff, 0x0064, 0x1a0c0009, 0x0068, 0xd81c0207,
|
||||
0x006c, 0xff000000, 0x0070, 0x000c1a00, 0x0074, 0x80093fff,
|
||||
0x0078, 0x043d0009, 0x007c, 0xd81c0207, 0x0080, 0xff000000,
|
||||
0x0084, 0x003d0400, 0x00a0, 0xe6400000, 0x00a4, 0x00000000,
|
||||
0x00a8, 0x010408d2, 0x00ac, 0x00000000, 0x00b0, 0x00000000,
|
||||
0x00b8, 0x00005fff, 0x00bc, 0x00000000, 0x00c0, 0x00000000,
|
||||
0x00c4, 0x00000000, 0x00c8, 0x00000000, 0x00cc, 0x00000000,
|
||||
0x00d0, 0x00000000, 0x00d4, 0x00000000, 0x00d8, 0x00000000,
|
||||
0x00dc, 0xe6447800, 0x00e0, 0x78000000, 0x00e4, 0x010408d2,
|
||||
0x00e8, 0x00000000, 0x00ec, 0x00000000, 0x00f4, 0x00005fff,
|
||||
0x00f8, 0x00000000, 0x00fc, 0x00000000, 0x0100, 0x00000000,
|
||||
0x0104, 0x00000000, 0x0108, 0x00000000, 0x010c, 0x02000000,
|
||||
0x0110, 0x00000000, 0x0114, 0x00000000, 0x0118, 0xe6447800,
|
||||
0x011c, 0x78000000, 0x0120, 0x010408d2, 0x0124, 0x00000000,
|
||||
0x0128, 0x00000000, 0x0130, 0x00005fff, 0x0134, 0x00000000,
|
||||
0x0138, 0x00000000, 0x013c, 0x00000000, 0x0140, 0x00000000,
|
||||
0x0144, 0x00000000, 0x0148, 0x02000000, 0x014c, 0x00000000,
|
||||
0x0150, 0x00000000, 0x0154, 0xe6447800, 0x0158, 0x78000000,
|
||||
0x015c, 0x010408d2, 0x0160, 0x00000000, 0x0164, 0x00000000,
|
||||
0x016c, 0x00005fff, 0x0170, 0x00000000, 0x0174, 0x00000000,
|
||||
0x0178, 0x00000000, 0x017c, 0x00000000, 0x0180, 0x00000000,
|
||||
0x0184, 0x02000000, 0x0188, 0x00000000, 0x018c, 0x00000000,
|
||||
0x0190, 0xe6447800, 0x0194, 0x78000000, 0x0198, 0x010408d2,
|
||||
0x019c, 0x00000000, 0x01a0, 0x00000000, 0x01a8, 0x00005fff,
|
||||
0x01ac, 0x00000000, 0x01b0, 0x00000000, 0x01b4, 0x00000000,
|
||||
0x01b8, 0x00000000, 0x01bc, 0x00000000, 0x01c0, 0x02000000,
|
||||
0x01c4, 0x00000000, 0x01c8, 0x00000000, 0x01cc, 0xe6407800,
|
||||
0x01d0, 0x78000000, 0x01d4, 0x010408d2, 0x01d8, 0x00000000,
|
||||
0x01dc, 0x00000000, 0x01e4, 0x00005fff, 0x01e8, 0x00000000,
|
||||
0x01ec, 0x00000000, 0x01f0, 0x00000000, 0x01f4, 0x00000000,
|
||||
0x01f8, 0x00000000, 0x01fc, 0x02000000, 0x0200, 0x00000000,
|
||||
0x0204, 0x00000000, 0x0208, 0x00000008, 0x020c, 0x0000000d,
|
||||
0x41fc, 0x00000000, 0x4400, 0x00000000, 0x4410, 0x00000000,
|
||||
0x4420, 0x00000000, 0x4430, 0x00000000, 0x4440, 0x00000000,
|
||||
0x4450, 0x00000000, 0x4460, 0x00000000, 0x4470, 0x00000000,
|
||||
0xf080, 0x00003018, 0xf084, 0x00000fff, 0xf800, 0x00000000,
|
||||
0xf804, 0x00002e00, 0xf8d0, 0x00000001, 0xf8d4, 0x00000000,
|
||||
0xff00, 0x00000301, 0xff0c, 0x01000000, 0xffe0, 0x00000000,
|
||||
0xfff4, 0x00004011, 0x0090, 0x00000000, 0x0094, 0x00000000,
|
||||
0x0098, 0x00000000, 0x009c, 0x3f3f3f3f,
|
||||
};
|
||||
|
||||
static const struct iio_event_spec aw_common_events[3] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
|
||||
BIT(IIO_EV_INFO_HYSTERESIS) |
|
||||
BIT(IIO_EV_INFO_VALUE),
|
||||
}
|
||||
};
|
||||
|
||||
#define AW_IIO_CHANNEL(idx) \
|
||||
{ \
|
||||
.type = IIO_PROXIMITY, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.channel = idx, \
|
||||
.event_spec = aw_common_events, \
|
||||
.num_event_specs = ARRAY_SIZE(aw_common_events), \
|
||||
} \
|
||||
|
||||
static const struct iio_chan_spec aw96103_channels[] = {
|
||||
AW_IIO_CHANNEL(0),
|
||||
AW_IIO_CHANNEL(1),
|
||||
AW_IIO_CHANNEL(2),
|
||||
AW_IIO_CHANNEL(3),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec aw96105_channels[] = {
|
||||
AW_IIO_CHANNEL(0),
|
||||
AW_IIO_CHANNEL(1),
|
||||
AW_IIO_CHANNEL(2),
|
||||
AW_IIO_CHANNEL(3),
|
||||
AW_IIO_CHANNEL(4),
|
||||
AW_IIO_CHANNEL(5),
|
||||
};
|
||||
|
||||
static const struct aw_chip_info aw_chip_info_tbl[] = {
|
||||
[AW96103_VAL] = {
|
||||
.name = "aw96103_sensor",
|
||||
.channels = aw96103_channels,
|
||||
.num_channels = ARRAY_SIZE(aw96103_channels),
|
||||
},
|
||||
[AW96105_VAL] = {
|
||||
.name = "aw96105_sensor",
|
||||
.channels = aw96105_channels,
|
||||
.num_channels = ARRAY_SIZE(aw96105_channels),
|
||||
},
|
||||
};
|
||||
|
||||
static void aw96103_parsing_bin_file(struct aw_bin *bin)
|
||||
{
|
||||
bin->valid_data_addr = AW96103_BIN_VALID_DATA_OFFSET;
|
||||
bin->valid_data_len =
|
||||
*(unsigned int *)(bin->data + AW96103_BIN_DATA_LEN_OFFSET) -
|
||||
AW96103_BIN_DATA_REG_NUM_SIZE;
|
||||
memcpy(bin->chip_type, bin->data + AW96103_BIN_CHIP_TYPE_OFFSET,
|
||||
AW96103_BIN_CHIP_TYPE_SIZE);
|
||||
}
|
||||
|
||||
static const struct regmap_config aw96103_regmap_confg = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 32,
|
||||
};
|
||||
|
||||
static int aw96103_get_diff_raw(struct aw96103 *aw96103, unsigned int chan,
|
||||
int *buf)
|
||||
{
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_DIFF_CH0 + chan * 4, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
*buf = (int)(data / AW_DATA_PROCESS_FACTOR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw96103_read_raw(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = aw96103_get_diff_raw(aw96103, chan->channel, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int aw96103_read_thresh(struct aw96103 *aw96103,
|
||||
const struct iio_chan_spec *chan, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_PROXTH0_CH(chan->channel), val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int aw96103_read_out_debounce(struct aw96103 *aw96103,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel), ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = FIELD_GET(AW96103_OUTDEB_MASK, reg_val);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int aw96103_read_in_debounce(struct aw96103 *aw96103,
|
||||
const struct iio_chan_spec *chan, int *val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel), ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = FIELD_GET(AW96103_INDEB_MASK, reg_val);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int aw96103_read_hysteresis(struct aw96103 *aw96103,
|
||||
const struct iio_chan_spec *chan, int *val)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel), ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = FIELD_GET(AW96103_THHYST_MASK, reg_val);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int aw96103_read_event_val(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
int *val, int *val2)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
|
||||
if (chan->type != IIO_PROXIMITY)
|
||||
return -EINVAL;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
return aw96103_read_thresh(aw96103, chan, val);
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return aw96103_read_out_debounce(aw96103, chan, val);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return aw96103_read_in_debounce(aw96103, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_HYSTERESIS:
|
||||
return aw96103_read_hysteresis(aw96103, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int aw96103_write_event_val(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info, int val, int val2)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
|
||||
if (chan->type != IIO_PROXIMITY)
|
||||
return -EINVAL;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
return regmap_write(aw96103->regmap,
|
||||
AW96103_REG_PROXTH0_CH(chan->channel), val);
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return regmap_update_bits(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel),
|
||||
AW96103_OUTDEB_MASK,
|
||||
FIELD_PREP(AW96103_OUTDEB_MASK, val));
|
||||
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return regmap_update_bits(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel),
|
||||
AW96103_INDEB_MASK,
|
||||
FIELD_PREP(AW96103_INDEB_MASK, val));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_HYSTERESIS:
|
||||
return regmap_update_bits(aw96103->regmap,
|
||||
AW96103_REG_PROXCTRL_CH(chan->channel),
|
||||
AW96103_THHYST_MASK,
|
||||
FIELD_PREP(AW96103_THHYST_MASK, val));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int aw96103_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
|
||||
return aw96103->channels_arr[chan->channel].used;
|
||||
}
|
||||
|
||||
static int aw96103_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
|
||||
aw96103->channels_arr[chan->channel].used = !!state;
|
||||
|
||||
return regmap_update_bits(aw96103->regmap, AW96103_REG_SCANCTRL0,
|
||||
BIT(chan->channel),
|
||||
state ? BIT(chan->channel) : 0);
|
||||
}
|
||||
|
||||
static struct iio_info iio_info = {
|
||||
.read_raw = aw96103_read_raw,
|
||||
.read_event_value = aw96103_read_event_val,
|
||||
.write_event_value = aw96103_write_event_val,
|
||||
.read_event_config = aw96103_read_event_config,
|
||||
.write_event_config = aw96103_write_event_config,
|
||||
};
|
||||
|
||||
static int aw96103_channel_scan_start(struct aw96103 *aw96103)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(aw96103->regmap, AW96103_REG_CMD,
|
||||
AW96103_ACTIVE_MODE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(aw96103->regmap, AW96103_REG_IRQEN,
|
||||
aw96103->hostirqen);
|
||||
}
|
||||
|
||||
static int aw96103_reg_version_comp(struct aw96103 *aw96103,
|
||||
struct aw_bin *aw_bin)
|
||||
{
|
||||
u32 blfilt1_data, fw_ver;
|
||||
unsigned char i;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_FWVER2, &fw_ver);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* If the chip version is AW96103A and the loaded register
|
||||
* configuration file is for AW96103, special handling of the
|
||||
* AW96103_REG_BLRSTRNG_CH0 register is required.
|
||||
*/
|
||||
if ((fw_ver != AW96103A) || (aw_bin->chip_type[7] != '\0'))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < aw96103->max_channels; i++) {
|
||||
ret = regmap_read(aw96103->regmap,
|
||||
AW96103_REG_BLFILT_CH0 + (AW96103_BLFILT_CH_STEP * i),
|
||||
&blfilt1_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (FIELD_GET(AW96103_BLERRTRIG_MASK, blfilt1_data) != 1)
|
||||
return 0;
|
||||
|
||||
ret = regmap_update_bits(aw96103->regmap,
|
||||
AW96103_REG_BLRSTRNG_CH0 + (AW96103_BLFILT_CH_STEP * i),
|
||||
AW96103_BLRSTRNG_MASK, 1 << i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw96103_bin_valid_loaded(struct aw96103 *aw96103,
|
||||
struct aw_bin *aw_bin_data_s)
|
||||
{
|
||||
unsigned int start_addr = aw_bin_data_s->valid_data_addr;
|
||||
u32 i, reg_data;
|
||||
u16 reg_addr;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < aw_bin_data_s->valid_data_len;
|
||||
i += 6, start_addr += 6) {
|
||||
reg_addr = get_unaligned_le16(aw_bin_data_s->data + start_addr);
|
||||
reg_data = get_unaligned_le32(aw_bin_data_s->data +
|
||||
start_addr + 2);
|
||||
if ((reg_addr == AW96103_REG_EEDA0) ||
|
||||
(reg_addr == AW96103_REG_EEDA1))
|
||||
continue;
|
||||
if (reg_addr == AW96103_REG_IRQEN) {
|
||||
aw96103->hostirqen = reg_data;
|
||||
continue;
|
||||
}
|
||||
if (reg_addr == AW96103_REG_SCANCTRL0)
|
||||
aw96103->chan_en = FIELD_GET(AW96103_CHAN_EN_MASK,
|
||||
reg_data);
|
||||
|
||||
ret = regmap_write(aw96103->regmap, reg_addr, reg_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aw96103_reg_version_comp(aw96103, aw_bin_data_s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return aw96103_channel_scan_start(aw96103);
|
||||
}
|
||||
|
||||
static int aw96103_para_loaded(struct aw96103 *aw96103)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aw96103_reg_default); i += 2) {
|
||||
ret = regmap_write(aw96103->regmap,
|
||||
(u16)aw96103_reg_default[i],
|
||||
(u32)aw96103_reg_default[i + 1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (aw96103_reg_default[i] == AW96103_REG_IRQEN)
|
||||
aw96103->hostirqen = aw96103_reg_default[i + 1];
|
||||
else if (aw96103_reg_default[i] == AW96103_REG_SCANCTRL0)
|
||||
aw96103->chan_en = FIELD_GET(AW96103_CHAN_EN_MASK,
|
||||
aw96103_reg_default[i + 1]);
|
||||
}
|
||||
|
||||
return aw96103_channel_scan_start(aw96103);
|
||||
}
|
||||
|
||||
static int aw96103_cfg_all_loaded(const struct firmware *cont,
|
||||
struct aw96103 *aw96103)
|
||||
{
|
||||
if (!cont)
|
||||
return -EINVAL;
|
||||
|
||||
struct aw_bin *aw_bin __free(kfree) =
|
||||
kzalloc(cont->size + sizeof(*aw_bin), GFP_KERNEL);
|
||||
if (!aw_bin)
|
||||
return -ENOMEM;
|
||||
|
||||
aw_bin->len = cont->size;
|
||||
memcpy(aw_bin->data, cont->data, cont->size);
|
||||
release_firmware(cont);
|
||||
aw96103_parsing_bin_file(aw_bin);
|
||||
|
||||
return aw96103_bin_valid_loaded(aw96103, aw_bin);
|
||||
}
|
||||
|
||||
static void aw96103_cfg_update(const struct firmware *fw, void *data)
|
||||
{
|
||||
struct aw96103 *aw96103 = data;
|
||||
int ret, i;
|
||||
|
||||
if (!fw || !fw->data) {
|
||||
dev_err(aw96103->dev, "No firmware.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = aw96103_cfg_all_loaded(fw, aw96103);
|
||||
/*
|
||||
* If loading the register configuration file fails,
|
||||
* load the default register configuration in the driver to
|
||||
* ensure the basic functionality of the device.
|
||||
*/
|
||||
if (ret) {
|
||||
ret = aw96103_para_loaded(aw96103);
|
||||
if (ret) {
|
||||
dev_err(aw96103->dev, "load param error.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < aw96103->max_channels; i++) {
|
||||
if ((aw96103->chan_en >> i) & 0x01)
|
||||
aw96103->channels_arr[i].used = true;
|
||||
else
|
||||
aw96103->channels_arr[i].used = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int aw96103_sw_reset(struct aw96103 *aw96103)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(aw96103->regmap, AW96103_REG_RESET, 0);
|
||||
/*
|
||||
* After reset, the initialization process starts to perform and
|
||||
* it will last for a bout 20ms.
|
||||
*/
|
||||
msleep(20);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum aw96103_irq_trigger_position {
|
||||
FAR = 0,
|
||||
TRIGGER_TH0 = 0x01,
|
||||
TRIGGER_TH1 = 0x03,
|
||||
TRIGGER_TH2 = 0x07,
|
||||
TRIGGER_TH3 = 0x0f,
|
||||
};
|
||||
|
||||
static irqreturn_t aw96103_irq(int irq, void *data)
|
||||
{
|
||||
unsigned int irq_status, curr_status_val, curr_status;
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
int ret, i;
|
||||
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_IRQSRC, &irq_status);
|
||||
if (ret)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_STAT0, &curr_status_val);
|
||||
if (ret)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* Iteratively analyze the interrupt status of different channels,
|
||||
* with each channel having 4 interrupt states.
|
||||
*/
|
||||
for (i = 0; i < aw96103->max_channels; i++) {
|
||||
if (!aw96103->channels_arr[i].used)
|
||||
continue;
|
||||
|
||||
curr_status = (((curr_status_val >> (24 + i)) & 0x1)) |
|
||||
(((curr_status_val >> (16 + i)) & 0x1) << 1) |
|
||||
(((curr_status_val >> (8 + i)) & 0x1) << 2) |
|
||||
(((curr_status_val >> i) & 0x1) << 3);
|
||||
if (aw96103->channels_arr[i].old_irq_status == curr_status)
|
||||
continue;
|
||||
|
||||
switch (curr_status) {
|
||||
case FAR:
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, i,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns(indio_dev));
|
||||
break;
|
||||
case TRIGGER_TH0:
|
||||
case TRIGGER_TH1:
|
||||
case TRIGGER_TH2:
|
||||
case TRIGGER_TH3:
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, i,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns(indio_dev));
|
||||
break;
|
||||
default:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
aw96103->channels_arr[i].old_irq_status = curr_status;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int aw96103_interrupt_init(struct iio_dev *indio_dev,
|
||||
struct i2c_client *i2c)
|
||||
{
|
||||
struct aw96103 *aw96103 = iio_priv(indio_dev);
|
||||
unsigned int irq_status;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(aw96103->regmap, AW96103_REG_IRQEN, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_IRQSRC, &irq_status);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = devm_request_threaded_irq(aw96103->dev, i2c->irq, NULL,
|
||||
aw96103_irq, IRQF_ONESHOT,
|
||||
"aw96103_irq", indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(aw96103->regmap, AW96103_REG_IRQEN,
|
||||
aw96103->hostirqen);
|
||||
}
|
||||
|
||||
static int aw96103_wait_chip_init(struct aw96103 *aw96103)
|
||||
{
|
||||
unsigned int cnt = 20;
|
||||
u32 reg_data;
|
||||
int ret;
|
||||
|
||||
while (cnt--) {
|
||||
/*
|
||||
* The device should generate an initialization completion
|
||||
* interrupt within 20ms.
|
||||
*/
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_IRQSRC,
|
||||
®_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (FIELD_GET(AW96103_INITOVERIRQ_MASK, reg_data))
|
||||
return 0;
|
||||
fsleep(1000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int aw96103_read_chipid(struct aw96103 *aw96103)
|
||||
{
|
||||
unsigned char cnt = 0;
|
||||
u32 reg_val = 0;
|
||||
int ret;
|
||||
|
||||
while (cnt < 3) {
|
||||
/*
|
||||
* This retry mechanism and the subsequent delay are just
|
||||
* attempts to read the chip ID as much as possible,
|
||||
* preventing occasional communication failures from causing
|
||||
* the chip ID read to fail.
|
||||
*/
|
||||
ret = regmap_read(aw96103->regmap, AW96103_REG_CHIPID,
|
||||
®_val);
|
||||
if (ret < 0) {
|
||||
cnt++;
|
||||
fsleep(2000);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cnt == 3)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (FIELD_GET(AW96103_CHIPID_MASK, reg_val) != AW96103_CHIP_ID)
|
||||
dev_info(aw96103->dev,
|
||||
"unexpected chipid, id=0x%08X\n", reg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw96103_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
const struct aw_chip_info *chip_info;
|
||||
struct iio_dev *indio_dev;
|
||||
struct aw96103 *aw96103;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&i2c->dev, sizeof(*aw96103));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
aw96103 = iio_priv(indio_dev);
|
||||
aw96103->dev = &i2c->dev;
|
||||
chip_info = i2c_get_match_data(i2c);
|
||||
aw96103->max_channels = chip_info->num_channels;
|
||||
|
||||
aw96103->regmap = devm_regmap_init_i2c(i2c, &aw96103_regmap_confg);
|
||||
if (IS_ERR(aw96103->regmap))
|
||||
return PTR_ERR(aw96103->regmap);
|
||||
|
||||
ret = devm_regulator_get_enable(aw96103->dev, "vcc");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = aw96103_read_chipid(aw96103);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aw96103_sw_reset(aw96103);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aw96103_wait_chip_init(aw96103);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = request_firmware_nowait(THIS_MODULE, true, "aw96103_0.bin",
|
||||
aw96103->dev, GFP_KERNEL, aw96103,
|
||||
aw96103_cfg_update);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aw96103_interrupt_init(indio_dev, i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->num_channels = chip_info->num_channels;
|
||||
indio_dev->channels = chip_info->channels;
|
||||
indio_dev->info = &iio_info;
|
||||
indio_dev->name = chip_info->name;
|
||||
|
||||
return devm_iio_device_register(aw96103->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id aw96103_dt_match[] = {
|
||||
{
|
||||
.compatible = "awinic,aw96103",
|
||||
.data = &aw_chip_info_tbl[AW96103_VAL]
|
||||
},
|
||||
{
|
||||
.compatible = "awinic,aw96105",
|
||||
.data = &aw_chip_info_tbl[AW96105_VAL]
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aw96103_dt_match);
|
||||
|
||||
static const struct i2c_device_id aw96103_i2c_id[] = {
|
||||
{ "aw96103", (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] },
|
||||
{ "aw96105", (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, aw96103_i2c_id);
|
||||
|
||||
static struct i2c_driver aw96103_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "aw96103_sensor",
|
||||
.of_match_table = aw96103_dt_match,
|
||||
},
|
||||
.probe = aw96103_i2c_probe,
|
||||
.id_table = aw96103_i2c_id,
|
||||
};
|
||||
module_i2c_driver(aw96103_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Wang Shuaijie <wangshuaijie@awinic.com>");
|
||||
MODULE_DESCRIPTION("Driver for Awinic AW96103 proximity sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -6,10 +6,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
@@ -209,13 +209,23 @@ static const struct regmap_access_table axp313a_volatile_table = {
|
||||
};
|
||||
|
||||
static const struct regmap_range axp717_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1),
|
||||
regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL),
|
||||
regmap_reg_range(AXP717_VSYS_V_POWEROFF, AXP717_VSYS_V_POWEROFF),
|
||||
regmap_reg_range(AXP717_IRQ0_EN, AXP717_IRQ4_EN),
|
||||
regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE),
|
||||
regmap_reg_range(AXP717_ICC_CHG_SET, AXP717_CV_CHG_SET),
|
||||
regmap_reg_range(AXP717_DCDC_OUTPUT_CONTROL, AXP717_CPUSLDO_CONTROL),
|
||||
regmap_reg_range(AXP717_ADC_CH_EN_CONTROL, AXP717_ADC_CH_EN_CONTROL),
|
||||
regmap_reg_range(AXP717_ADC_DATA_SEL, AXP717_ADC_DATA_SEL),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp717_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP717_ON_INDICATE, AXP717_PMU_FAULT),
|
||||
regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE),
|
||||
regmap_reg_range(AXP717_BATT_PERCENT_DATA, AXP717_BATT_PERCENT_DATA),
|
||||
regmap_reg_range(AXP717_BATT_V_H, AXP717_BATT_CHRG_I_L),
|
||||
regmap_reg_range(AXP717_ADC_DATA_H, AXP717_ADC_DATA_L),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp717_writeable_table = {
|
||||
@@ -308,6 +318,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
|
||||
};
|
||||
|
||||
static const struct resource axp717_usb_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_OVER_V, "VBUS_OVER_V"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
|
||||
};
|
||||
|
||||
/* AXP803 and AXP813/AXP818 share the same interrupts */
|
||||
static const struct resource axp803_usb_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
|
||||
@@ -422,7 +438,7 @@ static const struct regmap_config axp717_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.wr_table = &axp717_writeable_table,
|
||||
.volatile_table = &axp717_volatile_table,
|
||||
.max_register = AXP717_CPUSLDO_CONTROL,
|
||||
.max_register = AXP717_ADC_DATA_L,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
|
||||
@@ -1024,6 +1040,13 @@ static struct mfd_cell axp313a_cells[] = {
|
||||
static struct mfd_cell axp717_cells[] = {
|
||||
MFD_CELL_NAME("axp20x-regulator"),
|
||||
MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
|
||||
MFD_CELL_OF("axp717-adc",
|
||||
NULL, NULL, 0, 0, "x-powers,axp717-adc"),
|
||||
MFD_CELL_OF("axp20x-usb-power-supply",
|
||||
axp717_usb_power_supply_resources, NULL, 0, 0,
|
||||
"x-powers,axp717-usb-power-supply"),
|
||||
MFD_CELL_OF("axp20x-battery-power-supply",
|
||||
NULL, NULL, 0, 0, "x-powers,axp717-battery-power-supply"),
|
||||
};
|
||||
|
||||
static const struct resource axp288_adc_resources[] = {
|
||||
|
||||
@@ -115,6 +115,16 @@ enum axp20x_variants {
|
||||
#define AXP313A_IRQ_STATE 0x21
|
||||
|
||||
#define AXP717_ON_INDICATE 0x00
|
||||
#define AXP717_PMU_STATUS_2 0x01
|
||||
#define AXP717_BC_DETECT 0x05
|
||||
#define AXP717_PMU_FAULT 0x08
|
||||
#define AXP717_MODULE_EN_CONTROL_1 0x0b
|
||||
#define AXP717_MIN_SYS_V_CONTROL 0x15
|
||||
#define AXP717_INPUT_VOL_LIMIT_CTRL 0x16
|
||||
#define AXP717_INPUT_CUR_LIMIT_CTRL 0x17
|
||||
#define AXP717_MODULE_EN_CONTROL_2 0x19
|
||||
#define AXP717_BOOST_CONTROL 0x1e
|
||||
#define AXP717_VSYS_V_POWEROFF 0x24
|
||||
#define AXP717_IRQ0_EN 0x40
|
||||
#define AXP717_IRQ1_EN 0x41
|
||||
#define AXP717_IRQ2_EN 0x42
|
||||
@@ -125,6 +135,9 @@ enum axp20x_variants {
|
||||
#define AXP717_IRQ2_STATE 0x4a
|
||||
#define AXP717_IRQ3_STATE 0x4b
|
||||
#define AXP717_IRQ4_STATE 0x4c
|
||||
#define AXP717_ICC_CHG_SET 0x62
|
||||
#define AXP717_ITERM_CHG_SET 0x63
|
||||
#define AXP717_CV_CHG_SET 0x64
|
||||
#define AXP717_DCDC_OUTPUT_CONTROL 0x80
|
||||
#define AXP717_DCDC1_CONTROL 0x83
|
||||
#define AXP717_DCDC2_CONTROL 0x84
|
||||
@@ -145,6 +158,19 @@ enum axp20x_variants {
|
||||
#define AXP717_CLDO3_CONTROL 0x9d
|
||||
#define AXP717_CLDO4_CONTROL 0x9e
|
||||
#define AXP717_CPUSLDO_CONTROL 0x9f
|
||||
#define AXP717_BATT_PERCENT_DATA 0xa4
|
||||
#define AXP717_ADC_CH_EN_CONTROL 0xc0
|
||||
#define AXP717_BATT_V_H 0xc4
|
||||
#define AXP717_BATT_V_L 0xc5
|
||||
#define AXP717_VBUS_V_H 0xc6
|
||||
#define AXP717_VBUS_V_L 0xc7
|
||||
#define AXP717_VSYS_V_H 0xc8
|
||||
#define AXP717_VSYS_V_L 0xc9
|
||||
#define AXP717_BATT_CHRG_I_H 0xca
|
||||
#define AXP717_BATT_CHRG_I_L 0xcb
|
||||
#define AXP717_ADC_DATA_SEL 0xcd
|
||||
#define AXP717_ADC_DATA_H 0xce
|
||||
#define AXP717_ADC_DATA_L 0xcf
|
||||
|
||||
#define AXP806_STARTUP_SRC 0x00
|
||||
#define AXP806_CHIP_ID 0x03
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog
|
||||
* Converter driver.
|
||||
*
|
||||
* Copyright 2012 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PLATFORM_DATA_AD5449_H__
|
||||
#define __LINUX_PLATFORM_DATA_AD5449_H__
|
||||
|
||||
/**
|
||||
* enum ad5449_sdo_mode - AD5449 SDO pin configuration
|
||||
* @AD5449_SDO_DRIVE_FULL: Drive the SDO pin with full strength.
|
||||
* @AD5449_SDO_DRIVE_WEAK: Drive the SDO pin with not full strength.
|
||||
* @AD5449_SDO_OPEN_DRAIN: Operate the SDO pin in open-drain mode.
|
||||
* @AD5449_SDO_DISABLED: Disable the SDO pin, in this mode it is not possible to
|
||||
* read back from the device.
|
||||
*/
|
||||
enum ad5449_sdo_mode {
|
||||
AD5449_SDO_DRIVE_FULL = 0x0,
|
||||
AD5449_SDO_DRIVE_WEAK = 0x1,
|
||||
AD5449_SDO_OPEN_DRAIN = 0x2,
|
||||
AD5449_SDO_DISABLED = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad5449_platform_data - Platform data for the ad5449 DAC driver
|
||||
* @sdo_mode: SDO pin mode
|
||||
* @hardware_clear_to_midscale: Whether asserting the hardware CLR pin sets the
|
||||
* outputs to midscale (true) or to zero scale(false).
|
||||
*/
|
||||
struct ad5449_platform_data {
|
||||
enum ad5449_sdo_mode sdo_mode;
|
||||
bool hardware_clear_to_midscale;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -58,7 +58,7 @@ $(OUTPUT)iio_generic_buffer: $(IIO_GENERIC_BUFFER_IN)
|
||||
clean:
|
||||
rm -f $(ALL_PROGRAMS)
|
||||
rm -rf $(OUTPUT)include/linux/iio
|
||||
find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
|
||||
find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -o -name '\.*.cmd' -delete
|
||||
|
||||
install: $(ALL_PROGRAMS)
|
||||
install -d -m 755 $(DESTDIR)$(bindir); \
|
||||
|
||||
@@ -498,6 +498,10 @@ int main(int argc, char **argv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
trigger_name = malloc(IIO_MAX_NAME_LENGTH);
|
||||
if (!trigger_name) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ret = read_sysfs_string("name", trig_dev_name, trigger_name);
|
||||
free(trig_dev_name);
|
||||
if (ret < 0) {
|
||||
|
||||
Reference in New Issue
Block a user