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:
Greg Kroah-Hartman
2024-09-08 13:23:57 +02:00
92 changed files with 2128 additions and 382 deletions

View File

@@ -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:

View File

@@ -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>;
};
};

View File

@@ -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:

View File

@@ -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

View File

@@ -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>;
};
};

View File

@@ -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

View File

@@ -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++)

View File

@@ -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

View File

@@ -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

View File

@@ -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),
&reg_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),
&reg_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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 = {

View File

@@ -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 = {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 = &ltc2496_info, },
{},
{ }
};
MODULE_DEVICE_TABLE(of, ltc2496_of_match);

View File

@@ -151,7 +151,7 @@ MODULE_DEVICE_TABLE(i2c, ltc2497_id);
static const struct of_device_id ltc2497_of_match[] = {
{ .compatible = "lltc,ltc2497", .data = &ltc2497_info[TYPE_LTC2497] },
{ .compatible = "lltc,ltc2499", .data = &ltc2497_info[TYPE_LTC2499] },
{},
{ }
};
MODULE_DEVICE_TABLE(of, ltc2497_of_match);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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" },

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View 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");

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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++) {

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View 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), &reg_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), &reg_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), &reg_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,
&reg_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,
&reg_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");

View File

@@ -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>

View File

@@ -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[] = {

View File

@@ -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

View File

@@ -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

View File

@@ -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); \

View File

@@ -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) {