Commit a3975dea authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.8c' of...

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

Jonathan writes:

Third set of IIO new device support, cleanups etc for the 5.8 cycle.

A rather late final set to pick up a couple of new drivers, a bunch
of cleanup and some fixes that can wait for the merge window.

In particularly I'd like to highlight the great core and driver
cleanup work that the Alex and the team at Analog devices are currently
doing.  Should see lots more of that in the next cycle give what is
currently under review.

This pull also has the first few fixes squashing a class of alignment
and small kernel data leak bugs that Lars-Peter Clausen picked up
on in a review.  Quite a few more of those to come.  They've been
there a long time so we aren't rushing the reviews.

New device support
* atlas ezo
  - new driver supporting this range of chemical and similar sensors
    with the odd interface of ascii strings over i2c.
* bma180
  - bma023, bma150 and smb380 support.  Note these are currently also
    supported by a driver in input which we will hopefully remove
    (eventually). There are Kconfig protections to avoid a clash
    in the meantime.
* vcnl3020
  - new driver for this proximity sensor.

Core change
* during buffer updates, change the current state variable before
  we actually call pre and post enable callbacks so drivers can know
  where we are going.  Note this is a precursor to only exposing
  one enable callback to drivers.  The (false) logic behind having two
  such callbacks has long been fixed, but only now is the mess getting
  cleaned up.

Features
* exynos adc.
  - add reporting of channels scale values.

Cleanups and minor fixes.
* core
  - drop now unused attrcount_orig variable.
* ad5360, ad5446, ad5449, ad5755, ad5761, ad5764, ad5380, ad5421,
  ad5592, ad5686 and vf610_dac
  - remove direct use of iio_dev->mlock from all these drivers.
    Its semantics used to be poorly defined, but now it is for core
    use only.  Removing it's use in drivers has been a long process
    of which this is the latest step!
* exynos_adc
  - drop a pointless check on the phy as the driver doesn't access it.
* ping
  - avoid a dance from iio_priv and iio_priv_to_dev back again by
    just passing the iio_dev into the functions.
* pms7003
  - alignment and potential data leak fix.
* sps30
  - alignment bug fix.

* tag 'iio-for-5.8c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (31 commits)
  iio:chemical:pms7003: Fix timestamp alignment and prevent data leak.
  iio:chemical:sps30: Fix timestamp alignment
  iio: adc: stm32-adc: fix a wrong error message when probing interrupts
  iio: light: gp2ap002: Take runtime PM reference on light read
  iio: proximity: ping: pass reference to IIO device as param to ping_read()
  iio: dac: ad5592r-base: Replace indio_dev->mlock with own device lock
  iio: proximity: Add driver support for vcnl3020 proximity sensor
  dt-bindings: proximity: provide vcnl3020 device tree binding document
  iio: buffer: remove attrcount_orig var from sysfs creation
  iio: chemical: add atlas-ezo-sensor initial support
  dt-bindings: iio: chemical: add CO2 EZO module documentation
  iio: adc: exynos: Simplify Exynos7-specific init
  iio: adc: Add scaling support to exynos adc driver
  iio: __iio_update_buffers: Update mode before preenable/after postdisable
  iio: dac: vf610_dac: Replace indio_dev->mlock with own device lock
  iio: dac: ad5686: Replace indio_dev->mlock with own device lock
  iio: dac: ad5421: Replace indio_dev->mlock with own device lock
  iio: dac: ad5380: Replace indio_dev->mlock with own device lock
  iio: dac: ad5764: Replace indio_dev->mlock with own device lock
  iio: dac: ad5761: Replace indio_dev->mlock with own device lock
  ...
parents 1dfb74b1 13e94563
* Bosch BMA180 / BMA25x triaxial acceleration sensor
* Bosch BMA023 / BMA150/ BMA180 / BMA25x / SMB380 triaxial acceleration sensor
https://media.digikey.com/pdf/Data%20Sheets/Bosch/BMA150.pdf
http://omapworld.com/BMA180_111_1002839.pdf
http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf
Required properties:
- compatible : should be one of:
"bosch,bma023"
"bosch,bma150"
"bosch,bma180"
"bosch,bma250"
"bosch,bma254"
"bosch,smb380"
- reg : the I2C address of the sensor
- vdd-supply : regulator phandle connected to the VDD pin
- vddio-supply : regulator phandle connected to the VDDIO pin
Optional properties:
......
......@@ -4,13 +4,13 @@
$id: http://devicetree.org/schemas/iio/chemical/atlas,sensor.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atlas Scientific OEM sensors
title: Atlas Scientific OEM + EZO sensors
maintainers:
- Matt Ranostay <matt.ranostay@konsulko.com>
description: |
Atlas Scientific OEM sensors connected via I2C
Atlas Scientific OEM + EZO sensors connected via I2C
Datasheets:
http://www.atlas-scientific.com/_files/_datasheets/_oem/DO_oem_datasheet.pdf
......@@ -18,6 +18,7 @@ description: |
http://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/RTD_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_probe/EZO_CO2_Datasheet.pdf
properties:
compatible:
......@@ -27,6 +28,7 @@ properties:
- atlas,orp-sm
- atlas,ph-sm
- atlas,rtd-sm
- atlas,co2-ezo
reg:
maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/vishay,vcnl3020.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Integrated Proximity Sensor With Infrared Emitter
maintainers:
- Ivan Mikhaylov <i.mikhaylov@yadro.com>
description: |
The VCNL3020 is a fully integrated proximity sensor. Fully integrated means
that the infrared emitter is included in the package. It has 16-bit
resolution. It includes a signal processing IC and features standard I2C
communication interface. It features an interrupt function.
Specifications about the devices can be found at:
https://www.vishay.com/docs/84150/vcnl3020.pdf
properties:
compatible:
enum:
- vishay,vcnl3020
reg:
maxItems: 1
interrupts:
maxItems: 1
vdd-supply:
description: Regulator that provides power to the sensor
vddio-supply:
description: Regulator that provides power to the bus
vishay,led-current-microamp:
description:
The driver current for the LED used in proximity sensing.
enum: [0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
100000, 110000, 120000, 130000, 140000, 150000, 160000, 170000,
180000, 190000, 200000]
default: 20000
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
proximity@13 {
compatible = "vishay,vcnl3020";
reg = <0x13>;
vishay,led-current-microamp = <200000>;
};
};
......@@ -89,13 +89,13 @@ config ADXL372_I2C
module will be called adxl372_i2c.
config BMA180
tristate "Bosch BMA180/BMA25x 3-Axis Accelerometer Driver"
depends on I2C
tristate "Bosch BMA023/BMA1x0/BMA25x 3-Axis Accelerometer Driver"
depends on I2C && INPUT_BMA150=n
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Bosch BMA180 or
BMA25x triaxial acceleration sensor.
Say Y here if you want to build a driver for the Bosch BMA023, BMA150
BMA180, SMB380, or BMA25x triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma180.
......
......@@ -7,6 +7,7 @@
* Support for BMA250 (c) Peter Meerwald <pmeerw@pmeerw.net>
*
* SPI is not supported by driver
* BMA023/BMA150/SMB380: 7-bit I2C slave address 0x38
* BMA180: 7-bit I2C slave address 0x40 or 0x41
* BMA250: 7-bit I2C slave address 0x18 or 0x19
* BMA254: 7-bit I2C slave address 0x18 or 0x19
......@@ -33,6 +34,8 @@
#define BMA180_IRQ_NAME "bma180_event"
enum chip_ids {
BMA023,
BMA150,
BMA180,
BMA250,
BMA254,
......@@ -48,7 +51,7 @@ struct bma180_part_info {
unsigned int num_scales;
const int *bw_table;
unsigned int num_bw;
int center_temp;
int temp_offset;
u8 int_reset_reg, int_reset_mask;
u8 sleep_reg, sleep_mask;
......@@ -57,13 +60,25 @@ struct bma180_part_info {
u8 power_reg, power_mask, lowpower_val;
u8 int_enable_reg, int_enable_mask;
u8 int_map_reg, int_enable_dataready_int1_mask;
u8 softreset_reg;
u8 softreset_reg, softreset_val;
int (*chip_config)(struct bma180_data *data);
void (*chip_disable)(struct bma180_data *data);
};
/* Register set */
#define BMA023_CTRL_REG0 0x0a
#define BMA023_CTRL_REG1 0x0b
#define BMA023_CTRL_REG2 0x14
#define BMA023_CTRL_REG3 0x15
#define BMA023_RANGE_MASK GENMASK(4, 3) /* Range of accel values */
#define BMA023_BW_MASK GENMASK(2, 0) /* Accel bandwidth */
#define BMA023_SLEEP BIT(0)
#define BMA023_INT_RESET_MASK BIT(6)
#define BMA023_NEW_DATA_INT BIT(5) /* Intr every new accel data is ready */
#define BMA023_RESET_VAL BIT(1)
#define BMA180_CHIP_ID 0x00 /* Need to distinguish BMA180 from other */
#define BMA180_ACC_X_LSB 0x02 /* First of 6 registers of accel data */
#define BMA180_TEMP 0x08
......@@ -94,6 +109,7 @@ struct bma180_part_info {
/* We have to write this value in reset register to do soft reset */
#define BMA180_RESET_VAL 0xb6
#define BMA023_ID_REG_VAL 0x02
#define BMA180_ID_REG_VAL 0x03
#define BMA250_ID_REG_VAL 0x03
#define BMA254_ID_REG_VAL 0xfa /* 250 decimal */
......@@ -156,6 +172,9 @@ enum bma180_chan {
TEMP
};
static int bma023_bw_table[] = { 25, 50, 100, 190, 375, 750, 1500 }; /* Hz */
static int bma023_scale_table[] = { 2452, 4903, 9709, };
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
......@@ -319,7 +338,8 @@ static int bma180_set_pmode(struct bma180_data *data, bool mode)
static int bma180_soft_reset(struct bma180_data *data)
{
int ret = i2c_smbus_write_byte_data(data->client,
data->part_info->softreset_reg, BMA180_RESET_VAL);
data->part_info->softreset_reg,
data->part_info->softreset_val);
if (ret)
dev_err(&data->client->dev, "failed to reset the chip\n");
......@@ -349,17 +369,37 @@ static int bma180_chip_init(struct bma180_data *data)
*/
msleep(20);
ret = bma180_set_new_data_intr_state(data, false);
return bma180_set_new_data_intr_state(data, false);
}
static int bma023_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
if (ret)
return ret;
goto err;
ret = bma180_set_bw(data, 50); /* 50 Hz */
if (ret)
goto err;
ret = bma180_set_scale(data, 2452); /* 2 G */
if (ret)
goto err;
return bma180_set_pmode(data, false);
return 0;
err:
dev_err(&data->client->dev, "failed to config the chip\n");
return ret;
}
static int bma180_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
if (ret)
goto err;
ret = bma180_set_pmode(data, false);
if (ret)
goto err;
ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1);
......@@ -389,6 +429,9 @@ static int bma25x_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
if (ret)
goto err;
ret = bma180_set_pmode(data, false);
if (ret)
goto err;
ret = bma180_set_bw(data, 16); /* 16 Hz */
......@@ -413,6 +456,17 @@ static int bma25x_chip_config(struct bma180_data *data)
return ret;
}
static void bma023_chip_disable(struct bma180_data *data)
{
if (bma180_set_sleep_state(data, true))
goto err;
return;
err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
static void bma180_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
......@@ -512,8 +566,12 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
if (chan->scan_type.sign == 's') {
*val = sign_extend32(ret >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
} else {
*val = ret;
}
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = data->bw;
......@@ -531,7 +589,7 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = data->part_info->center_temp;
*val = data->part_info->temp_offset;
return IIO_VAL_INT;
default:
return -EINVAL;
......@@ -609,6 +667,11 @@ static const struct iio_enum bma180_power_mode_enum = {
.set = bma180_set_power_mode,
};
static const struct iio_chan_spec_ext_info bma023_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma180_accel_get_mount_matrix),
{ }
};
static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
......@@ -616,6 +679,35 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
{ }
};
#define BMA023_ACC_CHANNEL(_axis, _bits) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = AXIS_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = _bits, \
.storagebits = 16, \
.shift = 16 - _bits, \
}, \
.ext_info = bma023_ext_info, \
}
#define BMA150_TEMP_CHANNEL { \
.type = IIO_TEMP, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = TEMP, \
.scan_type = { \
.sign = 'u', \
.realbits = 8, \
.storagebits = 16, \
}, \
}
#define BMA180_ACC_CHANNEL(_axis, _bits) { \
.type = IIO_ACCEL, \
.modified = 1, \
......@@ -645,6 +737,21 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
}, \
}
static const struct iio_chan_spec bma023_channels[] = {
BMA023_ACC_CHANNEL(X, 10),
BMA023_ACC_CHANNEL(Y, 10),
BMA023_ACC_CHANNEL(Z, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec bma150_channels[] = {
BMA023_ACC_CHANNEL(X, 10),
BMA023_ACC_CHANNEL(Y, 10),
BMA023_ACC_CHANNEL(Z, 10),
BMA150_TEMP_CHANNEL,
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec bma180_channels[] = {
BMA180_ACC_CHANNEL(X, 14),
BMA180_ACC_CHANNEL(Y, 14),
......@@ -670,6 +777,63 @@ static const struct iio_chan_spec bma254_channels[] = {
};
static const struct bma180_part_info bma180_part_info[] = {
[BMA023] = {
.chip_id = BMA023_ID_REG_VAL,
.channels = bma023_channels,
.num_channels = ARRAY_SIZE(bma023_channels),
.scale_table = bma023_scale_table,
.num_scales = ARRAY_SIZE(bma023_scale_table),
.bw_table = bma023_bw_table,
.num_bw = ARRAY_SIZE(bma023_bw_table),
/* No temperature channel */
.temp_offset = 0,
.int_reset_reg = BMA023_CTRL_REG0,
.int_reset_mask = BMA023_INT_RESET_MASK,
.sleep_reg = BMA023_CTRL_REG0,
.sleep_mask = BMA023_SLEEP,
.bw_reg = BMA023_CTRL_REG2,
.bw_mask = BMA023_BW_MASK,
.scale_reg = BMA023_CTRL_REG2,
.scale_mask = BMA023_RANGE_MASK,
/* No power mode on bma023 */
.power_reg = 0,
.power_mask = 0,
.lowpower_val = 0,
.int_enable_reg = BMA023_CTRL_REG3,
.int_enable_mask = BMA023_NEW_DATA_INT,
.softreset_reg = BMA023_CTRL_REG0,
.softreset_val = BMA023_RESET_VAL,
.chip_config = bma023_chip_config,
.chip_disable = bma023_chip_disable,
},
[BMA150] = {
.chip_id = BMA023_ID_REG_VAL,
.channels = bma150_channels,
.num_channels = ARRAY_SIZE(bma150_channels),
.scale_table = bma023_scale_table,
.num_scales = ARRAY_SIZE(bma023_scale_table),
.bw_table = bma023_bw_table,
.num_bw = ARRAY_SIZE(bma023_bw_table),
.temp_offset = -60, /* 0 LSB @ -30 degree C */
.int_reset_reg = BMA023_CTRL_REG0,
.int_reset_mask = BMA023_INT_RESET_MASK,
.sleep_reg = BMA023_CTRL_REG0,
.sleep_mask = BMA023_SLEEP,
.bw_reg = BMA023_CTRL_REG2,
.bw_mask = BMA023_BW_MASK,
.scale_reg = BMA023_CTRL_REG2,
.scale_mask = BMA023_RANGE_MASK,
/* No power mode on bma150 */
.power_reg = 0,
.power_mask = 0,
.lowpower_val = 0,
.int_enable_reg = BMA023_CTRL_REG3,
.int_enable_mask = BMA023_NEW_DATA_INT,
.softreset_reg = BMA023_CTRL_REG0,
.softreset_val = BMA023_RESET_VAL,
.chip_config = bma023_chip_config,
.chip_disable = bma023_chip_disable,
},
[BMA180] = {
.chip_id = BMA180_ID_REG_VAL,
.channels = bma180_channels,
......@@ -678,7 +842,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.num_scales = ARRAY_SIZE(bma180_scale_table),
.bw_table = bma180_bw_table,
.num_bw = ARRAY_SIZE(bma180_bw_table),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.temp_offset = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA180_CTRL_REG0,
.int_reset_mask = BMA180_RESET_INT,
.sleep_reg = BMA180_CTRL_REG0,
......@@ -693,6 +857,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.int_enable_reg = BMA180_CTRL_REG3,
.int_enable_mask = BMA180_NEW_DATA_INT,
.softreset_reg = BMA180_RESET,
.softreset_val = BMA180_RESET_VAL,
.chip_config = bma180_chip_config,
.chip_disable = bma180_chip_disable,
},
......@@ -704,7 +869,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.num_scales = ARRAY_SIZE(bma25x_scale_table),
.bw_table = bma25x_bw_table,
.num_bw = ARRAY_SIZE(bma25x_bw_table),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.temp_offset = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA250_INT_RESET_REG,
.int_reset_mask = BMA250_INT_RESET_MASK,
.sleep_reg = BMA250_POWER_REG,
......@@ -721,6 +886,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.int_map_reg = BMA250_INT_MAP_REG,
.int_enable_dataready_int1_mask = BMA250_INT1_DATA_MASK,
.softreset_reg = BMA250_RESET_REG,
.softreset_val = BMA180_RESET_VAL,
.chip_config = bma25x_chip_config,
.chip_disable = bma25x_chip_disable,
},
......@@ -732,7 +898,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.num_scales = ARRAY_SIZE(bma25x_scale_table),
.bw_table = bma25x_bw_table,
.num_bw = ARRAY_SIZE(bma25x_bw_table),
.center_temp = 46, /* 0 LSB @ 23 degree C */
.temp_offset = 46, /* 0 LSB @ 23 degree C */
.int_reset_reg = BMA254_INT_RESET_REG,
.int_reset_mask = BMA254_INT_RESET_MASK,
.sleep_reg = BMA254_POWER_REG,
......@@ -749,6 +915,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.int_map_reg = BMA254_INT_MAP_REG,
.int_enable_dataready_int1_mask = BMA254_INT1_DATA_MASK,
.softreset_reg = BMA254_RESET_REG,
.softreset_val = BMA180_RESET_VAL,
.chip_config = bma25x_chip_config,
.chip_disable = bma25x_chip_disable,
},
......@@ -990,15 +1157,26 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
#endif
static const struct i2c_device_id bma180_ids[] = {
{ "bma023", BMA023 },
{ "bma150", BMA150 },
{ "bma180", BMA180 },
{ "bma250", BMA250 },
{ "bma254", BMA254 },
{ "smb380", BMA150 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma180_ids);
static const struct of_device_id bma180_of_match[] = {
{
.compatible = "bosch,bma023",
.data = (void *)BMA023
},
{
.compatible = "bosch,bma150",
.data = (void *)BMA150
},
{
.compatible = "bosch,bma180",
.data = (void *)BMA180
......@@ -1011,6 +1189,10 @@ static const struct of_device_id bma180_of_match[] = {
.compatible = "bosch,bma254",
.data = (void *)BMA254
},
{
.compatible = "bosch,smb380",
.data = (void *)BMA150
},
{ }
};
MODULE_DEVICE_TABLE(of, bma180_of_match);
......@@ -1030,5 +1212,5 @@ module_i2c_driver(bma180_driver);
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("Bosch BMA180/BMA25x triaxial acceleration sensor");
MODULE_DESCRIPTION("Bosch BMA023/BMA1x0/BMA25x triaxial acceleration sensor");
MODULE_LICENSE("GPL");
......@@ -449,9 +449,6 @@ static void exynos_adc_exynos7_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
if (info->data->needs_adc_phy)
regmap_write(info->pmu_map, info->data->phy_offset, 1);
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
......@@ -531,8 +528,19 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
unsigned long timeout;
int ret;
if (mask != IIO_CHAN_INFO_RAW)
if (mask == IIO_CHAN_INFO_SCALE) {
ret = regulator_get_voltage(info->vdd);
if (ret < 0)
return ret;
/* Regulator voltage is in uV, but need mV */
*val = ret / 1000;
*val2 = info->data->mask;
return IIO_VAL_FRACTIONAL;
} else if (mask != IIO_CHAN_INFO_RAW) {
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
......@@ -683,6 +691,7 @@ static const struct iio_info exynos_adc_iio_info = {
.channel = _index, \
.address = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = _id, \
}
......
......@@ -65,12 +65,14 @@ struct stm32_adc_priv;
* @clk_sel: clock selection routine
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
* @has_syscfg: SYSCFG capability flags
* @num_irqs: number of interrupt lines
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
u32 max_clk_rate_hz;
unsigned int has_syscfg;
unsigned int num_irqs;
};
/**
......@@ -375,22 +377,16 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
unsigned int i;
for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
priv->irq[i] = platform_get_irq(pdev, i);
if (priv->irq[i] < 0) {
/*
* At least one interrupt must be provided, make others
* optional:
* - stm32f4/h7 shares a common interrupt.
* - stm32mp1, has one line per ADC (either for ADC1,
* ADC2 or both).
* Interrupt(s) must be provided, depending on the compatible:
* - stm32f4/h7 shares a common interrupt line.
* - stm32mp1, has one line per ADC
*/
if (i && priv->irq[i] == -ENXIO)
continue;
for (i = 0; i < priv->cfg->num_irqs; i++) {
priv->irq[i] = platform_get_irq(pdev, i);
if (priv->irq[i] < 0)
return priv->irq[i];
}
}
priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
&stm32_adc_domain_ops,
......@@ -400,9 +396,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
return -ENOMEM;
}
for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
if (priv->irq[i] < 0)
continue;
for (i = 0; i < priv->cfg->num_irqs; i++) {
irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler);
irq_set_handler_data(priv->irq[i], priv);
}
......@@ -420,11 +414,8 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
irq_domain_remove(priv->domain);
for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
if (priv->irq[i] < 0)
continue;
for (i = 0; i < priv->cfg->num_irqs; i++)
irq_set_chained_handler(priv->irq[i], NULL);
}
}
static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv,
......@@ -817,6 +808,7 @@ static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel,
.max_clk_rate_hz = 36000000,
.num_irqs = 1,
};
static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
......@@ -824,6 +816,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
.clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 36000000,
.has_syscfg = HAS_VBOOSTER,
.num_irqs = 1,
};
static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
......@@ -831,6 +824,7 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 40000000,
.has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD,
.num_irqs = 2,
};
static const struct of_device_id stm32_adc_of_match[] = {
......
......@@ -22,6 +22,17 @@ config ATLAS_PH_SENSOR
To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor.
config ATLAS_EZO_SENSOR
tristate "Atlas Scientific EZO sensors"
depends on I2C
help
Say Y here to build I2C interface support for the following
Atlas Scientific EZO sensors
* CO2 EZO Sensor
To compile this driver as module, choose M here: the
module will be called atlas-ezo-sensor.
config BME680
tristate "Bosch Sensortec BME680 sensor driver"
depends on (I2C || SPI)
......
......@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-sensor.o
obj-$(CONFIG_ATLAS_EZO_SENSOR) += atlas-ezo-sensor.o
obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* atlas-ezo-sensor.c - Support for Atlas Scientific EZO sensors
*
* Copyright (C) 2020 Konsulko Group
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/iio/iio.h>
#define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor"
#define ATLAS_CO2_INT_TIME_IN_MS 950
enum {
ATLAS_CO2_EZO,
};
struct atlas_ezo_device {
const struct iio_chan_spec *channels;
int num_channels;
int delay;
};
struct atlas_ezo_data {
struct i2c_client *client;
struct atlas_ezo_device *chip;
/* lock to avoid multiple concurrent read calls */
struct mutex lock;
u8 buffer[8];
};
static const struct iio_chan_spec atlas_co2_ezo_channels[] = {
{
.type = IIO_CONCENTRATION,
.modified = 1,
.channel2 = IIO_MOD_CO2,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
},
};
static struct atlas_ezo_device atlas_ezo_devices[] = {
[ATLAS_CO2_EZO] = {
.channels = atlas_co2_ezo_channels,
.num_channels = 1,
.delay = ATLAS_CO2_INT_TIME_IN_MS,
},
};
static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct atlas_ezo_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
int ret = 0;
if (chan->type != IIO_CONCENTRATION)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW: {
long tmp;
mutex_lock(&data->lock);
tmp = i2c_smbus_write_byte(client, 'R');
if (tmp < 0) {
mutex_unlock(&data->lock);
return tmp;
}
msleep(data->chip->delay);
tmp = i2c_master_recv(client, data->buffer, sizeof(data->buffer));
if (tmp < 0 || data->buffer[0] != 1) {
mutex_unlock(&data->lock);
return -EBUSY;
}
ret = kstrtol(data->buffer + 1, 10, &tmp);
*val = tmp;
mutex_unlock(&data->lock);
return ret ? ret : IIO_VAL_INT;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 100; /* 0.0001 */
return IIO_VAL_INT_PLUS_MICRO;
}
return ret;
}
static const struct iio_info atlas_info = {
.read_raw = atlas_ezo_read_raw,
};
static const struct i2c_device_id atlas_ezo_id[] = {
{ "atlas-co2-ezo", ATLAS_CO2_EZO },
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
static const struct of_device_id atlas_ezo_dt_ids[] = {
{ .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, },
{}
};
MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
static int atlas_ezo_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct atlas_ezo_data *data;
struct atlas_ezo_device *chip;
const struct of_device_id *of_id;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
of_id = of_match_device(atlas_ezo_dt_ids, &client->dev);
if (!of_id)
chip = &atlas_ezo_devices[id->driver_data];
else
chip = &atlas_ezo_devices[(unsigned long)of_id->data];
indio_dev->info = &atlas_info;
indio_dev->name = ATLAS_EZO_DRV_NAME;
indio_dev->channels = chip->channels;
indio_dev->num_channels = chip->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->dev.parent = &client->dev;
data = iio_priv(indio_dev);
data->client = client;
data->chip = chip;
mutex_init(&data->lock);
return devm_iio_device_register(&client->dev, indio_dev);
};
static struct i2c_driver atlas_ezo_driver = {
.driver = {
.name = ATLAS_EZO_DRV_NAME,
.of_match_table = atlas_ezo_dt_ids,
},
.probe = atlas_ezo_probe,
.id_table = atlas_ezo_id,
};
module_i2c_driver(atlas_ezo_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Atlas Scientific EZO sensors");
MODULE_LICENSE("GPL");
......@@ -73,6 +73,11 @@ struct pms7003_state {
struct pms7003_frame frame;
struct completion frame_ready;
struct mutex lock; /* must be held whenever state gets touched */
/* Used to construct scan to push to the IIO buffer */
struct {
u16 data[3]; /* PM1, PM2P5, PM10 */
s64 ts;
} scan;
};
static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
......@@ -104,7 +109,6 @@ static irqreturn_t pms7003_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
u16 data[3 + 1 + 4]; /* PM1, PM2P5, PM10, padding, timestamp */
int ret;
mutex_lock(&state->lock);
......@@ -114,12 +118,15 @@ static irqreturn_t pms7003_trigger_handler(int irq, void *p)
goto err;
}
data[PM1] = pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
data[PM2P5] = pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
data[PM10] = pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
state->scan.data[PM1] =
pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
state->scan.data[PM2P5] =
pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
state->scan.data[PM10] =
pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
mutex_unlock(&state->lock);
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_push_to_buffers_with_timestamp(indio_dev, &state->scan,
iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
......
......@@ -230,15 +230,18 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct sps30_state *state = iio_priv(indio_dev);
int ret;
s32 data[4 + 2]; /* PM1, PM2P5, PM4, PM10, timestamp */
struct {
s32 data[4]; /* PM1, PM2P5, PM4, PM10 */
s64 ts;
} scan;
mutex_lock(&state->lock);
ret = sps30_do_meas(state, data, 4);
ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data));
mutex_unlock(&state->lock);
if (ret)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_push_to_buffers_with_timestamp(indio_dev, &scan,
iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
......
......@@ -67,6 +67,7 @@ struct ad5360_chip_info {
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulators
* @ctrl: control register cache
* @lock lock to protect the data buffer during SPI ops
* @data: spi transfer buffers
*/
......@@ -75,6 +76,7 @@ struct ad5360_state {
const struct ad5360_chip_info *chip_info;
struct regulator_bulk_data vref_reg[3];
unsigned int ctrl;
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
......@@ -205,10 +207,11 @@ static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
unsigned int addr, unsigned int val, unsigned int shift)
{
int ret;
struct ad5360_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -229,7 +232,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
},
};
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
AD5360_ADDR(AD5360_REG_SF_READBACK) |
......@@ -240,7 +243,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -261,7 +264,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
struct ad5360_state *st = iio_priv(indio_dev);
unsigned int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->ctrl |= set;
st->ctrl &= ~clr;
......@@ -269,7 +272,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
AD5360_REG_SF_CTRL, st->ctrl, 0);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -479,6 +482,8 @@ static int ad5360_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = st->chip_info->num_channels;
mutex_init(&st->lock);
ret = ad5360_alloc_channels(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
......
......@@ -51,6 +51,7 @@ struct ad5380_chip_info {
* @vref_reg: vref supply regulator
* @vref: actual reference voltage used in uA
* @pwr_down: whether the chip is currently in power down mode
* @lock lock to protect the data buffer during regmap ops
*/
struct ad5380_state {
......@@ -59,6 +60,7 @@ struct ad5380_state {
struct regulator *vref_reg;
int vref;
bool pwr_down;
struct mutex lock;
};
enum ad5380_type {
......@@ -98,7 +100,7 @@ static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
if (pwr_down)
ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
......@@ -107,7 +109,7 @@ static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
st->pwr_down = pwr_down;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret ? ret : len;
}
......@@ -390,6 +392,8 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = st->chip_info->num_channels;
mutex_init(&st->lock);
ret = ad5380_alloc_channels(indio_dev);
if (ret) {
dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
......
......@@ -62,12 +62,14 @@
* @current_range: current range which the device is configured for
* @data: spi transfer buffers
* @fault_mask: software masking of events
* @lock lock to protect the data buffer during SPI ops
*/
struct ad5421_state {
struct spi_device *spi;
unsigned int ctrl;
enum ad5421_current_range current_range;
unsigned int fault_mask;
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
......@@ -142,11 +144,12 @@ static int ad5421_write_unlocked(struct iio_dev *indio_dev,
static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
struct ad5421_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad5421_write_unlocked(indio_dev, reg, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -166,7 +169,7 @@ static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
},
};
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
......@@ -174,7 +177,7 @@ static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -185,14 +188,14 @@ static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->ctrl &= ~clr;
st->ctrl |= set;
ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -400,12 +403,12 @@ static int ad5421_write_event_config(struct iio_dev *indio_dev,
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
if (state)
st->fault_mask |= mask;
else
st->fault_mask &= ~mask;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return 0;
}
......@@ -491,6 +494,8 @@ static int ad5421_probe(struct spi_device *spi)
indio_dev->channels = ad5421_channels;
indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
mutex_init(&st->lock);
st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
AD5421_CTRL_AUTO_FAULT_READBACK;
......
......@@ -33,6 +33,7 @@
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @lock lock to protect the data buffer during write ops
*/
struct ad5446_state {
......@@ -43,6 +44,7 @@ struct ad5446_state {
unsigned cached_val;
unsigned pwr_down_mode;
unsigned pwr_down;
struct mutex lock;
};
/**
......@@ -112,7 +114,7 @@ static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->pwr_down = powerdown;
if (st->pwr_down) {
......@@ -123,7 +125,7 @@ static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
}
ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret ? ret : len;
}
......@@ -197,11 +199,11 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
val <<= chan->scan_type.shift;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->cached_val = val;
if (!st->pwr_down)
ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
break;
default:
ret = -EINVAL;
......@@ -256,6 +258,8 @@ static int ad5446_probe(struct device *dev, const char *name,
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
mutex_init(&st->lock);
st->pwr_down_mode = MODE_PWRDWN_1k;
if (st->chip_info->int_vref_mv)
......
......@@ -56,11 +56,13 @@ struct ad5449_chip_info {
* @has_sdo: whether the SDO line is connected
* @dac_cache: Cache for the DAC values
* @data: spi transfer buffers
* @lock lock to protect the data buffer during SPI ops
*/
struct ad5449 {
struct spi_device *spi;
const struct ad5449_chip_info *chip_info;
struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS];
struct mutex lock;
bool has_sdo;
uint16_t dac_cache[AD5449_MAX_CHANNELS];
......@@ -87,10 +89,10 @@ static int ad5449_write(struct iio_dev *indio_dev, unsigned int addr,
struct ad5449 *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0] = cpu_to_be16((addr << 12) | val);
ret = spi_write(st->spi, st->data, 2);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -112,7 +114,7 @@ static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr,
},
};
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0] = cpu_to_be16(addr << 12);
st->data[1] = cpu_to_be16(AD5449_CMD_NOOP);
......@@ -123,7 +125,7 @@ static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr,
*val = be16_to_cpu(st->data[1]);
out_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -302,6 +304,8 @@ static int ad5449_spi_probe(struct spi_device *spi)
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
mutex_init(&st->lock);
if (st->chip_info->has_ctrl) {
unsigned int ctrl = 0x00;
if (pdata) {
......
......@@ -156,7 +156,6 @@ static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
static int ad5592r_reset(struct ad5592r_state *st)
{
struct gpio_desc *gpio;
struct iio_dev *iio_dev = iio_priv_to_dev(st);
gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
......@@ -166,10 +165,10 @@ static int ad5592r_reset(struct ad5592r_state *st)
udelay(1);
gpiod_set_value(gpio, 1);
} else {
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
/* Writing this magic value resets the device */
st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
}
udelay(250);
......@@ -197,7 +196,6 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
const struct ad5592r_rw_ops *ops = st->ops;
int ret;
unsigned i;
struct iio_dev *iio_dev = iio_priv_to_dev(st);
u8 pulldown = 0, tristate = 0, dac = 0, adc = 0;
u16 read_back;
......@@ -247,7 +245,7 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
}
}
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
/* Pull down unused pins to GND */
ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
......@@ -285,7 +283,7 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
ret = -EIO;
err_unlock:
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -314,11 +312,11 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
if (!chan->output)
return -EINVAL;
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
ret = st->ops->write_dac(st, chan->channel, val);
if (!ret)
st->cached_dac[chan->channel] = val;
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_VOLTAGE) {
......@@ -333,12 +331,12 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
else
return -EINVAL;
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
&st->cached_gp_ctrl);
if (ret < 0) {
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -360,7 +358,7 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
st->cached_gp_ctrl);
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -382,7 +380,7 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
if (!chan->output) {
ret = st->ops->read_adc(st, chan->channel, &read_val);
......@@ -419,7 +417,7 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
} else {
int mult;
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
if (chan->output)
mult = !!(st->cached_gp_ctrl &
......@@ -437,7 +435,7 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_OFFSET:
ret = ad5592r_get_vref(st);
mutex_lock(&iio_dev->mlock);
mutex_lock(&st->lock);
if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
*val = (-34365 * 25) / ret;
......@@ -450,7 +448,7 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
}
unlock:
mutex_unlock(&iio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -625,6 +623,8 @@ int ad5592r_probe(struct device *dev, const char *name,
iio_dev->info = &ad5592r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
mutex_init(&st->lock);
ad5592r_init_scales(st, ad5592r_get_vref(st));
ret = ad5592r_reset(st);
......
......@@ -52,6 +52,7 @@ struct ad5592r_state {
struct regulator *reg;
struct gpio_chip gpiochip;
struct mutex gpio_lock; /* Protect cached gpio_out, gpio_val, etc. */
struct mutex lock;
unsigned int num_channels;
const struct ad5592r_rw_ops *ops;
int scale_avail[2][2];
......
......@@ -127,9 +127,9 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = st->read(st, chan->address);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
......@@ -157,12 +157,12 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = st->write(st,
AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
chan->address,
val << chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
break;
default:
ret = -EINVAL;
......@@ -468,6 +468,8 @@ int ad5686_probe(struct device *dev,
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
mutex_init(&st->lock);
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
......
......@@ -117,6 +117,7 @@ struct ad5686_chip_info {
* @pwr_down_mask: power down mask
* @pwr_down_mode: current power down mode
* @use_internal_vref: set to true if the internal reference voltage is used
* @lock lock to protect the data buffer during regmap ops
* @data: spi transfer buffers
*/
......@@ -130,6 +131,7 @@ struct ad5686_state {
ad5686_write_func write;
ad5686_read_func read;
bool use_internal_vref;
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
......
......@@ -82,6 +82,7 @@ struct ad5755_chip_info {
* @pwr_down: bitmask which contains hether a channel is powered down or not
* @ctrl: software shadow of the channel ctrl registers
* @channels: iio channel spec for the device
* @lock lock to protect the data buffer during SPI ops
* @data: spi transfer buffers
*/
struct ad5755_state {
......@@ -90,6 +91,7 @@ struct ad5755_state {
unsigned int pwr_down;
unsigned int ctrl[AD5755_NUM_CHANNELS];
struct iio_chan_spec channels[AD5755_NUM_CHANNELS];
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
......@@ -174,11 +176,12 @@ static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev,
static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
struct ad5755_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad5755_write_unlocked(indio_dev, reg, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -186,11 +189,12 @@ static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg,
static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel,
unsigned int reg, unsigned int val)
{
struct ad5755_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -211,7 +215,7 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
},
};
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16));
st->data[1].d32 = cpu_to_be32(AD5755_NOOP);
......@@ -220,7 +224,7 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -246,7 +250,7 @@ static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev,
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int mask = BIT(channel);
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
if ((bool)(st->pwr_down & mask) == pwr_down)
goto out_unlock;
......@@ -266,7 +270,7 @@ static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev,
}
out_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return 0;
}
......@@ -746,6 +750,8 @@ static int ad5755_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5755_NUM_CHANNELS;
mutex_init(&st->lock);
if (spi->dev.of_node)
pdata = ad5755_parse_dt(&spi->dev);
else
......
......@@ -57,11 +57,13 @@ enum ad5761_supported_device_ids {
* @use_intref: true when the internal voltage reference is used
* @vref: actual voltage reference in mVolts
* @range: output range mode used
* @lock lock to protect the data buffer during SPI ops
* @data: cache aligned spi buffer
*/
struct ad5761_state {
struct spi_device *spi;
struct regulator *vref_reg;
struct mutex lock;
bool use_intref;
int vref;
......@@ -124,9 +126,9 @@ static int ad5761_spi_write(struct iio_dev *indio_dev, u8 addr, u16 val)
struct ad5761_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = _ad5761_spi_write(st, addr, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -163,9 +165,9 @@ static int ad5761_spi_read(struct iio_dev *indio_dev, u8 addr, u16 *val)
struct ad5761_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = _ad5761_spi_read(st, addr, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -368,6 +370,8 @@ static int ad5761_probe(struct spi_device *spi)
if (pdata)
voltage_range = pdata->voltage_range;
mutex_init(&st->lock);
ret = ad5761_spi_set_range(st, voltage_range);
if (ret)
goto disable_regulator_err;
......
......@@ -46,6 +46,7 @@ struct ad5764_chip_info {
* @spi: spi_device
* @chip_info: chip info
* @vref_reg: vref supply regulators
* @lock lock to protect the data buffer during SPI ops
* @data: spi transfer buffers
*/
......@@ -53,6 +54,7 @@ struct ad5764_state {
struct spi_device *spi;
const struct ad5764_chip_info *chip_info;
struct regulator_bulk_data vref_reg[2];
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
......@@ -126,11 +128,11 @@ static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg,
struct ad5764_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0].d32 = cpu_to_be32((reg << 16) | val);
ret = spi_write(st->spi, &st->data[0].d8[1], 3);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -151,7 +153,7 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
},
};
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
......@@ -159,7 +161,7 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
if (ret >= 0)
*val = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
......@@ -295,6 +297,8 @@ static int ad5764_probe(struct spi_device *spi)
indio_dev->num_channels = AD5764_NUM_CHANNELS;
indio_dev->channels = st->chip_info->channels;
mutex_init(&st->lock);
if (st->chip_info->int_vref == 0) {
st->vref_reg[0].supply = "vrefAB";
st->vref_reg[1].supply = "vrefCD";
......
......@@ -36,6 +36,7 @@ struct vf610_dac {
struct device *dev;
enum vf610_conversion_mode_sel conv_mode;
void __iomem *regs;
struct mutex lock;
};
static void vf610_dac_init(struct vf610_dac *info)
......@@ -64,7 +65,7 @@ static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
struct vf610_dac *info = iio_priv(indio_dev);
int val;
mutex_lock(&indio_dev->mlock);
mutex_lock(&info->lock);
info->conv_mode = mode;
val = readl(info->regs + VF610_DACx_STATCTRL);
if (mode)
......@@ -72,7 +73,7 @@ static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
else
val &= ~VF610_DAC_LPEN;
writel(val, info->regs + VF610_DACx_STATCTRL);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&info->lock);
return 0;
}
......@@ -147,9 +148,9 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
mutex_lock(&info->lock);
writel(VF610_DAC_DAT0(val), info->regs);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&info->lock);
return 0;
default:
......@@ -205,6 +206,8 @@ static int vf610_dac_probe(struct platform_device *pdev)
indio_dev->channels = vf610_dac_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vf610_dac_iio_channels);
mutex_init(&info->lock);
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev,
......
......@@ -927,6 +927,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
indio_dev->active_scan_mask = config->scan_mask;
indio_dev->scan_timestamp = config->scan_timestamp;
indio_dev->scan_bytes = config->scan_bytes;
indio_dev->currentmode = config->mode;
iio_update_demux(indio_dev);
......@@ -962,8 +963,6 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
goto err_disable_buffers;
}
indio_dev->currentmode = config->mode;
if (indio_dev->setup_ops->postenable) {
ret = indio_dev->setup_ops->postenable(indio_dev);
if (ret) {
......@@ -980,10 +979,10 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
buffer_list)
iio_buffer_disable(buffer, indio_dev);
err_run_postdisable:
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
err_undo_config:
indio_dev->currentmode = INDIO_DIRECT_MODE;
indio_dev->active_scan_mask = NULL;
return ret;
......@@ -1018,8 +1017,6 @@ static int iio_disable_buffers(struct iio_dev *indio_dev)
ret = ret2;
}
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
ret2 = indio_dev->setup_ops->postdisable(indio_dev);
if (ret2 && !ret)
......@@ -1028,6 +1025,7 @@ static int iio_disable_buffers(struct iio_dev *indio_dev)
iio_free_scan_mask(indio_dev, indio_dev->active_scan_mask);
indio_dev->active_scan_mask = NULL;
indio_dev->currentmode = INDIO_DIRECT_MODE;
return ret;
}
......@@ -1244,7 +1242,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
struct iio_dev_attr *p;
struct attribute **attr;
struct iio_buffer *buffer = indio_dev->buffer;
int ret, i, attrn, attrcount, attrcount_orig = 0;
int ret, i, attrn, attrcount;
const struct iio_chan_spec *channels;
channels = indio_dev->channels;
......@@ -1288,7 +1286,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
attrcount = attrcount_orig;
attrcount = 0;
INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
channels = indio_dev->channels;
if (channels) {
......@@ -1325,7 +1323,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_free_scan_mask;
}
attrn = attrcount_orig;
attrn = 0;
list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
......
......@@ -158,6 +158,9 @@ static irqreturn_t gp2ap002_prox_irq(int irq, void *d)
int val;
int ret;
if (!gp2ap002->enabled)
goto err_retrig;
ret = regmap_read(gp2ap002->map, GP2AP002_PROX, &val);
if (ret) {
dev_err(gp2ap002->dev, "error reading proximity\n");
......@@ -247,6 +250,8 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev,
struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
int ret;
pm_runtime_get_sync(gp2ap002->dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
......@@ -255,13 +260,21 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
ret = IIO_VAL_INT;
goto out;
default:
return -EINVAL;
ret = -EINVAL;
goto out;
}
default:
return -EINVAL;
ret = -EINVAL;
}
out:
pm_runtime_mark_last_busy(gp2ap002->dev);
pm_runtime_put_autosuspend(gp2ap002->dev);
return ret;
}
static int gp2ap002_init(struct gp2ap002 *gp2ap002)
......
......@@ -140,6 +140,17 @@ config SRF08
To compile this driver as a module, choose M here: the
module will be called srf08.
config VCNL3020
tristate "VCNL3020 proximity sensor"
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VCNL3020
proximity sensor.
To compile this driver as a module, choose M here: the
module will be called vcnl3020.
config VL53L0X_I2C
tristate "STMicroelectronics VL53L0X ToF ranger sensor (I2C)"
depends on I2C
......
......@@ -14,5 +14,6 @@ obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9310) += sx9310.o
obj-$(CONFIG_SX9500) += sx9500.o
obj-$(CONFIG_VCNL3020) += vcnl3020.o
obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o
......@@ -89,14 +89,14 @@ static irqreturn_t ping_handle_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int ping_read(struct ping_data *data)
static int ping_read(struct iio_dev *indio_dev)
{
struct ping_data *data = iio_priv(indio_dev);
int ret;
ktime_t ktime_dt;
s64 dt_ns;
u32 time_ns, distance_mm;
struct platform_device *pdev = to_platform_device(data->dev);
struct iio_dev *indio_dev = iio_priv_to_dev(data);
/*
* just one read-echo-cycle can take place at a time
......@@ -228,7 +228,6 @@ static int ping_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long info)
{
struct ping_data *data = iio_priv(indio_dev);
int ret;
if (channel->type != IIO_DISTANCE)
......@@ -236,7 +235,7 @@ static int ping_read_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_RAW:
ret = ping_read(data);
ret = ping_read(indio_dev);
if (ret < 0)
return ret;
*val = ret;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for Vishay VCNL3020 proximity sensor on i2c bus.
* Based on Vishay VCNL4000 driver code.
*
* TODO: interrupts.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define VCNL3020_PROD_ID 0x21
#define VCNL_COMMAND 0x80 /* Command register */
#define VCNL_PROD_REV 0x81 /* Product ID and Revision ID */
#define VCNL_PROXIMITY_RATE 0x82 /* Rate of Proximity Measurement */
#define VCNL_LED_CURRENT 0x83 /* IR LED current for proximity mode */
#define VCNL_PS_RESULT_HI 0x87 /* Proximity result register, MSB */
#define VCNL_PS_RESULT_LO 0x88 /* Proximity result register, LSB */
#define VCNL_PS_ICR 0x89 /* Interrupt Control Register */
#define VCNL_PS_LO_THR_HI 0x8a /* High byte of low threshold value */
#define VCNL_PS_LO_THR_LO 0x8b /* Low byte of low threshold value */
#define VCNL_PS_HI_THR_HI 0x8c /* High byte of high threshold value */
#define VCNL_PS_HI_THR_LO 0x8d /* Low byte of high threshold value */
#define VCNL_ISR 0x8e /* Interrupt Status Register */
#define VCNL_PS_MOD_ADJ 0x8f /* Proximity Modulator Timing Adjustment */
/* Bit masks for COMMAND register */
#define VCNL_PS_RDY BIT(5) /* proximity data ready? */
#define VCNL_PS_OD BIT(3) /* start on-demand proximity
* measurement
*/
#define VCNL_ON_DEMAND_TIMEOUT_US 100000
#define VCNL_POLL_US 20000
/**
* struct vcnl3020_data - vcnl3020 specific data.
* @regmap: device register map.
* @dev: vcnl3020 device.
* @rev: revision id.
* @lock: lock for protecting access to device hardware registers.
*/
struct vcnl3020_data {
struct regmap *regmap;
struct device *dev;
u8 rev;
struct mutex lock;
};
/**
* struct vcnl3020_property - vcnl3020 property.
* @name: property name.
* @reg: i2c register offset.
* @conversion_func: conversion function.
*/
struct vcnl3020_property {
const char *name;
u32 reg;
u32 (*conversion_func)(u32 *val);
};
static u32 microamp_to_reg(u32 *val)
{
/*
* An example of conversion from uA to reg val:
* 200000 uA == 200 mA == 20
*/
return *val /= 10000;
};
static struct vcnl3020_property vcnl3020_led_current_property = {
.name = "vishay,led-current-microamp",
.reg = VCNL_LED_CURRENT,
.conversion_func = microamp_to_reg,
};
static int vcnl3020_get_and_apply_property(struct vcnl3020_data *data,
struct vcnl3020_property prop)
{
int rc;
u32 val;
rc = device_property_read_u32(data->dev, prop.name, &val);
if (rc)
return 0;
if (prop.conversion_func)
prop.conversion_func(&val);
rc = regmap_write(data->regmap, prop.reg, val);
if (rc) {
dev_err(data->dev, "Error (%d) setting property (%s)\n",
rc, prop.name);
}
return rc;
}
static int vcnl3020_init(struct vcnl3020_data *data)
{
int rc;
unsigned int reg;
rc = regmap_read(data->regmap, VCNL_PROD_REV, &reg);
if (rc) {
dev_err(data->dev,
"Error (%d) reading product revision\n", rc);
return rc;
}
if (reg != VCNL3020_PROD_ID) {
dev_err(data->dev,
"Product id (%x) did not match vcnl3020 (%x)\n", reg,
VCNL3020_PROD_ID);
return -ENODEV;
}
data->rev = reg;
mutex_init(&data->lock);
return vcnl3020_get_and_apply_property(data,
vcnl3020_led_current_property);
};
static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
{
int rc;
unsigned int reg;
__be16 res;
mutex_lock(&data->lock);
rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD);
if (rc)
goto err_unlock;
/* wait for data to become ready */
rc = regmap_read_poll_timeout(data->regmap, VCNL_COMMAND, reg,
reg & VCNL_PS_RDY, VCNL_POLL_US,
VCNL_ON_DEMAND_TIMEOUT_US);
if (rc) {
dev_err(data->dev,
"Error (%d) reading vcnl3020 command register\n", rc);
goto err_unlock;
}
/* high & low result bytes read */
rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &res,
sizeof(res));
if (rc)
goto err_unlock;
*val = be16_to_cpu(res);
err_unlock:
mutex_unlock(&data->lock);
return rc;
}
static const struct iio_chan_spec vcnl3020_channels[] = {
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
};
static int vcnl3020_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int rc;
struct vcnl3020_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
rc = vcnl3020_measure_proximity(data, val);
if (rc)
return rc;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info vcnl3020_info = {
.read_raw = vcnl3020_read_raw,
};
static const struct regmap_config vcnl3020_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = VCNL_PS_MOD_ADJ,
};
static int vcnl3020_probe(struct i2c_client *client)
{
struct vcnl3020_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
int rc;
regmap = devm_regmap_init_i2c(client, &vcnl3020_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap_init failed\n");
return PTR_ERR(regmap);
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->regmap = regmap;
data->dev = &client->dev;
rc = vcnl3020_init(data);
if (rc)
return rc;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &vcnl3020_info;
indio_dev->channels = vcnl3020_channels;
indio_dev->num_channels = ARRAY_SIZE(vcnl3020_channels);
indio_dev->name = "vcnl3020";
indio_dev->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct of_device_id vcnl3020_of_match[] = {
{
.compatible = "vishay,vcnl3020",
},
{}
};
MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
static struct i2c_driver vcnl3020_driver = {
.driver = {
.name = "vcnl3020",
.of_match_table = vcnl3020_of_match,
},
.probe_new = vcnl3020_probe,
};
module_i2c_driver(vcnl3020_driver);
MODULE_AUTHOR("Ivan Mikhaylov <i.mikhaylov@yadro.com>");
MODULE_DESCRIPTION("Vishay VCNL3020 proximity sensor driver");
MODULE_LICENSE("GPL");
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