Commit 82aec3ed authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.16a' of...

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

Jonathan writes:

First set of new device support, cleanups and features for IIO in the 4.16 cycle

New device support
* IDT Z0PT2201 ambient light and UVB sensor
  - new driver and DT bindings.
* MAX30102 (pulse oximetery sensor)
  - support for MAX30105 sensor (smoke detector)  Just goes to show
    how two supposedly totally different applications can use very similar
    devices.
* UVIS25 UV sensor
  - new driver and DT bindings.

Major new features
* at91-sama5d2-adc
  - DMA support including bindings + a fix for an issue with acking the
    interrupt to prevent false overrun reports.
* ina2xx
  - allow control of shunt voltage PGA and bus voltage range to give better
    accuracy in some cases.
* stm32-adc
  - support differential channels (precursor patch reworked how channel names
    were created to enable this).

Cleanups / minor fixes / features
* core
  - mark a deliberate switch fallthrough.
  - macro to populate struct iio_map array elements.
* docs
  - typo fix.
* MAINTAINERS
  - add some missing entries for IIO ABI files.

* ad7152
  - tidy up unlocking paths.
* ad7746
  - tidy up unlocking paths.
* ak8975
  - add an ACPI id found on a prototype board.
* aspeed-adc
  - deassert reset in probe to ensure device is usable.
* bfin-trigger
  - platform_get_irq return value fixing.
* bmc150
  - OF device ID table for i2c (spi to be done).
* cros_ec
  - unused variable cleanup.
* da208
  - ACPI binding seen on Linx 820 tablet.
* ina2xx
  - shift down raw value to drop status flags from value (likely to have
    been hidden in the noise).
  - tidy up a special case that wasn't needed.
* inv_mpu6050
  - i2c_unregister_device knows about null values so don't check it twice.
* kxsd9
  - fix missing MODULE_LICENSE and MODULE_DESCRIPTION.
* max30102
  - missing new lines in dev_err.
  - inconsistent punctuation in error messages.
  - fix LED mode mask number of bits.
  - check return value of power mode functions to handle errors.
  - introduce an intensity channel macro to reduce duplication.
  - fix minor issue where device wasn't necessarily enabled during
    a get temperature.
  - use indicies for LED channels.
  - move the mode seetting to buffer_postenable - precursor to new device
    support.
  - prepare to allow copying of varying numbers of measurement.
* meson-saradc
  - drop irrelevant clock and update bindings.
* mma8452
  - a couple of renames for readability reasons.
* qcom_vadc
  - fix missing MODULE_LICENSE and MODULE_DESCRIPTION.
* st_accel
  - drop an unused variable.
* sx9500
  - add an ACPI id found on a prototype board.
parents dfe571ac 8d05ffd2
......@@ -1290,7 +1290,7 @@ KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
Description:
Unit-less light intensity. Modifiers both and ir indicate
that measurements contains visible and infrared light
that measurements contain visible and infrared light
components or just infrared light, respectively. Modifier uv indicates
that measurements contain ultraviolet light components.
......
......@@ -15,7 +15,6 @@ Required properties:
- "clkin" for the reference clock (typically XTAL)
- "core" for the SAR ADC core clock
optional clocks:
- "sana" for the analog clock
- "adc_clk" for the ADC (sampling) clock
- "adc_sel" for the ADC (sampling) clock mux
- vref-supply: the regulator supply for the ADC reference voltage
......
......@@ -8,6 +8,7 @@ Required properties:
- reg: memory window mapping address and length
- clocks: Input clock used to derive the sample clock. Expected to be the
SoC's APB clock.
- resets: Reset controller phandle
- #io-channel-cells: Must be set to <1> to indicate channels are selected
by index.
......@@ -15,6 +16,7 @@ Example:
adc@1e6e9000 {
compatible = "aspeed,ast2400-adc";
reg = <0x1e6e9000 0xb0>;
clocks = <&clk_apb>;
clocks = <&syscon ASPEED_CLK_APB>;
resets = <&syscon ASPEED_RESET_ADC>;
#io-channel-cells = <1>;
};
......@@ -17,6 +17,11 @@ Required properties:
This property uses the IRQ edge types values: IRQ_TYPE_EDGE_RISING ,
IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH
Optional properties:
- dmas: Phandle to dma channel for the ADC.
- dma-names: Must be "rx" when dmas property is being used.
See ../../dma/dma.txt for details.
Example:
adc: adc@fc030000 {
......@@ -31,4 +36,6 @@ adc: adc@fc030000 {
vddana-supply = <&vdd_3v3_lp_reg>;
vref-supply = <&vdd_3v3_lp_reg>;
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>;
dma-names = "rx";
}
......@@ -62,6 +62,15 @@ Required properties:
- st,adc-channels: List of single-ended channels muxed for this ADC.
It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered
from 0 to 15 or 19 (resp. for in0..in15 or in0..in19).
- st,adc-diff-channels: List of differential channels muxed for this ADC.
Depending on part used, some channels can be configured as differential
instead of single-ended (e.g. stm32h7). List here positive and negative
inputs pairs as <vinp vinn>, <vinp vinn>,... vinp and vinn are numbered
from 0 to 19 on stm32h7)
Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is required.
Both properties can be used together. Some channels can be used as
single-ended and some other ones as differential (mixed). But channels
can't be configured both as single-ended and differential (invalid).
- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
Documentation/devicetree/bindings/iio/iio-bindings.txt
......@@ -111,3 +120,18 @@ Example:
...
other adc child nodes follow...
};
Example to setup:
- channel 1 as single-ended
- channels 2 & 3 as differential (with resp. 6 & 7 negative inputs)
adc: adc@40022000 {
compatible = "st,stm32h7-adc-core";
...
adc1: adc@0 {
compatible = "st,stm32h7-adc";
...
st,adc-channels = <1>;
st,adc-diff-channels = <2 6>, <3 7>;
};
};
Maxim MAX30102 heart rate and pulse oximeter sensor
Maxim MAX30105 optical particle-sensing module
* https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf
Required properties:
- compatible: must be "maxim,max30102"
- compatible: must be "maxim,max30102" or "maxim,max30105"
- reg: the I2C address of the sensor
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: the sole interrupt generated by the device
......@@ -12,8 +14,10 @@ Required properties:
interrupt client node bindings.
Optional properties:
- maxim,red-led-current-microamp: configuration for RED LED current
- maxim,red-led-current-microamp: configuration for red LED current
- maxim,ir-led-current-microamp: configuration for IR LED current
- maxim,green-led-current-microamp: configuration for green LED current
(max30105 only)
Note that each step is approximately 200 microamps, ranging from 0 uA to
50800 uA.
......
* ST UVIS25 uv sensor
Required properties:
- compatible: should be "st,uvis25"
- reg: i2c address of the sensor / spi cs line
Optional properties:
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ. It should be configured with
flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
IRQ_TYPE_EDGE_FALLING.
Refer to interrupt-controller/interrupts.txt for generic interrupt
client node bindings.
Example:
uvis25@47 {
compatible = "st,uvis25";
reg = <0x47>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
......@@ -262,6 +262,7 @@ ACCES 104-QUAD-8 IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
F: drivers/iio/counter/104-quad-8.c
ACCES PCI-IDIO-16 GPIO DRIVER
......@@ -845,6 +846,8 @@ M: Michael Hennerich <Michael.Hennerich@analog.com>
W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc2497*
X: drivers/iio/*/adjd*
......@@ -4126,6 +4129,7 @@ DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
F: drivers/iio/proximity/srf*.c
DEVICE COREDUMP (DEV_COREDUMP)
......@@ -6829,6 +6833,8 @@ R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
L: linux-iio@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
S: Maintained
F: Documentation/ABI/testing/configfs-iio*
F: Documentation/ABI/testing/sysfs-bus-iio*
F: Documentation/devicetree/bindings/iio/
F: drivers/iio/
F: drivers/staging/iio/
......
......@@ -81,9 +81,21 @@ static const struct i2c_device_id bmc150_accel_id[] = {
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
static const struct of_device_id bmc150_accel_of_match[] = {
{ .compatible = "bosch,bmc150_accel" },
{ .compatible = "bosch,bmi055_accel" },
{ .compatible = "bosch,bma255" },
{ .compatible = "bosch,bma250e" },
{ .compatible = "bosch,bma222e" },
{ .compatible = "bosch,bma280" },
{ },
};
MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
static struct i2c_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_i2c",
.of_match_table = bmc150_accel_of_match,
.acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
.pm = &bmc150_accel_pm_ops,
},
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/byteorder/generic.h>
......@@ -25,7 +26,7 @@
#define DA280_MODE_ENABLE 0x1e
#define DA280_MODE_DISABLE 0x9e
enum { da226, da280 };
enum da280_chipset { da226, da280 };
/*
* a value of + or -4096 corresponds to + or - 1G
......@@ -91,12 +92,24 @@ static const struct iio_info da280_info = {
.read_raw = da280_read_raw,
};
static enum da280_chipset da280_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return -EINVAL;
return (enum da280_chipset) id->driver_data;
}
static int da280_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct da280_data *data;
enum da280_chipset chip;
ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
if (ret != DA280_CHIP_ID)
......@@ -114,7 +127,14 @@ static int da280_probe(struct i2c_client *client,
indio_dev->info = &da280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = da280_channels;
if (id->driver_data == da226) {
if (ACPI_HANDLE(&client->dev)) {
chip = da280_match_acpi_device(&client->dev);
} else {
chip = id->driver_data;
}
if (chip == da226) {
indio_dev->name = "da226";
indio_dev->num_channels = 2;
} else {
......@@ -158,6 +178,12 @@ static int da280_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
static const struct acpi_device_id da280_acpi_match[] = {
{"MIRAACC", da280},
{},
};
MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
static const struct i2c_device_id da280_i2c_id[] = {
{ "da226", da226 },
{ "da280", da280 },
......@@ -168,6 +194,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
static struct i2c_driver da280_driver = {
.driver = {
.name = "da280",
.acpi_match_table = ACPI_PTR(da280_acpi_match),
.pm = &da280_pm_ops,
},
.probe = da280_probe,
......
......@@ -63,3 +63,6 @@ static struct i2c_driver kxsd9_i2c_driver = {
.id_table = kxsd9_i2c_id,
};
module_i2c_driver(kxsd9_i2c_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface");
......@@ -135,7 +135,7 @@ struct mma8452_event_regs {
u8 ev_count;
};
static const struct mma8452_event_regs ev_regs_accel_falling = {
static const struct mma8452_event_regs ff_mt_ev_regs = {
.ev_cfg = MMA8452_FF_MT_CFG,
.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
.ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT,
......@@ -145,7 +145,7 @@ static const struct mma8452_event_regs ev_regs_accel_falling = {
.ev_count = MMA8452_FF_MT_COUNT
};
static const struct mma8452_event_regs ev_regs_accel_rising = {
static const struct mma8452_event_regs trans_ev_regs = {
.ev_cfg = MMA8452_TRANSIENT_CFG,
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
.ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT,
......@@ -284,7 +284,7 @@ static const int mma8452_samp_freq[8][2] = {
};
/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
static const unsigned int mma8452_transient_time_step_us[4][8] = {
static const unsigned int mma8452_time_step_us[4][8] = {
{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */
{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */
{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/
......@@ -777,12 +777,12 @@ static int mma8452_get_event_regs(struct mma8452_data *data,
& MMA8452_INT_TRANS) &&
(data->chip_info->enabled_events
& MMA8452_INT_TRANS))
*ev_reg = &ev_regs_accel_rising;
*ev_reg = &trans_ev_regs;
else
*ev_reg = &ev_regs_accel_falling;
*ev_reg = &ff_mt_ev_regs;
return 0;
case IIO_EV_DIR_FALLING:
*ev_reg = &ev_regs_accel_falling;
*ev_reg = &ff_mt_ev_regs;
return 0;
default:
return -EINVAL;
......@@ -826,7 +826,7 @@ static int mma8452_read_event_value(struct iio_dev *indio_dev,
if (power_mode < 0)
return power_mode;
us = ret * mma8452_transient_time_step_us[power_mode][
us = ret * mma8452_time_step_us[power_mode][
mma8452_get_odr_index(data)];
*val = us / USEC_PER_SEC;
*val2 = us % USEC_PER_SEC;
......@@ -883,7 +883,7 @@ static int mma8452_write_event_value(struct iio_dev *indio_dev,
return ret;
steps = (val * USEC_PER_SEC + val2) /
mma8452_transient_time_step_us[ret][
mma8452_time_step_us[ret][
mma8452_get_odr_index(data)];
if (steps < 0 || steps > 0xff)
......
......@@ -920,8 +920,6 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev);
int err;
......@@ -948,9 +946,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
&adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
if (!pdata)
pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
if (err < 0)
goto st_accel_power_off;
......
......@@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC
tristate "Atmel AT91 SAMA5D2 ADC"
depends on ARCH_AT91 || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Atmel SAMA5D2 ADC which is
......
......@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/types.h>
......@@ -53,11 +54,12 @@ struct aspeed_adc_model_data {
};
struct aspeed_adc_data {
struct device *dev;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *clk_prescaler;
struct clk_hw *clk_scaler;
struct device *dev;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *clk_prescaler;
struct clk_hw *clk_scaler;
struct reset_control *rst;
};
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
......@@ -217,6 +219,15 @@ static int aspeed_adc_probe(struct platform_device *pdev)
goto scaler_error;
}
data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(data->rst)) {
dev_err(&pdev->dev,
"invalid or missing reset controller device tree entry");
ret = PTR_ERR(data->rst);
goto reset_error;
}
reset_control_deassert(data->rst);
model_data = of_device_get_match_data(&pdev->dev);
if (model_data->wait_init_sequence) {
......@@ -263,9 +274,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
data->base + ASPEED_REG_ENGINE_CONTROL);
clk_disable_unprepare(data->clk_scaler->clk);
reset_error:
reset_control_assert(data->rst);
clk_enable_error:
clk_hw_unregister_divider(data->clk_scaler);
scaler_error:
clk_hw_unregister_divider(data->clk_prescaler);
return ret;
......@@ -280,6 +292,7 @@ static int aspeed_adc_remove(struct platform_device *pdev)
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
data->base + ASPEED_REG_ENGINE_CONTROL);
clk_disable_unprepare(data->clk_scaler->clk);
reset_control_assert(data->rst);
clk_hw_unregister_divider(data->clk_scaler);
clk_hw_unregister_divider(data->clk_prescaler);
......
This diff is collapsed.
......@@ -92,22 +92,14 @@ static const struct iio_chan_spec axp288_adc_channels[] = {
},
};
#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
_consumer_channel) \
{ \
.adc_channel_label = _adc_channel_label, \
.consumer_dev_name = _consumer_dev_name, \
.consumer_channel = _consumer_channel, \
}
/* for consumer drivers */
static struct iio_map axp288_adc_default_maps[] = {
AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
{},
};
......
......@@ -44,13 +44,14 @@
#define INA226_MASK_ENABLE 0x06
#define INA226_CVRF BIT(3)
#define INA219_CNVR BIT(1)
#define INA2XX_MAX_REGISTERS 8
/* settings - depend on use case */
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=1/8, BRNG=32V */
#define INA219_DEFAULT_IT 532
#define INA219_DEFAULT_BRNG 1 /* 32V */
#define INA219_DEFAULT_PGA 125 /* 1000/8 */
#define INA226_CONFIG_DEFAULT 0x4327
#define INA226_DEFAULT_AVG 4
#define INA226_DEFAULT_IT 1110
......@@ -63,6 +64,14 @@
*/
#define INA2XX_MODE_MASK GENMASK(3, 0)
/* Gain for VShunt: 1/8 (default), 1/4, 1/2, 1 */
#define INA219_PGA_MASK GENMASK(12, 11)
#define INA219_SHIFT_PGA(val) ((val) << 11)
/* VBus range: 32V (default), 16V */
#define INA219_BRNG_MASK BIT(13)
#define INA219_SHIFT_BRNG(val) ((val) << 13)
/* Averaging for VBus/VShunt/Power */
#define INA226_AVG_MASK GENMASK(11, 9)
#define INA226_SHIFT_AVG(val) ((val) << 9)
......@@ -79,6 +88,11 @@
#define INA226_ITS_MASK GENMASK(5, 3)
#define INA226_SHIFT_ITS(val) ((val) << 3)
/* INA219 Bus voltage register, low bits are flags */
#define INA219_OVF BIT(0)
#define INA219_CNVR BIT(1)
#define INA219_BUS_VOLTAGE_SHIFT 3
/* Cosmetic macro giving the sampling period for a full P=UxI cycle */
#define SAMPLING_PERIOD(c) ((c->int_time_vbus + c->int_time_vshunt) \
* c->avg)
......@@ -111,8 +125,8 @@ enum ina2xx_ids { ina219, ina226 };
struct ina2xx_config {
u16 config_default;
int calibration_factor;
int shunt_div;
int bus_voltage_shift;
int shunt_voltage_lsb; /* nV */
int bus_voltage_shift; /* position of lsb */
int bus_voltage_lsb; /* uV */
int power_lsb; /* uW */
enum ina2xx_ids chip_id;
......@@ -127,6 +141,8 @@ struct ina2xx_chip_info {
int avg;
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
int range_vbus; /* Bus voltage maximum in V */
int pga_gain_vshunt; /* Shunt voltage PGA gain */
bool allow_async_readout;
};
......@@ -134,8 +150,8 @@ static const struct ina2xx_config ina2xx_config[] = {
[ina219] = {
.config_default = INA219_CONFIG_DEFAULT,
.calibration_factor = 40960000,
.shunt_div = 100,
.bus_voltage_shift = 3,
.shunt_voltage_lsb = 10000,
.bus_voltage_shift = INA219_BUS_VOLTAGE_SHIFT,
.bus_voltage_lsb = 4000,
.power_lsb = 20000,
.chip_id = ina219,
......@@ -143,7 +159,7 @@ static const struct ina2xx_config ina2xx_config[] = {
[ina226] = {
.config_default = INA226_CONFIG_DEFAULT,
.calibration_factor = 5120000,
.shunt_div = 400,
.shunt_voltage_lsb = 2500,
.bus_voltage_shift = 0,
.bus_voltage_lsb = 1250,
.power_lsb = 25000,
......@@ -170,6 +186,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
else
*val = regval;
if (chan->address == INA2XX_BUS_VOLTAGE)
*val >>= chip->config->bus_voltage_shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
......@@ -197,15 +216,15 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
/* processed (mV) = raw/shunt_div */
*val2 = chip->config->shunt_div;
*val = 1;
/* processed (mV) = raw * lsb(nV) / 1000000 */
*val = chip->config->shunt_voltage_lsb;
*val2 = 1000000;
return IIO_VAL_FRACTIONAL;
case INA2XX_BUS_VOLTAGE:
/* processed (mV) = raw*lsb (uV) / (1000 << shift) */
/* processed (mV) = raw * lsb (uV) / 1000 */
*val = chip->config->bus_voltage_lsb;
*val2 = 1000 << chip->config->bus_voltage_shift;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case INA2XX_POWER:
......@@ -219,6 +238,18 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
*val = 1;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_HARDWAREGAIN:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
*val = chip->pga_gain_vshunt;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case INA2XX_BUS_VOLTAGE:
*val = chip->range_vbus == 32 ? 1 : 2;
return IIO_VAL_INT;
}
}
return -EINVAL;
......@@ -353,6 +384,74 @@ static int ina219_set_int_time_vshunt(struct ina2xx_chip_info *chip,
return 0;
}
static const int ina219_vbus_range_tab[] = { 1, 2 };
static int ina219_set_vbus_range_denom(struct ina2xx_chip_info *chip,
unsigned int range,
unsigned int *config)
{
if (range == 1)
chip->range_vbus = 32;
else if (range == 2)
chip->range_vbus = 16;
else
return -EINVAL;
*config &= ~INA219_BRNG_MASK;
*config |= INA219_SHIFT_BRNG(range == 1 ? 1 : 0) & INA219_BRNG_MASK;
return 0;
}
static const int ina219_vshunt_gain_tab[] = { 125, 250, 500, 1000 };
static const int ina219_vshunt_gain_frac[] = {
125, 1000, 250, 1000, 500, 1000, 1000, 1000 };
static int ina219_set_vshunt_pga_gain(struct ina2xx_chip_info *chip,
unsigned int gain,
unsigned int *config)
{
int bits;
if (gain < 125 || gain > 1000)
return -EINVAL;
bits = find_closest(gain, ina219_vshunt_gain_tab,
ARRAY_SIZE(ina219_vshunt_gain_tab));
chip->pga_gain_vshunt = ina219_vshunt_gain_tab[bits];
bits = 3 - bits;
*config &= ~INA219_PGA_MASK;
*config |= INA219_SHIFT_PGA(bits) & INA219_PGA_MASK;
return 0;
}
static int ina2xx_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
*type = IIO_VAL_FRACTIONAL;
*length = sizeof(ina219_vshunt_gain_frac) / sizeof(int);
*vals = ina219_vshunt_gain_frac;
return IIO_AVAIL_LIST;
case INA2XX_BUS_VOLTAGE:
*type = IIO_VAL_INT;
*length = sizeof(ina219_vbus_range_tab) / sizeof(int);
*vals = ina219_vbus_range_tab;
return IIO_AVAIL_LIST;
}
}
return -EINVAL;
}
static int ina2xx_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
......@@ -395,6 +494,14 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_HARDWAREGAIN:
if (chan->address == INA2XX_SHUNT_VOLTAGE)
ret = ina219_set_vshunt_pga_gain(chip, val * 1000 +
val2 / 1000, &tmp);
else
ret = ina219_set_vbus_range_denom(chip, val, &tmp);
break;
default:
ret = -EINVAL;
}
......@@ -532,19 +639,23 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
* Sampling Freq is a consequence of the integration times of
* the Voltage channels.
*/
#define INA219_CHAN_VOLTAGE(_index, _address) { \
#define INA219_CHAN_VOLTAGE(_index, _address, _shift) { \
.type = IIO_VOLTAGE, \
.address = (_address), \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
BIT(IIO_CHAN_INFO_INT_TIME) | \
BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.info_mask_separate_available = \
BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.shift = _shift, \
.realbits = 16 - _shift, \
.storagebits = 16, \
.endianness = IIO_LE, \
} \
......@@ -579,8 +690,8 @@ static const struct iio_chan_spec ina226_channels[] = {
};
static const struct iio_chan_spec ina219_channels[] = {
INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE),
INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE),
INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE, 0),
INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE, INA219_BUS_VOLTAGE_SHIFT),
INA219_CHAN(IIO_POWER, 2, INA2XX_POWER),
INA219_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT),
IIO_CHAN_SOFT_TIMESTAMP(4),
......@@ -746,7 +857,6 @@ static IIO_CONST_ATTR_NAMED(ina226_integration_time_available,
integration_time_available,
"0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR,
ina2xx_allow_async_readout_show,
ina2xx_allow_async_readout_store, 0);
......@@ -780,6 +890,7 @@ static const struct attribute_group ina226_attribute_group = {
static const struct iio_info ina219_info = {
.attrs = &ina219_attribute_group,
.read_raw = ina2xx_read_raw,
.read_avail = ina2xx_read_avail,
.write_raw = ina2xx_write_raw,
.debugfs_reg_access = ina2xx_debug_reg,
};
......@@ -860,6 +971,8 @@ static int ina2xx_probe(struct i2c_client *client,
chip->avg = 1;
ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val);
ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val);
ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val);
ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val);
}
ret = ina2xx_init(chip, val);
......
......@@ -231,7 +231,6 @@ struct meson_sar_adc_priv {
const struct meson_sar_adc_data *data;
struct clk *clkin;
struct clk *core_clk;
struct clk *sana_clk;
struct clk *adc_sel_clk;
struct clk *adc_clk;
struct clk_gate clk_gate;
......@@ -708,12 +707,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
goto err_core_clk;
}
ret = clk_prepare_enable(priv->sana_clk);
if (ret) {
dev_err(indio_dev->dev.parent, "failed to enable sana clk\n");
goto err_sana_clk;
}
regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval);
......@@ -741,8 +734,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
MESON_SAR_ADC_REG3_ADC_EN, 0);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
clk_disable_unprepare(priv->sana_clk);
err_sana_clk:
clk_disable_unprepare(priv->core_clk);
err_core_clk:
regulator_disable(priv->vref);
......@@ -768,7 +759,6 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
clk_disable_unprepare(priv->sana_clk);
clk_disable_unprepare(priv->core_clk);
regulator_disable(priv->vref);
......@@ -961,16 +951,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
return PTR_ERR(priv->core_clk);
}
priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
if (IS_ERR(priv->sana_clk)) {
if (PTR_ERR(priv->sana_clk) == -ENOENT) {
priv->sana_clk = NULL;
} else {
dev_err(&pdev->dev, "failed to get sana clk\n");
return PTR_ERR(priv->sana_clk);
}
}
priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
if (IS_ERR(priv->adc_clk)) {
if (PTR_ERR(priv->adc_clk) == -ENOENT) {
......
......@@ -5,6 +5,7 @@
#include <linux/math64.h>
#include <linux/log2.h>
#include <linux/err.h>
#include <linux/module.h>
#include "qcom-vadc-common.h"
......@@ -229,3 +230,6 @@ int qcom_vadc_decimation_from_dt(u32 value)
return __ffs64(value / VADC_DECIMATION_MIN);
}
EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm ADC common functionality");
......@@ -92,6 +92,7 @@
#define STM32H7_ADC_SQR3 0x38
#define STM32H7_ADC_SQR4 0x3C
#define STM32H7_ADC_DR 0x40
#define STM32H7_ADC_DIFSEL 0xC0
#define STM32H7_ADC_CALFACT 0xC4
#define STM32H7_ADC_CALFACT2 0xC8
......@@ -153,6 +154,8 @@ enum stm32h7_adc_dmngt {
/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
#define STM32H7_BOOST_CLKRATE 20000000UL
#define STM32_ADC_CH_MAX 20 /* max number of channels */
#define STM32_ADC_CH_SZ 10 /* max channel name size */
#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
#define STM32_ADC_TIMEOUT_US 100000
......@@ -297,9 +300,11 @@ struct stm32_adc_cfg {
* @rx_buf: dma rx buffer cpu address
* @rx_dma_buf: dma rx buffer bus address
* @rx_buf_sz: dma rx buffer size
* @difsel bitmask to set single-ended/differential channel
* @pcsel bitmask to preselect channels on some devices
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
* @cal: optional calibration data on some devices
* @chan_name: channel name array
*/
struct stm32_adc {
struct stm32_adc_common *common;
......@@ -318,72 +323,37 @@ struct stm32_adc {
u8 *rx_buf;
dma_addr_t rx_dma_buf;
unsigned int rx_buf_sz;
u32 difsel;
u32 pcsel;
u32 smpr_val[2];
struct stm32_adc_calib cal;
char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
};
/**
* struct stm32_adc_chan_spec - specification of stm32 adc channel
* @type: IIO channel type
* @channel: channel number (single ended)
* @name: channel name (single ended)
*/
struct stm32_adc_chan_spec {
enum iio_chan_type type;
int channel;
const char *name;
struct stm32_adc_diff_channel {
u32 vinp;
u32 vinn;
};
/**
* struct stm32_adc_info - stm32 ADC, per instance config data
* @channels: Reference to stm32 channels spec
* @max_channels: Number of channels
* @resolutions: available resolutions
* @num_res: number of available resolutions
*/
struct stm32_adc_info {
const struct stm32_adc_chan_spec *channels;
int max_channels;
const unsigned int *resolutions;
const unsigned int num_res;
};
/*
* Input definitions common for all instances:
* stm32f4 can have up to 16 channels
* stm32h7 can have up to 20 channels
*/
static const struct stm32_adc_chan_spec stm32_adc_channels[] = {
{ IIO_VOLTAGE, 0, "in0" },
{ IIO_VOLTAGE, 1, "in1" },
{ IIO_VOLTAGE, 2, "in2" },
{ IIO_VOLTAGE, 3, "in3" },
{ IIO_VOLTAGE, 4, "in4" },
{ IIO_VOLTAGE, 5, "in5" },
{ IIO_VOLTAGE, 6, "in6" },
{ IIO_VOLTAGE, 7, "in7" },
{ IIO_VOLTAGE, 8, "in8" },
{ IIO_VOLTAGE, 9, "in9" },
{ IIO_VOLTAGE, 10, "in10" },
{ IIO_VOLTAGE, 11, "in11" },
{ IIO_VOLTAGE, 12, "in12" },
{ IIO_VOLTAGE, 13, "in13" },
{ IIO_VOLTAGE, 14, "in14" },
{ IIO_VOLTAGE, 15, "in15" },
{ IIO_VOLTAGE, 16, "in16" },
{ IIO_VOLTAGE, 17, "in17" },
{ IIO_VOLTAGE, 18, "in18" },
{ IIO_VOLTAGE, 19, "in19" },
};
static const unsigned int stm32f4_adc_resolutions[] = {
/* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */
12, 10, 8, 6,
};
/* stm32f4 can have up to 16 channels */
static const struct stm32_adc_info stm32f4_adc_info = {
.channels = stm32_adc_channels,
.max_channels = 16,
.resolutions = stm32f4_adc_resolutions,
.num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
......@@ -394,9 +364,9 @@ static const unsigned int stm32h7_adc_resolutions[] = {
16, 14, 12, 10, 8,
};
/* stm32h7 can have up to 20 channels */
static const struct stm32_adc_info stm32h7_adc_info = {
.channels = stm32_adc_channels,
.max_channels = 20,
.max_channels = STM32_ADC_CH_MAX,
.resolutions = stm32h7_adc_resolutions,
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
};
......@@ -983,15 +953,19 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
* stm32h7_adc_prepare() - Leave power down mode to enable ADC.
* @adc: stm32 adc instance
* Leave power down mode.
* Configure channels as single ended or differential before enabling ADC.
* Enable ADC.
* Restore calibration data.
* Pre-select channels that may be used in PCSEL (required by input MUX / IO).
* Pre-select channels that may be used in PCSEL (required by input MUX / IO):
* - Only one input is selected for single ended (e.g. 'vinp')
* - Two inputs are selected for differential channels (e.g. 'vinp' & 'vinn')
*/
static int stm32h7_adc_prepare(struct stm32_adc *adc)
{
int ret;
stm32h7_adc_exit_pwr_down(adc);
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(adc);
if (ret)
......@@ -1263,10 +1237,23 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
return ret;
case IIO_CHAN_INFO_SCALE:
*val = adc->common->vref_mv;
*val2 = chan->scan_type.realbits;
if (chan->differential) {
*val = adc->common->vref_mv * 2;
*val2 = chan->scan_type.realbits;
} else {
*val = adc->common->vref_mv;
*val2 = chan->scan_type.realbits;
}
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
if (chan->differential)
/* ADC_full_scale / 2 */
*val = -((1 << chan->scan_type.realbits) / 2);
else
*val = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
......@@ -1628,29 +1615,40 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
}
static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
struct iio_chan_spec *chan,
const struct stm32_adc_chan_spec *channel,
int scan_index, u32 smp)
struct iio_chan_spec *chan, u32 vinp,
u32 vinn, int scan_index, bool differential)
{
struct stm32_adc *adc = iio_priv(indio_dev);
chan->type = channel->type;
chan->channel = channel->channel;
chan->datasheet_name = channel->name;
char *name = adc->chan_name[vinp];
chan->type = IIO_VOLTAGE;
chan->channel = vinp;
if (differential) {
chan->differential = 1;
chan->channel2 = vinn;
snprintf(name, STM32_ADC_CH_SZ, "in%d-in%d", vinp, vinn);
} else {
snprintf(name, STM32_ADC_CH_SZ, "in%d", vinp);
}
chan->datasheet_name = name;
chan->scan_index = scan_index;
chan->indexed = 1;
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET);
chan->scan_type.sign = 'u';
chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res];
chan->scan_type.storagebits = 16;
chan->ext_info = stm32_adc_ext_info;
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, chan->channel, smp);
/* pre-build selected channels mask */
adc->pcsel |= BIT(chan->channel);
if (differential) {
/* pre-build diff channels mask */
adc->difsel |= BIT(chan->channel);
/* Also add negative input to pre-selected channels */
adc->pcsel |= BIT(chan->channel2);
}
}
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
......@@ -1658,17 +1656,40 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
struct device_node *node = indio_dev->dev.of_node;
struct stm32_adc *adc = iio_priv(indio_dev);
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
struct property *prop;
const __be32 *cur;
struct iio_chan_spec *channels;
int scan_index = 0, num_channels, ret;
int scan_index = 0, num_channels = 0, num_diff = 0, ret, i;
u32 val, smp = 0;
num_channels = of_property_count_u32_elems(node, "st,adc-channels");
if (num_channels < 0 ||
num_channels > adc_info->max_channels) {
ret = of_property_count_u32_elems(node, "st,adc-channels");
if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-channels?\n");
return num_channels < 0 ? num_channels : -EINVAL;
return -EINVAL;
} else if (ret > 0) {
num_channels += ret;
}
ret = of_property_count_elems_of_size(node, "st,adc-diff-channels",
sizeof(*diff));
if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
return -EINVAL;
} else if (ret > 0) {
int size = ret * sizeof(*diff) / sizeof(u32);
num_diff = ret;
num_channels += ret;
ret = of_property_read_u32_array(node, "st,adc-diff-channels",
(u32 *)diff, size);
if (ret)
return ret;
}
if (!num_channels) {
dev_err(&indio_dev->dev, "No channels configured\n");
return -ENODATA;
}
/* Optional sample time is provided either for each, or all channels */
......@@ -1689,6 +1710,33 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
return -EINVAL;
}
/* Channel can't be configured both as single-ended & diff */
for (i = 0; i < num_diff; i++) {
if (val == diff[i].vinp) {
dev_err(&indio_dev->dev,
"channel %d miss-configured\n", val);
return -EINVAL;
}
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
0, scan_index, false);
scan_index++;
}
for (i = 0; i < num_diff; i++) {
if (diff[i].vinp >= adc_info->max_channels ||
diff[i].vinn >= adc_info->max_channels) {
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
diff[i].vinp, diff[i].vinn);
return -EINVAL;
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
diff[i].vinp, diff[i].vinn, scan_index,
true);
scan_index++;
}
for (i = 0; i < scan_index; i++) {
/*
* Using of_property_read_u32_index(), smp value will only be
* modified if valid u32 value can be decoded. This allows to
......@@ -1696,12 +1744,9 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
* value per channel.
*/
of_property_read_u32_index(node, "st,min-sample-time-nsecs",
scan_index, &smp);
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
&adc_info->channels[val],
scan_index, smp);
scan_index++;
i, &smp);
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, channels[i].channel, smp);
}
indio_dev->num_channels = scan_index;
......
......@@ -191,7 +191,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *ec_device;
struct iio_dev *indio_dev;
struct cros_ec_sensors_state *state;
struct iio_chan_spec *channel;
......@@ -201,7 +200,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "No CROS EC device found.\n");
return -EINVAL;
}
ec_device = ec_dev->ec_dev;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
if (!indio_dev)
......
This diff is collapsed.
......@@ -196,8 +196,7 @@ void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
{
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
if (st->mux_client)
i2c_unregister_device(st->mux_client);
i2c_unregister_device(st->mux_client);
}
#else
......
......@@ -588,6 +588,7 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
return snprintf(buf, len, "%d", vals[0]);
case IIO_VAL_INT_PLUS_MICRO_DB:
scale_db = true;
/* fall through */
case IIO_VAL_INT_PLUS_MICRO:
if (vals[1] < 0)
return snprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
......
......@@ -334,6 +334,30 @@ config STK3310
Choosing M will build the driver as a module. If so, the module
will be called stk3310.
config ST_UVIS25
tristate "STMicroelectronics UVIS25 sensor driver"
depends on (I2C || SPI)
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select ST_UVIS25_I2C if (I2C)
select ST_UVIS25_SPI if (SPI_MASTER)
help
Say yes here to build support for STMicroelectronics UVIS25
uv sensor
To compile this driver as a module, choose M here: the module
will be called st_uvis25.
config ST_UVIS25_I2C
tristate
depends on ST_UVIS25
select REGMAP_I2C
config ST_UVIS25_SPI
tristate
depends on ST_UVIS25
select REGMAP_SPI
config TCS3414
tristate "TAOS TCS3414 digital color sensor"
depends on I2C
......@@ -425,4 +449,14 @@ config VL6180
To compile this driver as a module, choose M here: the
module will be called vl6180.
config ZOPT2201
tristate "ZOPT2201 ALS and UV B sensor"
depends on I2C
help
Say Y here if you want to build a driver for the IDT
ZOPT2201 ambient light and UV B sensor.
To compile this driver as a module, choose M here: the
module will be called zopt2201.
endmenu
......@@ -33,6 +33,9 @@ obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o
obj-$(CONFIG_ST_UVIS25_I2C) += st_uvis25_i2c.o
obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL2583) += tsl2583.o
......@@ -41,3 +44,4 @@ obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VL6180) += vl6180.o
obj-$(CONFIG_ZOPT2201) += zopt2201.o
......@@ -181,7 +181,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *ec_device;
struct iio_dev *indio_dev;
struct cros_ec_light_prox_state *state;
struct iio_chan_spec *channel;
......@@ -191,7 +190,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
dev_warn(dev, "No CROS EC device found.\n");
return -EINVAL;
}
ec_device = ec_dev->ec_dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
if (!indio_dev)
......
/*
* STMicroelectronics uvis25 sensor driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#ifndef ST_UVIS25_H
#define ST_UVIS25_H
#define ST_UVIS25_DEV_NAME "uvis25"
#include <linux/iio/iio.h>
/**
* struct st_uvis25_hw - ST UVIS25 sensor instance
* @regmap: Register map of the device.
* @trig: The trigger in use by the driver.
* @enabled: Status of the sensor (false->off, true->on).
* @irq: Device interrupt line (I2C or SPI).
*/
struct st_uvis25_hw {
struct regmap *regmap;
struct iio_trigger *trig;
bool enabled;
int irq;
};
extern const struct dev_pm_ops st_uvis25_pm_ops;
int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap);
#endif /* ST_UVIS25_H */
/*
* STMicroelectronics uvis25 sensor driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/iio/sysfs.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/buffer.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define ST_UVIS25_REG_WHOAMI_ADDR 0x0f
#define ST_UVIS25_REG_WHOAMI_VAL 0xca
#define ST_UVIS25_REG_CTRL1_ADDR 0x20
#define ST_UVIS25_REG_ODR_MASK BIT(0)
#define ST_UVIS25_REG_BDU_MASK BIT(1)
#define ST_UVIS25_REG_CTRL2_ADDR 0x21
#define ST_UVIS25_REG_BOOT_MASK BIT(7)
#define ST_UVIS25_REG_CTRL3_ADDR 0x22
#define ST_UVIS25_REG_HL_MASK BIT(7)
#define ST_UVIS25_REG_STATUS_ADDR 0x27
#define ST_UVIS25_REG_UV_DA_MASK BIT(0)
#define ST_UVIS25_REG_OUT_ADDR 0x28
static const struct iio_chan_spec st_uvis25_channels[] = {
{
.type = IIO_UVINDEX,
.address = ST_UVIS25_REG_OUT_ADDR,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 8,
.storagebits = 8,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int st_uvis25_check_whoami(struct st_uvis25_hw *hw)
{
int err, data;
err = regmap_read(hw->regmap, ST_UVIS25_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(regmap_get_device(hw->regmap),
"failed to read whoami register\n");
return err;
}
if (data != ST_UVIS25_REG_WHOAMI_VAL) {
dev_err(regmap_get_device(hw->regmap),
"wrong whoami {%02x vs %02x}\n",
data, ST_UVIS25_REG_WHOAMI_VAL);
return -ENODEV;
}
return 0;
}
static int st_uvis25_set_enable(struct st_uvis25_hw *hw, bool enable)
{
int err;
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, enable);
if (err < 0)
return err;
hw->enabled = enable;
return 0;
}
static int st_uvis25_read_oneshot(struct st_uvis25_hw *hw, u8 addr, int *val)
{
int err;
err = st_uvis25_set_enable(hw, true);
if (err < 0)
return err;
msleep(1500);
/*
* in order to avoid possible race conditions with interrupt
* generation, disable the sensor first and then poll output
* register. That sequence guarantees the interrupt will be reset
* when irq line is unmasked
*/
err = st_uvis25_set_enable(hw, false);
if (err < 0)
return err;
err = regmap_read(hw->regmap, addr, val);
return err < 0 ? err : IIO_VAL_INT;
}
static int st_uvis25_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *ch,
int *val, int *val2, long mask)
{
int ret;
ret = iio_device_claim_direct_mode(iio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED: {
struct st_uvis25_hw *hw = iio_priv(iio_dev);
/*
* mask irq line during oneshot read since the sensor
* does not export the capability to disable data-ready line
* in the register map and it is enabled by default.
* If the line is unmasked during read_raw() it will be set
* active and never reset since the trigger is disabled
*/
if (hw->irq > 0)
disable_irq(hw->irq);
ret = st_uvis25_read_oneshot(hw, ch->address, val);
if (hw->irq > 0)
enable_irq(hw->irq);
break;
}
default:
ret = -EINVAL;
break;
}
iio_device_release_direct_mode(iio_dev);
return ret;
}
static irqreturn_t st_uvis25_trigger_handler_thread(int irq, void *private)
{
struct st_uvis25_hw *hw = private;
int err, status;
err = regmap_read(hw->regmap, ST_UVIS25_REG_STATUS_ADDR, &status);
if (err < 0)
return IRQ_HANDLED;
if (!(status & ST_UVIS25_REG_UV_DA_MASK))
return IRQ_NONE;
iio_trigger_poll_chained(hw->trig);
return IRQ_HANDLED;
}
static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
{
struct st_uvis25_hw *hw = iio_priv(iio_dev);
struct device *dev = regmap_get_device(hw->regmap);
bool irq_active_low = false;
unsigned long irq_type;
int err;
irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
switch (irq_type) {
case IRQF_TRIGGER_HIGH:
case IRQF_TRIGGER_RISING:
break;
case IRQF_TRIGGER_LOW:
case IRQF_TRIGGER_FALLING:
irq_active_low = true;
break;
default:
dev_info(dev, "mode %lx unsupported\n", irq_type);
return -EINVAL;
}
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL3_ADDR,
ST_UVIS25_REG_HL_MASK, irq_active_low);
if (err < 0)
return err;
err = devm_request_threaded_irq(dev, hw->irq, NULL,
st_uvis25_trigger_handler_thread,
irq_type | IRQF_ONESHOT,
iio_dev->name, hw);
if (err) {
dev_err(dev, "failed to request trigger irq %d\n",
hw->irq);
return err;
}
hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger",
iio_dev->name);
if (!hw->trig)
return -ENOMEM;
iio_trigger_set_drvdata(hw->trig, iio_dev);
hw->trig->dev.parent = dev;
return devm_iio_trigger_register(dev, hw->trig);
}
static int st_uvis25_buffer_preenable(struct iio_dev *iio_dev)
{
return st_uvis25_set_enable(iio_priv(iio_dev), true);
}
static int st_uvis25_buffer_postdisable(struct iio_dev *iio_dev)
{
return st_uvis25_set_enable(iio_priv(iio_dev), false);
}
static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
.preenable = st_uvis25_buffer_preenable,
.postenable = iio_triggered_buffer_postenable,
.predisable = iio_triggered_buffer_predisable,
.postdisable = st_uvis25_buffer_postdisable,
};
static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
{
u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
struct iio_poll_func *pf = p;
struct iio_dev *iio_dev = pf->indio_dev;
struct st_uvis25_hw *hw = iio_priv(iio_dev);
int err;
err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
if (err < 0)
goto out;
iio_push_to_buffers_with_timestamp(iio_dev, buffer,
iio_get_time_ns(iio_dev));
out:
iio_trigger_notify_done(hw->trig);
return IRQ_HANDLED;
}
static int st_uvis25_allocate_buffer(struct iio_dev *iio_dev)
{
struct st_uvis25_hw *hw = iio_priv(iio_dev);
return devm_iio_triggered_buffer_setup(regmap_get_device(hw->regmap),
iio_dev, NULL,
st_uvis25_buffer_handler_thread,
&st_uvis25_buffer_ops);
}
static const struct iio_info st_uvis25_info = {
.read_raw = st_uvis25_read_raw,
};
static int st_uvis25_init_sensor(struct st_uvis25_hw *hw)
{
int err;
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL2_ADDR,
ST_UVIS25_REG_BOOT_MASK, 1);
if (err < 0)
return err;
msleep(2000);
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_BDU_MASK, 1);
}
int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
{
struct st_uvis25_hw *hw;
struct iio_dev *iio_dev;
int err;
iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));
if (!iio_dev)
return -ENOMEM;
dev_set_drvdata(dev, (void *)iio_dev);
hw = iio_priv(iio_dev);
hw->irq = irq;
hw->regmap = regmap;
err = st_uvis25_check_whoami(hw);
if (err < 0)
return err;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->dev.parent = dev;
iio_dev->channels = st_uvis25_channels;
iio_dev->num_channels = ARRAY_SIZE(st_uvis25_channels);
iio_dev->name = ST_UVIS25_DEV_NAME;
iio_dev->info = &st_uvis25_info;
err = st_uvis25_init_sensor(hw);
if (err < 0)
return err;
if (hw->irq > 0) {
err = st_uvis25_allocate_buffer(iio_dev);
if (err < 0)
return err;
err = st_uvis25_allocate_trigger(iio_dev);
if (err)
return err;
}
return devm_iio_device_register(dev, iio_dev);
}
EXPORT_SYMBOL(st_uvis25_probe);
static int __maybe_unused st_uvis25_suspend(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, 0);
}
static int __maybe_unused st_uvis25_resume(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
if (hw->enabled)
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, 1);
return 0;
}
const struct dev_pm_ops st_uvis25_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume)
};
EXPORT_SYMBOL(st_uvis25_pm_ops);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver");
MODULE_LICENSE("GPL v2");
/*
* STMicroelectronics uvis25 i2c driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define UVIS25_I2C_AUTO_INCREMENT BIT(7)
const struct regmap_config st_uvis25_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.write_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
.read_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
};
static int st_uvis25_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &st_uvis25_i2c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_uvis25_probe(&client->dev, client->irq, regmap);
}
static const struct of_device_id st_uvis25_i2c_of_match[] = {
{ .compatible = "st,uvis25", },
{},
};
MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match);
static const struct i2c_device_id st_uvis25_i2c_id_table[] = {
{ ST_UVIS25_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table);
static struct i2c_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_i2c",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_i2c_of_match),
},
.probe = st_uvis25_i2c_probe,
.id_table = st_uvis25_i2c_id_table,
};
module_i2c_driver(st_uvis25_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 i2c driver");
MODULE_LICENSE("GPL v2");
/*
* STMicroelectronics uvis25 spi driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define UVIS25_SENSORS_SPI_READ BIT(7)
#define UVIS25_SPI_AUTO_INCREMENT BIT(6)
const struct regmap_config st_uvis25_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = UVIS25_SENSORS_SPI_READ | UVIS25_SPI_AUTO_INCREMENT,
.write_flag_mask = UVIS25_SPI_AUTO_INCREMENT,
};
static int st_uvis25_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &st_uvis25_spi_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_uvis25_probe(&spi->dev, spi->irq, regmap);
}
static const struct of_device_id st_uvis25_spi_of_match[] = {
{ .compatible = "st,uvis25", },
{},
};
MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match);
static const struct spi_device_id st_uvis25_spi_id_table[] = {
{ ST_UVIS25_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table);
static struct spi_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_spi",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_spi_of_match),
},
.probe = st_uvis25_spi_probe,
.id_table = st_uvis25_spi_id_table,
};
module_spi_driver(st_uvis25_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 spi driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
......@@ -788,6 +788,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"AK8975", AK8975},
{"AK8963", AK8963},
{"INVN6500", AK8963},
{"AK009911", AK09911},
{"AK09911", AK09911},
{"AK09912", AK09912},
{ },
......
......@@ -1022,6 +1022,7 @@ static const struct dev_pm_ops sx9500_pm_ops = {
static const struct acpi_device_id sx9500_acpi_match[] = {
{"SSX9500", 0},
{"SASX9500", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
......
......@@ -118,22 +118,23 @@ static inline ssize_t ad7152_start_calib(struct device *dev,
mutex_lock(&chip->state_lock);
ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG, regval);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
if (ret < 0)
goto unlock;
do {
mdelay(20);
ret = i2c_smbus_read_byte_data(chip->client, AD7152_REG_CFG);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
if (ret < 0)
goto unlock;
} while ((ret == regval) && timeout--);
mutex_unlock(&chip->state_lock);
return len;
unlock:
mutex_unlock(&chip->state_lock);
return ret;
}
static ssize_t ad7152_start_offset_calib(struct device *dev,
......
......@@ -302,23 +302,24 @@ static inline ssize_t ad7746_start_calib(struct device *dev,
mutex_lock(&chip->lock);
regval |= chip->config;
ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_CFG, regval);
if (ret < 0) {
mutex_unlock(&chip->lock);
return ret;
}
if (ret < 0)
goto unlock;
do {
msleep(20);
ret = i2c_smbus_read_byte_data(chip->client, AD7746_REG_CFG);
if (ret < 0) {
mutex_unlock(&chip->lock);
return ret;
}
if (ret < 0)
goto unlock;
} while ((ret == regval) && timeout--);
mutex_unlock(&chip->lock);
return len;
unlock:
mutex_unlock(&chip->lock);
return ret;
}
static ssize_t ad7746_start_offset_calib(struct device *dev,
......
......@@ -187,9 +187,9 @@ static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
return -ENOMEM;
st->irq = platform_get_irq(pdev, 0);
if (!st->irq) {
if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQs specified");
return -ENODEV;
return st->irq;
}
ret = iio_bfin_tmr_get_number(st->irq);
......
......@@ -28,4 +28,11 @@ struct iio_map {
void *consumer_data;
};
#define IIO_MAP(_provider_channel, _consumer_dev_name, _consumer_channel) \
{ \
.adc_channel_label = _provider_channel, \
.consumer_dev_name = _consumer_dev_name, \
.consumer_channel = _consumer_channel, \
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment